celerp 2.0.0__tar.gz → 2.1.0__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 (617) hide show
  1. {celerp-2.0.0 → celerp-2.1.0}/PKG-INFO +1 -1
  2. {celerp-2.0.0 → celerp-2.1.0}/celerp/cli.py +51 -22
  3. {celerp-2.0.0 → celerp-2.1.0}/celerp/events/schemas.py +7 -0
  4. {celerp-2.0.0 → celerp-2.1.0}/celerp/main.py +28 -2
  5. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/_data_reconcile.py +30 -12
  6. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/env.py +6 -1
  7. celerp-2.1.0/celerp/migrations/versions/e7c9a1b3d5f2_work_center_default_columns.py +51 -0
  8. celerp-2.1.0/celerp/migrations/versions/f8a9b0c1d2e3_work_center_default_backfill.py +93 -0
  9. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/company.py +11 -1
  10. {celerp-2.0.0 → celerp-2.1.0}/celerp/modules/slots.py +4 -2
  11. {celerp-2.0.0 → celerp-2.1.0}/celerp/routers/companies.py +16 -0
  12. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/backup_import.py +13 -4
  13. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/field_schema.py +6 -0
  14. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/permissions.py +30 -29
  15. celerp-2.1.0/celerp/services/reorder.py +372 -0
  16. celerp-2.1.0/celerp/services/status_doc_backfill.py +101 -0
  17. {celerp-2.0.0 → celerp-2.1.0}/celerp.egg-info/PKG-INFO +1 -1
  18. {celerp-2.0.0 → celerp-2.1.0}/celerp.egg-info/SOURCES.txt +5 -0
  19. {celerp-2.0.0 → celerp-2.1.0}/celerp.egg-info/scm_file_list.json +958 -945
  20. celerp-2.1.0/celerp.egg-info/scm_version.json +8 -0
  21. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-inventory/celerp_inventory/routes.py +123 -11
  22. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/__init__.py +6 -0
  23. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/celerp_manufacturing/routes.py +189 -15
  24. celerp-2.1.0/default_modules/celerp-manufacturing/tests/test_auto_complete_on_finalize.py +171 -0
  25. celerp-2.1.0/default_modules/celerp-manufacturing/tests/test_work_centers_and_settings.py +374 -0
  26. {celerp-2.0.0 → celerp-2.1.0}/default_modules/first_party.lock.json +2 -2
  27. {celerp-2.0.0 → celerp-2.1.0}/ui/api_client.py +5 -0
  28. {celerp-2.0.0 → celerp-2.1.0}/ui/components/activity.py +34 -1
  29. {celerp-2.0.0 → celerp-2.1.0}/ui/components/cloud_gate.py +37 -0
  30. {celerp-2.0.0 → celerp-2.1.0}/ui/components/shell.py +217 -6
  31. {celerp-2.0.0 → celerp-2.1.0}/ui/components/table.py +19 -6
  32. {celerp-2.0.0 → celerp-2.1.0}/ui/locales/ar.json +4 -1
  33. {celerp-2.0.0 → celerp-2.1.0}/ui/locales/de.json +4 -1
  34. {celerp-2.0.0 → celerp-2.1.0}/ui/locales/en.json +12 -1
  35. {celerp-2.0.0 → celerp-2.1.0}/ui/locales/es.json +4 -1
  36. {celerp-2.0.0 → celerp-2.1.0}/ui/locales/fr.json +4 -1
  37. {celerp-2.0.0 → celerp-2.1.0}/ui/locales/id.json +4 -1
  38. {celerp-2.0.0 → celerp-2.1.0}/ui/locales/it.json +4 -1
  39. {celerp-2.0.0 → celerp-2.1.0}/ui/locales/ja.json +4 -1
  40. {celerp-2.0.0 → celerp-2.1.0}/ui/locales/pt.json +4 -1
  41. {celerp-2.0.0 → celerp-2.1.0}/ui/locales/th.json +4 -1
  42. {celerp-2.0.0 → celerp-2.1.0}/ui/locales/vi.json +4 -1
  43. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/account.py +33 -6
  44. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/contacts.py +3 -2
  45. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/documents.py +8 -6
  46. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/inventory.py +880 -446
  47. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/manufacturing.py +74 -17
  48. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/settings.py +6 -6
  49. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/settings_accounting.py +1 -1
  50. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/settings_connectors.py +2 -14
  51. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/settings_inventory.py +33 -9
  52. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/settings_manufacturing.py +31 -26
  53. celerp-2.1.0/ui/security.py +19 -0
  54. {celerp-2.0.0 → celerp-2.1.0}/ui/static/app.css +63 -14
  55. celerp-2.0.0/celerp/services/reorder.py +0 -279
  56. celerp-2.0.0/celerp.egg-info/scm_version.json +0 -8
  57. celerp-2.0.0/default_modules/celerp-manufacturing/tests/test_work_centers_and_settings.py +0 -120
  58. {celerp-2.0.0 → celerp-2.1.0}/CLA.md +0 -0
  59. {celerp-2.0.0 → celerp-2.1.0}/CONTRIBUTING.md +0 -0
  60. {celerp-2.0.0 → celerp-2.1.0}/LICENSE +0 -0
  61. {celerp-2.0.0 → celerp-2.1.0}/LICENSING.md +0 -0
  62. {celerp-2.0.0 → celerp-2.1.0}/MANIFEST.in +0 -0
  63. {celerp-2.0.0 → celerp-2.1.0}/NOTICE +0 -0
  64. {celerp-2.0.0 → celerp-2.1.0}/README.md +0 -0
  65. {celerp-2.0.0 → celerp-2.1.0}/alembic.ini +0 -0
  66. {celerp-2.0.0 → celerp-2.1.0}/celerp/__init__.py +0 -0
  67. {celerp-2.0.0 → celerp-2.1.0}/celerp/__main__.py +0 -0
  68. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/__init__.py +0 -0
  69. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/batch.py +0 -0
  70. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/cleanup.py +0 -0
  71. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/commands.py +0 -0
  72. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/conversations.py +0 -0
  73. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/files.py +0 -0
  74. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/intent.py +0 -0
  75. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/llm.py +0 -0
  76. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/memory.py +0 -0
  77. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/models.py +0 -0
  78. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/page_count.py +0 -0
  79. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/quota.py +0 -0
  80. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/service.py +0 -0
  81. {celerp-2.0.0 → celerp-2.1.0}/celerp/ai/tools.py +0 -0
  82. {celerp-2.0.0 → celerp-2.1.0}/celerp/alembic.ini +0 -0
  83. {celerp-2.0.0 → celerp-2.1.0}/celerp/alembic_config.py +0 -0
  84. {celerp-2.0.0 → celerp-2.1.0}/celerp/compat.py +0 -0
  85. {celerp-2.0.0 → celerp-2.1.0}/celerp/compute/__init__.py +0 -0
  86. {celerp-2.0.0 → celerp-2.1.0}/celerp/compute/aggregations.py +0 -0
  87. {celerp-2.0.0 → celerp-2.1.0}/celerp/compute/valuation.py +0 -0
  88. {celerp-2.0.0 → celerp-2.1.0}/celerp/config.py +0 -0
  89. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/__init__.py +0 -0
  90. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/base.py +0 -0
  91. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/daily_scheduler.py +0 -0
  92. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/http.py +0 -0
  93. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/images.py +0 -0
  94. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/quickbooks.py +0 -0
  95. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/registry.py +0 -0
  96. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/relay_token.py +0 -0
  97. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/shopify.py +0 -0
  98. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/sync_runner.py +0 -0
  99. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/upsert.py +0 -0
  100. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/util.py +0 -0
  101. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/webhooks.py +0 -0
  102. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/woocommerce.py +0 -0
  103. {celerp-2.0.0 → celerp-2.1.0}/celerp/connectors/xero.py +0 -0
  104. {celerp-2.0.0 → celerp-2.1.0}/celerp/constants.py +0 -0
  105. {celerp-2.0.0 → celerp-2.1.0}/celerp/db.py +0 -0
  106. {celerp-2.0.0 → celerp-2.1.0}/celerp/embedded_pg.py +0 -0
  107. {celerp-2.0.0 → celerp-2.1.0}/celerp/events/__init__.py +0 -0
  108. {celerp-2.0.0 → celerp-2.1.0}/celerp/events/engine.py +0 -0
  109. {celerp-2.0.0 → celerp-2.1.0}/celerp/events/types.py +0 -0
  110. {celerp-2.0.0 → celerp-2.1.0}/celerp/gateway/__init__.py +0 -0
  111. {celerp-2.0.0 → celerp-2.1.0}/celerp/gateway/client.py +0 -0
  112. {celerp-2.0.0 → celerp-2.1.0}/celerp/gateway/state.py +0 -0
  113. {celerp-2.0.0 → celerp-2.1.0}/celerp/importers/__init__.py +0 -0
  114. {celerp-2.0.0 → celerp-2.1.0}/celerp/importers/importer.py +0 -0
  115. {celerp-2.0.0 → celerp-2.1.0}/celerp/importers/schema.py +0 -0
  116. {celerp-2.0.0 → celerp-2.1.0}/celerp/middleware.py +0 -0
  117. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/README.md +0 -0
  118. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/_auto_stamp.py +0 -0
  119. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/_json_compat.py +0 -0
  120. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/script.py.mako +0 -0
  121. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/a0b1c2d3e4f5_seed_landed_cost_clearing_accounts.py +0 -0
  122. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/a1b2c3d4e5f6_add_doc_share_tokens.py +0 -0
  123. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/b1c2d3e4f5a6_add_supporter_badges.py +0 -0
  124. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/b2c3d4e5f6a7_add_import_batches.py +0 -0
  125. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/c1d2e3f4a5b6_add_marketplace.py +0 -0
  126. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/c2d3e4f5a6b7_add_is_sync_to_shopify.py +0 -0
  127. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/c4d5e6f7a8b9_account_cash_flow_category.py +0 -0
  128. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/d0e1f2a3b4c5_add_share_token_expiry.py +0 -0
  129. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/d2e3f4a5b6c7_add_password_reset_token.py +0 -0
  130. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/d5e6f7a8b9c0_rename_fx_rounding_to_fx_difference.py +0 -0
  131. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/e3f4a5b6c7d8_add_company_is_active.py +0 -0
  132. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/e4f5a6b7c8d9_backfill_connector_idempotency_key.py +0 -0
  133. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/f1a2b3c4d5e6_move_accounts_marketplace_to_modules.py +0 -0
  134. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/f6a7b8c9d0e1_seed_fx_rounding_account.py +0 -0
  135. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/fd5de461e14e_initial_schema.py +0 -0
  136. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/g1h2i3j4k5l6_add_consignment_flag.py +0 -0
  137. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/h2i3j4k5l6m7_add_bank_accounts_and_reconciliation.py +0 -0
  138. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/j4k5l6m7n8o9_labels_db_persistence.py +0 -0
  139. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/k5l6m7n8o9p0_add_reconciliation_v2.py +0 -0
  140. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/l6m7n8o9p0q1_add_sync_runs_table.py +0 -0
  141. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/m7n8o9p0q1r2_add_connector_configs_and_outbound_queue.py +0 -0
  142. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/n8o9p0q1r2s3_backfill_payment_date.py +0 -0
  143. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/o9p0q1r2s3t4_backfill_item_price_fields.py +0 -0
  144. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/p1q2r3s4t5u6_add_session_registry_and_user_auth_state.py +0 -0
  145. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/q2r3s4t5u6v7_add_system_runtime_state.py +0 -0
  146. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/r3s4t5u6v7w8_add_projections_company_entity_type_index.py +0 -0
  147. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/s4t5u6v7w8x9_drop_user_company_id_role.py +0 -0
  148. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/t5u6v7w8x9y0_seed_inventory_sub_accounts.py +0 -0
  149. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/u6v7w8x9y0z1_backfill_item_prices_from_attributes.py +0 -0
  150. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/v7w8x9y0z1a2_backfill_purchase_unit_defaults.py +0 -0
  151. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/w8x9y0z1a2b3_backfill_category_unit_defaults.py +0 -0
  152. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/x7y8z9a0b1c2_add_projection_created_at.py +0 -0
  153. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/y8z9a0b1c2d3_per_company_ledger_idempotency.py +0 -0
  154. {celerp-2.0.0 → celerp-2.1.0}/celerp/migrations/versions/z9a0b1c2d3e4_work_centers.py +0 -0
  155. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/__init__.py +0 -0
  156. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/accounting.py +0 -0
  157. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/ai.py +0 -0
  158. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/auth.py +0 -0
  159. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/base.py +0 -0
  160. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/connector_config.py +0 -0
  161. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/import_batch.py +0 -0
  162. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/ledger.py +0 -0
  163. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/marketplace.py +0 -0
  164. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/notification.py +0 -0
  165. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/projections.py +0 -0
  166. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/share.py +0 -0
  167. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/supporter.py +0 -0
  168. {celerp-2.0.0 → celerp-2.1.0}/celerp/models/sync_run.py +0 -0
  169. {celerp-2.0.0 → celerp-2.1.0}/celerp/modules/__init__.py +0 -0
  170. {celerp-2.0.0 → celerp-2.1.0}/celerp/modules/api.py +0 -0
  171. {celerp-2.0.0 → celerp-2.1.0}/celerp/modules/audit.py +0 -0
  172. {celerp-2.0.0 → celerp-2.1.0}/celerp/modules/demotion.py +0 -0
  173. {celerp-2.0.0 → celerp-2.1.0}/celerp/modules/importer.py +0 -0
  174. {celerp-2.0.0 → celerp-2.1.0}/celerp/modules/license.py +0 -0
  175. {celerp-2.0.0 → celerp-2.1.0}/celerp/modules/loader.py +0 -0
  176. {celerp-2.0.0 → celerp-2.1.0}/celerp/modules/meta.py +0 -0
  177. {celerp-2.0.0 → celerp-2.1.0}/celerp/modules/migrations_runner.py +0 -0
  178. {celerp-2.0.0 → celerp-2.1.0}/celerp/modules/references.py +0 -0
  179. {celerp-2.0.0 → celerp-2.1.0}/celerp/modules/registry.py +0 -0
  180. {celerp-2.0.0 → celerp-2.1.0}/celerp/notifications/__init__.py +0 -0
  181. {celerp-2.0.0 → celerp-2.1.0}/celerp/notifications/service.py +0 -0
  182. {celerp-2.0.0 → celerp-2.1.0}/celerp/notifications/sse.py +0 -0
  183. {celerp-2.0.0 → celerp-2.1.0}/celerp/output/__init__.py +0 -0
  184. {celerp-2.0.0 → celerp-2.1.0}/celerp/output/branding.py +0 -0
  185. {celerp-2.0.0 → celerp-2.1.0}/celerp/output/doc_print.py +0 -0
  186. {celerp-2.0.0 → celerp-2.1.0}/celerp/output/pdf.py +0 -0
  187. {celerp-2.0.0 → celerp-2.1.0}/celerp/output/share_render.py +0 -0
  188. {celerp-2.0.0 → celerp-2.1.0}/celerp/projections/__init__.py +0 -0
  189. {celerp-2.0.0 → celerp-2.1.0}/celerp/projections/engine.py +0 -0
  190. {celerp-2.0.0 → celerp-2.1.0}/celerp/projections/handlers/__init__.py +0 -0
  191. {celerp-2.0.0 → celerp-2.1.0}/celerp/projections/handlers/marketplace.py +0 -0
  192. {celerp-2.0.0 → celerp-2.1.0}/celerp/projections/handlers/scanning.py +0 -0
  193. {celerp-2.0.0 → celerp-2.1.0}/celerp/projections/handlers/shopify.py +0 -0
  194. {celerp-2.0.0 → celerp-2.1.0}/celerp/projections/handlers/system.py +0 -0
  195. {celerp-2.0.0 → celerp-2.1.0}/celerp/routers/__init__.py +0 -0
  196. {celerp-2.0.0 → celerp-2.1.0}/celerp/routers/auth.py +0 -0
  197. {celerp-2.0.0 → celerp-2.1.0}/celerp/routers/debug.py +0 -0
  198. {celerp-2.0.0 → celerp-2.1.0}/celerp/routers/doctor.py +0 -0
  199. {celerp-2.0.0 → celerp-2.1.0}/celerp/routers/events.py +0 -0
  200. {celerp-2.0.0 → celerp-2.1.0}/celerp/routers/health.py +0 -0
  201. {celerp-2.0.0 → celerp-2.1.0}/celerp/routers/ledger.py +0 -0
  202. {celerp-2.0.0 → celerp-2.1.0}/celerp/routers/notifications.py +0 -0
  203. {celerp-2.0.0 → celerp-2.1.0}/celerp/routers/stars.py +0 -0
  204. {celerp-2.0.0 → celerp-2.1.0}/celerp/routers/system.py +0 -0
  205. {celerp-2.0.0 → celerp-2.1.0}/celerp/schemas/__init__.py +0 -0
  206. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/__init__.py +0 -0
  207. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/activity_redaction.py +0 -0
  208. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/attachments.py +0 -0
  209. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/auth.py +0 -0
  210. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/auto_je.py +0 -0
  211. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/backup.py +0 -0
  212. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/backup_export.py +0 -0
  213. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/backup_repo.py +0 -0
  214. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/backup_scheduler.py +0 -0
  215. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/backup_state.py +0 -0
  216. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/cost_visibility.py +0 -0
  217. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/demo.py +0 -0
  218. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/dev_release_guard.py +0 -0
  219. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/email.py +0 -0
  220. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/fulfill.py +0 -0
  221. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/holdings.py +0 -0
  222. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/je_keys.py +0 -0
  223. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/landed_cost.py +0 -0
  224. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/line_measures.py +0 -0
  225. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/list_behavior.py +0 -0
  226. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/money.py +0 -0
  227. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/payments.py +0 -0
  228. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/pick.py +0 -0
  229. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/pricing.py +0 -0
  230. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/relay_share.py +0 -0
  231. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/runtime_state.py +0 -0
  232. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/session_tracker.py +0 -0
  233. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/shipping.py +0 -0
  234. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/star_cta.py +0 -0
  235. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/supporter_badge.py +0 -0
  236. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/system_health.py +0 -0
  237. {celerp-2.0.0 → celerp-2.1.0}/celerp/services/units.py +0 -0
  238. {celerp-2.0.0 → celerp-2.1.0}/celerp/session_gate.py +0 -0
  239. {celerp-2.0.0 → celerp-2.1.0}/celerp/tax_regimes.py +0 -0
  240. {celerp-2.0.0 → celerp-2.1.0}/celerp.egg-info/dependency_links.txt +0 -0
  241. {celerp-2.0.0 → celerp-2.1.0}/celerp.egg-info/entry_points.txt +0 -0
  242. {celerp-2.0.0 → celerp-2.1.0}/celerp.egg-info/requires.txt +0 -0
  243. {celerp-2.0.0 → celerp-2.1.0}/celerp.egg-info/top_level.txt +0 -0
  244. {celerp-2.0.0 → celerp-2.1.0}/conftest.py +0 -0
  245. {celerp-2.0.0 → celerp-2.1.0}/default_modules/__init__.py +0 -0
  246. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/LICENSE +0 -0
  247. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/__init__.py +0 -0
  248. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/celerp_accounting/__init__.py +0 -0
  249. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/celerp_accounting/api_setup.py +0 -0
  250. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/celerp_accounting/csv_parser.py +0 -0
  251. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/celerp_accounting/matcher.py +0 -0
  252. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/celerp_accounting/models.py +0 -0
  253. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/celerp_accounting/projections.py +0 -0
  254. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/celerp_accounting/routes.py +0 -0
  255. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/celerp_accounting/ui_routes.py +0 -0
  256. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/report_goldens/balance-sheet.html +0 -0
  257. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/report_goldens/cash-flow.html +0 -0
  258. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-csv.csv +0 -0
  259. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/report_goldens/extended-journal-print.html +0 -0
  260. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/report_goldens/extended-journal.html +0 -0
  261. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/report_goldens/general-ledger.html +0 -0
  262. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/report_goldens/journal-csv.csv +0 -0
  263. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/report_goldens/journal-print.html +0 -0
  264. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/report_goldens/journal.html +0 -0
  265. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/report_goldens/ledger.html +0 -0
  266. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/report_goldens/pnl.html +0 -0
  267. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/report_goldens/statement.html +0 -0
  268. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/report_goldens/trial-balance.html +0 -0
  269. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/test_accounting_banking.py +0 -0
  270. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/test_accounting_banking_routers.py +0 -0
  271. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/test_accounting_gaps.py +0 -0
  272. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/test_accounting_import_idempotency.py +0 -0
  273. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/test_cash_flow.py +0 -0
  274. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/test_financial_reports_ui.py +0 -0
  275. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/test_journal_gl_soa.py +0 -0
  276. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/test_journal_gl_soa_ui.py +0 -0
  277. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/test_reconciliation_v2.py +0 -0
  278. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/test_reports_end_to_end.py +0 -0
  279. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-accounting/tests/test_route_permissions.py +0 -0
  280. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-admin/__init__.py +0 -0
  281. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-admin/celerp_admin/__init__.py +0 -0
  282. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-admin/celerp_admin/routes.py +0 -0
  283. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-admin/celerp_admin/setup.py +0 -0
  284. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/__init__.py +0 -0
  285. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/celerp_ai/__init__.py +0 -0
  286. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/celerp_ai/routes.py +0 -0
  287. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/celerp_ai/setup.py +0 -0
  288. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/celerp_ai/ui_routes.py +0 -0
  289. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/conftest.py +0 -0
  290. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_batch.py +0 -0
  291. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_cleanup.py +0 -0
  292. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_conversations.py +0 -0
  293. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_coverage_gaps.py +0 -0
  294. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_intent.py +0 -0
  295. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_llm.py +0 -0
  296. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_memory.py +0 -0
  297. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_models.py +0 -0
  298. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_page_count.py +0 -0
  299. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_quota.py +0 -0
  300. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_router.py +0 -0
  301. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_routes_coverage.py +0 -0
  302. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_service.py +0 -0
  303. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-ai/tests/test_tools.py +0 -0
  304. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-backup/__init__.py +0 -0
  305. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-backup/celerp_backup/__init__.py +0 -0
  306. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-backup/celerp_backup/routes.py +0 -0
  307. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-backup/celerp_backup/setup.py +0 -0
  308. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/__init__.py +0 -0
  309. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/celerp_connectors/__init__.py +0 -0
  310. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/celerp_connectors/models.py +0 -0
  311. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/celerp_connectors/routes.py +0 -0
  312. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/__init__.py +0 -0
  313. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/conftest.py +0 -0
  314. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/test_compliance.py +0 -0
  315. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/test_connector_correctness.py +0 -0
  316. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/test_connectors.py +0 -0
  317. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/test_credentials_routes.py +0 -0
  318. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/test_images.py +0 -0
  319. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/test_outbound.py +0 -0
  320. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/test_quickbooks.py +0 -0
  321. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/test_rate_limiting.py +0 -0
  322. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/test_shopify.py +0 -0
  323. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/test_wiring.py +0 -0
  324. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/test_woocommerce.py +0 -0
  325. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/test_woocommerce_webhooks.py +0 -0
  326. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-connectors/tests/test_xero.py +0 -0
  327. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-contacts/LICENSE +0 -0
  328. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-contacts/__init__.py +0 -0
  329. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-contacts/celerp_contacts/__init__.py +0 -0
  330. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-contacts/celerp_contacts/migrations.py +0 -0
  331. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-contacts/celerp_contacts/projections.py +0 -0
  332. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-contacts/celerp_contacts/routes.py +0 -0
  333. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-contacts/celerp_contacts/services.py +0 -0
  334. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-contacts/celerp_contacts/ui_routes.py +0 -0
  335. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-dashboard/LICENSE +0 -0
  336. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-dashboard/__init__.py +0 -0
  337. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-dashboard/celerp_dashboard/__init__.py +0 -0
  338. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-dashboard/celerp_dashboard/routes.py +0 -0
  339. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-dashboard/celerp_dashboard/setup.py +0 -0
  340. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/LICENSE +0 -0
  341. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/__init__.py +0 -0
  342. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/celerp_docs/__init__.py +0 -0
  343. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/celerp_docs/api_setup.py +0 -0
  344. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/celerp_docs/doc_constants.py +0 -0
  345. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/celerp_docs/doc_email.py +0 -0
  346. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/celerp_docs/doc_projections.py +0 -0
  347. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/celerp_docs/doc_service.py +0 -0
  348. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/celerp_docs/models_share.py +0 -0
  349. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/celerp_docs/routes.py +0 -0
  350. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/celerp_docs/routes_payments.py +0 -0
  351. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/celerp_docs/routes_share.py +0 -0
  352. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/celerp_docs/sequences.py +0 -0
  353. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/celerp_docs/taxes.py +0 -0
  354. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/celerp_docs/ui_routes.py +0 -0
  355. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/conftest.py +0 -0
  356. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_audits.py +0 -0
  357. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_freight_je.py +0 -0
  358. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_freight_lines.py +0 -0
  359. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_fulfill_no_split.py +0 -0
  360. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_fulfillment_activity.py +0 -0
  361. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_inbound_je_lifecycle.py +0 -0
  362. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_inventory_account_reconciliation.py +0 -0
  363. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_landed_receive.py +0 -0
  364. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_line_delete_persist.py +0 -0
  365. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_line_identifier.py +0 -0
  366. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_payment_void_activity.py +0 -0
  367. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_receive_sku_batch.py +0 -0
  368. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_send_visibility.py +0 -0
  369. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_service_lines.py +0 -0
  370. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-docs/tests/test_void_guards.py +0 -0
  371. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-inventory/LICENSE +0 -0
  372. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-inventory/__init__.py +0 -0
  373. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-inventory/celerp_inventory/__init__.py +0 -0
  374. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-inventory/celerp_inventory/models_import_batch.py +0 -0
  375. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-inventory/celerp_inventory/projections.py +0 -0
  376. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-inventory/celerp_inventory/routes_attachments.py +0 -0
  377. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-inventory/celerp_inventory/routes_scanning.py +0 -0
  378. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-inventory/celerp_inventory/services.py +0 -0
  379. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-inventory/celerp_inventory/ui_routes.py +0 -0
  380. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-inventory/tests/test_item_recipe_projection.py +0 -0
  381. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-inventory/tests/test_item_workflow_projection.py +0 -0
  382. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-inventory/tests/test_landed_cost_projection.py +0 -0
  383. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-labels/LICENSE +0 -0
  384. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-labels/__init__.py +0 -0
  385. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-labels/celerp_labels/__init__.py +0 -0
  386. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-labels/celerp_labels/models.py +0 -0
  387. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-labels/celerp_labels/presets.py +0 -0
  388. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-labels/celerp_labels/routes.py +0 -0
  389. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-labels/celerp_labels/service.py +0 -0
  390. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-labels/celerp_labels/ui_routes.py +0 -0
  391. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-labels/requirements.txt +0 -0
  392. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-labels/tests/test_labels.py +0 -0
  393. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-labels/tests/test_labels_module.py +0 -0
  394. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/LICENSE +0 -0
  395. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/celerp_manufacturing/__init__.py +0 -0
  396. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/celerp_manufacturing/costing.py +0 -0
  397. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/celerp_manufacturing/expansion.py +0 -0
  398. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/celerp_manufacturing/labor.py +0 -0
  399. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/celerp_manufacturing/migrations.py +0 -0
  400. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/celerp_manufacturing/projection_handler.py +0 -0
  401. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/celerp_manufacturing/ui_routes.py +0 -0
  402. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/requirements.txt +0 -0
  403. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_bom_removed.py +0 -0
  404. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_build_api.py +0 -0
  405. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_item_recipe_api.py +0 -0
  406. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_item_workflow_api.py +0 -0
  407. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_labor_providers.py +0 -0
  408. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_manufacture_from_doc.py +0 -0
  409. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_manufacturing.py +0 -0
  410. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_manufacturing_import_idempotency.py +0 -0
  411. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_manufacturing_module.py +0 -0
  412. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_mfg_events.py +0 -0
  413. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_phase2_manufacturing_validations.py +0 -0
  414. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_production_order.py +0 -0
  415. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_recipe_costing.py +0 -0
  416. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_recipe_expansion.py +0 -0
  417. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_recost_api.py +0 -0
  418. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_to_make_allocation.py +0 -0
  419. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_where_used.py +0 -0
  420. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-manufacturing/tests/test_workflow_time.py +0 -0
  421. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-reports/LICENSE +0 -0
  422. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-reports/__init__.py +0 -0
  423. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-reports/celerp_reports/__init__.py +0 -0
  424. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-reports/celerp_reports/api_setup.py +0 -0
  425. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-reports/celerp_reports/routes.py +0 -0
  426. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-reports/celerp_reports/ui_routes.py +0 -0
  427. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-reports/tests/test_reports_full.py +0 -0
  428. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-reports/tests/test_reports_unit.py +0 -0
  429. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-subscriptions/LICENSE +0 -0
  430. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-subscriptions/__init__.py +0 -0
  431. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-subscriptions/celerp_subscriptions/__init__.py +0 -0
  432. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-subscriptions/celerp_subscriptions/routes.py +0 -0
  433. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-subscriptions/celerp_subscriptions/ui_routes.py +0 -0
  434. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-subscriptions/tests/test_subscriptions.py +0 -0
  435. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-subscriptions/tests/test_subscriptions_ui.py +0 -0
  436. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/LICENSE +0 -0
  437. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/__init__.py +0 -0
  438. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/__init__.py +0 -0
  439. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/accessory_fashion.json +0 -0
  440. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/activewear.json +0 -0
  441. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/art_photography.json +0 -0
  442. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/audio_equipment.json +0 -0
  443. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/bag_handbag.json +0 -0
  444. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/banknote.json +0 -0
  445. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/beauty_tool.json +0 -0
  446. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/bed_bedroom.json +0 -0
  447. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/beer.json +0 -0
  448. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/beverage_nonalc.json +0 -0
  449. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/body_part_auto.json +0 -0
  450. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/book.json +0 -0
  451. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/bottoms.json +0 -0
  452. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/brake_suspension.json +0 -0
  453. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/bullion_coin.json +0 -0
  454. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/camera.json +0 -0
  455. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/colored_stone.json +0 -0
  456. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/comic.json +0 -0
  457. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/commercial_space.json +0 -0
  458. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/component_part.json +0 -0
  459. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/confectionery.json +0 -0
  460. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/consulting_service.json +0 -0
  461. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/decorative_art.json +0 -0
  462. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/diamond.json +0 -0
  463. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/drawing.json +0 -0
  464. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/dress_jumpsuit.json +0 -0
  465. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_auto.json +0 -0
  466. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_component.json +0 -0
  467. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/emerald.json +0 -0
  468. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/engine_part.json +0 -0
  469. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/fastener.json +0 -0
  470. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/fertilizer_chemical.json +0 -0
  471. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/film_video.json +0 -0
  472. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/fine_writing_instrument.json +0 -0
  473. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/fluid_lubricant.json +0 -0
  474. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/footwear.json +0 -0
  475. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/fragrance.json +0 -0
  476. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_food.json +0 -0
  477. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_produce.json +0 -0
  478. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/frozen_food.json +0 -0
  479. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/gaming_console.json +0 -0
  480. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/gold_bullion.json +0 -0
  481. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/grain_cereal.json +0 -0
  482. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/haircare.json +0 -0
  483. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/hand_tool.json +0 -0
  484. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/ingredient_bulk.json +0 -0
  485. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/interior_part.json +0 -0
  486. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/jewelry.json +0 -0
  487. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/kitchen_dining.json +0 -0
  488. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/laptop.json +0 -0
  489. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/lighting.json +0 -0
  490. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/livestock_feed.json +0 -0
  491. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/makeup.json +0 -0
  492. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/measuring_instrument.json +0 -0
  493. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/medal_token.json +0 -0
  494. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/mineral_specimen.json +0 -0
  495. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/mobile_phone.json +0 -0
  496. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/music_cd.json +0 -0
  497. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/music_vinyl.json +0 -0
  498. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/nail.json +0 -0
  499. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/numismatic_coin.json +0 -0
  500. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/outdoor_furniture.json +0 -0
  501. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/outerwear.json +0 -0
  502. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/packaged_food.json +0 -0
  503. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/painting.json +0 -0
  504. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/parking_bay.json +0 -0
  505. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/pearl.json +0 -0
  506. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/personal_care.json +0 -0
  507. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/pipe_plumbing.json +0 -0
  508. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/platinum_bullion.json +0 -0
  509. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/power_tool.json +0 -0
  510. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/print_edition.json +0 -0
  511. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/residential_unit.json +0 -0
  512. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/rough_gemstone.json +0 -0
  513. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/ruby.json +0 -0
  514. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/saas_plan.json +0 -0
  515. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/safety_ppe.json +0 -0
  516. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/sapphire.json +0 -0
  517. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/sculpture.json +0 -0
  518. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/seating.json +0 -0
  519. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/seeds.json +0 -0
  520. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/silver_bullion.json +0 -0
  521. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/skincare.json +0 -0
  522. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/soft_furnishing.json +0 -0
  523. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/software_addon.json +0 -0
  524. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/software_license.json +0 -0
  525. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/spirit.json +0 -0
  526. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/storage_furniture.json +0 -0
  527. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/swimwear.json +0 -0
  528. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/table_desk.json +0 -0
  529. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/tablet.json +0 -0
  530. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/tire_wheel.json +0 -0
  531. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/tops.json +0 -0
  532. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/trading_card.json +0 -0
  533. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/tv_display.json +0 -0
  534. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/video_game.json +0 -0
  535. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/watch.json +0 -0
  536. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/watch_strap.json +0 -0
  537. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/categories/wine.json +0 -0
  538. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/agricultural.json +0 -0
  539. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/artwork.json +0 -0
  540. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/automotive.json +0 -0
  541. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/blank.json +0 -0
  542. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/books_media.json +0 -0
  543. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/coins_precious_metals.json +0 -0
  544. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/consulting.json +0 -0
  545. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/cosmetics.json +0 -0
  546. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/electronics.json +0 -0
  547. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/fashion.json +0 -0
  548. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/food_beverage.json +0 -0
  549. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/furniture.json +0 -0
  550. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/gemstones.json +0 -0
  551. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/hardware.json +0 -0
  552. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/property_rental.json +0 -0
  553. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/saas.json +0 -0
  554. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/watches.json +0 -0
  555. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/presets/wine_spirits.json +0 -0
  556. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/routes.py +0 -0
  557. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/celerp_verticals/ui_routes.py +0 -0
  558. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/tests/test_verticals.py +0 -0
  559. {celerp-2.0.0 → celerp-2.1.0}/default_modules/celerp-verticals/tests/test_verticals_routers.py +0 -0
  560. {celerp-2.0.0 → celerp-2.1.0}/legal/OFFICIAL-COMPONENTS.md +0 -0
  561. {celerp-2.0.0 → celerp-2.1.0}/legal/TRADEMARK.md +0 -0
  562. {celerp-2.0.0 → celerp-2.1.0}/packaging/winget/Celerp.Celerp.installer.yaml +0 -0
  563. {celerp-2.0.0 → celerp-2.1.0}/packaging/winget/Celerp.Celerp.locale.en-US.yaml +0 -0
  564. {celerp-2.0.0 → celerp-2.1.0}/packaging/winget/Celerp.Celerp.yaml +0 -0
  565. {celerp-2.0.0 → celerp-2.1.0}/packaging/winget/README.md +0 -0
  566. {celerp-2.0.0 → celerp-2.1.0}/pyproject.toml +0 -0
  567. {celerp-2.0.0 → celerp-2.1.0}/setup.cfg +0 -0
  568. {celerp-2.0.0 → celerp-2.1.0}/test_helpers.py +0 -0
  569. {celerp-2.0.0 → celerp-2.1.0}/ui/__init__.py +0 -0
  570. {celerp-2.0.0 → celerp-2.1.0}/ui/app.py +0 -0
  571. {celerp-2.0.0 → celerp-2.1.0}/ui/components/__init__.py +0 -0
  572. {celerp-2.0.0 → celerp-2.1.0}/ui/components/attrs.py +0 -0
  573. {celerp-2.0.0 → celerp-2.1.0}/ui/components/backup.py +0 -0
  574. {celerp-2.0.0 → celerp-2.1.0}/ui/components/currency.py +0 -0
  575. {celerp-2.0.0 → celerp-2.1.0}/ui/components/files.py +0 -0
  576. {celerp-2.0.0 → celerp-2.1.0}/ui/components/journal.py +0 -0
  577. {celerp-2.0.0 → celerp-2.1.0}/ui/components/notes.py +0 -0
  578. {celerp-2.0.0 → celerp-2.1.0}/ui/components/phone.py +0 -0
  579. {celerp-2.0.0 → celerp-2.1.0}/ui/components/report_kit.py +0 -0
  580. {celerp-2.0.0 → celerp-2.1.0}/ui/config.py +0 -0
  581. {celerp-2.0.0 → celerp-2.1.0}/ui/i18n.py +0 -0
  582. {celerp-2.0.0 → celerp-2.1.0}/ui/marketplace_catalog.py +0 -0
  583. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/__init__.py +0 -0
  584. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/accounting.py +0 -0
  585. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/accounting_import.py +0 -0
  586. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/auth.py +0 -0
  587. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/csv_import.py +0 -0
  588. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/dashboard.py +0 -0
  589. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/docs_import.py +0 -0
  590. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/events.py +0 -0
  591. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/financial_reports.py +0 -0
  592. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/lists_import.py +0 -0
  593. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/modules_page.py +0 -0
  594. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/notifications.py +0 -0
  595. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/reconciliation.py +0 -0
  596. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/reports.py +0 -0
  597. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/search.py +0 -0
  598. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/settings_cloud.py +0 -0
  599. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/settings_contacts.py +0 -0
  600. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/settings_general.py +0 -0
  601. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/settings_import.py +0 -0
  602. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/settings_payments.py +0 -0
  603. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/settings_purchasing.py +0 -0
  604. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/settings_sales.py +0 -0
  605. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/setup.py +0 -0
  606. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/stars.py +0 -0
  607. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/subscriptions.py +0 -0
  608. {celerp-2.0.0 → celerp-2.1.0}/ui/routes/subscriptions_import.py +0 -0
  609. {celerp-2.0.0 → celerp-2.1.0}/ui/static/htmx.min.js +0 -0
  610. {celerp-2.0.0 → celerp-2.1.0}/ui/static/icon.png +0 -0
  611. {celerp-2.0.0 → celerp-2.1.0}/ui/static/logo.png +0 -0
  612. {celerp-2.0.0 → celerp-2.1.0}/ui/static/vendor/intl-tel-input/img/flags.webp +0 -0
  613. {celerp-2.0.0 → celerp-2.1.0}/ui/static/vendor/intl-tel-input/img/flags@2x.webp +0 -0
  614. {celerp-2.0.0 → celerp-2.1.0}/ui/static/vendor/intl-tel-input/intlTelInput.min.css +0 -0
  615. {celerp-2.0.0 → celerp-2.1.0}/ui/static/vendor/intl-tel-input/intlTelInput.min.js +0 -0
  616. {celerp-2.0.0 → celerp-2.1.0}/ui/static/vendor/intl-tel-input/intlTelInputWithUtils.min.js +0 -0
  617. {celerp-2.0.0 → celerp-2.1.0}/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.0
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,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
  )
@@ -559,10 +559,19 @@ async def list_users(company_id=Depends(get_current_company_id), session: AsyncS
559
559
  return {"items": items, "total": len(items)}
560
560
 
561
561
 
562
+ def _assert_role_assignable(caller_role: str, target_role: str) -> None:
563
+ """A holder of manage_users may not assign a role above their own. The matrix can
564
+ grant manage_users down to any role, so this ceiling is what stops that from
565
+ becoming a self-promotion path."""
566
+ if ROLE_LEVELS[target_role] > ROLE_LEVELS[caller_role]:
567
+ raise HTTPException(status_code=403, detail="You cannot assign a role above your own.")
568
+
569
+
562
570
  @router.post("/me/users")
563
571
  async def create_user(
564
572
  payload: UserCreate,
565
573
  company_id=Depends(get_current_company_id),
574
+ caller_role: str = Depends(get_current_role),
566
575
  _: None = require_permission("manage_users"),
567
576
  session: AsyncSession = Depends(get_session),
568
577
  ) -> dict:
@@ -570,6 +579,7 @@ async def create_user(
570
579
 
571
580
  if payload.role not in ROLE_LEVELS:
572
581
  raise HTTPException(400, f"Invalid role. Must be one of: {', '.join(sorted(ROLE_LEVELS, key=ROLE_LEVELS.get))}")
582
+ _assert_role_assignable(caller_role, payload.role)
573
583
 
574
584
  # Check if user with this email already exists globally; if so, just link them.
575
585
  existing_user = (await session.execute(select(User).where(User.email == payload.email))).scalar_one_or_none()
@@ -615,6 +625,7 @@ async def patch_user(
615
625
  user_id: uuid.UUID,
616
626
  payload: UserPatch,
617
627
  company_id=Depends(get_current_company_id),
628
+ caller_role: str = Depends(get_current_role),
618
629
  _: None = require_permission("manage_users"),
619
630
  session: AsyncSession = Depends(get_session),
620
631
  ) -> dict:
@@ -627,11 +638,16 @@ async def patch_user(
627
638
  )).scalar_one_or_none()
628
639
  if not user or not link:
629
640
  raise HTTPException(status_code=404, detail="User not found")
641
+ # A holder of manage_users may not modify a user whose role outranks their own.
642
+ if ROLE_LEVELS.get(link.role, 0) > ROLE_LEVELS[caller_role]:
643
+ raise HTTPException(status_code=403, detail="You cannot modify a user whose role is above your own.")
630
644
  if payload.name is not None:
631
645
  user.name = payload.name
632
646
  if payload.role is not None:
633
647
  if payload.role not in ROLE_LEVELS:
634
648
  raise HTTPException(400, f"Invalid role. Must be one of: {', '.join(sorted(ROLE_LEVELS, key=ROLE_LEVELS.get))}")
649
+ # Nor may they promote anyone above their own role.
650
+ _assert_role_assignable(caller_role, payload.role)
635
651
  # Guard: cannot demote the last active owner
636
652
  old_level = ROLE_LEVELS.get(link.role, 0)
637
653
  new_level = ROLE_LEVELS.get(payload.role, 0)
@@ -298,10 +298,19 @@ async def _reconcile_schema() -> str | None:
298
298
  from celerp.config import settings
299
299
 
300
300
  def _sync() -> None:
301
- from celerp.cli import _apply_migrations, _post_migration_grants, _reconcile_after_migrate
302
- _apply_migrations(settings.database_url)
303
- _post_migration_grants(settings.database_url)
304
- _reconcile_after_migrate(settings.database_url)
301
+ from celerp.cli import (
302
+ _apply_migrations,
303
+ _migration_lock,
304
+ _post_migration_grants,
305
+ _reconcile_after_migrate,
306
+ )
307
+ # Serialize under the shared migration advisory lock, the same one
308
+ # `celerp migrate`/`celerp start` hold, so a restore reconcile cannot
309
+ # run concurrently with a service migration or a second restore.
310
+ with _migration_lock(settings.database_url):
311
+ _apply_migrations(settings.database_url)
312
+ _post_migration_grants(settings.database_url)
313
+ _reconcile_after_migrate(settings.database_url)
305
314
 
306
315
  try:
307
316
  await asyncio.get_event_loop().run_in_executor(None, _sync)
@@ -19,6 +19,11 @@ from celerp.services.pricing import is_cost_list_name, is_derived, price_key
19
19
  # "Mixed", stored and displayed verbatim — no separate lowercase sentinel vs capitalized label.
20
20
  MIXED_VALUE = "Mixed"
21
21
 
22
+ # Item amount fields hand-edited on the item surface, gated by the
23
+ # edit_inventory_amounts permission. One source of truth, mirroring the
24
+ # COST_ITEM_KEYS precedent in celerp.services.cost_visibility.
25
+ AMOUNT_ITEM_KEYS: frozenset[str] = frozenset({"quantity", "weight", "pieces", "gross_weight"})
26
+
22
27
  # Default price lists (used when company has none configured)
23
28
  _DEFAULT_PRICE_LISTS: list[dict] = [
24
29
  {"name": "Wholesale"},
@@ -51,6 +56,7 @@ _BASE_FIELDS: list[dict] = [
51
56
  {"key": "barcode", "label": "Barcode", "type": "text", "editable": True, "required": False, "options": [], "visible_to_roles": [], "position": 104, "show_in_table": True, "tooltip_key": "field.tooltip.barcode"},
52
57
  {"key": "hs_code", "label": "HS Code", "type": "text", "editable": True, "required": False, "options": [], "visible_to_roles": [], "position": 104.5, "show_in_table": False, "tooltip_key": "field.tooltip.hs_code"},
53
58
  {"key": "country_of_origin", "label": "Country of Origin", "type": "text", "editable": True, "required": False, "options": [], "visible_to_roles": [], "position": 104.52,"show_in_table": False, "tooltip_key": "field.tooltip.country_of_origin"},
59
+ {"key": "preferred_supplier","label": "Preferred Supplier","type": "text", "editable": True, "required": False, "options": [], "visible_to_roles": [], "position": 104.54,"show_in_table": False, "tooltip_key": "field.tooltip.preferred_supplier"},
54
60
  {"key": "batch_no", "label": "Batch / Lot No", "type": "text", "editable": True, "required": False, "options": [], "visible_to_roles": [], "position": 104.55,"show_in_table": False, "tooltip_key": "field.tooltip.batch_no"},
55
61
  {"key": "purchase_sku", "label": "Purchase SKU", "type": "text", "editable": True, "required": False, "options": [], "visible_to_roles": [], "position": 104.6, "show_in_table": False, "tooltip_key": "field.tooltip.purchase_sku"},
56
62
  {"key": "purchase_name", "label": "Purchase Name", "type": "text", "editable": True, "required": False, "options": [], "visible_to_roles": [], "position": 104.7, "show_in_table": False, "tooltip_key": "field.tooltip.purchase_name"},