celerp 2.0.0__tar.gz → 2.1.1__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 (618) hide show
  1. {celerp-2.0.0 → celerp-2.1.1}/PKG-INFO +1 -1
  2. {celerp-2.0.0 → celerp-2.1.1}/celerp/cli.py +51 -22
  3. {celerp-2.0.0 → celerp-2.1.1}/celerp/events/schemas.py +7 -0
  4. {celerp-2.0.0 → celerp-2.1.1}/celerp/main.py +28 -2
  5. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/_data_reconcile.py +30 -12
  6. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/env.py +6 -1
  7. celerp-2.1.1/celerp/migrations/versions/b3c4d5e6f7a8_expand_role_permissions_to_role_grants.py +175 -0
  8. celerp-2.1.1/celerp/migrations/versions/e7c9a1b3d5f2_work_center_default_columns.py +51 -0
  9. celerp-2.1.1/celerp/migrations/versions/f8a9b0c1d2e3_work_center_default_backfill.py +93 -0
  10. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/company.py +11 -1
  11. {celerp-2.0.0 → celerp-2.1.1}/celerp/modules/slots.py +4 -2
  12. {celerp-2.0.0 → celerp-2.1.1}/celerp/routers/companies.py +45 -20
  13. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/backup_import.py +13 -4
  14. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/field_schema.py +13 -0
  15. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/permissions.py +54 -43
  16. celerp-2.1.1/celerp/services/reorder.py +372 -0
  17. celerp-2.1.1/celerp/services/status_doc_backfill.py +101 -0
  18. {celerp-2.0.0 → celerp-2.1.1}/celerp.egg-info/PKG-INFO +1 -1
  19. {celerp-2.0.0 → celerp-2.1.1}/celerp.egg-info/SOURCES.txt +6 -0
  20. {celerp-2.0.0 → celerp-2.1.1}/celerp.egg-info/scm_file_list.json +959 -945
  21. celerp-2.1.1/celerp.egg-info/scm_version.json +8 -0
  22. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-inventory/celerp_inventory/routes.py +135 -11
  23. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/__init__.py +6 -0
  24. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/celerp_manufacturing/routes.py +189 -15
  25. celerp-2.1.1/default_modules/celerp-manufacturing/tests/test_auto_complete_on_finalize.py +171 -0
  26. celerp-2.1.1/default_modules/celerp-manufacturing/tests/test_work_centers_and_settings.py +374 -0
  27. {celerp-2.0.0 → celerp-2.1.1}/default_modules/first_party.lock.json +2 -2
  28. {celerp-2.0.0 → celerp-2.1.1}/test_helpers.py +24 -7
  29. {celerp-2.0.0 → celerp-2.1.1}/ui/api_client.py +5 -0
  30. {celerp-2.0.0 → celerp-2.1.1}/ui/components/activity.py +34 -1
  31. {celerp-2.0.0 → celerp-2.1.1}/ui/components/cloud_gate.py +37 -0
  32. {celerp-2.0.0 → celerp-2.1.1}/ui/components/shell.py +222 -6
  33. {celerp-2.0.0 → celerp-2.1.1}/ui/components/table.py +41 -12
  34. {celerp-2.0.0 → celerp-2.1.1}/ui/locales/ar.json +4 -1
  35. {celerp-2.0.0 → celerp-2.1.1}/ui/locales/de.json +4 -1
  36. {celerp-2.0.0 → celerp-2.1.1}/ui/locales/en.json +12 -1
  37. {celerp-2.0.0 → celerp-2.1.1}/ui/locales/es.json +4 -1
  38. {celerp-2.0.0 → celerp-2.1.1}/ui/locales/fr.json +4 -1
  39. {celerp-2.0.0 → celerp-2.1.1}/ui/locales/id.json +4 -1
  40. {celerp-2.0.0 → celerp-2.1.1}/ui/locales/it.json +4 -1
  41. {celerp-2.0.0 → celerp-2.1.1}/ui/locales/ja.json +4 -1
  42. {celerp-2.0.0 → celerp-2.1.1}/ui/locales/pt.json +4 -1
  43. {celerp-2.0.0 → celerp-2.1.1}/ui/locales/th.json +4 -1
  44. {celerp-2.0.0 → celerp-2.1.1}/ui/locales/vi.json +4 -1
  45. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/account.py +33 -6
  46. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/contacts.py +3 -2
  47. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/documents.py +8 -6
  48. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/inventory.py +883 -446
  49. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/manufacturing.py +74 -17
  50. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/settings.py +11 -10
  51. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/settings_accounting.py +1 -1
  52. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/settings_connectors.py +2 -14
  53. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/settings_inventory.py +33 -9
  54. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/settings_manufacturing.py +31 -26
  55. celerp-2.1.1/ui/security.py +19 -0
  56. {celerp-2.0.0 → celerp-2.1.1}/ui/static/app.css +76 -14
  57. celerp-2.0.0/celerp/services/reorder.py +0 -279
  58. celerp-2.0.0/celerp.egg-info/scm_version.json +0 -8
  59. celerp-2.0.0/default_modules/celerp-manufacturing/tests/test_work_centers_and_settings.py +0 -120
  60. {celerp-2.0.0 → celerp-2.1.1}/CLA.md +0 -0
  61. {celerp-2.0.0 → celerp-2.1.1}/CONTRIBUTING.md +0 -0
  62. {celerp-2.0.0 → celerp-2.1.1}/LICENSE +0 -0
  63. {celerp-2.0.0 → celerp-2.1.1}/LICENSING.md +0 -0
  64. {celerp-2.0.0 → celerp-2.1.1}/MANIFEST.in +0 -0
  65. {celerp-2.0.0 → celerp-2.1.1}/NOTICE +0 -0
  66. {celerp-2.0.0 → celerp-2.1.1}/README.md +0 -0
  67. {celerp-2.0.0 → celerp-2.1.1}/alembic.ini +0 -0
  68. {celerp-2.0.0 → celerp-2.1.1}/celerp/__init__.py +0 -0
  69. {celerp-2.0.0 → celerp-2.1.1}/celerp/__main__.py +0 -0
  70. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/__init__.py +0 -0
  71. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/batch.py +0 -0
  72. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/cleanup.py +0 -0
  73. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/commands.py +0 -0
  74. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/conversations.py +0 -0
  75. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/files.py +0 -0
  76. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/intent.py +0 -0
  77. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/llm.py +0 -0
  78. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/memory.py +0 -0
  79. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/models.py +0 -0
  80. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/page_count.py +0 -0
  81. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/quota.py +0 -0
  82. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/service.py +0 -0
  83. {celerp-2.0.0 → celerp-2.1.1}/celerp/ai/tools.py +0 -0
  84. {celerp-2.0.0 → celerp-2.1.1}/celerp/alembic.ini +0 -0
  85. {celerp-2.0.0 → celerp-2.1.1}/celerp/alembic_config.py +0 -0
  86. {celerp-2.0.0 → celerp-2.1.1}/celerp/compat.py +0 -0
  87. {celerp-2.0.0 → celerp-2.1.1}/celerp/compute/__init__.py +0 -0
  88. {celerp-2.0.0 → celerp-2.1.1}/celerp/compute/aggregations.py +0 -0
  89. {celerp-2.0.0 → celerp-2.1.1}/celerp/compute/valuation.py +0 -0
  90. {celerp-2.0.0 → celerp-2.1.1}/celerp/config.py +0 -0
  91. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/__init__.py +0 -0
  92. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/base.py +0 -0
  93. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/daily_scheduler.py +0 -0
  94. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/http.py +0 -0
  95. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/images.py +0 -0
  96. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/quickbooks.py +0 -0
  97. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/registry.py +0 -0
  98. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/relay_token.py +0 -0
  99. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/shopify.py +0 -0
  100. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/sync_runner.py +0 -0
  101. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/upsert.py +0 -0
  102. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/util.py +0 -0
  103. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/webhooks.py +0 -0
  104. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/woocommerce.py +0 -0
  105. {celerp-2.0.0 → celerp-2.1.1}/celerp/connectors/xero.py +0 -0
  106. {celerp-2.0.0 → celerp-2.1.1}/celerp/constants.py +0 -0
  107. {celerp-2.0.0 → celerp-2.1.1}/celerp/db.py +0 -0
  108. {celerp-2.0.0 → celerp-2.1.1}/celerp/embedded_pg.py +0 -0
  109. {celerp-2.0.0 → celerp-2.1.1}/celerp/events/__init__.py +0 -0
  110. {celerp-2.0.0 → celerp-2.1.1}/celerp/events/engine.py +0 -0
  111. {celerp-2.0.0 → celerp-2.1.1}/celerp/events/types.py +0 -0
  112. {celerp-2.0.0 → celerp-2.1.1}/celerp/gateway/__init__.py +0 -0
  113. {celerp-2.0.0 → celerp-2.1.1}/celerp/gateway/client.py +0 -0
  114. {celerp-2.0.0 → celerp-2.1.1}/celerp/gateway/state.py +0 -0
  115. {celerp-2.0.0 → celerp-2.1.1}/celerp/importers/__init__.py +0 -0
  116. {celerp-2.0.0 → celerp-2.1.1}/celerp/importers/importer.py +0 -0
  117. {celerp-2.0.0 → celerp-2.1.1}/celerp/importers/schema.py +0 -0
  118. {celerp-2.0.0 → celerp-2.1.1}/celerp/middleware.py +0 -0
  119. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/README.md +0 -0
  120. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/_auto_stamp.py +0 -0
  121. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/_json_compat.py +0 -0
  122. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/script.py.mako +0 -0
  123. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/a0b1c2d3e4f5_seed_landed_cost_clearing_accounts.py +0 -0
  124. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/a1b2c3d4e5f6_add_doc_share_tokens.py +0 -0
  125. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/b1c2d3e4f5a6_add_supporter_badges.py +0 -0
  126. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/b2c3d4e5f6a7_add_import_batches.py +0 -0
  127. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/c1d2e3f4a5b6_add_marketplace.py +0 -0
  128. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/c2d3e4f5a6b7_add_is_sync_to_shopify.py +0 -0
  129. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/c4d5e6f7a8b9_account_cash_flow_category.py +0 -0
  130. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/d0e1f2a3b4c5_add_share_token_expiry.py +0 -0
  131. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/d2e3f4a5b6c7_add_password_reset_token.py +0 -0
  132. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/d5e6f7a8b9c0_rename_fx_rounding_to_fx_difference.py +0 -0
  133. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/e3f4a5b6c7d8_add_company_is_active.py +0 -0
  134. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/e4f5a6b7c8d9_backfill_connector_idempotency_key.py +0 -0
  135. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/f1a2b3c4d5e6_move_accounts_marketplace_to_modules.py +0 -0
  136. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/f6a7b8c9d0e1_seed_fx_rounding_account.py +0 -0
  137. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/fd5de461e14e_initial_schema.py +0 -0
  138. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/g1h2i3j4k5l6_add_consignment_flag.py +0 -0
  139. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/h2i3j4k5l6m7_add_bank_accounts_and_reconciliation.py +0 -0
  140. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/j4k5l6m7n8o9_labels_db_persistence.py +0 -0
  141. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/k5l6m7n8o9p0_add_reconciliation_v2.py +0 -0
  142. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/l6m7n8o9p0q1_add_sync_runs_table.py +0 -0
  143. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/m7n8o9p0q1r2_add_connector_configs_and_outbound_queue.py +0 -0
  144. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/n8o9p0q1r2s3_backfill_payment_date.py +0 -0
  145. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/o9p0q1r2s3t4_backfill_item_price_fields.py +0 -0
  146. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/p1q2r3s4t5u6_add_session_registry_and_user_auth_state.py +0 -0
  147. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/q2r3s4t5u6v7_add_system_runtime_state.py +0 -0
  148. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/r3s4t5u6v7w8_add_projections_company_entity_type_index.py +0 -0
  149. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/s4t5u6v7w8x9_drop_user_company_id_role.py +0 -0
  150. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/t5u6v7w8x9y0_seed_inventory_sub_accounts.py +0 -0
  151. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/u6v7w8x9y0z1_backfill_item_prices_from_attributes.py +0 -0
  152. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/v7w8x9y0z1a2_backfill_purchase_unit_defaults.py +0 -0
  153. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/w8x9y0z1a2b3_backfill_category_unit_defaults.py +0 -0
  154. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/x7y8z9a0b1c2_add_projection_created_at.py +0 -0
  155. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/y8z9a0b1c2d3_per_company_ledger_idempotency.py +0 -0
  156. {celerp-2.0.0 → celerp-2.1.1}/celerp/migrations/versions/z9a0b1c2d3e4_work_centers.py +0 -0
  157. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/__init__.py +0 -0
  158. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/accounting.py +0 -0
  159. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/ai.py +0 -0
  160. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/auth.py +0 -0
  161. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/base.py +0 -0
  162. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/connector_config.py +0 -0
  163. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/import_batch.py +0 -0
  164. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/ledger.py +0 -0
  165. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/marketplace.py +0 -0
  166. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/notification.py +0 -0
  167. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/projections.py +0 -0
  168. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/share.py +0 -0
  169. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/supporter.py +0 -0
  170. {celerp-2.0.0 → celerp-2.1.1}/celerp/models/sync_run.py +0 -0
  171. {celerp-2.0.0 → celerp-2.1.1}/celerp/modules/__init__.py +0 -0
  172. {celerp-2.0.0 → celerp-2.1.1}/celerp/modules/api.py +0 -0
  173. {celerp-2.0.0 → celerp-2.1.1}/celerp/modules/audit.py +0 -0
  174. {celerp-2.0.0 → celerp-2.1.1}/celerp/modules/demotion.py +0 -0
  175. {celerp-2.0.0 → celerp-2.1.1}/celerp/modules/importer.py +0 -0
  176. {celerp-2.0.0 → celerp-2.1.1}/celerp/modules/license.py +0 -0
  177. {celerp-2.0.0 → celerp-2.1.1}/celerp/modules/loader.py +0 -0
  178. {celerp-2.0.0 → celerp-2.1.1}/celerp/modules/meta.py +0 -0
  179. {celerp-2.0.0 → celerp-2.1.1}/celerp/modules/migrations_runner.py +0 -0
  180. {celerp-2.0.0 → celerp-2.1.1}/celerp/modules/references.py +0 -0
  181. {celerp-2.0.0 → celerp-2.1.1}/celerp/modules/registry.py +0 -0
  182. {celerp-2.0.0 → celerp-2.1.1}/celerp/notifications/__init__.py +0 -0
  183. {celerp-2.0.0 → celerp-2.1.1}/celerp/notifications/service.py +0 -0
  184. {celerp-2.0.0 → celerp-2.1.1}/celerp/notifications/sse.py +0 -0
  185. {celerp-2.0.0 → celerp-2.1.1}/celerp/output/__init__.py +0 -0
  186. {celerp-2.0.0 → celerp-2.1.1}/celerp/output/branding.py +0 -0
  187. {celerp-2.0.0 → celerp-2.1.1}/celerp/output/doc_print.py +0 -0
  188. {celerp-2.0.0 → celerp-2.1.1}/celerp/output/pdf.py +0 -0
  189. {celerp-2.0.0 → celerp-2.1.1}/celerp/output/share_render.py +0 -0
  190. {celerp-2.0.0 → celerp-2.1.1}/celerp/projections/__init__.py +0 -0
  191. {celerp-2.0.0 → celerp-2.1.1}/celerp/projections/engine.py +0 -0
  192. {celerp-2.0.0 → celerp-2.1.1}/celerp/projections/handlers/__init__.py +0 -0
  193. {celerp-2.0.0 → celerp-2.1.1}/celerp/projections/handlers/marketplace.py +0 -0
  194. {celerp-2.0.0 → celerp-2.1.1}/celerp/projections/handlers/scanning.py +0 -0
  195. {celerp-2.0.0 → celerp-2.1.1}/celerp/projections/handlers/shopify.py +0 -0
  196. {celerp-2.0.0 → celerp-2.1.1}/celerp/projections/handlers/system.py +0 -0
  197. {celerp-2.0.0 → celerp-2.1.1}/celerp/routers/__init__.py +0 -0
  198. {celerp-2.0.0 → celerp-2.1.1}/celerp/routers/auth.py +0 -0
  199. {celerp-2.0.0 → celerp-2.1.1}/celerp/routers/debug.py +0 -0
  200. {celerp-2.0.0 → celerp-2.1.1}/celerp/routers/doctor.py +0 -0
  201. {celerp-2.0.0 → celerp-2.1.1}/celerp/routers/events.py +0 -0
  202. {celerp-2.0.0 → celerp-2.1.1}/celerp/routers/health.py +0 -0
  203. {celerp-2.0.0 → celerp-2.1.1}/celerp/routers/ledger.py +0 -0
  204. {celerp-2.0.0 → celerp-2.1.1}/celerp/routers/notifications.py +0 -0
  205. {celerp-2.0.0 → celerp-2.1.1}/celerp/routers/stars.py +0 -0
  206. {celerp-2.0.0 → celerp-2.1.1}/celerp/routers/system.py +0 -0
  207. {celerp-2.0.0 → celerp-2.1.1}/celerp/schemas/__init__.py +0 -0
  208. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/__init__.py +0 -0
  209. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/activity_redaction.py +0 -0
  210. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/attachments.py +0 -0
  211. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/auth.py +0 -0
  212. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/auto_je.py +0 -0
  213. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/backup.py +0 -0
  214. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/backup_export.py +0 -0
  215. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/backup_repo.py +0 -0
  216. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/backup_scheduler.py +0 -0
  217. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/backup_state.py +0 -0
  218. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/cost_visibility.py +0 -0
  219. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/demo.py +0 -0
  220. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/dev_release_guard.py +0 -0
  221. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/email.py +0 -0
  222. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/fulfill.py +0 -0
  223. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/holdings.py +0 -0
  224. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/je_keys.py +0 -0
  225. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/landed_cost.py +0 -0
  226. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/line_measures.py +0 -0
  227. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/list_behavior.py +0 -0
  228. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/money.py +0 -0
  229. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/payments.py +0 -0
  230. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/pick.py +0 -0
  231. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/pricing.py +0 -0
  232. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/relay_share.py +0 -0
  233. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/runtime_state.py +0 -0
  234. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/session_tracker.py +0 -0
  235. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/shipping.py +0 -0
  236. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/star_cta.py +0 -0
  237. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/supporter_badge.py +0 -0
  238. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/system_health.py +0 -0
  239. {celerp-2.0.0 → celerp-2.1.1}/celerp/services/units.py +0 -0
  240. {celerp-2.0.0 → celerp-2.1.1}/celerp/session_gate.py +0 -0
  241. {celerp-2.0.0 → celerp-2.1.1}/celerp/tax_regimes.py +0 -0
  242. {celerp-2.0.0 → celerp-2.1.1}/celerp.egg-info/dependency_links.txt +0 -0
  243. {celerp-2.0.0 → celerp-2.1.1}/celerp.egg-info/entry_points.txt +0 -0
  244. {celerp-2.0.0 → celerp-2.1.1}/celerp.egg-info/requires.txt +0 -0
  245. {celerp-2.0.0 → celerp-2.1.1}/celerp.egg-info/top_level.txt +0 -0
  246. {celerp-2.0.0 → celerp-2.1.1}/conftest.py +0 -0
  247. {celerp-2.0.0 → celerp-2.1.1}/default_modules/__init__.py +0 -0
  248. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/LICENSE +0 -0
  249. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/__init__.py +0 -0
  250. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/celerp_accounting/__init__.py +0 -0
  251. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/celerp_accounting/api_setup.py +0 -0
  252. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/celerp_accounting/csv_parser.py +0 -0
  253. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/celerp_accounting/matcher.py +0 -0
  254. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/celerp_accounting/models.py +0 -0
  255. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/celerp_accounting/projections.py +0 -0
  256. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/celerp_accounting/routes.py +0 -0
  257. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/celerp_accounting/ui_routes.py +0 -0
  258. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/report_goldens/balance-sheet.html +0 -0
  259. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/report_goldens/cash-flow.html +0 -0
  260. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-csv.csv +0 -0
  261. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-print.html +0 -0
  262. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/report_goldens/extended-journal.html +0 -0
  263. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/report_goldens/general-ledger.html +0 -0
  264. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/report_goldens/journal-csv.csv +0 -0
  265. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/report_goldens/journal-print.html +0 -0
  266. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/report_goldens/journal.html +0 -0
  267. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/report_goldens/ledger.html +0 -0
  268. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/report_goldens/pnl.html +0 -0
  269. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/report_goldens/statement.html +0 -0
  270. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/report_goldens/trial-balance.html +0 -0
  271. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/test_accounting_banking.py +0 -0
  272. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/test_accounting_banking_routers.py +0 -0
  273. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/test_accounting_gaps.py +0 -0
  274. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/test_accounting_import_idempotency.py +0 -0
  275. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/test_cash_flow.py +0 -0
  276. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/test_financial_reports_ui.py +0 -0
  277. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/test_journal_gl_soa.py +0 -0
  278. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/test_journal_gl_soa_ui.py +0 -0
  279. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/test_reconciliation_v2.py +0 -0
  280. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/test_reports_end_to_end.py +0 -0
  281. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-accounting/tests/test_route_permissions.py +0 -0
  282. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-admin/__init__.py +0 -0
  283. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-admin/celerp_admin/__init__.py +0 -0
  284. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-admin/celerp_admin/routes.py +0 -0
  285. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-admin/celerp_admin/setup.py +0 -0
  286. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/__init__.py +0 -0
  287. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/celerp_ai/__init__.py +0 -0
  288. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/celerp_ai/routes.py +0 -0
  289. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/celerp_ai/setup.py +0 -0
  290. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/celerp_ai/ui_routes.py +0 -0
  291. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/conftest.py +0 -0
  292. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_batch.py +0 -0
  293. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_cleanup.py +0 -0
  294. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_conversations.py +0 -0
  295. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_coverage_gaps.py +0 -0
  296. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_intent.py +0 -0
  297. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_llm.py +0 -0
  298. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_memory.py +0 -0
  299. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_models.py +0 -0
  300. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_page_count.py +0 -0
  301. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_quota.py +0 -0
  302. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_router.py +0 -0
  303. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_routes_coverage.py +0 -0
  304. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_service.py +0 -0
  305. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-ai/tests/test_tools.py +0 -0
  306. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-backup/__init__.py +0 -0
  307. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-backup/celerp_backup/__init__.py +0 -0
  308. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-backup/celerp_backup/routes.py +0 -0
  309. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-backup/celerp_backup/setup.py +0 -0
  310. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/__init__.py +0 -0
  311. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/celerp_connectors/__init__.py +0 -0
  312. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/celerp_connectors/models.py +0 -0
  313. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/celerp_connectors/routes.py +0 -0
  314. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/__init__.py +0 -0
  315. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/conftest.py +0 -0
  316. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/test_compliance.py +0 -0
  317. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/test_connector_correctness.py +0 -0
  318. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/test_connectors.py +0 -0
  319. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/test_credentials_routes.py +0 -0
  320. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/test_images.py +0 -0
  321. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/test_outbound.py +0 -0
  322. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/test_quickbooks.py +0 -0
  323. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/test_rate_limiting.py +0 -0
  324. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/test_shopify.py +0 -0
  325. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/test_wiring.py +0 -0
  326. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/test_woocommerce.py +0 -0
  327. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/test_woocommerce_webhooks.py +0 -0
  328. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-connectors/tests/test_xero.py +0 -0
  329. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-contacts/LICENSE +0 -0
  330. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-contacts/__init__.py +0 -0
  331. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-contacts/celerp_contacts/__init__.py +0 -0
  332. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-contacts/celerp_contacts/migrations.py +0 -0
  333. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-contacts/celerp_contacts/projections.py +0 -0
  334. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-contacts/celerp_contacts/routes.py +0 -0
  335. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-contacts/celerp_contacts/services.py +0 -0
  336. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-contacts/celerp_contacts/ui_routes.py +0 -0
  337. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-dashboard/LICENSE +0 -0
  338. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-dashboard/__init__.py +0 -0
  339. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-dashboard/celerp_dashboard/__init__.py +0 -0
  340. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-dashboard/celerp_dashboard/routes.py +0 -0
  341. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-dashboard/celerp_dashboard/setup.py +0 -0
  342. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/LICENSE +0 -0
  343. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/__init__.py +0 -0
  344. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/celerp_docs/__init__.py +0 -0
  345. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/celerp_docs/api_setup.py +0 -0
  346. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/celerp_docs/doc_constants.py +0 -0
  347. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/celerp_docs/doc_email.py +0 -0
  348. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/celerp_docs/doc_projections.py +0 -0
  349. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/celerp_docs/doc_service.py +0 -0
  350. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/celerp_docs/models_share.py +0 -0
  351. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/celerp_docs/routes.py +0 -0
  352. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/celerp_docs/routes_payments.py +0 -0
  353. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/celerp_docs/routes_share.py +0 -0
  354. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/celerp_docs/sequences.py +0 -0
  355. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/celerp_docs/taxes.py +0 -0
  356. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/celerp_docs/ui_routes.py +0 -0
  357. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/conftest.py +0 -0
  358. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_audits.py +0 -0
  359. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_freight_je.py +0 -0
  360. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_freight_lines.py +0 -0
  361. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_fulfill_no_split.py +0 -0
  362. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_fulfillment_activity.py +0 -0
  363. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_inbound_je_lifecycle.py +0 -0
  364. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_inventory_account_reconciliation.py +0 -0
  365. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_landed_receive.py +0 -0
  366. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_line_delete_persist.py +0 -0
  367. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_line_identifier.py +0 -0
  368. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_payment_void_activity.py +0 -0
  369. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_receive_sku_batch.py +0 -0
  370. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_send_visibility.py +0 -0
  371. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_service_lines.py +0 -0
  372. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-docs/tests/test_void_guards.py +0 -0
  373. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-inventory/LICENSE +0 -0
  374. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-inventory/__init__.py +0 -0
  375. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-inventory/celerp_inventory/__init__.py +0 -0
  376. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-inventory/celerp_inventory/models_import_batch.py +0 -0
  377. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-inventory/celerp_inventory/projections.py +0 -0
  378. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-inventory/celerp_inventory/routes_attachments.py +0 -0
  379. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-inventory/celerp_inventory/routes_scanning.py +0 -0
  380. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-inventory/celerp_inventory/services.py +0 -0
  381. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-inventory/celerp_inventory/ui_routes.py +0 -0
  382. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-inventory/tests/test_item_recipe_projection.py +0 -0
  383. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-inventory/tests/test_item_workflow_projection.py +0 -0
  384. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-inventory/tests/test_landed_cost_projection.py +0 -0
  385. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-labels/LICENSE +0 -0
  386. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-labels/__init__.py +0 -0
  387. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-labels/celerp_labels/__init__.py +0 -0
  388. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-labels/celerp_labels/models.py +0 -0
  389. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-labels/celerp_labels/presets.py +0 -0
  390. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-labels/celerp_labels/routes.py +0 -0
  391. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-labels/celerp_labels/service.py +0 -0
  392. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-labels/celerp_labels/ui_routes.py +0 -0
  393. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-labels/requirements.txt +0 -0
  394. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-labels/tests/test_labels.py +0 -0
  395. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-labels/tests/test_labels_module.py +0 -0
  396. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/LICENSE +0 -0
  397. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/celerp_manufacturing/__init__.py +0 -0
  398. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/celerp_manufacturing/costing.py +0 -0
  399. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/celerp_manufacturing/expansion.py +0 -0
  400. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/celerp_manufacturing/labor.py +0 -0
  401. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/celerp_manufacturing/migrations.py +0 -0
  402. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/celerp_manufacturing/projection_handler.py +0 -0
  403. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/celerp_manufacturing/ui_routes.py +0 -0
  404. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/requirements.txt +0 -0
  405. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_bom_removed.py +0 -0
  406. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_build_api.py +0 -0
  407. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_item_recipe_api.py +0 -0
  408. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_item_workflow_api.py +0 -0
  409. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_labor_providers.py +0 -0
  410. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_manufacture_from_doc.py +0 -0
  411. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_manufacturing.py +0 -0
  412. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_manufacturing_import_idempotency.py +0 -0
  413. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_manufacturing_module.py +0 -0
  414. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_mfg_events.py +0 -0
  415. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_phase2_manufacturing_validations.py +0 -0
  416. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_production_order.py +0 -0
  417. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_recipe_costing.py +0 -0
  418. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_recipe_expansion.py +0 -0
  419. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_recost_api.py +0 -0
  420. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_to_make_allocation.py +0 -0
  421. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_where_used.py +0 -0
  422. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-manufacturing/tests/test_workflow_time.py +0 -0
  423. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-reports/LICENSE +0 -0
  424. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-reports/__init__.py +0 -0
  425. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-reports/celerp_reports/__init__.py +0 -0
  426. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-reports/celerp_reports/api_setup.py +0 -0
  427. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-reports/celerp_reports/routes.py +0 -0
  428. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-reports/celerp_reports/ui_routes.py +0 -0
  429. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-reports/tests/test_reports_full.py +0 -0
  430. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-reports/tests/test_reports_unit.py +0 -0
  431. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-subscriptions/LICENSE +0 -0
  432. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-subscriptions/__init__.py +0 -0
  433. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-subscriptions/celerp_subscriptions/__init__.py +0 -0
  434. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-subscriptions/celerp_subscriptions/routes.py +0 -0
  435. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-subscriptions/celerp_subscriptions/ui_routes.py +0 -0
  436. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-subscriptions/tests/test_subscriptions.py +0 -0
  437. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-subscriptions/tests/test_subscriptions_ui.py +0 -0
  438. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/LICENSE +0 -0
  439. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/__init__.py +0 -0
  440. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/__init__.py +0 -0
  441. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/accessory_fashion.json +0 -0
  442. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/activewear.json +0 -0
  443. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/art_photography.json +0 -0
  444. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/audio_equipment.json +0 -0
  445. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/bag_handbag.json +0 -0
  446. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/banknote.json +0 -0
  447. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/beauty_tool.json +0 -0
  448. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/bed_bedroom.json +0 -0
  449. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/beer.json +0 -0
  450. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/beverage_nonalc.json +0 -0
  451. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/body_part_auto.json +0 -0
  452. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/book.json +0 -0
  453. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/bottoms.json +0 -0
  454. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/brake_suspension.json +0 -0
  455. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/bullion_coin.json +0 -0
  456. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/camera.json +0 -0
  457. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/colored_stone.json +0 -0
  458. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/comic.json +0 -0
  459. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/commercial_space.json +0 -0
  460. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/component_part.json +0 -0
  461. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/confectionery.json +0 -0
  462. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/consulting_service.json +0 -0
  463. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/decorative_art.json +0 -0
  464. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/diamond.json +0 -0
  465. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/drawing.json +0 -0
  466. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/dress_jumpsuit.json +0 -0
  467. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_auto.json +0 -0
  468. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_component.json +0 -0
  469. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/emerald.json +0 -0
  470. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/engine_part.json +0 -0
  471. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/fastener.json +0 -0
  472. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/fertilizer_chemical.json +0 -0
  473. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/film_video.json +0 -0
  474. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/fine_writing_instrument.json +0 -0
  475. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/fluid_lubricant.json +0 -0
  476. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/footwear.json +0 -0
  477. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/fragrance.json +0 -0
  478. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_food.json +0 -0
  479. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_produce.json +0 -0
  480. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/frozen_food.json +0 -0
  481. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/gaming_console.json +0 -0
  482. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/gold_bullion.json +0 -0
  483. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/grain_cereal.json +0 -0
  484. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/haircare.json +0 -0
  485. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/hand_tool.json +0 -0
  486. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/ingredient_bulk.json +0 -0
  487. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/interior_part.json +0 -0
  488. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/jewelry.json +0 -0
  489. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/kitchen_dining.json +0 -0
  490. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/laptop.json +0 -0
  491. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/lighting.json +0 -0
  492. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/livestock_feed.json +0 -0
  493. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/makeup.json +0 -0
  494. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/measuring_instrument.json +0 -0
  495. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/medal_token.json +0 -0
  496. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/mineral_specimen.json +0 -0
  497. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/mobile_phone.json +0 -0
  498. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/music_cd.json +0 -0
  499. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/music_vinyl.json +0 -0
  500. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/nail.json +0 -0
  501. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/numismatic_coin.json +0 -0
  502. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/outdoor_furniture.json +0 -0
  503. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/outerwear.json +0 -0
  504. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/packaged_food.json +0 -0
  505. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/painting.json +0 -0
  506. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/parking_bay.json +0 -0
  507. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/pearl.json +0 -0
  508. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/personal_care.json +0 -0
  509. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/pipe_plumbing.json +0 -0
  510. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/platinum_bullion.json +0 -0
  511. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/power_tool.json +0 -0
  512. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/print_edition.json +0 -0
  513. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/residential_unit.json +0 -0
  514. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/rough_gemstone.json +0 -0
  515. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/ruby.json +0 -0
  516. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/saas_plan.json +0 -0
  517. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/safety_ppe.json +0 -0
  518. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/sapphire.json +0 -0
  519. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/sculpture.json +0 -0
  520. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/seating.json +0 -0
  521. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/seeds.json +0 -0
  522. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/silver_bullion.json +0 -0
  523. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/skincare.json +0 -0
  524. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/soft_furnishing.json +0 -0
  525. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/software_addon.json +0 -0
  526. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/software_license.json +0 -0
  527. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/spirit.json +0 -0
  528. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/storage_furniture.json +0 -0
  529. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/swimwear.json +0 -0
  530. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/table_desk.json +0 -0
  531. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/tablet.json +0 -0
  532. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/tire_wheel.json +0 -0
  533. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/tops.json +0 -0
  534. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/trading_card.json +0 -0
  535. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/tv_display.json +0 -0
  536. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/video_game.json +0 -0
  537. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/watch.json +0 -0
  538. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/watch_strap.json +0 -0
  539. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/categories/wine.json +0 -0
  540. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/agricultural.json +0 -0
  541. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/artwork.json +0 -0
  542. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/automotive.json +0 -0
  543. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/blank.json +0 -0
  544. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/books_media.json +0 -0
  545. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/coins_precious_metals.json +0 -0
  546. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/consulting.json +0 -0
  547. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/cosmetics.json +0 -0
  548. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/electronics.json +0 -0
  549. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/fashion.json +0 -0
  550. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/food_beverage.json +0 -0
  551. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/furniture.json +0 -0
  552. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/gemstones.json +0 -0
  553. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/hardware.json +0 -0
  554. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/property_rental.json +0 -0
  555. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/saas.json +0 -0
  556. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/watches.json +0 -0
  557. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/presets/wine_spirits.json +0 -0
  558. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/routes.py +0 -0
  559. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/celerp_verticals/ui_routes.py +0 -0
  560. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/tests/test_verticals.py +0 -0
  561. {celerp-2.0.0 → celerp-2.1.1}/default_modules/celerp-verticals/tests/test_verticals_routers.py +0 -0
  562. {celerp-2.0.0 → celerp-2.1.1}/legal/OFFICIAL-COMPONENTS.md +0 -0
  563. {celerp-2.0.0 → celerp-2.1.1}/legal/TRADEMARK.md +0 -0
  564. {celerp-2.0.0 → celerp-2.1.1}/packaging/winget/Celerp.Celerp.installer.yaml +0 -0
  565. {celerp-2.0.0 → celerp-2.1.1}/packaging/winget/Celerp.Celerp.locale.en-US.yaml +0 -0
  566. {celerp-2.0.0 → celerp-2.1.1}/packaging/winget/Celerp.Celerp.yaml +0 -0
  567. {celerp-2.0.0 → celerp-2.1.1}/packaging/winget/README.md +0 -0
  568. {celerp-2.0.0 → celerp-2.1.1}/pyproject.toml +0 -0
  569. {celerp-2.0.0 → celerp-2.1.1}/setup.cfg +0 -0
  570. {celerp-2.0.0 → celerp-2.1.1}/ui/__init__.py +0 -0
  571. {celerp-2.0.0 → celerp-2.1.1}/ui/app.py +0 -0
  572. {celerp-2.0.0 → celerp-2.1.1}/ui/components/__init__.py +0 -0
  573. {celerp-2.0.0 → celerp-2.1.1}/ui/components/attrs.py +0 -0
  574. {celerp-2.0.0 → celerp-2.1.1}/ui/components/backup.py +0 -0
  575. {celerp-2.0.0 → celerp-2.1.1}/ui/components/currency.py +0 -0
  576. {celerp-2.0.0 → celerp-2.1.1}/ui/components/files.py +0 -0
  577. {celerp-2.0.0 → celerp-2.1.1}/ui/components/journal.py +0 -0
  578. {celerp-2.0.0 → celerp-2.1.1}/ui/components/notes.py +0 -0
  579. {celerp-2.0.0 → celerp-2.1.1}/ui/components/phone.py +0 -0
  580. {celerp-2.0.0 → celerp-2.1.1}/ui/components/report_kit.py +0 -0
  581. {celerp-2.0.0 → celerp-2.1.1}/ui/config.py +0 -0
  582. {celerp-2.0.0 → celerp-2.1.1}/ui/i18n.py +0 -0
  583. {celerp-2.0.0 → celerp-2.1.1}/ui/marketplace_catalog.py +0 -0
  584. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/__init__.py +0 -0
  585. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/accounting.py +0 -0
  586. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/accounting_import.py +0 -0
  587. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/auth.py +0 -0
  588. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/csv_import.py +0 -0
  589. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/dashboard.py +0 -0
  590. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/docs_import.py +0 -0
  591. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/events.py +0 -0
  592. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/financial_reports.py +0 -0
  593. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/lists_import.py +0 -0
  594. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/modules_page.py +0 -0
  595. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/notifications.py +0 -0
  596. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/reconciliation.py +0 -0
  597. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/reports.py +0 -0
  598. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/search.py +0 -0
  599. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/settings_cloud.py +0 -0
  600. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/settings_contacts.py +0 -0
  601. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/settings_general.py +0 -0
  602. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/settings_import.py +0 -0
  603. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/settings_payments.py +0 -0
  604. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/settings_purchasing.py +0 -0
  605. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/settings_sales.py +0 -0
  606. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/setup.py +0 -0
  607. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/stars.py +0 -0
  608. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/subscriptions.py +0 -0
  609. {celerp-2.0.0 → celerp-2.1.1}/ui/routes/subscriptions_import.py +0 -0
  610. {celerp-2.0.0 → celerp-2.1.1}/ui/static/htmx.min.js +0 -0
  611. {celerp-2.0.0 → celerp-2.1.1}/ui/static/icon.png +0 -0
  612. {celerp-2.0.0 → celerp-2.1.1}/ui/static/logo.png +0 -0
  613. {celerp-2.0.0 → celerp-2.1.1}/ui/static/vendor/intl-tel-input/img/flags.webp +0 -0
  614. {celerp-2.0.0 → celerp-2.1.1}/ui/static/vendor/intl-tel-input/img/flags@2x.webp +0 -0
  615. {celerp-2.0.0 → celerp-2.1.1}/ui/static/vendor/intl-tel-input/intlTelInput.min.css +0 -0
  616. {celerp-2.0.0 → celerp-2.1.1}/ui/static/vendor/intl-tel-input/intlTelInput.min.js +0 -0
  617. {celerp-2.0.0 → celerp-2.1.1}/ui/static/vendor/intl-tel-input/intlTelInputWithUtils.min.js +0 -0
  618. {celerp-2.0.0 → celerp-2.1.1}/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.0.0
3
+ Version: 2.1.1
4
4
  Summary: Free, self-hosted ERP for small businesses
5
5
  License: Business Source License 1.1
6
6
 
@@ -10,6 +10,7 @@ import signal
10
10
  import subprocess
11
11
  import sys
12
12
  import time
13
+ from contextlib import contextmanager
13
14
  from pathlib import Path
14
15
 
15
16
  import click
@@ -639,21 +640,19 @@ def _stamped_revision(db_url: str) -> str | None:
639
640
  engine.dispose()
640
641
 
641
642
 
642
- def _migrate_to_head(db_url: str) -> None:
643
- """Apply pending migrations, the grants, then the develop→release reconcile.
643
+ @contextmanager
644
+ def _migration_lock(db_url: str):
645
+ """Hold the shared Postgres migration advisory lock for the wrapped block.
644
646
 
645
- Shared by `celerp migrate` and `celerp start` so the steps and their order
646
- exist once. The start path cannot drift from the explicit command.
647
+ Single source of the lock protocol (acquire, guaranteed release, engine
648
+ disposal), so every path that migrates a database serializes the same way
649
+ and cannot drift. Reused by `_migrate_to_head` and the restore reconcile.
647
650
 
648
- Held under a Postgres advisory lock, because a service restart overlapping a
649
- manual start would otherwise have both processes migrating the same database:
650
- the loser re-applies DDL that already exists and is stamped past it by the
651
+ The lock exists because a service restart overlapping a manual start would
652
+ otherwise have both processes migrating the same database: the loser
653
+ re-applies DDL that already exists and is stamped past it by the
651
654
  duplicate-object handler, which reaches the right answer for the wrong
652
655
  reason. The second holder waits here and then finds nothing pending.
653
-
654
- Reports the stamp it moved, and says nothing when it moved nothing, so a
655
- routine start is as quiet as it was and a start that changed the schema
656
- cannot be mistaken for one that did not.
657
656
  """
658
657
  from sqlalchemy import create_engine, text
659
658
 
@@ -662,25 +661,40 @@ def _migrate_to_head(db_url: str) -> None:
662
661
  engine = create_engine(_sync_url(db_url), pool_pre_ping=True).execution_options(
663
662
  isolation_level="AUTOCOMMIT"
664
663
  )
665
- before = after = None
666
664
  try:
667
665
  with engine.connect() as lock_conn:
668
666
  lock_conn.execute(text("SELECT pg_advisory_lock(:key)"), {"key": _MIGRATION_LOCK_KEY})
669
667
  try:
670
- before = _stamped_revision(db_url)
671
- _run_migrations(db_url)
672
- _post_migration_grants(db_url)
673
- _reconcile_after_migrate(db_url)
674
- # Read inside the lock: outside it, a process queued behind this
675
- # one could move the stamp further and this would report a
676
- # transition that never happened here.
677
- after = _stamped_revision(db_url)
668
+ yield
678
669
  finally:
679
670
  lock_conn.execute(
680
671
  text("SELECT pg_advisory_unlock(:key)"), {"key": _MIGRATION_LOCK_KEY}
681
672
  )
682
673
  finally:
683
674
  engine.dispose()
675
+
676
+
677
+ def _migrate_to_head(db_url: str) -> None:
678
+ """Apply pending migrations, the grants, then the develop→release reconcile.
679
+
680
+ Shared by `celerp migrate` and `celerp start` so the steps and their order
681
+ exist once. The start path cannot drift from the explicit command. Held
682
+ under the shared migration advisory lock (`_migration_lock`).
683
+
684
+ Reports the stamp it moved, and says nothing when it moved nothing, so a
685
+ routine start is as quiet as it was and a start that changed the schema
686
+ cannot be mistaken for one that did not.
687
+ """
688
+ before = after = None
689
+ with _migration_lock(db_url):
690
+ before = _stamped_revision(db_url)
691
+ _run_migrations(db_url)
692
+ _post_migration_grants(db_url)
693
+ _reconcile_after_migrate(db_url)
694
+ # Read inside the lock: outside it, a process queued behind this one
695
+ # could move the stamp further and this would report a transition that
696
+ # never happened here.
697
+ after = _stamped_revision(db_url)
684
698
  if after != before:
685
699
  click.echo(f" ✓ Database migrated: {before or 'base'} -> {after}")
686
700
 
@@ -693,6 +707,13 @@ def _reconcile_after_migrate(db_url: str) -> None:
693
707
  are idempotent, so a redundant run would be a no-op anyway. The projection
694
708
  rebuild (the other half of the version-change reconcile) runs in the API
695
709
  lifespan, where module projection handlers are loaded.
710
+
711
+ Each backfill replays in its own transaction; the version marker is written
712
+ in a SEPARATE final transaction, and only when every backfill succeeded, so
713
+ a backfill that fails is retried on the next start instead of being marked
714
+ done for this version's lifetime. The marker write no longer shares a
715
+ transaction with the replay, so its own failure cannot roll back committed
716
+ backfills.
696
717
  """
697
718
  import sqlalchemy as _sa
698
719
 
@@ -710,8 +731,16 @@ def _reconcile_after_migrate(db_url: str) -> None:
710
731
  with engine.begin() as conn:
711
732
  if get_meta(conn, BACKFILL_VERSION_KEY) == __version__:
712
733
  return # already reconciled for this version
713
- replayed = replay_data_backfills(conn)
714
- set_meta(conn, BACKFILL_VERSION_KEY, __version__)
734
+ replayed, failures = replay_data_backfills(engine)
735
+ if failures:
736
+ click.echo(
737
+ f" ! {len(failures)} data-backfill migration(s) failed to reconcile for "
738
+ f"{__version__}; leaving the version marker unset so they retry next start: "
739
+ f"{', '.join(failures)}"
740
+ )
741
+ else:
742
+ with engine.begin() as conn:
743
+ set_meta(conn, BACKFILL_VERSION_KEY, __version__)
715
744
  if replayed:
716
745
  click.echo(f" · Reconciled {len(replayed)} data-backfill migration(s) for {__version__}")
717
746
  finally:
@@ -125,6 +125,10 @@ class ItemSplit(BaseModel):
125
125
  # One entry per child: {child_id, child_sku, origin_event_id, qty_before, qty_after,
126
126
  # pieces_before, pieces_after, weight_before, weight_after}. Sequential mother deltas.
127
127
  children_detail: list[dict[str, Any]] = Field(default_factory=list)
128
+ # Weight expected to remain minus weight measured, recorded only when a real
129
+ # measurement exists (full weighed break-up, or an operator re-weigh). None when
130
+ # the remainder is only derived, so no false anomaly is asserted.
131
+ delta: float | None = None
128
132
 
129
133
 
130
134
  class ItemSplitFrom(BaseModel):
@@ -150,6 +154,9 @@ class ItemTransform(BaseModel):
150
154
  pieces_after: float | None = None
151
155
  weight_before: float | None = None
152
156
  weight_after: float | None = None
157
+ # Processing/trim loss: mother weight in minus child weight out, recorded only
158
+ # when both weights exist. None otherwise (no fabricated loss).
159
+ delta: float | None = None
153
160
 
154
161
 
155
162
  class ItemTransformedFrom(BaseModel):
@@ -211,9 +211,20 @@ async def lifespan(_app: FastAPI):
211
211
  # instance that already has companies).
212
212
  from celerp.modules.slots import fire_lifecycle as _fire
213
213
  from celerp.db import SessionLocal as _SessionLocal
214
+ # Best-effort, like the two sibling blocks below: a hook that fails
215
+ # during flush poisons the shared session, so the commit raises.
216
+ # Roll back and log at ERROR rather than let that crash boot - the
217
+ # manufacturing seed hook, for one, must never be able to take the
218
+ # app down.
214
219
  async with _SessionLocal() as _sess:
215
- await _fire("on_modules_ready", session=_sess)
216
- await _sess.commit()
220
+ try:
221
+ await _fire("on_modules_ready", session=_sess)
222
+ await _sess.commit()
223
+ except Exception:
224
+ await _sess.rollback()
225
+ logging.getLogger(__name__).exception(
226
+ "on_modules_ready hooks failed (non-fatal); their data was rolled back"
227
+ )
217
228
 
218
229
  # A bundled default whose content no longer matches the first-party
219
230
  # lock is demoted to untrusted. Surface that in the notification bell
@@ -255,6 +266,21 @@ async def lifespan(_app: FastAPI):
255
266
  "stale until rebuilt via doctor or /ledger/rebuild"
256
267
  )
257
268
 
269
+ # One-time backfill: stamp the status→document pairing on items sold, memo'd,
270
+ # or consigned in before that field shipped, so their inventory status links
271
+ # to its document. Marker-gated (runs once); non-fatal like the guard above.
272
+ try:
273
+ from celerp.db import SessionLocal as _BackfillSession
274
+ from celerp.services.status_doc_backfill import run_status_doc_backfill
275
+ async with _BackfillSession() as _bf_sess:
276
+ await run_status_doc_backfill(_bf_sess)
277
+ await _bf_sess.commit()
278
+ except Exception:
279
+ logging.getLogger(__name__).exception(
280
+ "Status-doc backfill failed (non-fatal); pre-existing sold/memo items "
281
+ "may show their status without a document link until a later boot"
282
+ )
283
+
258
284
  # Bring up the relay tunnel per the lazy free-tier lifecycle (3.1). A token-holder
259
285
  # is past first activation and never re-enters it. Paid instances (public_url set)
260
286
  # keep the tunnel always-on; a free instance opens it at boot only when it already
@@ -20,13 +20,16 @@ against — so no SQL is duplicated and nothing is monkeypatched.
20
20
  """
21
21
  from __future__ import annotations
22
22
 
23
+ import logging
23
24
  from pathlib import Path
24
25
  from typing import TYPE_CHECKING
25
26
 
26
27
  from celerp.migrations._auto_stamp import extract_signatures
27
28
 
28
29
  if TYPE_CHECKING:
29
- from sqlalchemy.engine import Connection
30
+ from sqlalchemy.engine import Connection, Engine
31
+
32
+ _log = logging.getLogger(__name__)
30
33
 
31
34
  # ── Instance metadata marker ────────────────────────────────────────────────
32
35
  # A tiny key/value table recording which celerp version last applied each
@@ -92,22 +95,37 @@ def data_backfill_scripts():
92
95
  return out
93
96
 
94
97
 
95
- def replay_data_backfills(connection: "Connection") -> list[str]:
96
- """Re-run every data-backfill migration's `upgrade()` against `connection`.
98
+ def replay_data_backfills(engine: "Engine") -> tuple[list[str], list[str]]:
99
+ """Re-run every data-backfill migration's `upgrade()`, each in its OWN
100
+ transaction, against `engine`.
101
+
102
+ A per-backfill top-level transaction (not a savepoint inside one outer
103
+ transaction) is what makes the replay durable: each backfill that succeeds
104
+ commits on its own, so a later backfill failure, or a failed marker write
105
+ afterwards, cannot silently undo work that already converged. One failing
106
+ backfill is logged loudly and skipped; the rest still run.
97
107
 
98
- `connection` is a sync SQLAlchemy Connection; the caller owns the
99
- transaction. Returns the revision ids replayed, in apply order.
108
+ Returns `(replayed, failures)`: the revision ids that applied cleanly and
109
+ the ids that raised, both in apply order.
100
110
  """
101
111
  from alembic.operations import Operations
102
112
  from alembic.runtime.migration import MigrationContext
103
113
 
104
114
  scripts = data_backfill_scripts()
105
- ctx = MigrationContext.configure(connection)
106
115
  replayed: list[str] = []
107
- # Operations.context binds the global `alembic.op` proxy these migrations
108
- # import, so their `op.get_bind()` returns this connection.
109
- with Operations.context(ctx):
110
- for sc in scripts:
111
- sc.module.upgrade()
116
+ failures: list[str] = []
117
+ for sc in scripts:
118
+ try:
119
+ with engine.begin() as conn:
120
+ ctx = MigrationContext.configure(conn)
121
+ # Operations.context binds the global `alembic.op` proxy these
122
+ # migrations import, so their `op.get_bind()` returns this
123
+ # connection; the with-block commits on clean exit, rolls back
124
+ # on any exception.
125
+ with Operations.context(ctx):
126
+ sc.module.upgrade()
112
127
  replayed.append(sc.revision)
113
- return replayed
128
+ except Exception:
129
+ _log.exception("data backfill %s failed to replay; skipping it", sc.revision)
130
+ failures.append(sc.revision)
131
+ return replayed, failures
@@ -35,7 +35,12 @@ except ImportError:
35
35
  config = context.config
36
36
 
37
37
  if config.config_file_name is not None:
38
- fileConfig(config.config_file_name)
38
+ # disable_existing_loggers=False: alembic runs in-process during
39
+ # `celerp migrate`/`celerp start` and the restore reconcile, so the default
40
+ # (True) would silence every application logger already created, including
41
+ # the reconcile's own failure logger. Configure alembic's loggers without
42
+ # muting the app's.
43
+ fileConfig(config.config_file_name, disable_existing_loggers=False)
39
44
 
40
45
  target_metadata = Base.metadata
41
46
 
@@ -0,0 +1,175 @@
1
+ # Copyright (c) 2026 Noah Severs
2
+ # SPDX-License-Identifier: BUSL-1.1
3
+
4
+ """expand the role_permissions threshold overrides into explicit role_grants sets
5
+
6
+ Revision ID: b3c4d5e6f7a8
7
+ Revises: f8a9b0c1d2e3
8
+ Create Date: 2026-08-09
9
+
10
+ The data half of the per-role permissions change. Role overrides used to be a
11
+ single minimum-role threshold per permission (Company.settings["role_permissions"]
12
+ = {permission_key: minimum_role_key}); every role at or above that threshold was
13
+ granted, so the roles moved as a block. They are now an explicit set of granted
14
+ roles per permission (Company.settings["role_grants"] = {permission_key:
15
+ [role_key, ...]}), each role granted independently. This migration rewrites every
16
+ stored threshold into the exact set of roles it used to grant, so no company's
17
+ effective permissions change, then drops the retired key.
18
+
19
+ Deltas only: it materializes a grant set for the keys a company actually
20
+ overrode, never the whole catalogue; unoverridden keys keep resolving to their
21
+ registry default. Each threshold expands to every role at or above it, clamped up
22
+ to the permission's floor (so a grandfathered sub-floor override lands on the
23
+ floor exactly as the resolver reads it). A threshold on a permission that is no
24
+ longer overridable, unknown to the catalogue, or naming a role that no longer
25
+ exists never resolved to anything but the default, so it becomes no delta and is
26
+ left absent.
27
+
28
+ Signature-less (data only), so the develop-to-release reconcile replays it on
29
+ every create_all/restore database. Idempotent: guarded on the presence of the
30
+ retired key, so a second application is a no-op. The downgrade is the best-effort
31
+ inverse: it collapses each grant set back to a single threshold at its lowest
32
+ granted role and restores the retired key, so a rollback to the threshold-reading
33
+ code keeps a company's effective permissions. This round-trips exactly for the
34
+ contiguous sets the upgrade produces; a hand-authored non-contiguous set is
35
+ documented lossy (it collapses to its lowest role, which the older resolver then
36
+ re-expands as a block).
37
+
38
+ The catalogue (floor role and overridability per permission) and the role levels
39
+ are snapshotted here as literals, because a migration is immutable history: it
40
+ must expand exactly as the rules stood when it was written, even after the
41
+ registry in celerp.services.permissions later changes.
42
+ """
43
+
44
+ from __future__ import annotations
45
+
46
+ import json
47
+
48
+ import sqlalchemy as sa
49
+ from alembic import op
50
+
51
+ revision = "b3c4d5e6f7a8"
52
+ down_revision = "f8a9b0c1d2e3"
53
+ branch_labels = None
54
+ depends_on = None
55
+
56
+ # Snapshot of auth.ROLE_LEVELS at this revision.
57
+ _ROLE_LEVELS = {"viewer": 1, "operator": 2, "manager": 3, "admin": 4, "owner": 5}
58
+
59
+ # Snapshot of the permission catalogue at this revision: key -> (floor_role,
60
+ # grantable). default_role is irrelevant here because every key processed carries
61
+ # an explicit override; only the floor (which clamps the expansion) and whether
62
+ # the key is overridable at all matter.
63
+ _CATALOGUE = {
64
+ "view_dashboards": ("viewer", True),
65
+ "view_documents": ("viewer", True),
66
+ "view_contacts": ("viewer", True),
67
+ "view_inventory": ("viewer", True),
68
+ "edit_documents": ("viewer", True),
69
+ "edit_contacts": ("viewer", True),
70
+ "edit_inventory": ("viewer", True),
71
+ "edit_inventory_amounts": ("viewer", True),
72
+ "finalize_documents": ("viewer", True),
73
+ "fulfill_documents": ("viewer", True),
74
+ "record_payments": ("viewer", True),
75
+ "manage_labels": ("viewer", True),
76
+ "manage_manufacturing": ("viewer", True),
77
+ "use_ai_assistant": ("viewer", True),
78
+ "run_backups": ("viewer", True),
79
+ "view_subscriptions": ("viewer", True),
80
+ "view_inventory_costs": ("viewer", True),
81
+ "set_inventory_prices": ("viewer", True),
82
+ "set_sales_doc_prices": ("viewer", True),
83
+ "delete_documents": ("viewer", True),
84
+ "adjust_inventory": ("viewer", True),
85
+ "import_export_data": ("viewer", True),
86
+ "view_payments": ("viewer", True),
87
+ "view_financial_reports": ("viewer", True),
88
+ "manage_accounting": ("viewer", True),
89
+ "manage_module_settings": ("viewer", True),
90
+ "manage_users": ("viewer", True),
91
+ "manage_company_settings": ("admin", True),
92
+ "manage_integrations": ("viewer", True),
93
+ "manage_permissions": ("owner", False),
94
+ "manage_company_lifecycle": ("owner", False),
95
+ "manage_billing": ("owner", False),
96
+ }
97
+
98
+
99
+ def _expand(stored_role: str, floor_role: str) -> list[str]:
100
+ """The role keys a threshold used to grant: every role at or above the
101
+ threshold, clamped up to the floor, ordered low to high."""
102
+ threshold = max(_ROLE_LEVELS[stored_role], _ROLE_LEVELS[floor_role])
103
+ return sorted(
104
+ (r for r, lvl in _ROLE_LEVELS.items() if lvl >= threshold),
105
+ key=lambda r: _ROLE_LEVELS[r],
106
+ )
107
+
108
+
109
+ def _collapse(granted_roles: list[str]) -> str | None:
110
+ """Best-effort inverse of _expand: the threshold role at the lowest granted
111
+ level. Exact for a contiguous set (the shape upgrade produces); lossy for a
112
+ non-contiguous set, which no longer round-trips to the same set. None when no
113
+ granted role is known, leaving the permission absent (resolves to default)."""
114
+ levels = [_ROLE_LEVELS[r] for r in granted_roles if r in _ROLE_LEVELS]
115
+ if not levels:
116
+ return None
117
+ low = min(levels)
118
+ return next(r for r, lvl in _ROLE_LEVELS.items() if lvl == low)
119
+
120
+
121
+ def upgrade() -> None:
122
+ conn = op.get_bind()
123
+ # Only companies that still carry the retired key; this is also the
124
+ # idempotency guard, so a replay after the key is stripped touches nothing.
125
+ rows = conn.execute(sa.text(
126
+ "SELECT id, settings FROM companies WHERE settings::jsonb ? 'role_permissions'"
127
+ )).fetchall()
128
+
129
+ for cid, settings in rows:
130
+ data = settings if isinstance(settings, dict) else json.loads(settings)
131
+ role_perms = data.get("role_permissions")
132
+ grants = dict(data.get("role_grants") or {})
133
+ if isinstance(role_perms, dict):
134
+ for key, stored_role in role_perms.items():
135
+ meta = _CATALOGUE.get(key)
136
+ if meta is None:
137
+ continue # unknown key: never resolved to an override
138
+ floor_role, grantable = meta
139
+ if not grantable:
140
+ continue # fixed permission: overrides were never honored
141
+ if stored_role not in _ROLE_LEVELS:
142
+ continue # stale role: resolved to the default, no delta
143
+ grants[key] = _expand(stored_role, floor_role)
144
+ if grants:
145
+ data["role_grants"] = grants
146
+ data.pop("role_permissions", None)
147
+ conn.execute(
148
+ sa.text("UPDATE companies SET settings = CAST(:s AS json) WHERE id = :id"),
149
+ {"s": json.dumps(data), "id": str(cid)},
150
+ )
151
+
152
+
153
+ def downgrade() -> None:
154
+ conn = op.get_bind()
155
+ # Only companies that carry the new key; this is also the idempotency guard.
156
+ rows = conn.execute(sa.text(
157
+ "SELECT id, settings FROM companies WHERE settings::jsonb ? 'role_grants'"
158
+ )).fetchall()
159
+
160
+ for cid, settings in rows:
161
+ data = settings if isinstance(settings, dict) else json.loads(settings)
162
+ grants = data.get("role_grants")
163
+ role_perms = dict(data.get("role_permissions") or {})
164
+ if isinstance(grants, dict):
165
+ for key, roles in grants.items():
166
+ threshold = _collapse(roles if isinstance(roles, list) else [])
167
+ if threshold is not None:
168
+ role_perms[key] = threshold
169
+ if role_perms:
170
+ data["role_permissions"] = role_perms
171
+ data.pop("role_grants", None)
172
+ conn.execute(
173
+ sa.text("UPDATE companies SET settings = CAST(:s AS json) WHERE id = :id"),
174
+ {"s": json.dumps(data), "id": str(cid)},
175
+ )
@@ -0,0 +1,51 @@
1
+ # Copyright (c) 2026 Noah Severs
2
+ # SPDX-License-Identifier: BUSL-1.1
3
+
4
+ """work center hours_per_day + is_default columns and the one-default index
5
+
6
+ Revision ID: e7c9a1b3d5f2
7
+ Revises: d5e6f7a8b9c0
8
+ Create Date: 2026-08-06
9
+
10
+ Adds hours_per_day and is_default to work_centers and the partial unique index
11
+ that enforces one default center per company. Verifiable DDL only (op.*), so
12
+ extract_signatures detects it and the auto-stamp walker never false-stamps a
13
+ create_all/restore database past these columns. The data move (seeding a
14
+ Default center, the notice, stripping the old setting) lives in the child
15
+ data-backfill migration f8a9b0c1d2e3. Forward-only.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import sqlalchemy as sa
21
+ from alembic import op
22
+
23
+ revision = "e7c9a1b3d5f2"
24
+ down_revision = "d5e6f7a8b9c0"
25
+ branch_labels = None
26
+ depends_on = None
27
+
28
+
29
+ def upgrade() -> None:
30
+ op.add_column("work_centers", sa.Column("hours_per_day", sa.Float(), nullable=True))
31
+ # NOT NULL with a transient server default so existing rows backfill to false,
32
+ # then drop the default for parity with the model (celerp/models/company.py
33
+ # declares none). is_default is added before the index that references it.
34
+ op.add_column(
35
+ "work_centers",
36
+ sa.Column("is_default", sa.Boolean(), nullable=False, server_default=sa.text("false")),
37
+ )
38
+ op.create_index(
39
+ "uq_work_center_one_default",
40
+ "work_centers",
41
+ ["company_id"],
42
+ unique=True,
43
+ postgresql_where=sa.text("is_default"),
44
+ )
45
+ op.alter_column("work_centers", "is_default", server_default=None)
46
+
47
+
48
+ def downgrade() -> None:
49
+ op.drop_index("uq_work_center_one_default", table_name="work_centers")
50
+ op.drop_column("work_centers", "is_default")
51
+ op.drop_column("work_centers", "hours_per_day")
@@ -0,0 +1,93 @@
1
+ # Copyright (c) 2026 Noah Severs
2
+ # SPDX-License-Identifier: BUSL-1.1
3
+
4
+ """seed a Default work center and move the hours_per_day setting onto it
5
+
6
+ Revision ID: f8a9b0c1d2e3
7
+ Revises: e7c9a1b3d5f2
8
+ Create Date: 2026-08-06
9
+
10
+ The data half of the work-center default split. Signature-less (raw SQL), so
11
+ the develop-to-release reconcile replays it on every create_all/restore
12
+ database once the schema migration has added the columns. Seeds one Default
13
+ center per manufacturing-active company carrying the old company hours value
14
+ (the module's x-or-8.0 mapping), posts one company-wide notice that the setting
15
+ moved, and strips the now-migrated settings key. Idempotent: every step guards
16
+ against a prior application, because it replays on each version-change
17
+ reconcile and, on a restore boot, can be both alembic-applied and
18
+ reconcile-replayed in one pass. Forward-only.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import sqlalchemy as sa
24
+ from alembic import op
25
+
26
+ revision = "f8a9b0c1d2e3"
27
+ down_revision = "e7c9a1b3d5f2"
28
+ branch_labels = None
29
+ depends_on = None
30
+
31
+ _NOTICE_TITLE = "Hours per day moved to work centers"
32
+ _NOTICE_BODY = (
33
+ "Your company Hours per day setting now lives on the new Default work center under "
34
+ "Settings > Manufacturing > Work centers. Nothing changed in your To-Make estimates."
35
+ )
36
+
37
+
38
+ def upgrade() -> None:
39
+ conn = op.get_bind()
40
+
41
+ # One dedicated Default center per manufacturing-active company, carrying its
42
+ # old hours value. The nested CASE mirrors the module's `x or 8.0`: a stored
43
+ # 0, blank, absent, or non-numeric value maps to 8.0. The regex guard runs
44
+ # BEFORE the ::float cast because Postgres does not guarantee AND
45
+ # short-circuit, so a flat `regex AND value::float` would still cast 'abc'
46
+ # and abort the whole insert. settings is a JSON column, so the ? membership
47
+ # test needs a jsonb cast; the -> / ->> extraction works on json directly.
48
+ conn.execute(sa.text("""
49
+ INSERT INTO work_centers (id, company_id, name, hours_per_day, is_default, created_at)
50
+ SELECT gen_random_uuid(), c.id, 'Default',
51
+ CASE WHEN (c.settings->'manufacturing'->>'hours_per_day') ~ '^[0-9]+(\\.[0-9]+)?$'
52
+ THEN CASE WHEN (c.settings->'manufacturing'->>'hours_per_day')::float <> 0
53
+ THEN (c.settings->'manufacturing'->>'hours_per_day')::float
54
+ ELSE 8.0 END
55
+ ELSE 8.0 END,
56
+ true, NOW()
57
+ FROM companies c
58
+ WHERE (c.settings::jsonb ? 'manufacturing'
59
+ OR EXISTS (SELECT 1 FROM work_centers wc WHERE wc.company_id = c.id))
60
+ AND NOT EXISTS (SELECT 1 FROM work_centers d WHERE d.company_id = c.id AND d.is_default)
61
+ """))
62
+
63
+ # One company-wide notice per company that just received a Default center
64
+ # (user_id NULL = company-wide). Guarded so a re-run never doubles it. The
65
+ # notifications table is created when the application boots, not by the
66
+ # migration chain, so on a database migrated before its first boot it is
67
+ # absent. Such a database has never run the app and therefore holds no
68
+ # company whose value could have moved, so there is nothing to notify. The
69
+ # regclass check is unqualified so it resolves against the same search path
70
+ # the INSERT targets (public in production), not a hardcoded schema.
71
+ if conn.execute(sa.text("SELECT to_regclass('notifications')")).scalar() is not None:
72
+ conn.execute(sa.text("""
73
+ INSERT INTO notifications
74
+ (id, company_id, user_id, category, title, body, action_url, priority, read, created_at)
75
+ SELECT gen_random_uuid(), w.company_id, NULL, 'manufacturing', :title, :body,
76
+ '/settings/manufacturing', 'high', false, NOW()
77
+ FROM work_centers w
78
+ WHERE w.is_default
79
+ AND w.name = 'Default'
80
+ AND NOT EXISTS (SELECT 1 FROM notifications n
81
+ WHERE n.company_id = w.company_id AND n.title = :title)
82
+ """), {"title": _NOTICE_TITLE, "body": _NOTICE_BODY})
83
+
84
+ # Strip the now-migrated key (jsonb #- needs the cast, then back to json).
85
+ conn.execute(sa.text(
86
+ "UPDATE companies SET settings = (settings::jsonb #- '{manufacturing,hours_per_day}')::json "
87
+ "WHERE settings::jsonb #> '{manufacturing,hours_per_day}' IS NOT NULL"
88
+ ))
89
+
90
+
91
+ def downgrade() -> None:
92
+ conn = op.get_bind()
93
+ conn.execute(sa.text("DELETE FROM work_centers WHERE is_default AND name = 'Default'"))
@@ -42,9 +42,17 @@ class WorkCenter(Base):
42
42
 
43
43
  Optionally carries a WIP location, an hourly labor rate and a capacity (capacity is reserved for
44
44
  later scheduling work). Runs may reference a work centre via work_center_id.
45
+
46
+ hours_per_day is the working day length used to turn daily labour into hours; the
47
+ company's default centre supplies it to the To-Make board. A partial unique index
48
+ keeps at most one default centre per company.
45
49
  """
46
50
  __tablename__ = "work_centers"
47
- __table_args__ = (UniqueConstraint("company_id", "name", name="uq_work_center_company_name"),)
51
+ __table_args__ = (
52
+ UniqueConstraint("company_id", "name", name="uq_work_center_company_name"),
53
+ sa.Index("uq_work_center_one_default", "company_id",
54
+ unique=True, postgresql_where=sa.text("is_default")),
55
+ )
48
56
 
49
57
  id: Mapped[uuid.UUID] = mapped_column(sa.Uuid(as_uuid=True), primary_key=True, default=uuid.uuid4)
50
58
  company_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("companies.id"), nullable=False)
@@ -52,6 +60,8 @@ class WorkCenter(Base):
52
60
  wip_location_id: Mapped[uuid.UUID | None] = mapped_column(sa.Uuid(as_uuid=True), nullable=True)
53
61
  labor_rate: Mapped[float | None] = mapped_column(sa.Float, nullable=True)
54
62
  capacity: Mapped[float | None] = mapped_column(sa.Float, nullable=True)
63
+ hours_per_day: Mapped[float | None] = mapped_column(sa.Float, nullable=True)
64
+ is_default: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
55
65
  created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), nullable=False)
56
66
 
57
67
 
@@ -60,7 +60,9 @@ async def fire_lifecycle(slot: str, **kwargs) -> None:
60
60
 
61
61
  Each contribution must have a "handler" key pointing to a dotted path
62
62
  "module.path:function_name". The function is called with **kwargs.
63
- Failures are logged and swallowed (non-fatal).
63
+ A failing hook never blocks its siblings or boot: it is logged at ERROR
64
+ (with traceback) and swallowed, so a recurrence surfaces as an alert
65
+ instead of vanishing.
64
66
  """
65
67
  import importlib
66
68
  import logging
@@ -77,7 +79,7 @@ async def fire_lifecycle(slot: str, **kwargs) -> None:
77
79
  func = getattr(mod, func_name)
78
80
  await func(**kwargs)
79
81
  except Exception as exc:
80
- _log.warning(
82
+ _log.exception(
81
83
  "Lifecycle hook %s from %s failed: %s",
82
84
  slot, contrib.get("_module", "?"), exc,
83
85
  )