celerp 2.3.2__tar.gz → 2.3.4__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 (653) hide show
  1. {celerp-2.3.2 → celerp-2.3.4}/PKG-INFO +1 -1
  2. celerp-2.3.4/celerp/db.py +136 -0
  3. {celerp-2.3.2 → celerp-2.3.4}/celerp/events/schemas.py +11 -0
  4. {celerp-2.3.2 → celerp-2.3.4}/celerp/gateway/client.py +225 -70
  5. {celerp-2.3.2 → celerp-2.3.4}/celerp/main.py +11 -10
  6. celerp-2.3.4/celerp/migrations/versions/c9d8e7f6a5b4_seed_shrinkage_writeoff_account.py +65 -0
  7. {celerp-2.3.2 → celerp-2.3.4}/celerp/modules/migrations_runner.py +33 -29
  8. {celerp-2.3.2 → celerp-2.3.4}/celerp/routers/doctor.py +8 -3
  9. {celerp-2.3.2 → celerp-2.3.4}/celerp/routers/ledger.py +15 -5
  10. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/auto_je.py +2 -2
  11. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/cost_visibility.py +17 -1
  12. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/field_schema.py +20 -1
  13. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/system_health.py +19 -8
  14. {celerp-2.3.2 → celerp-2.3.4}/celerp.egg-info/PKG-INFO +1 -1
  15. {celerp-2.3.2 → celerp-2.3.4}/celerp.egg-info/SOURCES.txt +13 -0
  16. {celerp-2.3.2 → celerp-2.3.4}/celerp.egg-info/scm_file_list.json +36 -0
  17. celerp-2.3.4/celerp.egg-info/scm_version.json +8 -0
  18. {celerp-2.3.2 → celerp-2.3.4}/conftest.py +15 -1
  19. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/celerp_accounting/routes.py +1 -0
  20. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/report_goldens/statement.html +1 -0
  21. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-admin/celerp_admin/routes.py +34 -29
  22. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/celerp_docs/doc_constants.py +3 -2
  23. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/celerp_docs/doc_projections.py +22 -2
  24. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/celerp_docs/routes.py +1147 -392
  25. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/celerp_docs/routes_payments.py +5 -5
  26. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_audits.py +150 -3
  27. celerp-2.3.4/default_modules/celerp-docs/tests/test_bulk_payment_alloc_lock.py +502 -0
  28. celerp-2.3.4/default_modules/celerp-docs/tests/test_cross_lot_settlement.py +168 -0
  29. celerp-2.3.4/default_modules/celerp-docs/tests/test_line_page_patch_truncate.py +245 -0
  30. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_list_concurrency.py +115 -2
  31. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_list_outcome_concurrency.py +268 -0
  32. celerp-2.3.4/default_modules/celerp-docs/tests/test_list_page_no_full_state.py +151 -0
  33. celerp-2.3.4/default_modules/celerp-docs/tests/test_list_query_pushdown.py +399 -0
  34. celerp-2.3.4/default_modules/celerp-docs/tests/test_memo_close.py +176 -0
  35. celerp-2.3.4/default_modules/celerp-docs/tests/test_memo_close_projection.py +26 -0
  36. celerp-2.3.4/default_modules/celerp-docs/tests/test_memo_close_review_fixes.py +450 -0
  37. celerp-2.3.4/default_modules/celerp-docs/tests/test_memo_lifecycle_concurrency.py +992 -0
  38. celerp-2.3.4/default_modules/celerp-docs/tests/test_memo_line_labels.py +191 -0
  39. celerp-2.3.4/default_modules/celerp-docs/tests/test_memo_unfulfilled_filter.py +47 -0
  40. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_send_visibility.py +16 -0
  41. celerp-2.3.4/default_modules/celerp-docs/tests/test_sold_label_ordering.py +95 -0
  42. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_writeoffs.py +303 -1
  43. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-inventory/celerp_inventory/routes.py +390 -49
  44. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/routes.py +5 -2
  45. {celerp-2.3.2 → celerp-2.3.4}/default_modules/first_party.lock.json +5 -5
  46. {celerp-2.3.2 → celerp-2.3.4}/ui/api_client.py +199 -8
  47. {celerp-2.3.2 → celerp-2.3.4}/ui/app.py +8 -0
  48. {celerp-2.3.2 → celerp-2.3.4}/ui/components/shell.py +93 -13
  49. {celerp-2.3.2 → celerp-2.3.4}/ui/locales/am.json +18 -7
  50. {celerp-2.3.2 → celerp-2.3.4}/ui/locales/ar.json +18 -7
  51. {celerp-2.3.2 → celerp-2.3.4}/ui/locales/de.json +18 -7
  52. {celerp-2.3.2 → celerp-2.3.4}/ui/locales/en.json +19 -8
  53. {celerp-2.3.2 → celerp-2.3.4}/ui/locales/es.json +18 -7
  54. {celerp-2.3.2 → celerp-2.3.4}/ui/locales/fr.json +18 -7
  55. {celerp-2.3.2 → celerp-2.3.4}/ui/locales/id.json +18 -7
  56. {celerp-2.3.2 → celerp-2.3.4}/ui/locales/it.json +18 -7
  57. {celerp-2.3.2 → celerp-2.3.4}/ui/locales/ja.json +18 -7
  58. {celerp-2.3.2 → celerp-2.3.4}/ui/locales/pt.json +18 -7
  59. {celerp-2.3.2 → celerp-2.3.4}/ui/locales/th.json +18 -7
  60. {celerp-2.3.2 → celerp-2.3.4}/ui/locales/vi.json +18 -7
  61. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/documents.py +403 -169
  62. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/settings.py +6 -2
  63. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/settings_cloud.py +0 -12
  64. {celerp-2.3.2 → celerp-2.3.4}/ui/static/app.css +1 -1
  65. celerp-2.3.2/celerp/db.py +0 -61
  66. celerp-2.3.2/celerp.egg-info/scm_version.json +0 -8
  67. {celerp-2.3.2 → celerp-2.3.4}/CLA.md +0 -0
  68. {celerp-2.3.2 → celerp-2.3.4}/CONTRIBUTING.md +0 -0
  69. {celerp-2.3.2 → celerp-2.3.4}/LICENSE +0 -0
  70. {celerp-2.3.2 → celerp-2.3.4}/LICENSING.md +0 -0
  71. {celerp-2.3.2 → celerp-2.3.4}/MANIFEST.in +0 -0
  72. {celerp-2.3.2 → celerp-2.3.4}/NOTICE +0 -0
  73. {celerp-2.3.2 → celerp-2.3.4}/README.md +0 -0
  74. {celerp-2.3.2 → celerp-2.3.4}/alembic.ini +0 -0
  75. {celerp-2.3.2 → celerp-2.3.4}/celerp/__init__.py +0 -0
  76. {celerp-2.3.2 → celerp-2.3.4}/celerp/__main__.py +0 -0
  77. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/__init__.py +0 -0
  78. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/batch.py +0 -0
  79. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/cleanup.py +0 -0
  80. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/commands.py +0 -0
  81. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/conversations.py +0 -0
  82. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/files.py +0 -0
  83. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/intent.py +0 -0
  84. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/llm.py +0 -0
  85. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/memory.py +0 -0
  86. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/models.py +0 -0
  87. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/page_count.py +0 -0
  88. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/quota.py +0 -0
  89. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/service.py +0 -0
  90. {celerp-2.3.2 → celerp-2.3.4}/celerp/ai/tools.py +0 -0
  91. {celerp-2.3.2 → celerp-2.3.4}/celerp/alembic.ini +0 -0
  92. {celerp-2.3.2 → celerp-2.3.4}/celerp/alembic_config.py +0 -0
  93. {celerp-2.3.2 → celerp-2.3.4}/celerp/cli.py +0 -0
  94. {celerp-2.3.2 → celerp-2.3.4}/celerp/compat.py +0 -0
  95. {celerp-2.3.2 → celerp-2.3.4}/celerp/compute/__init__.py +0 -0
  96. {celerp-2.3.2 → celerp-2.3.4}/celerp/compute/aggregations.py +0 -0
  97. {celerp-2.3.2 → celerp-2.3.4}/celerp/compute/valuation.py +0 -0
  98. {celerp-2.3.2 → celerp-2.3.4}/celerp/config.py +0 -0
  99. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/__init__.py +0 -0
  100. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/base.py +0 -0
  101. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/daily_scheduler.py +0 -0
  102. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/http.py +0 -0
  103. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/images.py +0 -0
  104. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/quickbooks.py +0 -0
  105. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/registry.py +0 -0
  106. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/relay_token.py +0 -0
  107. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/shopify.py +0 -0
  108. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/sync_runner.py +0 -0
  109. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/upsert.py +0 -0
  110. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/util.py +0 -0
  111. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/webhooks.py +0 -0
  112. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/woocommerce.py +0 -0
  113. {celerp-2.3.2 → celerp-2.3.4}/celerp/connectors/xero.py +0 -0
  114. {celerp-2.3.2 → celerp-2.3.4}/celerp/constants.py +0 -0
  115. {celerp-2.3.2 → celerp-2.3.4}/celerp/embedded_pg.py +0 -0
  116. {celerp-2.3.2 → celerp-2.3.4}/celerp/events/__init__.py +0 -0
  117. {celerp-2.3.2 → celerp-2.3.4}/celerp/events/engine.py +0 -0
  118. {celerp-2.3.2 → celerp-2.3.4}/celerp/events/types.py +0 -0
  119. {celerp-2.3.2 → celerp-2.3.4}/celerp/gateway/__init__.py +0 -0
  120. {celerp-2.3.2 → celerp-2.3.4}/celerp/gateway/state.py +0 -0
  121. {celerp-2.3.2 → celerp-2.3.4}/celerp/importers/__init__.py +0 -0
  122. {celerp-2.3.2 → celerp-2.3.4}/celerp/importers/importer.py +0 -0
  123. {celerp-2.3.2 → celerp-2.3.4}/celerp/importers/schema.py +0 -0
  124. {celerp-2.3.2 → celerp-2.3.4}/celerp/inventory_codes.py +0 -0
  125. {celerp-2.3.2 → celerp-2.3.4}/celerp/middleware.py +0 -0
  126. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/README.md +0 -0
  127. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/_auto_stamp.py +0 -0
  128. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/_data_reconcile.py +0 -0
  129. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/_json_compat.py +0 -0
  130. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/env.py +0 -0
  131. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/script.py.mako +0 -0
  132. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/a0b1c2d3e4f5_seed_landed_cost_clearing_accounts.py +0 -0
  133. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/a1b2c3d4e5f6_add_doc_share_tokens.py +0 -0
  134. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/b1c2d3e4f5a6_add_supporter_badges.py +0 -0
  135. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/b2c3d4e5f6a7_add_import_batches.py +0 -0
  136. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/b3c4d5e6f7a8_expand_role_permissions_to_role_grants.py +0 -0
  137. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/bc0d1e2f3a4b_barcode_unique_index.py +0 -0
  138. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/c1d2e3f4a5b6_add_marketplace.py +0 -0
  139. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/c2d3e4f5a6b7_add_is_sync_to_shopify.py +0 -0
  140. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/c4d5e6f7a8b9_account_cash_flow_category.py +0 -0
  141. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/d0e1f2a3b4c5_add_share_token_expiry.py +0 -0
  142. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/d2e3f4a5b6c7_add_password_reset_token.py +0 -0
  143. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/d5e6f7a8b9c0_rename_fx_rounding_to_fx_difference.py +0 -0
  144. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/e3f4a5b6c7d8_add_company_is_active.py +0 -0
  145. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/e4f5a6b7c8d9_backfill_connector_idempotency_key.py +0 -0
  146. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/e7c9a1b3d5f2_work_center_default_columns.py +0 -0
  147. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/f1a2b3c4d5e6_move_accounts_marketplace_to_modules.py +0 -0
  148. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/f6a7b8c9d0e1_seed_fx_rounding_account.py +0 -0
  149. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/f8a9b0c1d2e3_work_center_default_backfill.py +0 -0
  150. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/fd5de461e14e_initial_schema.py +0 -0
  151. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/g1h2i3j4k5l6_add_consignment_flag.py +0 -0
  152. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/h2i3j4k5l6m7_add_bank_accounts_and_reconciliation.py +0 -0
  153. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/j4k5l6m7n8o9_labels_db_persistence.py +0 -0
  154. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/k5l6m7n8o9p0_add_reconciliation_v2.py +0 -0
  155. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/l6m7n8o9p0q1_add_sync_runs_table.py +0 -0
  156. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/m7n8o9p0q1r2_add_connector_configs_and_outbound_queue.py +0 -0
  157. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/n8o9p0q1r2s3_backfill_payment_date.py +0 -0
  158. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/o9p0q1r2s3t4_backfill_item_price_fields.py +0 -0
  159. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/p1q2r3s4t5u6_add_session_registry_and_user_auth_state.py +0 -0
  160. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/q2r3s4t5u6v7_add_system_runtime_state.py +0 -0
  161. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/r3s4t5u6v7w8_add_projections_company_entity_type_index.py +0 -0
  162. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/s4t5u6v7w8x9_drop_user_company_id_role.py +0 -0
  163. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/t5u6v7w8x9y0_seed_inventory_sub_accounts.py +0 -0
  164. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/u6v7w8x9y0z1_backfill_item_prices_from_attributes.py +0 -0
  165. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/v7w8x9y0z1a2_backfill_purchase_unit_defaults.py +0 -0
  166. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/w8x9y0z1a2b3_backfill_category_unit_defaults.py +0 -0
  167. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/x7y8z9a0b1c2_add_projection_created_at.py +0 -0
  168. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/y8z9a0b1c2d3_per_company_ledger_idempotency.py +0 -0
  169. {celerp-2.3.2 → celerp-2.3.4}/celerp/migrations/versions/z9a0b1c2d3e4_work_centers.py +0 -0
  170. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/__init__.py +0 -0
  171. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/accounting.py +0 -0
  172. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/ai.py +0 -0
  173. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/auth.py +0 -0
  174. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/base.py +0 -0
  175. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/company.py +0 -0
  176. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/connector_config.py +0 -0
  177. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/import_batch.py +0 -0
  178. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/ledger.py +0 -0
  179. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/marketplace.py +0 -0
  180. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/notification.py +0 -0
  181. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/projections.py +0 -0
  182. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/share.py +0 -0
  183. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/supporter.py +0 -0
  184. {celerp-2.3.2 → celerp-2.3.4}/celerp/models/sync_run.py +0 -0
  185. {celerp-2.3.2 → celerp-2.3.4}/celerp/modules/__init__.py +0 -0
  186. {celerp-2.3.2 → celerp-2.3.4}/celerp/modules/api.py +0 -0
  187. {celerp-2.3.2 → celerp-2.3.4}/celerp/modules/audit.py +0 -0
  188. {celerp-2.3.2 → celerp-2.3.4}/celerp/modules/demotion.py +0 -0
  189. {celerp-2.3.2 → celerp-2.3.4}/celerp/modules/importer.py +0 -0
  190. {celerp-2.3.2 → celerp-2.3.4}/celerp/modules/license.py +0 -0
  191. {celerp-2.3.2 → celerp-2.3.4}/celerp/modules/loader.py +0 -0
  192. {celerp-2.3.2 → celerp-2.3.4}/celerp/modules/meta.py +0 -0
  193. {celerp-2.3.2 → celerp-2.3.4}/celerp/modules/references.py +0 -0
  194. {celerp-2.3.2 → celerp-2.3.4}/celerp/modules/registry.py +0 -0
  195. {celerp-2.3.2 → celerp-2.3.4}/celerp/modules/slots.py +0 -0
  196. {celerp-2.3.2 → celerp-2.3.4}/celerp/notifications/__init__.py +0 -0
  197. {celerp-2.3.2 → celerp-2.3.4}/celerp/notifications/service.py +0 -0
  198. {celerp-2.3.2 → celerp-2.3.4}/celerp/notifications/sse.py +0 -0
  199. {celerp-2.3.2 → celerp-2.3.4}/celerp/output/__init__.py +0 -0
  200. {celerp-2.3.2 → celerp-2.3.4}/celerp/output/branding.py +0 -0
  201. {celerp-2.3.2 → celerp-2.3.4}/celerp/output/doc_print.py +0 -0
  202. {celerp-2.3.2 → celerp-2.3.4}/celerp/output/pdf.py +0 -0
  203. {celerp-2.3.2 → celerp-2.3.4}/celerp/output/share_render.py +0 -0
  204. {celerp-2.3.2 → celerp-2.3.4}/celerp/projections/__init__.py +0 -0
  205. {celerp-2.3.2 → celerp-2.3.4}/celerp/projections/engine.py +0 -0
  206. {celerp-2.3.2 → celerp-2.3.4}/celerp/projections/handlers/__init__.py +0 -0
  207. {celerp-2.3.2 → celerp-2.3.4}/celerp/projections/handlers/marketplace.py +0 -0
  208. {celerp-2.3.2 → celerp-2.3.4}/celerp/projections/handlers/scanning.py +0 -0
  209. {celerp-2.3.2 → celerp-2.3.4}/celerp/projections/handlers/shopify.py +0 -0
  210. {celerp-2.3.2 → celerp-2.3.4}/celerp/projections/handlers/system.py +0 -0
  211. {celerp-2.3.2 → celerp-2.3.4}/celerp/routers/__init__.py +0 -0
  212. {celerp-2.3.2 → celerp-2.3.4}/celerp/routers/auth.py +0 -0
  213. {celerp-2.3.2 → celerp-2.3.4}/celerp/routers/companies.py +0 -0
  214. {celerp-2.3.2 → celerp-2.3.4}/celerp/routers/debug.py +0 -0
  215. {celerp-2.3.2 → celerp-2.3.4}/celerp/routers/events.py +0 -0
  216. {celerp-2.3.2 → celerp-2.3.4}/celerp/routers/health.py +0 -0
  217. {celerp-2.3.2 → celerp-2.3.4}/celerp/routers/notifications.py +0 -0
  218. {celerp-2.3.2 → celerp-2.3.4}/celerp/routers/stars.py +0 -0
  219. {celerp-2.3.2 → celerp-2.3.4}/celerp/routers/system.py +0 -0
  220. {celerp-2.3.2 → celerp-2.3.4}/celerp/schemas/__init__.py +0 -0
  221. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/__init__.py +0 -0
  222. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/activity_redaction.py +0 -0
  223. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/attachments.py +0 -0
  224. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/auth.py +0 -0
  225. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/backup.py +0 -0
  226. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/backup_export.py +0 -0
  227. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/backup_import.py +0 -0
  228. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/backup_repo.py +0 -0
  229. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/backup_scheduler.py +0 -0
  230. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/backup_state.py +0 -0
  231. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/cogs_backfill.py +0 -0
  232. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/demo.py +0 -0
  233. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/dev_release_guard.py +0 -0
  234. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/email.py +0 -0
  235. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/fulfill.py +0 -0
  236. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/holdings.py +0 -0
  237. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/je_keys.py +0 -0
  238. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/landed_cost.py +0 -0
  239. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/line_measures.py +0 -0
  240. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/list_behavior.py +0 -0
  241. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/money.py +0 -0
  242. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/payments.py +0 -0
  243. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/permissions.py +0 -0
  244. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/pick.py +0 -0
  245. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/pricing.py +0 -0
  246. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/relay_share.py +0 -0
  247. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/reorder.py +0 -0
  248. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/runtime_state.py +0 -0
  249. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/session_tracker.py +0 -0
  250. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/shipping.py +0 -0
  251. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/star_cta.py +0 -0
  252. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/status_doc_backfill.py +0 -0
  253. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/supporter_badge.py +0 -0
  254. {celerp-2.3.2 → celerp-2.3.4}/celerp/services/units.py +0 -0
  255. {celerp-2.3.2 → celerp-2.3.4}/celerp/session_gate.py +0 -0
  256. {celerp-2.3.2 → celerp-2.3.4}/celerp/tax_regimes.py +0 -0
  257. {celerp-2.3.2 → celerp-2.3.4}/celerp.egg-info/dependency_links.txt +0 -0
  258. {celerp-2.3.2 → celerp-2.3.4}/celerp.egg-info/entry_points.txt +0 -0
  259. {celerp-2.3.2 → celerp-2.3.4}/celerp.egg-info/requires.txt +0 -0
  260. {celerp-2.3.2 → celerp-2.3.4}/celerp.egg-info/top_level.txt +0 -0
  261. {celerp-2.3.2 → celerp-2.3.4}/conftest_support.py +0 -0
  262. {celerp-2.3.2 → celerp-2.3.4}/default_modules/__init__.py +0 -0
  263. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/LICENSE +0 -0
  264. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/__init__.py +0 -0
  265. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/celerp_accounting/__init__.py +0 -0
  266. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/celerp_accounting/api_setup.py +0 -0
  267. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/celerp_accounting/csv_parser.py +0 -0
  268. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/celerp_accounting/matcher.py +0 -0
  269. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/celerp_accounting/models.py +0 -0
  270. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/celerp_accounting/projections.py +0 -0
  271. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/celerp_accounting/ui_routes.py +0 -0
  272. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/report_goldens/balance-sheet.html +0 -0
  273. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/report_goldens/cash-flow.html +0 -0
  274. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-csv.csv +0 -0
  275. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-print.html +0 -0
  276. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/report_goldens/extended-journal.html +0 -0
  277. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/report_goldens/general-ledger.html +0 -0
  278. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/report_goldens/journal-csv.csv +0 -0
  279. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/report_goldens/journal-print.html +0 -0
  280. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/report_goldens/journal.html +0 -0
  281. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/report_goldens/ledger.html +0 -0
  282. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/report_goldens/pnl.html +0 -0
  283. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/report_goldens/trial-balance.html +0 -0
  284. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/test_accounting_banking.py +0 -0
  285. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/test_accounting_banking_routers.py +0 -0
  286. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/test_accounting_gaps.py +0 -0
  287. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/test_accounting_import_idempotency.py +0 -0
  288. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/test_cash_flow.py +0 -0
  289. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/test_financial_reports_ui.py +0 -0
  290. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/test_journal_gl_soa.py +0 -0
  291. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/test_journal_gl_soa_ui.py +0 -0
  292. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/test_reconciliation_v2.py +0 -0
  293. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/test_reports_end_to_end.py +0 -0
  294. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-accounting/tests/test_route_permissions.py +0 -0
  295. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-admin/__init__.py +0 -0
  296. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-admin/celerp_admin/__init__.py +0 -0
  297. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-admin/celerp_admin/setup.py +0 -0
  298. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/__init__.py +0 -0
  299. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/celerp_ai/__init__.py +0 -0
  300. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/celerp_ai/routes.py +0 -0
  301. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/celerp_ai/setup.py +0 -0
  302. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/celerp_ai/ui_routes.py +0 -0
  303. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/conftest.py +0 -0
  304. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_batch.py +0 -0
  305. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_cleanup.py +0 -0
  306. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_conversations.py +0 -0
  307. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_coverage_gaps.py +0 -0
  308. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_intent.py +0 -0
  309. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_llm.py +0 -0
  310. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_memory.py +0 -0
  311. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_models.py +0 -0
  312. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_page_count.py +0 -0
  313. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_quota.py +0 -0
  314. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_router.py +0 -0
  315. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_routes_coverage.py +0 -0
  316. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_service.py +0 -0
  317. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-ai/tests/test_tools.py +0 -0
  318. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-backup/__init__.py +0 -0
  319. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-backup/celerp_backup/__init__.py +0 -0
  320. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-backup/celerp_backup/routes.py +0 -0
  321. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-backup/celerp_backup/setup.py +0 -0
  322. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/__init__.py +0 -0
  323. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/celerp_connectors/__init__.py +0 -0
  324. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/celerp_connectors/models.py +0 -0
  325. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/celerp_connectors/routes.py +0 -0
  326. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/__init__.py +0 -0
  327. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/conftest.py +0 -0
  328. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/test_compliance.py +0 -0
  329. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/test_connector_correctness.py +0 -0
  330. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/test_connectors.py +0 -0
  331. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/test_credentials_routes.py +0 -0
  332. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/test_images.py +0 -0
  333. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/test_outbound.py +0 -0
  334. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/test_quickbooks.py +0 -0
  335. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/test_rate_limiting.py +0 -0
  336. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/test_shopify.py +0 -0
  337. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/test_wiring.py +0 -0
  338. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/test_woocommerce.py +0 -0
  339. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/test_woocommerce_webhooks.py +0 -0
  340. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-connectors/tests/test_xero.py +0 -0
  341. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-contacts/LICENSE +0 -0
  342. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-contacts/__init__.py +0 -0
  343. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-contacts/celerp_contacts/__init__.py +0 -0
  344. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-contacts/celerp_contacts/migrations.py +0 -0
  345. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-contacts/celerp_contacts/projections.py +0 -0
  346. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-contacts/celerp_contacts/routes.py +0 -0
  347. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-contacts/celerp_contacts/services.py +0 -0
  348. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-contacts/celerp_contacts/ui_routes.py +0 -0
  349. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-dashboard/LICENSE +0 -0
  350. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-dashboard/__init__.py +0 -0
  351. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-dashboard/celerp_dashboard/__init__.py +0 -0
  352. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-dashboard/celerp_dashboard/routes.py +0 -0
  353. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-dashboard/celerp_dashboard/setup.py +0 -0
  354. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/LICENSE +0 -0
  355. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/__init__.py +0 -0
  356. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/celerp_docs/__init__.py +0 -0
  357. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/celerp_docs/api_setup.py +0 -0
  358. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/celerp_docs/doc_email.py +0 -0
  359. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/celerp_docs/doc_service.py +0 -0
  360. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/celerp_docs/models_share.py +0 -0
  361. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/celerp_docs/routes_share.py +0 -0
  362. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/celerp_docs/sequences.py +0 -0
  363. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/celerp_docs/taxes.py +0 -0
  364. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/celerp_docs/ui_routes.py +0 -0
  365. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/conftest.py +0 -0
  366. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_consolidate_lots.py +0 -0
  367. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_freight_je.py +0 -0
  368. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_freight_lines.py +0 -0
  369. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_fulfill_no_split.py +0 -0
  370. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_fulfillment_activity.py +0 -0
  371. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_inbound_je_lifecycle.py +0 -0
  372. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_inventory_account_reconciliation.py +0 -0
  373. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_landed_receive.py +0 -0
  374. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_line_delete_persist.py +0 -0
  375. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_line_identifier.py +0 -0
  376. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_payment_void_activity.py +0 -0
  377. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_receive_sku_batch.py +0 -0
  378. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_service_lines.py +0 -0
  379. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-docs/tests/test_void_guards.py +0 -0
  380. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-inventory/LICENSE +0 -0
  381. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-inventory/__init__.py +0 -0
  382. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-inventory/celerp_inventory/__init__.py +0 -0
  383. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-inventory/celerp_inventory/models_import_batch.py +0 -0
  384. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-inventory/celerp_inventory/projections.py +0 -0
  385. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-inventory/celerp_inventory/routes_attachments.py +0 -0
  386. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-inventory/celerp_inventory/routes_scanning.py +0 -0
  387. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-inventory/celerp_inventory/services.py +0 -0
  388. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-inventory/celerp_inventory/ui_routes.py +0 -0
  389. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-inventory/tests/test_item_recipe_projection.py +0 -0
  390. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-inventory/tests/test_item_workflow_projection.py +0 -0
  391. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-inventory/tests/test_landed_cost_projection.py +0 -0
  392. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/LICENSE +0 -0
  393. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/__init__.py +0 -0
  394. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/__init__.py +0 -0
  395. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/locales/am.json +0 -0
  396. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/locales/ar.json +0 -0
  397. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/locales/de.json +0 -0
  398. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/locales/en.json +0 -0
  399. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/locales/es.json +0 -0
  400. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/locales/fr.json +0 -0
  401. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/locales/id.json +0 -0
  402. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/locales/it.json +0 -0
  403. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/locales/ja.json +0 -0
  404. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/locales/pt.json +0 -0
  405. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/locales/th.json +0 -0
  406. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/locales/vi.json +0 -0
  407. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/models.py +0 -0
  408. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/presets.py +0 -0
  409. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/service.py +0 -0
  410. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/celerp_labels/ui_routes.py +0 -0
  411. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/requirements.txt +0 -0
  412. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/tests/test_labels.py +0 -0
  413. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-labels/tests/test_labels_module.py +0 -0
  414. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/LICENSE +0 -0
  415. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/__init__.py +0 -0
  416. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/celerp_manufacturing/__init__.py +0 -0
  417. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/celerp_manufacturing/costing.py +0 -0
  418. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/celerp_manufacturing/expansion.py +0 -0
  419. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/celerp_manufacturing/labor.py +0 -0
  420. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/celerp_manufacturing/migrations.py +0 -0
  421. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/celerp_manufacturing/projection_handler.py +0 -0
  422. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/celerp_manufacturing/routes.py +0 -0
  423. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/celerp_manufacturing/ui_routes.py +0 -0
  424. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/requirements.txt +0 -0
  425. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_auto_complete_on_finalize.py +0 -0
  426. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_bom_removed.py +0 -0
  427. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_build_api.py +0 -0
  428. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_completion_lock_order.py +0 -0
  429. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_item_recipe_api.py +0 -0
  430. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_item_workflow_api.py +0 -0
  431. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_labor_providers.py +0 -0
  432. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_manufacture_from_doc.py +0 -0
  433. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_manufacturing.py +0 -0
  434. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_manufacturing_import_idempotency.py +0 -0
  435. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_manufacturing_module.py +0 -0
  436. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_mfg_events.py +0 -0
  437. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_phase2_manufacturing_validations.py +0 -0
  438. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_production_order.py +0 -0
  439. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_recipe_costing.py +0 -0
  440. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_recipe_expansion.py +0 -0
  441. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_recost_api.py +0 -0
  442. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_run_records.py +0 -0
  443. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_to_make_allocation.py +0 -0
  444. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_where_used.py +0 -0
  445. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_work_centers_and_settings.py +0 -0
  446. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-manufacturing/tests/test_workflow_time.py +0 -0
  447. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-reports/LICENSE +0 -0
  448. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-reports/__init__.py +0 -0
  449. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-reports/celerp_reports/__init__.py +0 -0
  450. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-reports/celerp_reports/api_setup.py +0 -0
  451. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-reports/celerp_reports/routes.py +0 -0
  452. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-reports/celerp_reports/ui_routes.py +0 -0
  453. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-reports/tests/test_reports_full.py +0 -0
  454. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-reports/tests/test_reports_unit.py +0 -0
  455. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-subscriptions/LICENSE +0 -0
  456. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-subscriptions/__init__.py +0 -0
  457. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-subscriptions/celerp_subscriptions/__init__.py +0 -0
  458. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-subscriptions/celerp_subscriptions/routes.py +0 -0
  459. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-subscriptions/celerp_subscriptions/ui_routes.py +0 -0
  460. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-subscriptions/tests/test_subscriptions.py +0 -0
  461. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-subscriptions/tests/test_subscriptions_ui.py +0 -0
  462. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/LICENSE +0 -0
  463. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/__init__.py +0 -0
  464. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/__init__.py +0 -0
  465. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/accessory_fashion.json +0 -0
  466. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/activewear.json +0 -0
  467. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/art_photography.json +0 -0
  468. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/audio_equipment.json +0 -0
  469. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/bag_handbag.json +0 -0
  470. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/banknote.json +0 -0
  471. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/beauty_tool.json +0 -0
  472. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/bed_bedroom.json +0 -0
  473. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/beer.json +0 -0
  474. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/beverage_nonalc.json +0 -0
  475. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/body_part_auto.json +0 -0
  476. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/book.json +0 -0
  477. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/bottoms.json +0 -0
  478. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/brake_suspension.json +0 -0
  479. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/bullion_coin.json +0 -0
  480. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/camera.json +0 -0
  481. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/colored_stone.json +0 -0
  482. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/comic.json +0 -0
  483. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/commercial_space.json +0 -0
  484. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/component_part.json +0 -0
  485. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/confectionery.json +0 -0
  486. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/consulting_service.json +0 -0
  487. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/decorative_art.json +0 -0
  488. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/diamond.json +0 -0
  489. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/drawing.json +0 -0
  490. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/dress_jumpsuit.json +0 -0
  491. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_auto.json +0 -0
  492. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_component.json +0 -0
  493. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/emerald.json +0 -0
  494. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/engine_part.json +0 -0
  495. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/fastener.json +0 -0
  496. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/fertilizer_chemical.json +0 -0
  497. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/film_video.json +0 -0
  498. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/fine_writing_instrument.json +0 -0
  499. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/fluid_lubricant.json +0 -0
  500. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/footwear.json +0 -0
  501. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/fragrance.json +0 -0
  502. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_food.json +0 -0
  503. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_produce.json +0 -0
  504. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/frozen_food.json +0 -0
  505. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/gaming_console.json +0 -0
  506. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/gold_bullion.json +0 -0
  507. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/grain_cereal.json +0 -0
  508. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/haircare.json +0 -0
  509. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/hand_tool.json +0 -0
  510. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/ingredient_bulk.json +0 -0
  511. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/interior_part.json +0 -0
  512. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/jewelry.json +0 -0
  513. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/kitchen_dining.json +0 -0
  514. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/laptop.json +0 -0
  515. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/lighting.json +0 -0
  516. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/livestock_feed.json +0 -0
  517. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/makeup.json +0 -0
  518. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/measuring_instrument.json +0 -0
  519. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/medal_token.json +0 -0
  520. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/mineral_specimen.json +0 -0
  521. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/mobile_phone.json +0 -0
  522. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/music_cd.json +0 -0
  523. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/music_vinyl.json +0 -0
  524. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/nail.json +0 -0
  525. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/numismatic_coin.json +0 -0
  526. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/outdoor_furniture.json +0 -0
  527. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/outerwear.json +0 -0
  528. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/packaged_food.json +0 -0
  529. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/painting.json +0 -0
  530. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/parking_bay.json +0 -0
  531. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/pearl.json +0 -0
  532. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/personal_care.json +0 -0
  533. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/pipe_plumbing.json +0 -0
  534. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/platinum_bullion.json +0 -0
  535. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/power_tool.json +0 -0
  536. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/print_edition.json +0 -0
  537. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/residential_unit.json +0 -0
  538. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/rough_gemstone.json +0 -0
  539. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/ruby.json +0 -0
  540. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/saas_plan.json +0 -0
  541. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/safety_ppe.json +0 -0
  542. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/sapphire.json +0 -0
  543. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/sculpture.json +0 -0
  544. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/seating.json +0 -0
  545. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/seeds.json +0 -0
  546. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/silver_bullion.json +0 -0
  547. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/skincare.json +0 -0
  548. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/soft_furnishing.json +0 -0
  549. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/software_addon.json +0 -0
  550. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/software_license.json +0 -0
  551. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/spirit.json +0 -0
  552. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/storage_furniture.json +0 -0
  553. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/swimwear.json +0 -0
  554. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/table_desk.json +0 -0
  555. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/tablet.json +0 -0
  556. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/tire_wheel.json +0 -0
  557. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/tops.json +0 -0
  558. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/trading_card.json +0 -0
  559. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/tv_display.json +0 -0
  560. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/video_game.json +0 -0
  561. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/watch.json +0 -0
  562. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/watch_strap.json +0 -0
  563. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/categories/wine.json +0 -0
  564. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/agricultural.json +0 -0
  565. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/artwork.json +0 -0
  566. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/automotive.json +0 -0
  567. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/blank.json +0 -0
  568. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/books_media.json +0 -0
  569. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/coins_precious_metals.json +0 -0
  570. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/consulting.json +0 -0
  571. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/cosmetics.json +0 -0
  572. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/electronics.json +0 -0
  573. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/fashion.json +0 -0
  574. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/food_beverage.json +0 -0
  575. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/furniture.json +0 -0
  576. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/gemstones.json +0 -0
  577. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/hardware.json +0 -0
  578. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/property_rental.json +0 -0
  579. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/saas.json +0 -0
  580. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/watches.json +0 -0
  581. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/presets/wine_spirits.json +0 -0
  582. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/routes.py +0 -0
  583. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/celerp_verticals/ui_routes.py +0 -0
  584. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/tests/test_verticals.py +0 -0
  585. {celerp-2.3.2 → celerp-2.3.4}/default_modules/celerp-verticals/tests/test_verticals_routers.py +0 -0
  586. {celerp-2.3.2 → celerp-2.3.4}/legal/OFFICIAL-COMPONENTS.md +0 -0
  587. {celerp-2.3.2 → celerp-2.3.4}/legal/TRADEMARK.md +0 -0
  588. {celerp-2.3.2 → celerp-2.3.4}/packaging/winget/Celerp.Celerp.installer.yaml +0 -0
  589. {celerp-2.3.2 → celerp-2.3.4}/packaging/winget/Celerp.Celerp.locale.en-US.yaml +0 -0
  590. {celerp-2.3.2 → celerp-2.3.4}/packaging/winget/Celerp.Celerp.yaml +0 -0
  591. {celerp-2.3.2 → celerp-2.3.4}/packaging/winget/README.md +0 -0
  592. {celerp-2.3.2 → celerp-2.3.4}/pyproject.toml +0 -0
  593. {celerp-2.3.2 → celerp-2.3.4}/setup.cfg +0 -0
  594. {celerp-2.3.2 → celerp-2.3.4}/test_helpers.py +0 -0
  595. {celerp-2.3.2 → celerp-2.3.4}/ui/__init__.py +0 -0
  596. {celerp-2.3.2 → celerp-2.3.4}/ui/components/__init__.py +0 -0
  597. {celerp-2.3.2 → celerp-2.3.4}/ui/components/activity.py +0 -0
  598. {celerp-2.3.2 → celerp-2.3.4}/ui/components/attrs.py +0 -0
  599. {celerp-2.3.2 → celerp-2.3.4}/ui/components/backup.py +0 -0
  600. {celerp-2.3.2 → celerp-2.3.4}/ui/components/cloud_gate.py +0 -0
  601. {celerp-2.3.2 → celerp-2.3.4}/ui/components/currency.py +0 -0
  602. {celerp-2.3.2 → celerp-2.3.4}/ui/components/files.py +0 -0
  603. {celerp-2.3.2 → celerp-2.3.4}/ui/components/journal.py +0 -0
  604. {celerp-2.3.2 → celerp-2.3.4}/ui/components/notes.py +0 -0
  605. {celerp-2.3.2 → celerp-2.3.4}/ui/components/phone.py +0 -0
  606. {celerp-2.3.2 → celerp-2.3.4}/ui/components/report_kit.py +0 -0
  607. {celerp-2.3.2 → celerp-2.3.4}/ui/components/table.py +0 -0
  608. {celerp-2.3.2 → celerp-2.3.4}/ui/config.py +0 -0
  609. {celerp-2.3.2 → celerp-2.3.4}/ui/i18n.py +0 -0
  610. {celerp-2.3.2 → celerp-2.3.4}/ui/marketplace_catalog.py +0 -0
  611. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/__init__.py +0 -0
  612. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/account.py +0 -0
  613. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/accounting.py +0 -0
  614. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/accounting_import.py +0 -0
  615. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/auth.py +0 -0
  616. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/contacts.py +0 -0
  617. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/csv_import.py +0 -0
  618. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/dashboard.py +0 -0
  619. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/docs_import.py +0 -0
  620. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/events.py +0 -0
  621. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/financial_reports.py +0 -0
  622. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/inventory.py +0 -0
  623. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/lists_import.py +0 -0
  624. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/manufacturing.py +0 -0
  625. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/modules_page.py +0 -0
  626. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/notifications.py +0 -0
  627. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/reconciliation.py +0 -0
  628. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/reports.py +0 -0
  629. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/search.py +0 -0
  630. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/settings_accounting.py +0 -0
  631. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/settings_connectors.py +0 -0
  632. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/settings_contacts.py +0 -0
  633. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/settings_general.py +0 -0
  634. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/settings_import.py +0 -0
  635. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/settings_inventory.py +0 -0
  636. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/settings_manufacturing.py +0 -0
  637. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/settings_payments.py +0 -0
  638. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/settings_purchasing.py +0 -0
  639. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/settings_sales.py +0 -0
  640. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/setup.py +0 -0
  641. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/stars.py +0 -0
  642. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/subscriptions.py +0 -0
  643. {celerp-2.3.2 → celerp-2.3.4}/ui/routes/subscriptions_import.py +0 -0
  644. {celerp-2.3.2 → celerp-2.3.4}/ui/security.py +0 -0
  645. {celerp-2.3.2 → celerp-2.3.4}/ui/static/htmx.min.js +0 -0
  646. {celerp-2.3.2 → celerp-2.3.4}/ui/static/icon.png +0 -0
  647. {celerp-2.3.2 → celerp-2.3.4}/ui/static/logo.png +0 -0
  648. {celerp-2.3.2 → celerp-2.3.4}/ui/static/vendor/intl-tel-input/img/flags.webp +0 -0
  649. {celerp-2.3.2 → celerp-2.3.4}/ui/static/vendor/intl-tel-input/img/flags@2x.webp +0 -0
  650. {celerp-2.3.2 → celerp-2.3.4}/ui/static/vendor/intl-tel-input/intlTelInput.min.css +0 -0
  651. {celerp-2.3.2 → celerp-2.3.4}/ui/static/vendor/intl-tel-input/intlTelInput.min.js +0 -0
  652. {celerp-2.3.2 → celerp-2.3.4}/ui/static/vendor/intl-tel-input/intlTelInputWithUtils.min.js +0 -0
  653. {celerp-2.3.2 → celerp-2.3.4}/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.2
3
+ Version: 2.3.4
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
@@ -546,6 +546,15 @@ class DocUnvoided(BaseModel):
546
546
  restored_status: str
547
547
 
548
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
+
549
558
  class DocSent(BaseModel):
550
559
  sent_via: str | None = None
551
560
  sent_to: str | None = None
@@ -1162,6 +1171,8 @@ EVENT_SCHEMA_MAP: dict[str, type[BaseModel]] = {
1162
1171
  "doc.voided": DocVoided,
1163
1172
  "doc.reverted_to_draft": DocRevertedToDraft,
1164
1173
  "doc.unvoided": DocUnvoided,
1174
+ "doc.closed": DocClosed,
1175
+ "doc.reopened": DocReopened,
1165
1176
  "doc.converted_to_bill": DocConvertedToBill,
1166
1177
  "doc.sent": DocSent,
1167
1178
  "doc.payment.received": DocPaymentReceived,
@@ -26,7 +26,6 @@ from websockets.exceptions import ConnectionClosed
26
26
 
27
27
  log = logging.getLogger(__name__)
28
28
 
29
- _PING_INTERVAL = 30 # seconds
30
29
  _BACKOFF_MAX = 60 # seconds
31
30
  # Consecutive auth rejections before the client stops retrying: a rejected
32
31
  # credential never heals on its own, so beyond a small allowance for a
@@ -37,6 +36,10 @@ _AUTH_FAILED_MAX = 3
37
36
  # a revoke-then-reshare so it does not flap connect/disconnect).
38
37
  _REAP_INTERVAL = 15 * 60 # seconds
39
38
  _REAP_GRACE = 5 * 60 # seconds
39
+ # A single websocket send that cannot be handed to the transport within this long means the
40
+ # socket is wedged (a stalled or backpressured peer). Bound every send so it surfaces as an
41
+ # error instead of pinning the proxy task holding a relay slot forever.
42
+ _SEND_DEADLINE = 30 # seconds
40
43
 
41
44
 
42
45
  def _shop_key(handle: str | None) -> str:
@@ -85,6 +88,22 @@ class GatewayClient:
85
88
  # Hold strong refs to fire-and-forget tasks so the loop can't GC them mid-run
86
89
  # (a dropped task = a lost proxy response or webhook sync).
87
90
  self._bg_tasks: set = set()
91
+ # In-flight proxy tasks keyed by relay request id so an http.cancel frame can
92
+ # abort exactly the one request it names, and no other.
93
+ self._inflight: dict[str, asyncio.Task] = {}
94
+ # Connection generation: bumped on every teardown so a response produced by a
95
+ # request that outlived its socket can be recognised as stale and dropped
96
+ # rather than sent on the freshly rebuilt connection.
97
+ self._generation: int = 0
98
+ # One shared httpx client for all proxied requests, built lazily with bounded
99
+ # connection limits. A fresh client per request opened an unbounded number of
100
+ # pools under load; one bounded client caps the concurrency into the local app.
101
+ self._http_client: Any = None
102
+ # Observability counters for the proxy path, surfaced when the connection ends.
103
+ self._proxied_count = 0
104
+ self._cancelled_count = 0
105
+ self._timeout_count = 0
106
+ self._stale_dropped_count = 0
88
107
  # Resolve local server ports for proxy routing.
89
108
  # In Electron builds the ports are dynamic; Electron passes them via
90
109
  # CELERP_API_PORT / CELERP_UI_PORT env vars so we don't rely on the
@@ -122,6 +141,22 @@ class GatewayClient:
122
141
  self._bg_tasks.add(task)
123
142
  task.add_done_callback(self._bg_tasks.discard)
124
143
 
144
+ def _spawn_proxy(self, payload: dict) -> None:
145
+ """Run a proxied request fire-and-forget, keyed by its relay request id so an
146
+ http.cancel frame can abort exactly that task. The key is cleared when the task
147
+ finishes (a cancel arriving after completion is then a harmless no-op)."""
148
+ request_id = payload.get("id", "")
149
+ task = asyncio.create_task(self._handle_proxy_request(payload))
150
+ self._bg_tasks.add(task)
151
+ self._inflight[request_id] = task
152
+
153
+ def _done(t: asyncio.Task) -> None:
154
+ self._bg_tasks.discard(t)
155
+ if self._inflight.get(request_id) is t:
156
+ del self._inflight[request_id]
157
+
158
+ task.add_done_callback(_done)
159
+
125
160
  # ── Public API ─────────────────────────────────────────────────────
126
161
 
127
162
  async def run(self) -> None:
@@ -198,6 +233,7 @@ class GatewayClient:
198
233
  await ws.close()
199
234
  except Exception:
200
235
  pass
236
+ await self._close_http_client()
201
237
 
202
238
  async def _should_reap(self) -> bool:
203
239
  """A free instance with no live share and no recent proxied request should
@@ -293,40 +329,61 @@ class GatewayClient:
293
329
  import ssl as _ssl
294
330
  _ssl_ctx = _ssl.create_default_context()
295
331
  _ssl_ctx.set_alpn_protocols(["http/1.1"])
296
- async with websockets.connect(
297
- self._url, ssl=_ssl_ctx, ping_interval=20, ping_timeout=20, max_size=160 * 1024 * 1024
298
- ) as ws:
299
- self._ws = ws
300
- # Read current TOS version from config
301
- from celerp.config import read_config
302
- cfg = read_config() or {}
303
- tos_version = cfg.get("cloud", {}).get("tos_version", "")
304
- # App version: the Electron wrapper passes the release version via
305
- # CELERP_APP_VERSION; fall back to the package version. Sent on every
306
- # connect so the handshake reflects the build that is actually running.
307
- from celerp import __version__ as _pkg_version
308
- app_version = os.environ.get("CELERP_APP_VERSION") or _pkg_version
309
- # Send hello handshake
310
- await self._send(ws, {
311
- "type": "hello",
312
- "id": str(uuid.uuid4()),
313
- "payload": {
314
- "gateway_token": self._token,
315
- "instance_id": self._instance_id,
316
- "tos_version": tos_version,
317
- "version": app_version,
318
- },
319
- })
320
- # Message dispatch loop
321
- async for raw in ws:
322
- try:
323
- msg = json.loads(raw)
324
- except json.JSONDecodeError:
325
- log.warning("Gateway sent non-JSON frame: %r", raw)
326
- continue
327
- await self._dispatch(msg)
328
- self._ws = None
329
- self._set_status("inactive")
332
+ try:
333
+ async with websockets.connect(
334
+ self._url, ssl=_ssl_ctx, ping_interval=20, ping_timeout=20, max_size=160 * 1024 * 1024
335
+ ) as ws:
336
+ self._ws = ws
337
+ # Read current TOS version from config
338
+ from celerp.config import read_config
339
+ cfg = read_config() or {}
340
+ tos_version = cfg.get("cloud", {}).get("tos_version", "")
341
+ # App version: the Electron wrapper passes the release version via
342
+ # CELERP_APP_VERSION; fall back to the package version. Sent on every
343
+ # connect so the handshake reflects the build that is actually running.
344
+ from celerp import __version__ as _pkg_version
345
+ app_version = os.environ.get("CELERP_APP_VERSION") or _pkg_version
346
+ # Send hello handshake
347
+ await self._send(ws, {
348
+ "type": "hello",
349
+ "id": str(uuid.uuid4()),
350
+ "payload": {
351
+ "gateway_token": self._token,
352
+ "instance_id": self._instance_id,
353
+ "tos_version": tos_version,
354
+ "version": app_version,
355
+ },
356
+ })
357
+ # Message dispatch loop
358
+ async for raw in ws:
359
+ try:
360
+ msg = json.loads(raw)
361
+ except json.JSONDecodeError:
362
+ log.warning("Gateway sent non-JSON frame: %r", raw)
363
+ continue
364
+ await self._dispatch(msg)
365
+ finally:
366
+ # Teardown runs on every exit - clean end of the message stream OR an
367
+ # abnormal disconnect raised mid-serve. Kept in a finally so an exception
368
+ # from the async-for can't leave a dangling socket, an unfenced generation,
369
+ # and a stuck status behind.
370
+ self._ws = None
371
+ # A new generation for the next connection: any proxy response still in
372
+ # flight from this socket is now stale and must not be sent on the rebuilt
373
+ # one. Cancel the in-flight proxy tasks that belong to the dead connection -
374
+ # their responses can never be delivered on a socket that no longer exists.
375
+ self._generation += 1
376
+ for task in list(self._inflight.values()):
377
+ if not task.done():
378
+ task.cancel()
379
+ self._inflight.clear()
380
+ log.debug(
381
+ "Gateway proxy activity this connection: proxied=%d cancelled=%d "
382
+ "timed_out=%d stale_dropped=%d",
383
+ self._proxied_count, self._cancelled_count,
384
+ self._timeout_count, self._stale_dropped_count,
385
+ )
386
+ self._set_status("inactive")
330
387
 
331
388
  async def _dispatch(self, msg: dict) -> None:
332
389
  msg_type = msg.get("type", "")
@@ -414,7 +471,13 @@ class GatewayClient:
414
471
  set_subscription_state(tier, status)
415
472
 
416
473
  elif msg_type == "http.request":
417
- self._spawn(self._handle_proxy_request(payload))
474
+ self._spawn_proxy(payload)
475
+
476
+ elif msg_type == "http.cancel":
477
+ request_id = payload.get("id", "")
478
+ task = self._inflight.get(request_id)
479
+ if task is not None and not task.done():
480
+ task.cancel()
418
481
 
419
482
  elif msg_type == "shopify.webhook":
420
483
  self._spawn(self._handle_shopify_webhook(payload))
@@ -533,6 +596,31 @@ class GatewayClient:
533
596
  except Exception as exc:
534
597
  log.warning("invoice.payment handling failed (entity=%s): %s", entity_id, exc)
535
598
 
599
+ def _get_http_client(self):
600
+ """Return the one shared httpx client used for every proxied request, building
601
+ it lazily on first use. A bounded connection pool caps how many concurrent
602
+ requests this client can drive into the local app, so a burst of relayed
603
+ requests can no longer open an unbounded number of pools. The default timeout
604
+ is the fixed cap; a per-request timeout_ms tightens it further."""
605
+ import httpx
606
+
607
+ if self._http_client is None:
608
+ self._http_client = httpx.AsyncClient(
609
+ timeout=180.0,
610
+ limits=httpx.Limits(max_connections=32, max_keepalive_connections=8),
611
+ )
612
+ return self._http_client
613
+
614
+ async def _close_http_client(self) -> None:
615
+ """Close the shared httpx client if one was built. Safe to call when none was."""
616
+ client = self._http_client
617
+ self._http_client = None
618
+ if client is not None:
619
+ try:
620
+ await client.aclose()
621
+ except Exception:
622
+ pass
623
+
536
624
  async def _handle_proxy_request(self, payload: dict) -> None:
537
625
  """Handle a proxied HTTP request from the relay.
538
626
 
@@ -545,10 +633,14 @@ class GatewayClient:
545
633
  local access.
546
634
  """
547
635
  import base64
548
- import httpx
549
636
 
550
637
  # Activity stamp for the reaper's grace window: any proxied request counts.
551
638
  self._last_request_monotonic = time.monotonic()
639
+ self._proxied_count += 1
640
+ # The generation this request belongs to: if the socket is rebuilt before the
641
+ # response is ready, self._generation advances past this and the response is
642
+ # dropped rather than sent on a connection that never issued the request.
643
+ generation = self._generation
552
644
 
553
645
  request_id = payload.get("id", "")
554
646
  method = payload.get("method", "GET")
@@ -557,6 +649,13 @@ class GatewayClient:
557
649
  headers = payload.get("headers", {})
558
650
  body_b64 = payload.get("body_b64", "")
559
651
  body = base64.b64decode(body_b64) if body_b64 else None
652
+ # Additive per-request deadline: a numeric timeout_ms bounds this request below
653
+ # the fixed cap so a single slow local handler can't pin a relay slot for 180s.
654
+ # Absent or non-numeric leaves the default cap in force.
655
+ timeout_ms = payload.get("timeout_ms")
656
+ deadline_s: float | None = None
657
+ if isinstance(timeout_ms, (int, float)) and not isinstance(timeout_ms, bool) and timeout_ms > 0:
658
+ deadline_s = timeout_ms / 1000.0
560
659
 
561
660
  # SSE / long-poll paths cannot be proxied over the WS request/response
562
661
  # protocol. Return an empty stream so the browser doesn't 500.
@@ -599,47 +698,98 @@ class GatewayClient:
599
698
  if query:
600
699
  url = f"{url}?{query}"
601
700
 
701
+ client = self._get_http_client()
602
702
  try:
603
- async with httpx.AsyncClient(timeout=180.0) as client:
703
+ if deadline_s is not None:
704
+ # asyncio.wait_for, not asyncio.timeout: the latter is 3.11+, and this package
705
+ # supports Python >=3.10 where it does not exist. wait_for cancels the request and
706
+ # raises TimeoutError on the deadline, which the handler below turns into an error
707
+ # response.
708
+ resp = await asyncio.wait_for(
709
+ client.request(
710
+ method=method,
711
+ url=url,
712
+ headers=headers,
713
+ content=body,
714
+ ),
715
+ deadline_s,
716
+ )
717
+ else:
604
718
  resp = await client.request(
605
719
  method=method,
606
720
  url=url,
607
721
  headers=headers,
608
722
  content=body,
609
723
  )
610
- resp_body_b64 = base64.b64encode(resp.content).decode() if resp.content else ""
611
- # Serialize as an ORDERED LIST of pairs (not a dict): a response can carry several
612
- # Set-Cookie headers (login/refresh emit access_token + refresh_token), and a dict would
613
- # collapse them into one comma-joined value the browser can't parse — so the refresh
614
- # cookie never reaches the browser and the session dies at the access token's hard cap.
615
- # multi_items() keeps each header separate. Drop content-length; the relay recomputes it.
616
- _skip = {"transfer-encoding", "connection", "keep-alive", "content-length"}
617
- resp_headers = [
618
- [k, v] for k, v in resp.headers.multi_items()
619
- if k.lower() not in _skip
620
- ]
621
- await self._send(self._ws, {
622
- "type": "http.response",
623
- "payload": {
624
- "id": request_id,
625
- "status": resp.status_code,
626
- "headers": resp_headers,
627
- "body_b64": resp_body_b64,
628
- },
629
- })
724
+ except asyncio.CancelledError:
725
+ # http.cancel aborted this request: emit nothing and let the cancellation
726
+ # propagate so the task is recorded cancelled.
727
+ self._cancelled_count += 1
728
+ raise
729
+ except TimeoutError:
730
+ # The per-request deadline elapsed before the local handler answered. Surface
731
+ # it as an error response instead of hanging to the fixed cap.
732
+ self._timeout_count += 1
733
+ log.warning("Proxy request timed out after %sms for %s %s", timeout_ms, method, path)
734
+ if generation == self._generation:
735
+ await self._send(self._ws, {
736
+ "type": "http.response",
737
+ "payload": {
738
+ "id": request_id,
739
+ "status": 504,
740
+ "headers": [["content-type", "text/plain"]],
741
+ "body_b64": base64.b64encode(b"Local app timed out").decode(),
742
+ },
743
+ })
744
+ else:
745
+ self._stale_dropped_count += 1
746
+ return
630
747
  except Exception as exc:
631
748
  log.warning("Proxy request failed for %s %s: %s", method, path, exc)
632
- await self._send(self._ws, {
633
- "type": "http.response",
634
- "payload": {
635
- "id": request_id,
636
- "status": 502,
637
- "headers": [["content-type", "text/plain"]],
638
- "body_b64": base64.b64encode(
639
- f"Local app error: {type(exc).__name__}: {exc}".encode()
640
- ).decode(),
641
- },
642
- })
749
+ if generation == self._generation:
750
+ await self._send(self._ws, {
751
+ "type": "http.response",
752
+ "payload": {
753
+ "id": request_id,
754
+ "status": 502,
755
+ "headers": [["content-type", "text/plain"]],
756
+ "body_b64": base64.b64encode(
757
+ f"Local app error: {type(exc).__name__}: {exc}".encode()
758
+ ).decode(),
759
+ },
760
+ })
761
+ else:
762
+ self._stale_dropped_count += 1
763
+ return
764
+
765
+ # The socket that carried this request may have been rebuilt while it was in
766
+ # flight. A response from a superseded generation belongs to a connection the
767
+ # relay no longer has; sending it on the new socket would answer the wrong
768
+ # request, so it is dropped.
769
+ if generation != self._generation:
770
+ self._stale_dropped_count += 1
771
+ return
772
+
773
+ resp_body_b64 = base64.b64encode(resp.content).decode() if resp.content else ""
774
+ # Serialize as an ORDERED LIST of pairs (not a dict): a response can carry several
775
+ # Set-Cookie headers (login/refresh emit access_token + refresh_token), and a dict would
776
+ # collapse them into one comma-joined value the browser can't parse, so the refresh
777
+ # cookie never reaches the browser and the session dies at the access token's hard cap.
778
+ # multi_items() keeps each header separate. Drop content-length; the relay recomputes it.
779
+ _skip = {"transfer-encoding", "connection", "keep-alive", "content-length"}
780
+ resp_headers = [
781
+ [k, v] for k, v in resp.headers.multi_items()
782
+ if k.lower() not in _skip
783
+ ]
784
+ await self._send(self._ws, {
785
+ "type": "http.response",
786
+ "payload": {
787
+ "id": request_id,
788
+ "status": resp.status_code,
789
+ "headers": resp_headers,
790
+ "body_b64": resp_body_b64,
791
+ },
792
+ })
643
793
 
644
794
  async def send_message(self, msg_type: str, **payload) -> None:
645
795
  """Send a JSON message over the active WS connection.
@@ -652,7 +802,12 @@ class GatewayClient:
652
802
 
653
803
  @staticmethod
654
804
  async def _send(ws, message: dict) -> None:
655
- await ws.send(json.dumps(message))
805
+ # Bound the send: a websocket send awaits until the frame is handed to the transport, and a
806
+ # stalled or backpressured peer would otherwise block it forever, pinning the proxy task and
807
+ # its relay slot. On the deadline the send is cancelled and TimeoutError surfaces to the
808
+ # caller, which lets the wedged socket be torn down and rebuilt. asyncio.wait_for, not
809
+ # asyncio.timeout: the latter is 3.11+ and this package supports Python >=3.10.
810
+ await asyncio.wait_for(ws.send(json.dumps(message)), _SEND_DEADLINE)
656
811
 
657
812
 
658
813
  # Module-level singleton — set by main.py lifespan
@@ -12,7 +12,7 @@ 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
16
  from celerp.inventory_codes import BarcodeConflictError
17
17
  from celerp.config import settings, assert_secure_jwt, ensure_instance_id, load_cloud_config, load_backup_config
18
18
  load_cloud_config()
@@ -164,7 +164,7 @@ async def _try_auto_activate() -> None:
164
164
  async def lifespan(_app: FastAPI):
165
165
  (settings.data_dir / "static" / "attachments").mkdir(parents=True, exist_ok=True)
166
166
  try:
167
- async with engine.begin() as conn:
167
+ async with lifecycle_engine.begin() as conn:
168
168
  await conn.run_sync(Base.metadata.create_all)
169
169
  except Exception as exc:
170
170
  masked_url = mask_db_credentials(settings.database_url)
@@ -205,19 +205,20 @@ async def lifespan(_app: FastAPI):
205
205
  register_api_routes(_app, _loaded_modules)
206
206
  # Module models register on Base.metadata at import time.
207
207
  # Run create_all again so module tables are created (idempotent).
208
- async with engine.begin() as conn:
208
+ async with lifecycle_engine.begin() as conn:
209
209
  await conn.run_sync(Base.metadata.create_all)
210
210
  # Allow modules to backfill data for existing companies (e.g. seed
211
211
  # chart of accounts when accounting module is first enabled on an
212
212
  # instance that already has companies).
213
213
  from celerp.modules.slots import fire_lifecycle as _fire
214
- from celerp.db import SessionLocal as _SessionLocal
214
+ from celerp.db import LifecycleSessionLocal as _LifecycleSession
215
215
  # Best-effort, like the two sibling blocks below: a hook that fails
216
216
  # during flush poisons the shared session, so the commit raises.
217
217
  # Roll back and log at ERROR rather than let that crash boot - the
218
218
  # manufacturing seed hook, for one, must never be able to take the
219
- # app down.
220
- 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:
221
222
  try:
222
223
  await _fire("on_modules_ready", session=_sess)
223
224
  await _sess.commit()
@@ -236,7 +237,7 @@ async def lifespan(_app: FastAPI):
236
237
  _demoted = demoted_first_party(_enabled)
237
238
  if _demoted:
238
239
  from celerp.modules.demotion import notify_demoted_modules
239
- async with _SessionLocal() as _dsess:
240
+ async with _LifecycleSession() as _dsess:
240
241
  await notify_demoted_modules(_dsess, _demoted)
241
242
  await _dsess.commit()
242
243
  except Exception:
@@ -256,7 +257,7 @@ async def lifespan(_app: FastAPI):
256
257
  # marker so it runs once per version. Non-fatal: a failure must not block
257
258
  # boot — the marker stays unset and a later boot retries.
258
259
  try:
259
- from celerp.db import SessionLocal as _GuardSession
260
+ from celerp.db import LifecycleSessionLocal as _GuardSession
260
261
  from celerp.services.dev_release_guard import run_upgrade_guard
261
262
  async with _GuardSession() as _guard_sess:
262
263
  await run_upgrade_guard(_guard_sess)
@@ -271,7 +272,7 @@ async def lifespan(_app: FastAPI):
271
272
  # or consigned in before that field shipped, so their inventory status links
272
273
  # to its document. Marker-gated (runs once); non-fatal like the guard above.
273
274
  try:
274
- from celerp.db import SessionLocal as _BackfillSession
275
+ from celerp.db import LifecycleSessionLocal as _BackfillSession
275
276
  from celerp.services.status_doc_backfill import run_status_doc_backfill
276
277
  async with _BackfillSession() as _bf_sess:
277
278
  await run_status_doc_backfill(_bf_sess)
@@ -287,7 +288,7 @@ async def lifespan(_app: FastAPI):
287
288
  # (runs once; retries stragglers while any doc is locked or errored);
288
289
  # non-fatal like the backfill above.
289
290
  try:
290
- from celerp.db import SessionLocal as _CogsSession
291
+ from celerp.db import LifecycleSessionLocal as _CogsSession
291
292
  from celerp.services.cogs_backfill import run_cogs_backfill
292
293
  async with _CogsSession() as _cogs_sess:
293
294
  await run_cogs_backfill(_cogs_sess)