celerp 2.3.1__tar.gz → 2.3.3__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.
Files changed (651) hide show
  1. {celerp-2.3.1 → celerp-2.3.3}/PKG-INFO +1 -1
  2. celerp-2.3.3/celerp/db.py +136 -0
  3. {celerp-2.3.1 → celerp-2.3.3}/celerp/events/schemas.py +54 -4
  4. celerp-2.3.3/celerp/inventory_codes.py +87 -0
  5. {celerp-2.3.1 → celerp-2.3.3}/celerp/main.py +20 -10
  6. celerp-2.3.3/celerp/migrations/versions/bc0d1e2f3a4b_barcode_unique_index.py +119 -0
  7. celerp-2.3.3/celerp/migrations/versions/c9d8e7f6a5b4_seed_shrinkage_writeoff_account.py +65 -0
  8. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/projections.py +16 -1
  9. {celerp-2.3.1 → celerp-2.3.3}/celerp/modules/migrations_runner.py +33 -29
  10. {celerp-2.3.1 → celerp-2.3.3}/celerp/projections/engine.py +26 -2
  11. {celerp-2.3.1 → celerp-2.3.3}/celerp/routers/doctor.py +8 -3
  12. {celerp-2.3.1 → celerp-2.3.3}/celerp/routers/ledger.py +15 -5
  13. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/auto_je.py +2 -2
  14. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/cost_visibility.py +17 -1
  15. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/field_schema.py +20 -1
  16. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/fulfill.py +22 -0
  17. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/system_health.py +19 -8
  18. {celerp-2.3.1 → celerp-2.3.3}/celerp/tax_regimes.py +16 -0
  19. {celerp-2.3.1 → celerp-2.3.3}/celerp.egg-info/PKG-INFO +1 -1
  20. {celerp-2.3.1 → celerp-2.3.3}/celerp.egg-info/SOURCES.txt +15 -0
  21. {celerp-2.3.1 → celerp-2.3.3}/celerp.egg-info/scm_file_list.json +32 -0
  22. celerp-2.3.3/celerp.egg-info/scm_version.json +8 -0
  23. {celerp-2.3.1 → celerp-2.3.3}/conftest.py +15 -1
  24. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/celerp_accounting/routes.py +1 -0
  25. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/report_goldens/statement.html +1 -0
  26. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-admin/celerp_admin/routes.py +34 -29
  27. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/celerp_docs/doc_constants.py +3 -2
  28. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/celerp_docs/doc_projections.py +11 -0
  29. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/celerp_docs/routes.py +1014 -421
  30. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/celerp_docs/routes_payments.py +5 -5
  31. celerp-2.3.3/default_modules/celerp-docs/tests/test_audits.py +815 -0
  32. celerp-2.3.3/default_modules/celerp-docs/tests/test_bulk_payment_alloc_lock.py +502 -0
  33. celerp-2.3.3/default_modules/celerp-docs/tests/test_cross_lot_settlement.py +168 -0
  34. celerp-2.3.3/default_modules/celerp-docs/tests/test_list_concurrency.py +291 -0
  35. celerp-2.3.3/default_modules/celerp-docs/tests/test_list_outcome_concurrency.py +632 -0
  36. celerp-2.3.3/default_modules/celerp-docs/tests/test_memo_close.py +176 -0
  37. celerp-2.3.3/default_modules/celerp-docs/tests/test_memo_close_projection.py +26 -0
  38. celerp-2.3.3/default_modules/celerp-docs/tests/test_memo_close_review_fixes.py +450 -0
  39. celerp-2.3.3/default_modules/celerp-docs/tests/test_memo_lifecycle_concurrency.py +992 -0
  40. celerp-2.3.3/default_modules/celerp-docs/tests/test_memo_line_labels.py +191 -0
  41. celerp-2.3.3/default_modules/celerp-docs/tests/test_memo_unfulfilled_filter.py +47 -0
  42. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_send_visibility.py +16 -0
  43. celerp-2.3.3/default_modules/celerp-docs/tests/test_sold_label_ordering.py +95 -0
  44. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_writeoffs.py +303 -1
  45. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-inventory/celerp_inventory/routes.py +527 -112
  46. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-inventory/celerp_inventory/routes_scanning.py +3 -1
  47. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-inventory/celerp_inventory/services.py +96 -0
  48. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/routes.py +5 -2
  49. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/celerp_manufacturing/routes.py +25 -0
  50. celerp-2.3.3/default_modules/celerp-manufacturing/tests/test_completion_lock_order.py +240 -0
  51. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_run_records.py +18 -0
  52. {celerp-2.3.1 → celerp-2.3.3}/default_modules/first_party.lock.json +6 -6
  53. {celerp-2.3.1 → celerp-2.3.3}/ui/api_client.py +56 -5
  54. {celerp-2.3.1 → celerp-2.3.3}/ui/components/shell.py +6 -2
  55. {celerp-2.3.1 → celerp-2.3.3}/ui/locales/am.json +27 -10
  56. {celerp-2.3.1 → celerp-2.3.3}/ui/locales/ar.json +27 -10
  57. {celerp-2.3.1 → celerp-2.3.3}/ui/locales/de.json +27 -10
  58. {celerp-2.3.1 → celerp-2.3.3}/ui/locales/en.json +28 -11
  59. {celerp-2.3.1 → celerp-2.3.3}/ui/locales/es.json +27 -10
  60. {celerp-2.3.1 → celerp-2.3.3}/ui/locales/fr.json +27 -10
  61. {celerp-2.3.1 → celerp-2.3.3}/ui/locales/id.json +27 -10
  62. {celerp-2.3.1 → celerp-2.3.3}/ui/locales/it.json +27 -10
  63. {celerp-2.3.1 → celerp-2.3.3}/ui/locales/ja.json +27 -10
  64. {celerp-2.3.1 → celerp-2.3.3}/ui/locales/pt.json +27 -10
  65. {celerp-2.3.1 → celerp-2.3.3}/ui/locales/th.json +27 -10
  66. {celerp-2.3.1 → celerp-2.3.3}/ui/locales/vi.json +27 -10
  67. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/documents.py +398 -172
  68. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/inventory.py +15 -1
  69. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/settings_cloud.py +0 -12
  70. {celerp-2.3.1 → celerp-2.3.3}/ui/static/app.css +1 -1
  71. celerp-2.3.1/celerp/db.py +0 -61
  72. celerp-2.3.1/celerp.egg-info/scm_version.json +0 -8
  73. celerp-2.3.1/default_modules/celerp-docs/tests/test_audits.py +0 -355
  74. {celerp-2.3.1 → celerp-2.3.3}/CLA.md +0 -0
  75. {celerp-2.3.1 → celerp-2.3.3}/CONTRIBUTING.md +0 -0
  76. {celerp-2.3.1 → celerp-2.3.3}/LICENSE +0 -0
  77. {celerp-2.3.1 → celerp-2.3.3}/LICENSING.md +0 -0
  78. {celerp-2.3.1 → celerp-2.3.3}/MANIFEST.in +0 -0
  79. {celerp-2.3.1 → celerp-2.3.3}/NOTICE +0 -0
  80. {celerp-2.3.1 → celerp-2.3.3}/README.md +0 -0
  81. {celerp-2.3.1 → celerp-2.3.3}/alembic.ini +0 -0
  82. {celerp-2.3.1 → celerp-2.3.3}/celerp/__init__.py +0 -0
  83. {celerp-2.3.1 → celerp-2.3.3}/celerp/__main__.py +0 -0
  84. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/__init__.py +0 -0
  85. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/batch.py +0 -0
  86. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/cleanup.py +0 -0
  87. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/commands.py +0 -0
  88. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/conversations.py +0 -0
  89. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/files.py +0 -0
  90. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/intent.py +0 -0
  91. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/llm.py +0 -0
  92. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/memory.py +0 -0
  93. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/models.py +0 -0
  94. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/page_count.py +0 -0
  95. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/quota.py +0 -0
  96. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/service.py +0 -0
  97. {celerp-2.3.1 → celerp-2.3.3}/celerp/ai/tools.py +0 -0
  98. {celerp-2.3.1 → celerp-2.3.3}/celerp/alembic.ini +0 -0
  99. {celerp-2.3.1 → celerp-2.3.3}/celerp/alembic_config.py +0 -0
  100. {celerp-2.3.1 → celerp-2.3.3}/celerp/cli.py +0 -0
  101. {celerp-2.3.1 → celerp-2.3.3}/celerp/compat.py +0 -0
  102. {celerp-2.3.1 → celerp-2.3.3}/celerp/compute/__init__.py +0 -0
  103. {celerp-2.3.1 → celerp-2.3.3}/celerp/compute/aggregations.py +0 -0
  104. {celerp-2.3.1 → celerp-2.3.3}/celerp/compute/valuation.py +0 -0
  105. {celerp-2.3.1 → celerp-2.3.3}/celerp/config.py +0 -0
  106. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/__init__.py +0 -0
  107. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/base.py +0 -0
  108. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/daily_scheduler.py +0 -0
  109. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/http.py +0 -0
  110. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/images.py +0 -0
  111. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/quickbooks.py +0 -0
  112. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/registry.py +0 -0
  113. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/relay_token.py +0 -0
  114. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/shopify.py +0 -0
  115. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/sync_runner.py +0 -0
  116. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/upsert.py +0 -0
  117. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/util.py +0 -0
  118. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/webhooks.py +0 -0
  119. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/woocommerce.py +0 -0
  120. {celerp-2.3.1 → celerp-2.3.3}/celerp/connectors/xero.py +0 -0
  121. {celerp-2.3.1 → celerp-2.3.3}/celerp/constants.py +0 -0
  122. {celerp-2.3.1 → celerp-2.3.3}/celerp/embedded_pg.py +0 -0
  123. {celerp-2.3.1 → celerp-2.3.3}/celerp/events/__init__.py +0 -0
  124. {celerp-2.3.1 → celerp-2.3.3}/celerp/events/engine.py +0 -0
  125. {celerp-2.3.1 → celerp-2.3.3}/celerp/events/types.py +0 -0
  126. {celerp-2.3.1 → celerp-2.3.3}/celerp/gateway/__init__.py +0 -0
  127. {celerp-2.3.1 → celerp-2.3.3}/celerp/gateway/client.py +0 -0
  128. {celerp-2.3.1 → celerp-2.3.3}/celerp/gateway/state.py +0 -0
  129. {celerp-2.3.1 → celerp-2.3.3}/celerp/importers/__init__.py +0 -0
  130. {celerp-2.3.1 → celerp-2.3.3}/celerp/importers/importer.py +0 -0
  131. {celerp-2.3.1 → celerp-2.3.3}/celerp/importers/schema.py +0 -0
  132. {celerp-2.3.1 → celerp-2.3.3}/celerp/middleware.py +0 -0
  133. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/README.md +0 -0
  134. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/_auto_stamp.py +0 -0
  135. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/_data_reconcile.py +0 -0
  136. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/_json_compat.py +0 -0
  137. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/env.py +0 -0
  138. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/script.py.mako +0 -0
  139. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/a0b1c2d3e4f5_seed_landed_cost_clearing_accounts.py +0 -0
  140. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/a1b2c3d4e5f6_add_doc_share_tokens.py +0 -0
  141. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/b1c2d3e4f5a6_add_supporter_badges.py +0 -0
  142. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/b2c3d4e5f6a7_add_import_batches.py +0 -0
  143. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/b3c4d5e6f7a8_expand_role_permissions_to_role_grants.py +0 -0
  144. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/c1d2e3f4a5b6_add_marketplace.py +0 -0
  145. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/c2d3e4f5a6b7_add_is_sync_to_shopify.py +0 -0
  146. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/c4d5e6f7a8b9_account_cash_flow_category.py +0 -0
  147. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/d0e1f2a3b4c5_add_share_token_expiry.py +0 -0
  148. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/d2e3f4a5b6c7_add_password_reset_token.py +0 -0
  149. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/d5e6f7a8b9c0_rename_fx_rounding_to_fx_difference.py +0 -0
  150. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/e3f4a5b6c7d8_add_company_is_active.py +0 -0
  151. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/e4f5a6b7c8d9_backfill_connector_idempotency_key.py +0 -0
  152. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/e7c9a1b3d5f2_work_center_default_columns.py +0 -0
  153. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/f1a2b3c4d5e6_move_accounts_marketplace_to_modules.py +0 -0
  154. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/f6a7b8c9d0e1_seed_fx_rounding_account.py +0 -0
  155. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/f8a9b0c1d2e3_work_center_default_backfill.py +0 -0
  156. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/fd5de461e14e_initial_schema.py +0 -0
  157. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/g1h2i3j4k5l6_add_consignment_flag.py +0 -0
  158. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/h2i3j4k5l6m7_add_bank_accounts_and_reconciliation.py +0 -0
  159. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/j4k5l6m7n8o9_labels_db_persistence.py +0 -0
  160. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/k5l6m7n8o9p0_add_reconciliation_v2.py +0 -0
  161. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/l6m7n8o9p0q1_add_sync_runs_table.py +0 -0
  162. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/m7n8o9p0q1r2_add_connector_configs_and_outbound_queue.py +0 -0
  163. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/n8o9p0q1r2s3_backfill_payment_date.py +0 -0
  164. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/o9p0q1r2s3t4_backfill_item_price_fields.py +0 -0
  165. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/p1q2r3s4t5u6_add_session_registry_and_user_auth_state.py +0 -0
  166. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/q2r3s4t5u6v7_add_system_runtime_state.py +0 -0
  167. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/r3s4t5u6v7w8_add_projections_company_entity_type_index.py +0 -0
  168. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/s4t5u6v7w8x9_drop_user_company_id_role.py +0 -0
  169. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/t5u6v7w8x9y0_seed_inventory_sub_accounts.py +0 -0
  170. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/u6v7w8x9y0z1_backfill_item_prices_from_attributes.py +0 -0
  171. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/v7w8x9y0z1a2_backfill_purchase_unit_defaults.py +0 -0
  172. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/w8x9y0z1a2b3_backfill_category_unit_defaults.py +0 -0
  173. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/x7y8z9a0b1c2_add_projection_created_at.py +0 -0
  174. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/y8z9a0b1c2d3_per_company_ledger_idempotency.py +0 -0
  175. {celerp-2.3.1 → celerp-2.3.3}/celerp/migrations/versions/z9a0b1c2d3e4_work_centers.py +0 -0
  176. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/__init__.py +0 -0
  177. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/accounting.py +0 -0
  178. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/ai.py +0 -0
  179. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/auth.py +0 -0
  180. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/base.py +0 -0
  181. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/company.py +0 -0
  182. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/connector_config.py +0 -0
  183. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/import_batch.py +0 -0
  184. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/ledger.py +0 -0
  185. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/marketplace.py +0 -0
  186. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/notification.py +0 -0
  187. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/share.py +0 -0
  188. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/supporter.py +0 -0
  189. {celerp-2.3.1 → celerp-2.3.3}/celerp/models/sync_run.py +0 -0
  190. {celerp-2.3.1 → celerp-2.3.3}/celerp/modules/__init__.py +0 -0
  191. {celerp-2.3.1 → celerp-2.3.3}/celerp/modules/api.py +0 -0
  192. {celerp-2.3.1 → celerp-2.3.3}/celerp/modules/audit.py +0 -0
  193. {celerp-2.3.1 → celerp-2.3.3}/celerp/modules/demotion.py +0 -0
  194. {celerp-2.3.1 → celerp-2.3.3}/celerp/modules/importer.py +0 -0
  195. {celerp-2.3.1 → celerp-2.3.3}/celerp/modules/license.py +0 -0
  196. {celerp-2.3.1 → celerp-2.3.3}/celerp/modules/loader.py +0 -0
  197. {celerp-2.3.1 → celerp-2.3.3}/celerp/modules/meta.py +0 -0
  198. {celerp-2.3.1 → celerp-2.3.3}/celerp/modules/references.py +0 -0
  199. {celerp-2.3.1 → celerp-2.3.3}/celerp/modules/registry.py +0 -0
  200. {celerp-2.3.1 → celerp-2.3.3}/celerp/modules/slots.py +0 -0
  201. {celerp-2.3.1 → celerp-2.3.3}/celerp/notifications/__init__.py +0 -0
  202. {celerp-2.3.1 → celerp-2.3.3}/celerp/notifications/service.py +0 -0
  203. {celerp-2.3.1 → celerp-2.3.3}/celerp/notifications/sse.py +0 -0
  204. {celerp-2.3.1 → celerp-2.3.3}/celerp/output/__init__.py +0 -0
  205. {celerp-2.3.1 → celerp-2.3.3}/celerp/output/branding.py +0 -0
  206. {celerp-2.3.1 → celerp-2.3.3}/celerp/output/doc_print.py +0 -0
  207. {celerp-2.3.1 → celerp-2.3.3}/celerp/output/pdf.py +0 -0
  208. {celerp-2.3.1 → celerp-2.3.3}/celerp/output/share_render.py +0 -0
  209. {celerp-2.3.1 → celerp-2.3.3}/celerp/projections/__init__.py +0 -0
  210. {celerp-2.3.1 → celerp-2.3.3}/celerp/projections/handlers/__init__.py +0 -0
  211. {celerp-2.3.1 → celerp-2.3.3}/celerp/projections/handlers/marketplace.py +0 -0
  212. {celerp-2.3.1 → celerp-2.3.3}/celerp/projections/handlers/scanning.py +0 -0
  213. {celerp-2.3.1 → celerp-2.3.3}/celerp/projections/handlers/shopify.py +0 -0
  214. {celerp-2.3.1 → celerp-2.3.3}/celerp/projections/handlers/system.py +0 -0
  215. {celerp-2.3.1 → celerp-2.3.3}/celerp/routers/__init__.py +0 -0
  216. {celerp-2.3.1 → celerp-2.3.3}/celerp/routers/auth.py +0 -0
  217. {celerp-2.3.1 → celerp-2.3.3}/celerp/routers/companies.py +0 -0
  218. {celerp-2.3.1 → celerp-2.3.3}/celerp/routers/debug.py +0 -0
  219. {celerp-2.3.1 → celerp-2.3.3}/celerp/routers/events.py +0 -0
  220. {celerp-2.3.1 → celerp-2.3.3}/celerp/routers/health.py +0 -0
  221. {celerp-2.3.1 → celerp-2.3.3}/celerp/routers/notifications.py +0 -0
  222. {celerp-2.3.1 → celerp-2.3.3}/celerp/routers/stars.py +0 -0
  223. {celerp-2.3.1 → celerp-2.3.3}/celerp/routers/system.py +0 -0
  224. {celerp-2.3.1 → celerp-2.3.3}/celerp/schemas/__init__.py +0 -0
  225. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/__init__.py +0 -0
  226. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/activity_redaction.py +0 -0
  227. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/attachments.py +0 -0
  228. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/auth.py +0 -0
  229. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/backup.py +0 -0
  230. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/backup_export.py +0 -0
  231. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/backup_import.py +0 -0
  232. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/backup_repo.py +0 -0
  233. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/backup_scheduler.py +0 -0
  234. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/backup_state.py +0 -0
  235. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/cogs_backfill.py +0 -0
  236. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/demo.py +0 -0
  237. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/dev_release_guard.py +0 -0
  238. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/email.py +0 -0
  239. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/holdings.py +0 -0
  240. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/je_keys.py +0 -0
  241. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/landed_cost.py +0 -0
  242. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/line_measures.py +0 -0
  243. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/list_behavior.py +0 -0
  244. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/money.py +0 -0
  245. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/payments.py +0 -0
  246. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/permissions.py +0 -0
  247. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/pick.py +0 -0
  248. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/pricing.py +0 -0
  249. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/relay_share.py +0 -0
  250. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/reorder.py +0 -0
  251. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/runtime_state.py +0 -0
  252. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/session_tracker.py +0 -0
  253. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/shipping.py +0 -0
  254. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/star_cta.py +0 -0
  255. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/status_doc_backfill.py +0 -0
  256. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/supporter_badge.py +0 -0
  257. {celerp-2.3.1 → celerp-2.3.3}/celerp/services/units.py +0 -0
  258. {celerp-2.3.1 → celerp-2.3.3}/celerp/session_gate.py +0 -0
  259. {celerp-2.3.1 → celerp-2.3.3}/celerp.egg-info/dependency_links.txt +0 -0
  260. {celerp-2.3.1 → celerp-2.3.3}/celerp.egg-info/entry_points.txt +0 -0
  261. {celerp-2.3.1 → celerp-2.3.3}/celerp.egg-info/requires.txt +0 -0
  262. {celerp-2.3.1 → celerp-2.3.3}/celerp.egg-info/top_level.txt +0 -0
  263. {celerp-2.3.1 → celerp-2.3.3}/conftest_support.py +0 -0
  264. {celerp-2.3.1 → celerp-2.3.3}/default_modules/__init__.py +0 -0
  265. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/LICENSE +0 -0
  266. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/__init__.py +0 -0
  267. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/celerp_accounting/__init__.py +0 -0
  268. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/celerp_accounting/api_setup.py +0 -0
  269. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/celerp_accounting/csv_parser.py +0 -0
  270. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/celerp_accounting/matcher.py +0 -0
  271. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/celerp_accounting/models.py +0 -0
  272. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/celerp_accounting/projections.py +0 -0
  273. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/celerp_accounting/ui_routes.py +0 -0
  274. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/report_goldens/balance-sheet.html +0 -0
  275. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/report_goldens/cash-flow.html +0 -0
  276. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-csv.csv +0 -0
  277. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-print.html +0 -0
  278. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/report_goldens/extended-journal.html +0 -0
  279. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/report_goldens/general-ledger.html +0 -0
  280. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/report_goldens/journal-csv.csv +0 -0
  281. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/report_goldens/journal-print.html +0 -0
  282. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/report_goldens/journal.html +0 -0
  283. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/report_goldens/ledger.html +0 -0
  284. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/report_goldens/pnl.html +0 -0
  285. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/report_goldens/trial-balance.html +0 -0
  286. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/test_accounting_banking.py +0 -0
  287. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/test_accounting_banking_routers.py +0 -0
  288. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/test_accounting_gaps.py +0 -0
  289. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/test_accounting_import_idempotency.py +0 -0
  290. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/test_cash_flow.py +0 -0
  291. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/test_financial_reports_ui.py +0 -0
  292. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/test_journal_gl_soa.py +0 -0
  293. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/test_journal_gl_soa_ui.py +0 -0
  294. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/test_reconciliation_v2.py +0 -0
  295. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/test_reports_end_to_end.py +0 -0
  296. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-accounting/tests/test_route_permissions.py +0 -0
  297. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-admin/__init__.py +0 -0
  298. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-admin/celerp_admin/__init__.py +0 -0
  299. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-admin/celerp_admin/setup.py +0 -0
  300. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/__init__.py +0 -0
  301. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/celerp_ai/__init__.py +0 -0
  302. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/celerp_ai/routes.py +0 -0
  303. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/celerp_ai/setup.py +0 -0
  304. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/celerp_ai/ui_routes.py +0 -0
  305. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/conftest.py +0 -0
  306. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_batch.py +0 -0
  307. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_cleanup.py +0 -0
  308. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_conversations.py +0 -0
  309. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_coverage_gaps.py +0 -0
  310. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_intent.py +0 -0
  311. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_llm.py +0 -0
  312. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_memory.py +0 -0
  313. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_models.py +0 -0
  314. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_page_count.py +0 -0
  315. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_quota.py +0 -0
  316. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_router.py +0 -0
  317. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_routes_coverage.py +0 -0
  318. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_service.py +0 -0
  319. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-ai/tests/test_tools.py +0 -0
  320. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-backup/__init__.py +0 -0
  321. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-backup/celerp_backup/__init__.py +0 -0
  322. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-backup/celerp_backup/routes.py +0 -0
  323. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-backup/celerp_backup/setup.py +0 -0
  324. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/__init__.py +0 -0
  325. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/celerp_connectors/__init__.py +0 -0
  326. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/celerp_connectors/models.py +0 -0
  327. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/celerp_connectors/routes.py +0 -0
  328. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/__init__.py +0 -0
  329. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/conftest.py +0 -0
  330. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/test_compliance.py +0 -0
  331. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/test_connector_correctness.py +0 -0
  332. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/test_connectors.py +0 -0
  333. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/test_credentials_routes.py +0 -0
  334. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/test_images.py +0 -0
  335. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/test_outbound.py +0 -0
  336. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/test_quickbooks.py +0 -0
  337. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/test_rate_limiting.py +0 -0
  338. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/test_shopify.py +0 -0
  339. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/test_wiring.py +0 -0
  340. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/test_woocommerce.py +0 -0
  341. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/test_woocommerce_webhooks.py +0 -0
  342. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-connectors/tests/test_xero.py +0 -0
  343. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-contacts/LICENSE +0 -0
  344. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-contacts/__init__.py +0 -0
  345. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-contacts/celerp_contacts/__init__.py +0 -0
  346. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-contacts/celerp_contacts/migrations.py +0 -0
  347. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-contacts/celerp_contacts/projections.py +0 -0
  348. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-contacts/celerp_contacts/routes.py +0 -0
  349. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-contacts/celerp_contacts/services.py +0 -0
  350. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-contacts/celerp_contacts/ui_routes.py +0 -0
  351. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-dashboard/LICENSE +0 -0
  352. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-dashboard/__init__.py +0 -0
  353. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-dashboard/celerp_dashboard/__init__.py +0 -0
  354. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-dashboard/celerp_dashboard/routes.py +0 -0
  355. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-dashboard/celerp_dashboard/setup.py +0 -0
  356. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/LICENSE +0 -0
  357. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/__init__.py +0 -0
  358. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/celerp_docs/__init__.py +0 -0
  359. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/celerp_docs/api_setup.py +0 -0
  360. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/celerp_docs/doc_email.py +0 -0
  361. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/celerp_docs/doc_service.py +0 -0
  362. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/celerp_docs/models_share.py +0 -0
  363. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/celerp_docs/routes_share.py +0 -0
  364. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/celerp_docs/sequences.py +0 -0
  365. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/celerp_docs/taxes.py +0 -0
  366. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/celerp_docs/ui_routes.py +0 -0
  367. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/conftest.py +0 -0
  368. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_consolidate_lots.py +0 -0
  369. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_freight_je.py +0 -0
  370. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_freight_lines.py +0 -0
  371. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_fulfill_no_split.py +0 -0
  372. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_fulfillment_activity.py +0 -0
  373. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_inbound_je_lifecycle.py +0 -0
  374. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_inventory_account_reconciliation.py +0 -0
  375. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_landed_receive.py +0 -0
  376. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_line_delete_persist.py +0 -0
  377. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_line_identifier.py +0 -0
  378. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_payment_void_activity.py +0 -0
  379. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_receive_sku_batch.py +0 -0
  380. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_service_lines.py +0 -0
  381. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-docs/tests/test_void_guards.py +0 -0
  382. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-inventory/LICENSE +0 -0
  383. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-inventory/__init__.py +0 -0
  384. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-inventory/celerp_inventory/__init__.py +0 -0
  385. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-inventory/celerp_inventory/models_import_batch.py +0 -0
  386. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-inventory/celerp_inventory/projections.py +0 -0
  387. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-inventory/celerp_inventory/routes_attachments.py +0 -0
  388. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-inventory/celerp_inventory/ui_routes.py +0 -0
  389. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-inventory/tests/test_item_recipe_projection.py +0 -0
  390. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-inventory/tests/test_item_workflow_projection.py +0 -0
  391. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-inventory/tests/test_landed_cost_projection.py +0 -0
  392. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/LICENSE +0 -0
  393. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/__init__.py +0 -0
  394. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/__init__.py +0 -0
  395. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/locales/am.json +0 -0
  396. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/locales/ar.json +0 -0
  397. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/locales/de.json +0 -0
  398. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/locales/en.json +0 -0
  399. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/locales/es.json +0 -0
  400. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/locales/fr.json +0 -0
  401. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/locales/id.json +0 -0
  402. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/locales/it.json +0 -0
  403. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/locales/ja.json +0 -0
  404. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/locales/pt.json +0 -0
  405. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/locales/th.json +0 -0
  406. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/locales/vi.json +0 -0
  407. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/models.py +0 -0
  408. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/presets.py +0 -0
  409. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/service.py +0 -0
  410. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/celerp_labels/ui_routes.py +0 -0
  411. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/requirements.txt +0 -0
  412. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/tests/test_labels.py +0 -0
  413. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-labels/tests/test_labels_module.py +0 -0
  414. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/LICENSE +0 -0
  415. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/__init__.py +0 -0
  416. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/celerp_manufacturing/__init__.py +0 -0
  417. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/celerp_manufacturing/costing.py +0 -0
  418. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/celerp_manufacturing/expansion.py +0 -0
  419. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/celerp_manufacturing/labor.py +0 -0
  420. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/celerp_manufacturing/migrations.py +0 -0
  421. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/celerp_manufacturing/projection_handler.py +0 -0
  422. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/celerp_manufacturing/ui_routes.py +0 -0
  423. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/requirements.txt +0 -0
  424. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_auto_complete_on_finalize.py +0 -0
  425. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_bom_removed.py +0 -0
  426. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_build_api.py +0 -0
  427. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_item_recipe_api.py +0 -0
  428. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_item_workflow_api.py +0 -0
  429. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_labor_providers.py +0 -0
  430. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_manufacture_from_doc.py +0 -0
  431. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_manufacturing.py +0 -0
  432. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_manufacturing_import_idempotency.py +0 -0
  433. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_manufacturing_module.py +0 -0
  434. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_mfg_events.py +0 -0
  435. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_phase2_manufacturing_validations.py +0 -0
  436. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_production_order.py +0 -0
  437. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_recipe_costing.py +0 -0
  438. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_recipe_expansion.py +0 -0
  439. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_recost_api.py +0 -0
  440. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_to_make_allocation.py +0 -0
  441. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_where_used.py +0 -0
  442. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_work_centers_and_settings.py +0 -0
  443. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-manufacturing/tests/test_workflow_time.py +0 -0
  444. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-reports/LICENSE +0 -0
  445. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-reports/__init__.py +0 -0
  446. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-reports/celerp_reports/__init__.py +0 -0
  447. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-reports/celerp_reports/api_setup.py +0 -0
  448. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-reports/celerp_reports/routes.py +0 -0
  449. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-reports/celerp_reports/ui_routes.py +0 -0
  450. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-reports/tests/test_reports_full.py +0 -0
  451. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-reports/tests/test_reports_unit.py +0 -0
  452. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-subscriptions/LICENSE +0 -0
  453. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-subscriptions/__init__.py +0 -0
  454. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-subscriptions/celerp_subscriptions/__init__.py +0 -0
  455. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-subscriptions/celerp_subscriptions/routes.py +0 -0
  456. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-subscriptions/celerp_subscriptions/ui_routes.py +0 -0
  457. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-subscriptions/tests/test_subscriptions.py +0 -0
  458. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-subscriptions/tests/test_subscriptions_ui.py +0 -0
  459. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/LICENSE +0 -0
  460. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/__init__.py +0 -0
  461. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/__init__.py +0 -0
  462. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/accessory_fashion.json +0 -0
  463. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/activewear.json +0 -0
  464. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/art_photography.json +0 -0
  465. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/audio_equipment.json +0 -0
  466. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/bag_handbag.json +0 -0
  467. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/banknote.json +0 -0
  468. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/beauty_tool.json +0 -0
  469. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/bed_bedroom.json +0 -0
  470. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/beer.json +0 -0
  471. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/beverage_nonalc.json +0 -0
  472. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/body_part_auto.json +0 -0
  473. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/book.json +0 -0
  474. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/bottoms.json +0 -0
  475. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/brake_suspension.json +0 -0
  476. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/bullion_coin.json +0 -0
  477. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/camera.json +0 -0
  478. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/colored_stone.json +0 -0
  479. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/comic.json +0 -0
  480. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/commercial_space.json +0 -0
  481. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/component_part.json +0 -0
  482. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/confectionery.json +0 -0
  483. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/consulting_service.json +0 -0
  484. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/decorative_art.json +0 -0
  485. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/diamond.json +0 -0
  486. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/drawing.json +0 -0
  487. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/dress_jumpsuit.json +0 -0
  488. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_auto.json +0 -0
  489. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_component.json +0 -0
  490. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/emerald.json +0 -0
  491. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/engine_part.json +0 -0
  492. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/fastener.json +0 -0
  493. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/fertilizer_chemical.json +0 -0
  494. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/film_video.json +0 -0
  495. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/fine_writing_instrument.json +0 -0
  496. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/fluid_lubricant.json +0 -0
  497. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/footwear.json +0 -0
  498. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/fragrance.json +0 -0
  499. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_food.json +0 -0
  500. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_produce.json +0 -0
  501. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/frozen_food.json +0 -0
  502. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/gaming_console.json +0 -0
  503. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/gold_bullion.json +0 -0
  504. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/grain_cereal.json +0 -0
  505. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/haircare.json +0 -0
  506. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/hand_tool.json +0 -0
  507. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/ingredient_bulk.json +0 -0
  508. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/interior_part.json +0 -0
  509. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/jewelry.json +0 -0
  510. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/kitchen_dining.json +0 -0
  511. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/laptop.json +0 -0
  512. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/lighting.json +0 -0
  513. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/livestock_feed.json +0 -0
  514. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/makeup.json +0 -0
  515. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/measuring_instrument.json +0 -0
  516. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/medal_token.json +0 -0
  517. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/mineral_specimen.json +0 -0
  518. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/mobile_phone.json +0 -0
  519. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/music_cd.json +0 -0
  520. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/music_vinyl.json +0 -0
  521. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/nail.json +0 -0
  522. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/numismatic_coin.json +0 -0
  523. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/outdoor_furniture.json +0 -0
  524. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/outerwear.json +0 -0
  525. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/packaged_food.json +0 -0
  526. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/painting.json +0 -0
  527. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/parking_bay.json +0 -0
  528. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/pearl.json +0 -0
  529. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/personal_care.json +0 -0
  530. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/pipe_plumbing.json +0 -0
  531. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/platinum_bullion.json +0 -0
  532. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/power_tool.json +0 -0
  533. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/print_edition.json +0 -0
  534. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/residential_unit.json +0 -0
  535. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/rough_gemstone.json +0 -0
  536. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/ruby.json +0 -0
  537. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/saas_plan.json +0 -0
  538. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/safety_ppe.json +0 -0
  539. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/sapphire.json +0 -0
  540. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/sculpture.json +0 -0
  541. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/seating.json +0 -0
  542. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/seeds.json +0 -0
  543. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/silver_bullion.json +0 -0
  544. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/skincare.json +0 -0
  545. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/soft_furnishing.json +0 -0
  546. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/software_addon.json +0 -0
  547. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/software_license.json +0 -0
  548. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/spirit.json +0 -0
  549. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/storage_furniture.json +0 -0
  550. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/swimwear.json +0 -0
  551. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/table_desk.json +0 -0
  552. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/tablet.json +0 -0
  553. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/tire_wheel.json +0 -0
  554. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/tops.json +0 -0
  555. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/trading_card.json +0 -0
  556. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/tv_display.json +0 -0
  557. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/video_game.json +0 -0
  558. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/watch.json +0 -0
  559. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/watch_strap.json +0 -0
  560. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/categories/wine.json +0 -0
  561. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/agricultural.json +0 -0
  562. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/artwork.json +0 -0
  563. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/automotive.json +0 -0
  564. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/blank.json +0 -0
  565. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/books_media.json +0 -0
  566. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/coins_precious_metals.json +0 -0
  567. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/consulting.json +0 -0
  568. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/cosmetics.json +0 -0
  569. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/electronics.json +0 -0
  570. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/fashion.json +0 -0
  571. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/food_beverage.json +0 -0
  572. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/furniture.json +0 -0
  573. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/gemstones.json +0 -0
  574. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/hardware.json +0 -0
  575. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/property_rental.json +0 -0
  576. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/saas.json +0 -0
  577. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/watches.json +0 -0
  578. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/presets/wine_spirits.json +0 -0
  579. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/routes.py +0 -0
  580. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/celerp_verticals/ui_routes.py +0 -0
  581. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/tests/test_verticals.py +0 -0
  582. {celerp-2.3.1 → celerp-2.3.3}/default_modules/celerp-verticals/tests/test_verticals_routers.py +0 -0
  583. {celerp-2.3.1 → celerp-2.3.3}/legal/OFFICIAL-COMPONENTS.md +0 -0
  584. {celerp-2.3.1 → celerp-2.3.3}/legal/TRADEMARK.md +0 -0
  585. {celerp-2.3.1 → celerp-2.3.3}/packaging/winget/Celerp.Celerp.installer.yaml +0 -0
  586. {celerp-2.3.1 → celerp-2.3.3}/packaging/winget/Celerp.Celerp.locale.en-US.yaml +0 -0
  587. {celerp-2.3.1 → celerp-2.3.3}/packaging/winget/Celerp.Celerp.yaml +0 -0
  588. {celerp-2.3.1 → celerp-2.3.3}/packaging/winget/README.md +0 -0
  589. {celerp-2.3.1 → celerp-2.3.3}/pyproject.toml +0 -0
  590. {celerp-2.3.1 → celerp-2.3.3}/setup.cfg +0 -0
  591. {celerp-2.3.1 → celerp-2.3.3}/test_helpers.py +0 -0
  592. {celerp-2.3.1 → celerp-2.3.3}/ui/__init__.py +0 -0
  593. {celerp-2.3.1 → celerp-2.3.3}/ui/app.py +0 -0
  594. {celerp-2.3.1 → celerp-2.3.3}/ui/components/__init__.py +0 -0
  595. {celerp-2.3.1 → celerp-2.3.3}/ui/components/activity.py +0 -0
  596. {celerp-2.3.1 → celerp-2.3.3}/ui/components/attrs.py +0 -0
  597. {celerp-2.3.1 → celerp-2.3.3}/ui/components/backup.py +0 -0
  598. {celerp-2.3.1 → celerp-2.3.3}/ui/components/cloud_gate.py +0 -0
  599. {celerp-2.3.1 → celerp-2.3.3}/ui/components/currency.py +0 -0
  600. {celerp-2.3.1 → celerp-2.3.3}/ui/components/files.py +0 -0
  601. {celerp-2.3.1 → celerp-2.3.3}/ui/components/journal.py +0 -0
  602. {celerp-2.3.1 → celerp-2.3.3}/ui/components/notes.py +0 -0
  603. {celerp-2.3.1 → celerp-2.3.3}/ui/components/phone.py +0 -0
  604. {celerp-2.3.1 → celerp-2.3.3}/ui/components/report_kit.py +0 -0
  605. {celerp-2.3.1 → celerp-2.3.3}/ui/components/table.py +0 -0
  606. {celerp-2.3.1 → celerp-2.3.3}/ui/config.py +0 -0
  607. {celerp-2.3.1 → celerp-2.3.3}/ui/i18n.py +0 -0
  608. {celerp-2.3.1 → celerp-2.3.3}/ui/marketplace_catalog.py +0 -0
  609. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/__init__.py +0 -0
  610. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/account.py +0 -0
  611. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/accounting.py +0 -0
  612. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/accounting_import.py +0 -0
  613. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/auth.py +0 -0
  614. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/contacts.py +0 -0
  615. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/csv_import.py +0 -0
  616. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/dashboard.py +0 -0
  617. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/docs_import.py +0 -0
  618. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/events.py +0 -0
  619. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/financial_reports.py +0 -0
  620. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/lists_import.py +0 -0
  621. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/manufacturing.py +0 -0
  622. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/modules_page.py +0 -0
  623. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/notifications.py +0 -0
  624. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/reconciliation.py +0 -0
  625. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/reports.py +0 -0
  626. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/search.py +0 -0
  627. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/settings.py +0 -0
  628. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/settings_accounting.py +0 -0
  629. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/settings_connectors.py +0 -0
  630. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/settings_contacts.py +0 -0
  631. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/settings_general.py +0 -0
  632. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/settings_import.py +0 -0
  633. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/settings_inventory.py +0 -0
  634. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/settings_manufacturing.py +0 -0
  635. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/settings_payments.py +0 -0
  636. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/settings_purchasing.py +0 -0
  637. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/settings_sales.py +0 -0
  638. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/setup.py +0 -0
  639. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/stars.py +0 -0
  640. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/subscriptions.py +0 -0
  641. {celerp-2.3.1 → celerp-2.3.3}/ui/routes/subscriptions_import.py +0 -0
  642. {celerp-2.3.1 → celerp-2.3.3}/ui/security.py +0 -0
  643. {celerp-2.3.1 → celerp-2.3.3}/ui/static/htmx.min.js +0 -0
  644. {celerp-2.3.1 → celerp-2.3.3}/ui/static/icon.png +0 -0
  645. {celerp-2.3.1 → celerp-2.3.3}/ui/static/logo.png +0 -0
  646. {celerp-2.3.1 → celerp-2.3.3}/ui/static/vendor/intl-tel-input/img/flags.webp +0 -0
  647. {celerp-2.3.1 → celerp-2.3.3}/ui/static/vendor/intl-tel-input/img/flags@2x.webp +0 -0
  648. {celerp-2.3.1 → celerp-2.3.3}/ui/static/vendor/intl-tel-input/intlTelInput.min.css +0 -0
  649. {celerp-2.3.1 → celerp-2.3.3}/ui/static/vendor/intl-tel-input/intlTelInput.min.js +0 -0
  650. {celerp-2.3.1 → celerp-2.3.3}/ui/static/vendor/intl-tel-input/intlTelInputWithUtils.min.js +0 -0
  651. {celerp-2.3.1 → celerp-2.3.3}/ui/static/vendor/intl-tel-input/utils.js +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: celerp
3
- Version: 2.3.1
3
+ Version: 2.3.3
4
4
  Summary: Free, self-hosted ERP for small businesses
5
5
  License: Business Source License 1.1
6
6
 
@@ -0,0 +1,136 @@
1
+ # Copyright (c) 2026 Noah Severs
2
+ # SPDX-License-Identifier: BUSL-1.1
3
+
4
+ import os
5
+ import re
6
+ from contextlib import asynccontextmanager
7
+
8
+ from sqlalchemy import text as _sql_text
9
+ from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
10
+ from sqlalchemy.pool import NullPool
11
+
12
+ from celerp.config import settings
13
+
14
+ # Shared advisory-lock key that serialises schema migrations across every process
15
+ # that might run them (the CLI upgrade command and the API startup phase). One
16
+ # key, one source of truth, so two boots can never migrate the same database at
17
+ # once.
18
+ _MIGRATION_LOCK_KEY = 4207320001
19
+
20
+ # Redacts the password in any Postgres URL: "://user:secret@host" -> "://user:***@host".
21
+ # One authoritative masker for logs and surfaced errors so a connection string
22
+ # never leaks a password.
23
+ _DB_CREDENTIALS_RE = re.compile(r"(://[^:]+:)[^@]+(@)")
24
+
25
+
26
+ def mask_db_credentials(text: str) -> str:
27
+ """Return text with any database URL password replaced by ``***``."""
28
+ return _DB_CREDENTIALS_RE.sub(r"\1***\2", text)
29
+
30
+ # Request-connection timeouts (ms). One source of truth: the engine sets them in
31
+ # server_settings, and lifecycle_timeouts_disabled restores exactly these values
32
+ # after clearing them for startup work.
33
+ _REQUEST_LOCK_TIMEOUT_MS = "3000"
34
+ _REQUEST_STATEMENT_TIMEOUT_MS = "30000"
35
+
36
+ # Pool budget: total_possible = (api_workers * (pool_size + max_overflow))
37
+ # + (gui_workers * (gui_pool_size + gui_max_overflow))
38
+ # Default workers 2 API + 1 GUI → 2*(10+5) + 1*(5+5) = 40 connections max.
39
+ # Postgres default max_connections=100 leaves 60 for migrations, admin tools, etc.
40
+ # If you increase worker counts, recalculate this budget before deploying.
41
+ if os.environ.get("CELERP_TEST_NULLPOOL"):
42
+ # Test mode: a fresh connection per use that closes on return, so a failed
43
+ # test can't leave a poisoned/locked connection lingering in a pooled
44
+ # connection and block the next test's TRUNCATE. Only ever set by the test
45
+ # harness; no effect in production.
46
+ engine = create_async_engine(settings.database_url, future=True, poolclass=NullPool)
47
+ else:
48
+ engine = create_async_engine(
49
+ settings.database_url,
50
+ future=True,
51
+ pool_pre_ping=True,
52
+ pool_size=10,
53
+ max_overflow=5,
54
+ # Bound how long any query may wait on a lock or run, so a stuck query is
55
+ # cancelled instead of pinning one of the few pooled connections for the
56
+ # full request lifetime (lock_timeout 3s, statement_timeout 30s, in ms).
57
+ # This is a per-connection default, so it applies to every request AND
58
+ # every pooled background job (connector syncs, the gateway, the daily
59
+ # scheduler) - all of which must stay bounded. Startup reconciliation and
60
+ # the projection rebuild are the only work that legitimately runs longer;
61
+ # they use lifecycle_engine below instead of this pool, and the migration
62
+ # advisory-lock wait self-exempts via lifecycle_timeouts_disabled.
63
+ connect_args={
64
+ "server_settings": {
65
+ "lock_timeout": _REQUEST_LOCK_TIMEOUT_MS,
66
+ "statement_timeout": _REQUEST_STATEMENT_TIMEOUT_MS,
67
+ }
68
+ },
69
+ )
70
+ SessionLocal = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
71
+
72
+ # Lifecycle/maintenance engine: a separate NullPool engine carrying NO statement
73
+ # or lock timeout. Startup reconciliation (create_all, module on_modules_ready
74
+ # seed hooks, the develop->release projection rebuild, the one-time status-doc and
75
+ # COGS backfills) and the on-demand projection rebuild routes run whole-table
76
+ # DELETEs and full-ledger replays that can legitimately exceed the request
77
+ # statement_timeout on a mature database. Running them on the bounded request pool
78
+ # would cancel them at 30s - permanently blocking boot's upgrade guard and the
79
+ # /ledger/rebuild recovery route. They run on this engine instead. NullPool: these
80
+ # operations are rare and brief, so no pooled slot is reserved and the request pool
81
+ # budget above is unaffected (at most one transient connection per concurrent
82
+ # lifecycle op).
83
+ lifecycle_engine = create_async_engine(settings.database_url, future=True, poolclass=NullPool)
84
+ LifecycleSessionLocal = async_sessionmaker(
85
+ lifecycle_engine, class_=AsyncSession, expire_on_commit=False
86
+ )
87
+
88
+
89
+ @asynccontextmanager
90
+ async def lifecycle_timeouts_disabled(conn):
91
+ """Clear the request statement/lock timeouts on the migration lock connection.
92
+
93
+ The migration advisory-lock wait runs on a connection drawn from the bounded
94
+ request engine (so a single engine serialises boots), but a second worker's
95
+ wait can legitimately exceed the 30s statement_timeout while the first worker
96
+ migrates, and a cancelled wait aborts the boot. This sets both timeouts to 0
97
+ (unbounded) for the block and restores the request defaults on exit, so the
98
+ connection returned to the pool still carries them. Other long-running startup
99
+ work uses lifecycle_engine (no timeout) rather than this in-place exemption.
100
+ Postgres only; a no-op on other dialects, which have no such settings.
101
+ """
102
+ if conn.dialect.name != "postgresql":
103
+ yield
104
+ return
105
+ await conn.execute(_sql_text("SET statement_timeout = 0"))
106
+ await conn.execute(_sql_text("SET lock_timeout = 0"))
107
+ try:
108
+ yield
109
+ finally:
110
+ await conn.execute(_sql_text(f"SET statement_timeout = {_REQUEST_STATEMENT_TIMEOUT_MS}"))
111
+ await conn.execute(_sql_text(f"SET lock_timeout = {_REQUEST_LOCK_TIMEOUT_MS}"))
112
+
113
+
114
+ async def get_session() -> AsyncSession:
115
+ async with SessionLocal() as session:
116
+ yield session
117
+
118
+
119
+ @asynccontextmanager
120
+ async def get_session_ctx():
121
+ """Standalone async context manager for use outside FastAPI request handlers."""
122
+ async with SessionLocal() as session:
123
+ yield session
124
+
125
+
126
+ @asynccontextmanager
127
+ async def get_lifecycle_session_ctx():
128
+ """Session on the unbounded lifecycle_engine, for known long-running work.
129
+
130
+ Use for the projection rebuild and startup backfills: a full rebuild's
131
+ whole-table DELETE and full-ledger replay can exceed the request
132
+ statement_timeout on a mature database, and must not be cancelled. Ordinary
133
+ request and background work uses get_session/get_session_ctx (bounded).
134
+ """
135
+ async with LifecycleSessionLocal() as session:
136
+ yield session
@@ -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 ItemCreated(BaseModel):
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(BaseModel):
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(BaseModel):
230
+ class ItemPatched(_SkuGuard):
192
231
  """CSV upsert patch: accepts any item data fields."""
193
232
  model_config = {"extra": "allow"}
194
233
 
@@ -507,6 +546,15 @@ class DocUnvoided(BaseModel):
507
546
  restored_status: str
508
547
 
509
548
 
549
+ class DocClosed(BaseModel):
550
+ reason: str | None = None
551
+ pre_close_status: str | None = None
552
+
553
+
554
+ class DocReopened(BaseModel):
555
+ restored_status: str
556
+
557
+
510
558
  class DocSent(BaseModel):
511
559
  sent_via: str | None = None
512
560
  sent_to: str | None = None
@@ -1123,6 +1171,8 @@ EVENT_SCHEMA_MAP: dict[str, type[BaseModel]] = {
1123
1171
  "doc.voided": DocVoided,
1124
1172
  "doc.reverted_to_draft": DocRevertedToDraft,
1125
1173
  "doc.unvoided": DocUnvoided,
1174
+ "doc.closed": DocClosed,
1175
+ "doc.reopened": DocReopened,
1126
1176
  "doc.converted_to_bill": DocConvertedToBill,
1127
1177
  "doc.sent": DocSent,
1128
1178
  "doc.payment.received": DocPaymentReceived,
@@ -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)
@@ -12,7 +12,8 @@ from slowapi import Limiter, _rate_limit_exceeded_handler
12
12
  from slowapi.errors import RateLimitExceeded
13
13
  from slowapi.util import get_remote_address
14
14
 
15
- from celerp.db import engine, mask_db_credentials
15
+ from celerp.db import engine, lifecycle_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()
@@ -163,7 +164,7 @@ async def _try_auto_activate() -> None:
163
164
  async def lifespan(_app: FastAPI):
164
165
  (settings.data_dir / "static" / "attachments").mkdir(parents=True, exist_ok=True)
165
166
  try:
166
- async with engine.begin() as conn:
167
+ async with lifecycle_engine.begin() as conn:
167
168
  await conn.run_sync(Base.metadata.create_all)
168
169
  except Exception as exc:
169
170
  masked_url = mask_db_credentials(settings.database_url)
@@ -204,19 +205,20 @@ async def lifespan(_app: FastAPI):
204
205
  register_api_routes(_app, _loaded_modules)
205
206
  # Module models register on Base.metadata at import time.
206
207
  # Run create_all again so module tables are created (idempotent).
207
- async with engine.begin() as conn:
208
+ async with lifecycle_engine.begin() as conn:
208
209
  await conn.run_sync(Base.metadata.create_all)
209
210
  # Allow modules to backfill data for existing companies (e.g. seed
210
211
  # chart of accounts when accounting module is first enabled on an
211
212
  # instance that already has companies).
212
213
  from celerp.modules.slots import fire_lifecycle as _fire
213
- from celerp.db import SessionLocal as _SessionLocal
214
+ from celerp.db import LifecycleSessionLocal as _LifecycleSession
214
215
  # Best-effort, like the two sibling blocks below: a hook that fails
215
216
  # during flush poisons the shared session, so the commit raises.
216
217
  # Roll back and log at ERROR rather than let that crash boot - the
217
218
  # manufacturing seed hook, for one, must never be able to take the
218
- # app down.
219
- async with _SessionLocal() as _sess:
219
+ # app down. Seed hooks can replay large ledgers, so they run on the
220
+ # unbounded lifecycle engine, not the timeout-bounded request pool.
221
+ async with _LifecycleSession() as _sess:
220
222
  try:
221
223
  await _fire("on_modules_ready", session=_sess)
222
224
  await _sess.commit()
@@ -235,7 +237,7 @@ async def lifespan(_app: FastAPI):
235
237
  _demoted = demoted_first_party(_enabled)
236
238
  if _demoted:
237
239
  from celerp.modules.demotion import notify_demoted_modules
238
- async with _SessionLocal() as _dsess:
240
+ async with _LifecycleSession() as _dsess:
239
241
  await notify_demoted_modules(_dsess, _demoted)
240
242
  await _dsess.commit()
241
243
  except Exception:
@@ -255,7 +257,7 @@ async def lifespan(_app: FastAPI):
255
257
  # marker so it runs once per version. Non-fatal: a failure must not block
256
258
  # boot — the marker stays unset and a later boot retries.
257
259
  try:
258
- from celerp.db import SessionLocal as _GuardSession
260
+ from celerp.db import LifecycleSessionLocal as _GuardSession
259
261
  from celerp.services.dev_release_guard import run_upgrade_guard
260
262
  async with _GuardSession() as _guard_sess:
261
263
  await run_upgrade_guard(_guard_sess)
@@ -270,7 +272,7 @@ async def lifespan(_app: FastAPI):
270
272
  # or consigned in before that field shipped, so their inventory status links
271
273
  # to its document. Marker-gated (runs once); non-fatal like the guard above.
272
274
  try:
273
- from celerp.db import SessionLocal as _BackfillSession
275
+ from celerp.db import LifecycleSessionLocal as _BackfillSession
274
276
  from celerp.services.status_doc_backfill import run_status_doc_backfill
275
277
  async with _BackfillSession() as _bf_sess:
276
278
  await run_status_doc_backfill(_bf_sess)
@@ -286,7 +288,7 @@ async def lifespan(_app: FastAPI):
286
288
  # (runs once; retries stragglers while any doc is locked or errored);
287
289
  # non-fatal like the backfill above.
288
290
  try:
289
- from celerp.db import SessionLocal as _CogsSession
291
+ from celerp.db import LifecycleSessionLocal as _CogsSession
290
292
  from celerp.services.cogs_backfill import run_cogs_backfill
291
293
  async with _CogsSession() as _cogs_sess:
292
294
  await run_cogs_backfill(_cogs_sess)
@@ -447,6 +449,14 @@ async def rate_limit_handler(_request: Request, _exc: RateLimitExceeded):
447
449
  return JSONResponse(status_code=429, content={"detail": "Rate limit exceeded"})
448
450
 
449
451
 
452
+ @app.exception_handler(BarcodeConflictError)
453
+ async def barcode_conflict_handler(_request: Request, exc: BarcodeConflictError):
454
+ # The projection applier raises this when the barcode unique index rejects a write
455
+ # that bypassed the allocation lock (imports, connectors). A more specific handler
456
+ # than the Exception catch-all, so it maps to 409 instead of a masked 500.
457
+ return JSONResponse(status_code=409, content={"detail": str(exc)})
458
+
459
+
450
460
  # Kernel routes — always present regardless of module configuration
451
461
  app.include_router(health.router, tags=["system"])
452
462
  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}")
@@ -0,0 +1,65 @@
1
+ # Copyright (c) 2026 Noah Severs
2
+ # SPDX-License-Identifier: BUSL-1.1
3
+
4
+ """seed the inventory shrinkage/write-off account 6970 for existing companies
5
+
6
+ Revision ID: c9d8e7f6a5b4
7
+ Revises: bc0d1e2f3a4b
8
+ Create Date: 2026-08-31
9
+
10
+ Inventory write-offs and audit shrinkage post to 6970. New companies get the
11
+ account from THAI_CHART_OF_ACCOUNTS on creation; this backfills existing ones,
12
+ which would otherwise be refused at posting time.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ from alembic import op
18
+ import sqlalchemy as sa
19
+
20
+ revision = "c9d8e7f6a5b4"
21
+ down_revision = "bc0d1e2f3a4b"
22
+ branch_labels = None
23
+ depends_on = None
24
+
25
+ _CODE = "6970"
26
+ _NAME = "Inventory Shrinkage & Write-offs"
27
+ _TYPE = "expense"
28
+ _PARENT = "6000"
29
+
30
+
31
+ def upgrade() -> None:
32
+ conn = op.get_bind()
33
+ # to_regclass resolves against the connection's search_path rather than
34
+ # assuming public, so the guard is correct for any schema the migration is
35
+ # actually run in.
36
+ table_exists = conn.execute(sa.text("SELECT to_regclass('accounts')")).scalar()
37
+ if not table_exists:
38
+ return # Nothing to backfill on fresh install
39
+
40
+ companies = conn.execute(
41
+ sa.text("SELECT DISTINCT company_id FROM accounts WHERE code = :parent"),
42
+ {"parent": _PARENT},
43
+ ).fetchall()
44
+
45
+ for (company_id,) in companies:
46
+ exists = conn.execute(
47
+ sa.text("SELECT 1 FROM accounts WHERE company_id = :cid AND code = :code"),
48
+ {"cid": company_id, "code": _CODE},
49
+ ).fetchone()
50
+ if not exists:
51
+ conn.execute(
52
+ sa.text(
53
+ "INSERT INTO accounts (id, company_id, code, name, account_type, parent_code, is_active, created_at) "
54
+ "VALUES (gen_random_uuid(), :cid, :code, :name, :acc_type, :parent, TRUE, NOW())"
55
+ ),
56
+ {"cid": company_id, "code": _CODE, "name": _NAME,
57
+ "acc_type": _TYPE, "parent": _PARENT},
58
+ )
59
+
60
+
61
+ def downgrade() -> None:
62
+ # The upgrade only inserts 6970 when absent, so a seeded row is indistinguishable from a
63
+ # company's own pre-existing 6970. Deleting on downgrade would destroy user data and orphan any
64
+ # ledger row referencing it, so the reversal intentionally leaves the account in place.
65
+ pass
@@ -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__ = (PrimaryKeyConstraint("company_id", "entity_id"),)
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)