celerp 1.2.4__tar.gz → 1.2.5__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 (545) hide show
  1. {celerp-1.2.4 → celerp-1.2.5}/PKG-INFO +1 -1
  2. {celerp-1.2.4 → celerp-1.2.5}/celerp/cli.py +26 -3
  3. {celerp-1.2.4 → celerp-1.2.5}/celerp/events/engine.py +6 -0
  4. {celerp-1.2.4 → celerp-1.2.5}/celerp/middleware.py +7 -4
  5. {celerp-1.2.4 → celerp-1.2.5}/celerp/routers/health.py +2 -5
  6. {celerp-1.2.4 → celerp-1.2.5}/celerp/routers/stars.py +7 -3
  7. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/backup.py +3 -94
  8. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/backup_export.py +3 -26
  9. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/backup_import.py +3 -3
  10. celerp-1.2.5/celerp/services/backup_repo.py +241 -0
  11. celerp-1.2.5/celerp/services/backup_scheduler.py +107 -0
  12. celerp-1.2.5/celerp/services/backup_state.py +31 -0
  13. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/supporter_badge.py +5 -3
  14. {celerp-1.2.4 → celerp-1.2.5}/celerp.egg-info/PKG-INFO +1 -1
  15. {celerp-1.2.4 → celerp-1.2.5}/celerp.egg-info/SOURCES.txt +3 -1
  16. {celerp-1.2.4 → celerp-1.2.5}/celerp.egg-info/scm_file_list.json +5 -2
  17. celerp-1.2.5/celerp.egg-info/scm_version.json +8 -0
  18. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-backup/celerp_backup/routes.py +26 -37
  19. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/celerp_docs/routes.py +16 -5
  20. celerp-1.2.5/default_modules/celerp-docs/tests/test_line_delete_persist.py +85 -0
  21. {celerp-1.2.4 → celerp-1.2.5}/ui/api_client.py +49 -29
  22. {celerp-1.2.4 → celerp-1.2.5}/ui/components/activity.py +60 -2
  23. {celerp-1.2.4 → celerp-1.2.5}/ui/components/backup.py +5 -15
  24. {celerp-1.2.4 → celerp-1.2.5}/ui/components/shell.py +42 -4
  25. {celerp-1.2.4 → celerp-1.2.5}/ui/locales/ar.json +0 -7
  26. {celerp-1.2.4 → celerp-1.2.5}/ui/locales/de.json +0 -7
  27. {celerp-1.2.4 → celerp-1.2.5}/ui/locales/en.json +2 -7
  28. {celerp-1.2.4 → celerp-1.2.5}/ui/locales/es.json +0 -7
  29. {celerp-1.2.4 → celerp-1.2.5}/ui/locales/fr.json +0 -7
  30. {celerp-1.2.4 → celerp-1.2.5}/ui/locales/id.json +0 -7
  31. {celerp-1.2.4 → celerp-1.2.5}/ui/locales/it.json +0 -7
  32. {celerp-1.2.4 → celerp-1.2.5}/ui/locales/ja.json +0 -7
  33. {celerp-1.2.4 → celerp-1.2.5}/ui/locales/pt.json +0 -7
  34. {celerp-1.2.4 → celerp-1.2.5}/ui/locales/th.json +0 -7
  35. {celerp-1.2.4 → celerp-1.2.5}/ui/locales/vi.json +0 -7
  36. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/dashboard.py +1 -1
  37. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/documents.py +39 -19
  38. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/settings.py +74 -71
  39. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/settings_cloud.py +0 -2
  40. celerp-1.2.4/celerp/services/backup_files.py +0 -181
  41. celerp-1.2.4/celerp/services/backup_scheduler.py +0 -171
  42. celerp-1.2.4/celerp.egg-info/scm_version.json +0 -8
  43. {celerp-1.2.4 → celerp-1.2.5}/CLA.md +0 -0
  44. {celerp-1.2.4 → celerp-1.2.5}/CONTRIBUTING.md +0 -0
  45. {celerp-1.2.4 → celerp-1.2.5}/LICENSE +0 -0
  46. {celerp-1.2.4 → celerp-1.2.5}/LICENSING.md +0 -0
  47. {celerp-1.2.4 → celerp-1.2.5}/MANIFEST.in +0 -0
  48. {celerp-1.2.4 → celerp-1.2.5}/NOTICE +0 -0
  49. {celerp-1.2.4 → celerp-1.2.5}/README.md +0 -0
  50. {celerp-1.2.4 → celerp-1.2.5}/alembic.ini +0 -0
  51. {celerp-1.2.4 → celerp-1.2.5}/celerp/__init__.py +0 -0
  52. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/__init__.py +0 -0
  53. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/batch.py +0 -0
  54. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/cleanup.py +0 -0
  55. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/commands.py +0 -0
  56. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/conversations.py +0 -0
  57. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/files.py +0 -0
  58. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/intent.py +0 -0
  59. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/llm.py +0 -0
  60. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/memory.py +0 -0
  61. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/models.py +0 -0
  62. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/page_count.py +0 -0
  63. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/quota.py +0 -0
  64. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/service.py +0 -0
  65. {celerp-1.2.4 → celerp-1.2.5}/celerp/ai/tools.py +0 -0
  66. {celerp-1.2.4 → celerp-1.2.5}/celerp/alembic.ini +0 -0
  67. {celerp-1.2.4 → celerp-1.2.5}/celerp/alembic_config.py +0 -0
  68. {celerp-1.2.4 → celerp-1.2.5}/celerp/compute/__init__.py +0 -0
  69. {celerp-1.2.4 → celerp-1.2.5}/celerp/compute/aggregations.py +0 -0
  70. {celerp-1.2.4 → celerp-1.2.5}/celerp/compute/valuation.py +0 -0
  71. {celerp-1.2.4 → celerp-1.2.5}/celerp/config.py +0 -0
  72. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/__init__.py +0 -0
  73. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/base.py +0 -0
  74. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/daily_scheduler.py +0 -0
  75. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/http.py +0 -0
  76. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/images.py +0 -0
  77. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/outbound_queue.py +0 -0
  78. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/quickbooks.py +0 -0
  79. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/registry.py +0 -0
  80. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/shopify.py +0 -0
  81. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/sync_runner.py +0 -0
  82. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/upsert.py +0 -0
  83. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/webhooks.py +0 -0
  84. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/woocommerce.py +0 -0
  85. {celerp-1.2.4 → celerp-1.2.5}/celerp/connectors/xero.py +0 -0
  86. {celerp-1.2.4 → celerp-1.2.5}/celerp/constants.py +0 -0
  87. {celerp-1.2.4 → celerp-1.2.5}/celerp/db.py +0 -0
  88. {celerp-1.2.4 → celerp-1.2.5}/celerp/events/__init__.py +0 -0
  89. {celerp-1.2.4 → celerp-1.2.5}/celerp/events/schemas.py +0 -0
  90. {celerp-1.2.4 → celerp-1.2.5}/celerp/events/types.py +0 -0
  91. {celerp-1.2.4 → celerp-1.2.5}/celerp/gateway/__init__.py +0 -0
  92. {celerp-1.2.4 → celerp-1.2.5}/celerp/gateway/client.py +0 -0
  93. {celerp-1.2.4 → celerp-1.2.5}/celerp/gateway/state.py +0 -0
  94. {celerp-1.2.4 → celerp-1.2.5}/celerp/importers/__init__.py +0 -0
  95. {celerp-1.2.4 → celerp-1.2.5}/celerp/importers/importer.py +0 -0
  96. {celerp-1.2.4 → celerp-1.2.5}/celerp/importers/schema.py +0 -0
  97. {celerp-1.2.4 → celerp-1.2.5}/celerp/main.py +0 -0
  98. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/README.md +0 -0
  99. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/_auto_stamp.py +0 -0
  100. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/env.py +0 -0
  101. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/script.py.mako +0 -0
  102. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/a0b1c2d3e4f5_seed_landed_cost_clearing_accounts.py +0 -0
  103. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/a1b2c3d4e5f6_add_doc_share_tokens.py +0 -0
  104. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/b1c2d3e4f5a6_add_supporter_badges.py +0 -0
  105. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/b2c3d4e5f6a7_add_import_batches.py +0 -0
  106. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/c1d2e3f4a5b6_add_marketplace.py +0 -0
  107. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/d2e3f4a5b6c7_add_password_reset_token.py +0 -0
  108. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/e3f4a5b6c7d8_add_company_is_active.py +0 -0
  109. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/f1a2b3c4d5e6_move_accounts_marketplace_to_modules.py +0 -0
  110. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/fd5de461e14e_initial_schema.py +0 -0
  111. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/g1h2i3j4k5l6_add_consignment_flag.py +0 -0
  112. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/h2i3j4k5l6m7_add_bank_accounts_and_reconciliation.py +0 -0
  113. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/j4k5l6m7n8o9_labels_db_persistence.py +0 -0
  114. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/k5l6m7n8o9p0_add_reconciliation_v2.py +0 -0
  115. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/l6m7n8o9p0q1_add_sync_runs_table.py +0 -0
  116. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/m7n8o9p0q1r2_add_connector_configs_and_outbound_queue.py +0 -0
  117. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/n8o9p0q1r2s3_backfill_payment_date.py +0 -0
  118. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/o9p0q1r2s3t4_backfill_item_price_fields.py +0 -0
  119. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/p1q2r3s4t5u6_add_session_registry_and_user_auth_state.py +0 -0
  120. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/q2r3s4t5u6v7_add_system_runtime_state.py +0 -0
  121. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/r3s4t5u6v7w8_add_projections_company_entity_type_index.py +0 -0
  122. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/s4t5u6v7w8x9_drop_user_company_id_role.py +0 -0
  123. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/t5u6v7w8x9y0_seed_inventory_sub_accounts.py +0 -0
  124. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/u6v7w8x9y0z1_backfill_item_prices_from_attributes.py +0 -0
  125. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/v7w8x9y0z1a2_backfill_purchase_unit_defaults.py +0 -0
  126. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/w8x9y0z1a2b3_backfill_category_unit_defaults.py +0 -0
  127. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/x7y8z9a0b1c2_add_projection_created_at.py +0 -0
  128. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/y8z9a0b1c2d3_per_company_ledger_idempotency.py +0 -0
  129. {celerp-1.2.4 → celerp-1.2.5}/celerp/migrations/versions/z9a0b1c2d3e4_work_centers.py +0 -0
  130. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/__init__.py +0 -0
  131. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/accounting.py +0 -0
  132. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/ai.py +0 -0
  133. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/auth.py +0 -0
  134. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/base.py +0 -0
  135. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/company.py +0 -0
  136. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/connector_config.py +0 -0
  137. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/import_batch.py +0 -0
  138. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/ledger.py +0 -0
  139. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/marketplace.py +0 -0
  140. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/notification.py +0 -0
  141. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/projections.py +0 -0
  142. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/share.py +0 -0
  143. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/supporter.py +0 -0
  144. {celerp-1.2.4 → celerp-1.2.5}/celerp/models/sync_run.py +0 -0
  145. {celerp-1.2.4 → celerp-1.2.5}/celerp/modules/__init__.py +0 -0
  146. {celerp-1.2.4 → celerp-1.2.5}/celerp/modules/api.py +0 -0
  147. {celerp-1.2.4 → celerp-1.2.5}/celerp/modules/audit.py +0 -0
  148. {celerp-1.2.4 → celerp-1.2.5}/celerp/modules/license.py +0 -0
  149. {celerp-1.2.4 → celerp-1.2.5}/celerp/modules/loader.py +0 -0
  150. {celerp-1.2.4 → celerp-1.2.5}/celerp/modules/references.py +0 -0
  151. {celerp-1.2.4 → celerp-1.2.5}/celerp/modules/registry.py +0 -0
  152. {celerp-1.2.4 → celerp-1.2.5}/celerp/modules/slots.py +0 -0
  153. {celerp-1.2.4 → celerp-1.2.5}/celerp/notifications/__init__.py +0 -0
  154. {celerp-1.2.4 → celerp-1.2.5}/celerp/notifications/service.py +0 -0
  155. {celerp-1.2.4 → celerp-1.2.5}/celerp/notifications/sse.py +0 -0
  156. {celerp-1.2.4 → celerp-1.2.5}/celerp/output/__init__.py +0 -0
  157. {celerp-1.2.4 → celerp-1.2.5}/celerp/output/pdf.py +0 -0
  158. {celerp-1.2.4 → celerp-1.2.5}/celerp/output/share_render.py +0 -0
  159. {celerp-1.2.4 → celerp-1.2.5}/celerp/projections/__init__.py +0 -0
  160. {celerp-1.2.4 → celerp-1.2.5}/celerp/projections/engine.py +0 -0
  161. {celerp-1.2.4 → celerp-1.2.5}/celerp/projections/handlers/__init__.py +0 -0
  162. {celerp-1.2.4 → celerp-1.2.5}/celerp/projections/handlers/marketplace.py +0 -0
  163. {celerp-1.2.4 → celerp-1.2.5}/celerp/projections/handlers/scanning.py +0 -0
  164. {celerp-1.2.4 → celerp-1.2.5}/celerp/projections/handlers/system.py +0 -0
  165. {celerp-1.2.4 → celerp-1.2.5}/celerp/routers/__init__.py +0 -0
  166. {celerp-1.2.4 → celerp-1.2.5}/celerp/routers/auth.py +0 -0
  167. {celerp-1.2.4 → celerp-1.2.5}/celerp/routers/companies.py +0 -0
  168. {celerp-1.2.4 → celerp-1.2.5}/celerp/routers/debug.py +0 -0
  169. {celerp-1.2.4 → celerp-1.2.5}/celerp/routers/doctor.py +0 -0
  170. {celerp-1.2.4 → celerp-1.2.5}/celerp/routers/events.py +0 -0
  171. {celerp-1.2.4 → celerp-1.2.5}/celerp/routers/ledger.py +0 -0
  172. {celerp-1.2.4 → celerp-1.2.5}/celerp/routers/notifications.py +0 -0
  173. {celerp-1.2.4 → celerp-1.2.5}/celerp/routers/system.py +0 -0
  174. {celerp-1.2.4 → celerp-1.2.5}/celerp/schemas/__init__.py +0 -0
  175. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/__init__.py +0 -0
  176. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/activity_redaction.py +0 -0
  177. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/attachments.py +0 -0
  178. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/auth.py +0 -0
  179. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/auto_je.py +0 -0
  180. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/demo.py +0 -0
  181. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/email.py +0 -0
  182. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/field_schema.py +0 -0
  183. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/fulfill.py +0 -0
  184. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/je_keys.py +0 -0
  185. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/landed_cost.py +0 -0
  186. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/line_measures.py +0 -0
  187. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/list_behavior.py +0 -0
  188. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/money.py +0 -0
  189. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/pick.py +0 -0
  190. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/runtime_state.py +0 -0
  191. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/session_tracker.py +0 -0
  192. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/star_cta.py +0 -0
  193. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/system_health.py +0 -0
  194. {celerp-1.2.4 → celerp-1.2.5}/celerp/services/units.py +0 -0
  195. {celerp-1.2.4 → celerp-1.2.5}/celerp/session_gate.py +0 -0
  196. {celerp-1.2.4 → celerp-1.2.5}/celerp/tax_regimes.py +0 -0
  197. {celerp-1.2.4 → celerp-1.2.5}/celerp.egg-info/dependency_links.txt +0 -0
  198. {celerp-1.2.4 → celerp-1.2.5}/celerp.egg-info/entry_points.txt +0 -0
  199. {celerp-1.2.4 → celerp-1.2.5}/celerp.egg-info/requires.txt +0 -0
  200. {celerp-1.2.4 → celerp-1.2.5}/celerp.egg-info/top_level.txt +0 -0
  201. {celerp-1.2.4 → celerp-1.2.5}/conftest.py +0 -0
  202. {celerp-1.2.4 → celerp-1.2.5}/default_modules/__init__.py +0 -0
  203. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/LICENSE +0 -0
  204. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/__init__.py +0 -0
  205. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/celerp_accounting/__init__.py +0 -0
  206. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/celerp_accounting/api_setup.py +0 -0
  207. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/celerp_accounting/csv_parser.py +0 -0
  208. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/celerp_accounting/matcher.py +0 -0
  209. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/celerp_accounting/models.py +0 -0
  210. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/celerp_accounting/projections.py +0 -0
  211. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/celerp_accounting/routes.py +0 -0
  212. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/celerp_accounting/ui_routes.py +0 -0
  213. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/tests/test_accounting_banking.py +0 -0
  214. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/tests/test_accounting_banking_routers.py +0 -0
  215. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/tests/test_accounting_gaps.py +0 -0
  216. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/tests/test_accounting_import_idempotency.py +0 -0
  217. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-accounting/tests/test_reconciliation_v2.py +0 -0
  218. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-admin/__init__.py +0 -0
  219. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-admin/celerp_admin/__init__.py +0 -0
  220. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-admin/celerp_admin/routes.py +0 -0
  221. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-admin/celerp_admin/setup.py +0 -0
  222. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/__init__.py +0 -0
  223. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/celerp_ai/__init__.py +0 -0
  224. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/celerp_ai/routes.py +0 -0
  225. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/celerp_ai/setup.py +0 -0
  226. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/celerp_ai/ui_routes.py +0 -0
  227. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/conftest.py +0 -0
  228. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_batch.py +0 -0
  229. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_cleanup.py +0 -0
  230. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_conversations.py +0 -0
  231. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_coverage_gaps.py +0 -0
  232. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_intent.py +0 -0
  233. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_llm.py +0 -0
  234. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_memory.py +0 -0
  235. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_models.py +0 -0
  236. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_page_count.py +0 -0
  237. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_quota.py +0 -0
  238. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_router.py +0 -0
  239. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_routes_coverage.py +0 -0
  240. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_service.py +0 -0
  241. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-ai/tests/test_tools.py +0 -0
  242. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-backup/__init__.py +0 -0
  243. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-backup/celerp_backup/__init__.py +0 -0
  244. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-backup/celerp_backup/setup.py +0 -0
  245. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/__init__.py +0 -0
  246. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/celerp_connectors/__init__.py +0 -0
  247. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/celerp_connectors/models.py +0 -0
  248. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/celerp_connectors/routes.py +0 -0
  249. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/tests/__init__.py +0 -0
  250. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/tests/conftest.py +0 -0
  251. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/tests/test_compliance.py +0 -0
  252. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/tests/test_connectors.py +0 -0
  253. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/tests/test_outbound.py +0 -0
  254. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/tests/test_quickbooks.py +0 -0
  255. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/tests/test_rate_limiting.py +0 -0
  256. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/tests/test_shopify.py +0 -0
  257. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/tests/test_woocommerce.py +0 -0
  258. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-connectors/tests/test_xero.py +0 -0
  259. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-contacts/LICENSE +0 -0
  260. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-contacts/__init__.py +0 -0
  261. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-contacts/celerp_contacts/__init__.py +0 -0
  262. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-contacts/celerp_contacts/migrations.py +0 -0
  263. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-contacts/celerp_contacts/projections.py +0 -0
  264. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-contacts/celerp_contacts/routes.py +0 -0
  265. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-contacts/celerp_contacts/services.py +0 -0
  266. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-contacts/celerp_contacts/ui_routes.py +0 -0
  267. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-dashboard/LICENSE +0 -0
  268. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-dashboard/__init__.py +0 -0
  269. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-dashboard/celerp_dashboard/__init__.py +0 -0
  270. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-dashboard/celerp_dashboard/routes.py +0 -0
  271. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-dashboard/celerp_dashboard/setup.py +0 -0
  272. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/LICENSE +0 -0
  273. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/__init__.py +0 -0
  274. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/celerp_docs/__init__.py +0 -0
  275. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/celerp_docs/api_setup.py +0 -0
  276. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/celerp_docs/doc_constants.py +0 -0
  277. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/celerp_docs/doc_projections.py +0 -0
  278. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/celerp_docs/doc_service.py +0 -0
  279. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/celerp_docs/models_share.py +0 -0
  280. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/celerp_docs/routes_share.py +0 -0
  281. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/celerp_docs/sequences.py +0 -0
  282. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/celerp_docs/taxes.py +0 -0
  283. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/celerp_docs/ui_routes.py +0 -0
  284. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/tests/conftest.py +0 -0
  285. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/tests/test_audits.py +0 -0
  286. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/tests/test_freight_je.py +0 -0
  287. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/tests/test_freight_lines.py +0 -0
  288. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/tests/test_fulfill_no_split.py +0 -0
  289. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/tests/test_fulfillment_activity.py +0 -0
  290. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/tests/test_inbound_je_lifecycle.py +0 -0
  291. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/tests/test_inventory_account_reconciliation.py +0 -0
  292. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/tests/test_landed_receive.py +0 -0
  293. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/tests/test_payment_void_activity.py +0 -0
  294. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/tests/test_send_visibility.py +0 -0
  295. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-docs/tests/test_service_lines.py +0 -0
  296. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-inventory/LICENSE +0 -0
  297. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-inventory/__init__.py +0 -0
  298. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-inventory/celerp_inventory/__init__.py +0 -0
  299. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-inventory/celerp_inventory/models_import_batch.py +0 -0
  300. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-inventory/celerp_inventory/projections.py +0 -0
  301. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-inventory/celerp_inventory/routes.py +0 -0
  302. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-inventory/celerp_inventory/routes_attachments.py +0 -0
  303. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-inventory/celerp_inventory/routes_scanning.py +0 -0
  304. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-inventory/celerp_inventory/services.py +0 -0
  305. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-inventory/celerp_inventory/ui_routes.py +0 -0
  306. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-inventory/tests/test_item_recipe_projection.py +0 -0
  307. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-inventory/tests/test_item_workflow_projection.py +0 -0
  308. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-inventory/tests/test_landed_cost_projection.py +0 -0
  309. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-labels/LICENSE +0 -0
  310. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-labels/__init__.py +0 -0
  311. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-labels/celerp_labels/__init__.py +0 -0
  312. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-labels/celerp_labels/migrations/__init__.py +0 -0
  313. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-labels/celerp_labels/migrations/labels_001_create_label_templates.py +0 -0
  314. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-labels/celerp_labels/models.py +0 -0
  315. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-labels/celerp_labels/presets.py +0 -0
  316. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-labels/celerp_labels/routes.py +0 -0
  317. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-labels/celerp_labels/service.py +0 -0
  318. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-labels/celerp_labels/ui_routes.py +0 -0
  319. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-labels/requirements.txt +0 -0
  320. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-labels/tests/test_labels.py +0 -0
  321. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-labels/tests/test_labels_module.py +0 -0
  322. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/LICENSE +0 -0
  323. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/__init__.py +0 -0
  324. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/celerp_manufacturing/__init__.py +0 -0
  325. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/celerp_manufacturing/costing.py +0 -0
  326. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/celerp_manufacturing/expansion.py +0 -0
  327. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/celerp_manufacturing/labor.py +0 -0
  328. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/celerp_manufacturing/migrations.py +0 -0
  329. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/celerp_manufacturing/projection_handler.py +0 -0
  330. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/celerp_manufacturing/routes.py +0 -0
  331. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/celerp_manufacturing/ui_routes.py +0 -0
  332. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/requirements.txt +0 -0
  333. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_bom_removed.py +0 -0
  334. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_build_api.py +0 -0
  335. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_item_recipe_api.py +0 -0
  336. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_item_workflow_api.py +0 -0
  337. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_labor_providers.py +0 -0
  338. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_manufacture_from_doc.py +0 -0
  339. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_manufacturing.py +0 -0
  340. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_manufacturing_import_idempotency.py +0 -0
  341. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_manufacturing_module.py +0 -0
  342. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_mfg_events.py +0 -0
  343. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_phase2_manufacturing_validations.py +0 -0
  344. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_production_order.py +0 -0
  345. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_recipe_costing.py +0 -0
  346. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_recipe_expansion.py +0 -0
  347. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_recost_api.py +0 -0
  348. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_to_make_allocation.py +0 -0
  349. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_where_used.py +0 -0
  350. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_work_centers_and_settings.py +0 -0
  351. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-manufacturing/tests/test_workflow_time.py +0 -0
  352. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-reports/LICENSE +0 -0
  353. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-reports/__init__.py +0 -0
  354. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-reports/celerp_reports/__init__.py +0 -0
  355. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-reports/celerp_reports/api_setup.py +0 -0
  356. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-reports/celerp_reports/routes.py +0 -0
  357. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-reports/celerp_reports/ui_routes.py +0 -0
  358. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-reports/tests/test_reports_full.py +0 -0
  359. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-reports/tests/test_reports_unit.py +0 -0
  360. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-subscriptions/LICENSE +0 -0
  361. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-subscriptions/__init__.py +0 -0
  362. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-subscriptions/celerp_subscriptions/__init__.py +0 -0
  363. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-subscriptions/celerp_subscriptions/routes.py +0 -0
  364. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-subscriptions/celerp_subscriptions/ui_routes.py +0 -0
  365. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-subscriptions/tests/test_subscriptions.py +0 -0
  366. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-subscriptions/tests/test_subscriptions_ui.py +0 -0
  367. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/LICENSE +0 -0
  368. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/__init__.py +0 -0
  369. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/__init__.py +0 -0
  370. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/accessory_fashion.json +0 -0
  371. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/activewear.json +0 -0
  372. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/art_photography.json +0 -0
  373. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/audio_equipment.json +0 -0
  374. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/bag_handbag.json +0 -0
  375. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/banknote.json +0 -0
  376. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/beauty_tool.json +0 -0
  377. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/bed_bedroom.json +0 -0
  378. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/beer.json +0 -0
  379. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/beverage_nonalc.json +0 -0
  380. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/body_part_auto.json +0 -0
  381. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/book.json +0 -0
  382. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/bottoms.json +0 -0
  383. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/brake_suspension.json +0 -0
  384. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/bullion_coin.json +0 -0
  385. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/camera.json +0 -0
  386. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/colored_stone.json +0 -0
  387. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/comic.json +0 -0
  388. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/commercial_space.json +0 -0
  389. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/component_part.json +0 -0
  390. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/confectionery.json +0 -0
  391. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/consulting_service.json +0 -0
  392. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/decorative_art.json +0 -0
  393. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/diamond.json +0 -0
  394. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/drawing.json +0 -0
  395. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/dress_jumpsuit.json +0 -0
  396. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_auto.json +0 -0
  397. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/electrical_component.json +0 -0
  398. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/emerald.json +0 -0
  399. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/engine_part.json +0 -0
  400. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/fastener.json +0 -0
  401. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/fertilizer_chemical.json +0 -0
  402. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/film_video.json +0 -0
  403. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/fine_writing_instrument.json +0 -0
  404. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/fluid_lubricant.json +0 -0
  405. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/footwear.json +0 -0
  406. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/fragrance.json +0 -0
  407. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_food.json +0 -0
  408. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/fresh_produce.json +0 -0
  409. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/frozen_food.json +0 -0
  410. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/gaming_console.json +0 -0
  411. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/gold_bullion.json +0 -0
  412. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/grain_cereal.json +0 -0
  413. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/haircare.json +0 -0
  414. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/hand_tool.json +0 -0
  415. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/ingredient_bulk.json +0 -0
  416. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/interior_part.json +0 -0
  417. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/jewelry.json +0 -0
  418. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/kitchen_dining.json +0 -0
  419. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/laptop.json +0 -0
  420. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/lighting.json +0 -0
  421. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/livestock_feed.json +0 -0
  422. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/makeup.json +0 -0
  423. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/measuring_instrument.json +0 -0
  424. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/medal_token.json +0 -0
  425. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/mineral_specimen.json +0 -0
  426. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/mobile_phone.json +0 -0
  427. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/music_cd.json +0 -0
  428. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/music_vinyl.json +0 -0
  429. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/nail.json +0 -0
  430. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/numismatic_coin.json +0 -0
  431. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/outdoor_furniture.json +0 -0
  432. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/outerwear.json +0 -0
  433. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/packaged_food.json +0 -0
  434. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/painting.json +0 -0
  435. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/parking_bay.json +0 -0
  436. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/pearl.json +0 -0
  437. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/personal_care.json +0 -0
  438. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/pipe_plumbing.json +0 -0
  439. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/platinum_bullion.json +0 -0
  440. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/power_tool.json +0 -0
  441. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/print_edition.json +0 -0
  442. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/residential_unit.json +0 -0
  443. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/rough_gemstone.json +0 -0
  444. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/ruby.json +0 -0
  445. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/saas_plan.json +0 -0
  446. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/safety_ppe.json +0 -0
  447. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/sapphire.json +0 -0
  448. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/sculpture.json +0 -0
  449. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/seating.json +0 -0
  450. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/seeds.json +0 -0
  451. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/silver_bullion.json +0 -0
  452. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/skincare.json +0 -0
  453. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/soft_furnishing.json +0 -0
  454. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/software_addon.json +0 -0
  455. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/software_license.json +0 -0
  456. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/spirit.json +0 -0
  457. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/storage_furniture.json +0 -0
  458. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/swimwear.json +0 -0
  459. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/table_desk.json +0 -0
  460. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/tablet.json +0 -0
  461. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/tire_wheel.json +0 -0
  462. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/tops.json +0 -0
  463. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/trading_card.json +0 -0
  464. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/tv_display.json +0 -0
  465. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/video_game.json +0 -0
  466. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/watch.json +0 -0
  467. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/watch_strap.json +0 -0
  468. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/categories/wine.json +0 -0
  469. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/agricultural.json +0 -0
  470. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/artwork.json +0 -0
  471. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/automotive.json +0 -0
  472. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/blank.json +0 -0
  473. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/books_media.json +0 -0
  474. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/coins_precious_metals.json +0 -0
  475. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/consulting.json +0 -0
  476. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/cosmetics.json +0 -0
  477. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/electronics.json +0 -0
  478. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/fashion.json +0 -0
  479. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/food_beverage.json +0 -0
  480. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/furniture.json +0 -0
  481. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/gemstones.json +0 -0
  482. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/hardware.json +0 -0
  483. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/property_rental.json +0 -0
  484. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/saas.json +0 -0
  485. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/watches.json +0 -0
  486. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/presets/wine_spirits.json +0 -0
  487. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/routes.py +0 -0
  488. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/celerp_verticals/ui_routes.py +0 -0
  489. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/tests/test_verticals.py +0 -0
  490. {celerp-1.2.4 → celerp-1.2.5}/default_modules/celerp-verticals/tests/test_verticals_routers.py +0 -0
  491. {celerp-1.2.4 → celerp-1.2.5}/legal/OFFICIAL-COMPONENTS.md +0 -0
  492. {celerp-1.2.4 → celerp-1.2.5}/legal/TRADEMARK.md +0 -0
  493. {celerp-1.2.4 → celerp-1.2.5}/memory/fix-receive-goods-bugs.md +0 -0
  494. {celerp-1.2.4 → celerp-1.2.5}/pyproject.toml +0 -0
  495. {celerp-1.2.4 → celerp-1.2.5}/setup.cfg +0 -0
  496. {celerp-1.2.4 → celerp-1.2.5}/test_helpers.py +0 -0
  497. {celerp-1.2.4 → celerp-1.2.5}/ui/__init__.py +0 -0
  498. {celerp-1.2.4 → celerp-1.2.5}/ui/app.py +0 -0
  499. {celerp-1.2.4 → celerp-1.2.5}/ui/components/__init__.py +0 -0
  500. {celerp-1.2.4 → celerp-1.2.5}/ui/components/cloud_gate.py +0 -0
  501. {celerp-1.2.4 → celerp-1.2.5}/ui/components/currency.py +0 -0
  502. {celerp-1.2.4 → celerp-1.2.5}/ui/components/files.py +0 -0
  503. {celerp-1.2.4 → celerp-1.2.5}/ui/components/notes.py +0 -0
  504. {celerp-1.2.4 → celerp-1.2.5}/ui/components/phone.py +0 -0
  505. {celerp-1.2.4 → celerp-1.2.5}/ui/components/table.py +0 -0
  506. {celerp-1.2.4 → celerp-1.2.5}/ui/config.py +0 -0
  507. {celerp-1.2.4 → celerp-1.2.5}/ui/i18n.py +0 -0
  508. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/__init__.py +0 -0
  509. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/accounting.py +0 -0
  510. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/accounting_import.py +0 -0
  511. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/auth.py +0 -0
  512. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/contacts.py +0 -0
  513. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/csv_import.py +0 -0
  514. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/docs_import.py +0 -0
  515. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/events.py +0 -0
  516. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/inventory.py +0 -0
  517. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/lists_import.py +0 -0
  518. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/manufacturing.py +0 -0
  519. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/notifications.py +0 -0
  520. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/reconciliation.py +0 -0
  521. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/reports.py +0 -0
  522. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/search.py +0 -0
  523. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/settings_accounting.py +0 -0
  524. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/settings_connectors.py +0 -0
  525. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/settings_contacts.py +0 -0
  526. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/settings_general.py +0 -0
  527. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/settings_import.py +0 -0
  528. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/settings_inventory.py +0 -0
  529. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/settings_manufacturing.py +0 -0
  530. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/settings_purchasing.py +0 -0
  531. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/settings_sales.py +0 -0
  532. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/setup.py +0 -0
  533. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/stars.py +0 -0
  534. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/subscriptions.py +0 -0
  535. {celerp-1.2.4 → celerp-1.2.5}/ui/routes/subscriptions_import.py +0 -0
  536. {celerp-1.2.4 → celerp-1.2.5}/ui/static/app.css +0 -0
  537. {celerp-1.2.4 → celerp-1.2.5}/ui/static/htmx.min.js +0 -0
  538. {celerp-1.2.4 → celerp-1.2.5}/ui/static/icon.png +0 -0
  539. {celerp-1.2.4 → celerp-1.2.5}/ui/static/logo.png +0 -0
  540. {celerp-1.2.4 → celerp-1.2.5}/ui/static/vendor/intl-tel-input/img/flags.webp +0 -0
  541. {celerp-1.2.4 → celerp-1.2.5}/ui/static/vendor/intl-tel-input/img/flags@2x.webp +0 -0
  542. {celerp-1.2.4 → celerp-1.2.5}/ui/static/vendor/intl-tel-input/intlTelInput.min.css +0 -0
  543. {celerp-1.2.4 → celerp-1.2.5}/ui/static/vendor/intl-tel-input/intlTelInput.min.js +0 -0
  544. {celerp-1.2.4 → celerp-1.2.5}/ui/static/vendor/intl-tel-input/intlTelInputWithUtils.min.js +0 -0
  545. {celerp-1.2.4 → celerp-1.2.5}/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: 1.2.4
3
+ Version: 1.2.5
4
4
  Summary: Free, self-hosted ERP for small businesses
5
5
  License: Business Source License 1.1
6
6
 
@@ -430,8 +430,9 @@ def main() -> None:
430
430
  @click.option("--api-port", default=None, type=int, help="API server port (default 8000).")
431
431
  @click.option("--ui-port", default=None, type=int, help="UI server port (default 8080).")
432
432
  @click.option("--cloud-token", default=None, help="Celerp Cloud token (optional).")
433
- @click.option("--force", is_flag=True, help="Overwrite existing config.")
434
- def init(db_url, api_port, ui_port, cloud_token, force):
433
+ @click.option("--force", is_flag=True, help="Reconfigure: WIPES the database and all attached files.")
434
+ @click.option("--yes", "-y", "assume_yes", is_flag=True, help="Skip the --force wipe confirmation (non-interactive use).")
435
+ def init(db_url, api_port, ui_port, cloud_token, force, assume_yes):
435
436
  """Initialize Celerp: write config and run database migrations."""
436
437
  config_path = _config_path()
437
438
 
@@ -441,6 +442,21 @@ def init(db_url, api_port, ui_port, cloud_token, force):
441
442
  return
442
443
 
443
444
  if force:
445
+ # --force is destructive: it drops the database AND removes attached files.
446
+ # init can run under sudo, so warn (with full paths) and confirm before wiping.
447
+ from celerp.config import settings
448
+ _purge_dirs = [
449
+ settings.data_dir / "static" / "attachments",
450
+ settings.data_dir / "ai_uploads",
451
+ ]
452
+ click.echo("⚠ `init --force` permanently WIPES this instance:")
453
+ click.echo(f" - database: {db_url or _DEFAULT_DB_URL}")
454
+ for _d in _purge_dirs:
455
+ click.echo(f" - files: {_d.resolve()}")
456
+ click.echo(" Make sure you have a backup.")
457
+ if not assume_yes and not click.confirm("Continue?", default=False):
458
+ click.echo("Aborted.")
459
+ return
444
460
  _stop_servers()
445
461
 
446
462
  enabled_modules: list[str] = []
@@ -469,6 +485,13 @@ def init(db_url, api_port, ui_port, cloud_token, force):
469
485
  )
470
486
  sys.exit(1)
471
487
  click.echo(" ✓ Database ready (fresh)")
488
+ # Wipe attached files too, so a forced re-init is a truly fresh instance and no
489
+ # orphaned files remain. Recreated automatically on next boot.
490
+ import shutil
491
+ for _d in _purge_dirs:
492
+ if _d.exists():
493
+ shutil.rmtree(_d, ignore_errors=True)
494
+ click.echo(f" ✓ Removed {_d.resolve()}")
472
495
  else:
473
496
  # Test DB connection — auto-provision if running as root
474
497
  click.echo("Connecting to database...")
@@ -549,7 +572,7 @@ def init(db_url, api_port, ui_port, cloud_token, force):
549
572
  from celerp.gateway.state import build_handoff_url as _handoff
550
573
  if _settings.star_cta_enabled:
551
574
  click.echo(
552
- "New and independent - founding supporters are how other teams find us.\n"
575
+ "New and independent - early stargazers are how other teams find us.\n"
553
576
  f" Back us early: {_handoff('/github', medium='cli')}\n"
554
577
  )
555
578
 
@@ -49,6 +49,12 @@ async def _check_period_lock(session, company_id, data: dict) -> None:
49
49
 
50
50
 
51
51
  async def emit_event(session, **kwargs) -> LedgerEntry:
52
+ # A backup represents a clean point in time: while one is building, pause writes
53
+ # (reads, which never emit, are unaffected) so nothing changes mid-backup.
54
+ from celerp.services.backup_state import is_active as _backup_active
55
+ if _backup_active():
56
+ raise HTTPException(status_code=503, detail="Backup in progress, try again shortly.")
57
+
52
58
  schema = EVENT_SCHEMA_MAP.get(kwargs["event_type"])
53
59
  if schema is None:
54
60
  raise ValueError(f"Unknown event_type: {kwargs['event_type']}")
@@ -73,10 +73,13 @@ class MaxBodySizeMiddleware:
73
73
  await self.app(scope, receive, send)
74
74
  return
75
75
 
76
- # Bulk file/cert import legitimately uploads a large ZIP (many small files);
77
- # exempt it from the body cap. It's bounded instead by the WS tunnel frame
78
- # size and the per-file 50 MB limit in store_upload().
79
- if scope.get("path", "").endswith(("/items/files/bulk", "/items/attachments/bulk")):
76
+ # Bulk file/cert import and backup restore legitimately upload large archives;
77
+ # exempt them from the body cap. Bulk imports are bounded by the WS tunnel frame
78
+ # size and the per-file 50 MB limit in store_upload(); a .celerp-backup restore is
79
+ # a trusted whole-instance archive (DB + files) that is inherently large.
80
+ if scope.get("path", "").endswith(
81
+ ("/items/files/bulk", "/items/attachments/bulk", "/backup/import", "/backup/import-bootstrap")
82
+ ):
80
83
  await self.app(scope, receive, send)
81
84
  return
82
85
 
@@ -131,22 +131,19 @@ async def backup_status() -> dict:
131
131
  """Return backup scheduler state: last results and next scheduled run times."""
132
132
  from celerp.config import settings
133
133
  from celerp.services import backup_scheduler
134
+ from celerp.services.backup_state import is_active
134
135
  db = backup_scheduler.last_db_result()
135
- fl = backup_scheduler.last_file_result()
136
136
  next_db = backup_scheduler.next_db_run_utc()
137
- next_fl = backup_scheduler.next_file_run_utc()
138
137
  running = bool(backup_scheduler._db_task and not backup_scheduler._db_task.done())
139
138
  return {
140
139
  "running": running,
140
+ "active": is_active(),
141
141
  "gateway_token_set": bool(settings.gateway_token),
142
142
  "enc_ok": bool(settings.backup_encryption_key),
143
143
  "enc_key": settings.backup_encryption_key or "",
144
144
  "db": {"ok": db.ok, "error": db.error, "size_bytes": db.size_bytes,
145
145
  "last_run": db.last_run.isoformat() if db.last_run else None},
146
- "file": {"ok": fl.ok, "error": fl.error, "size_bytes": fl.size_bytes,
147
- "last_run": fl.last_run.isoformat() if fl.last_run else None},
148
146
  "next_db_utc": next_db.isoformat() if next_db else None,
149
- "next_file_utc": next_fl.isoformat() if next_fl else None,
150
147
  }
151
148
 
152
149
 
@@ -53,7 +53,8 @@ async def dismiss(
53
53
  @router.get("/badge/verify-url")
54
54
  async def badge_verify_url(return_url: str, _user=Depends(get_current_user)) -> dict:
55
55
  """The relay verify-start URL to open in the browser. ``return_url`` is where the
56
- relay redirects back with the credential (the install's own page)."""
56
+ relay redirects back with the credential (the install's own page). Claiming a badge
57
+ lists the founder on the public wall - there is no separate opt-in."""
57
58
  from urllib.parse import urlencode
58
59
 
59
60
  iid = ensure_instance_id()
@@ -66,8 +67,11 @@ async def get_badge(
66
67
  user=Depends(get_current_user),
67
68
  session: AsyncSession = Depends(get_session),
68
69
  ) -> dict:
69
- """The current user's supporter badge, or null."""
70
- return {"badge": _badge.to_dict(await _badge.get(session, user.id))}
70
+ """The current user's supporter badge (or null) + the public founders wall URL."""
71
+ return {
72
+ "badge": _badge.to_dict(await _badge.get(session, user.id)),
73
+ "wall_url": f"{relay_http_url()}/github/founders",
74
+ }
71
75
 
72
76
 
73
77
  @router.post("/badge")
@@ -1,30 +1,26 @@
1
1
  # Copyright (c) 2026 Noah Severs
2
2
  # SPDX-License-Identifier: BUSL-1.1
3
3
 
4
- """Cloud backup service — pg_dump → AES-256-GCM encrypt → upload to relay.
4
+ """Backup primitives — pg_dump/pg_restore and AES-256-GCM encrypt/decrypt.
5
5
 
6
6
  Encryption:
7
7
  - Key: 32-byte random, base64-encoded, stored in config.toml [cloud] section
8
8
  - Nonce: 12-byte random, prepended to ciphertext
9
9
  - Wire format: nonce (12 bytes) + ciphertext (variable) + tag (16 bytes, appended by GCM)
10
10
 
11
- Upload:
12
- - Encrypted blob is uploaded to the relay REST API via POST /backup/upload
13
- - Auth: X-Session-Token + X-Instance-ID headers (from live gateway session)
11
+ These primitives are shared by the local export/import path and the content-addressed
12
+ cloud snapshot client (``backup_repo``).
14
13
  """
15
14
 
16
15
  from __future__ import annotations
17
16
 
18
17
  import base64
19
- import io
20
- import os
21
18
  import subprocess
22
19
  import sys
23
20
  from dataclasses import dataclass, field
24
21
  from pathlib import Path
25
22
 
26
23
  from celerp.config import settings
27
- from celerp.gateway.state import get_session_token, relay_http_url, relay_session_headers
28
24
 
29
25
  _NONCE_BYTES = 12
30
26
 
@@ -173,49 +169,6 @@ def decrypt(blob: bytes, key: bytes) -> bytes:
173
169
  return aesgcm.decrypt(nonce, ciphertext, associated_data=None)
174
170
 
175
171
 
176
- async def upload_to_relay(
177
- blob: bytes,
178
- backup_type: str = "database",
179
- label: str | None = None,
180
- ) -> dict:
181
- """Upload encrypted blob to relay REST API. Returns response dict."""
182
- import httpx
183
- url = f"{relay_http_url()}/backup/upload"
184
- params: dict[str, str] = {"backup_type": backup_type}
185
- if label:
186
- params["label"] = label
187
-
188
- async with httpx.AsyncClient(timeout=120) as client:
189
- response = await client.post(
190
- url,
191
- headers=relay_session_headers(),
192
- params=params,
193
- files={"file": ("backup.bin", io.BytesIO(blob), "application/octet-stream")},
194
- )
195
- if response.status_code != 200:
196
- raise RuntimeError(
197
- f"Relay upload failed with HTTP {response.status_code}: {response.text[:200]}"
198
- )
199
- return response.json()
200
-
201
-
202
- async def download_from_relay(backup_id: str) -> bytes:
203
- """Download encrypted backup blob from relay via presigned URL."""
204
- import httpx
205
- url = f"{relay_http_url()}/backup/{backup_id}"
206
- async with httpx.AsyncClient(timeout=30) as client:
207
- response = await client.get(url, headers=relay_session_headers())
208
- if response.status_code != 200:
209
- raise RuntimeError(f"Failed to get download URL: HTTP {response.status_code}")
210
-
211
- presigned_url = response.json()["url"]
212
- async with httpx.AsyncClient(timeout=120) as client:
213
- dl = await client.get(presigned_url)
214
- if dl.status_code != 200:
215
- raise RuntimeError(f"Download failed: HTTP {dl.status_code}")
216
- return dl.content
217
-
218
-
219
172
  def restore_database(dump_bytes: bytes, database_url: str) -> None:
220
173
  """Run pg_restore from dump bytes into database_url.
221
174
 
@@ -239,47 +192,3 @@ def restore_database(dump_bytes: bytes, database_url: str) -> None:
239
192
  # pg_restore returns non-zero for warnings too; only raise on real errors
240
193
  if "ERROR" in stderr.upper():
241
194
  raise RuntimeError(f"pg_restore failed (exit {result.returncode}): {stderr}")
242
-
243
-
244
- async def run_backup(label: str | None = None) -> BackupResult:
245
- """Orchestrate a full DB backup: dump → encrypt → upload to relay.
246
-
247
- Returns BackupResult. Never raises — errors are captured in result.error.
248
- """
249
- if not settings.backup_encryption_key:
250
- return BackupResult(ok=False, size_bytes=0, error="BACKUP_ENCRYPTION_KEY is not configured")
251
-
252
- if not get_session_token():
253
- return BackupResult(ok=False, size_bytes=0, error="Relay not connected - skipping backup")
254
-
255
- try:
256
- key = _parse_key(settings.backup_encryption_key)
257
- dump = dump_database(settings.database_url)
258
- blob = encrypt(dump, key)
259
- await upload_to_relay(blob, backup_type="database", label=label)
260
- return BackupResult(ok=True, size_bytes=len(blob))
261
- except Exception as exc:
262
- return BackupResult(ok=False, size_bytes=0, error=str(exc))
263
-
264
-
265
- async def run_restore(backup_id: str) -> BackupResult:
266
- """Download, decrypt, and restore a database backup.
267
-
268
- Creates a safety backup first. Returns BackupResult.
269
- """
270
- if not settings.backup_encryption_key:
271
- return BackupResult(ok=False, size_bytes=0, error="BACKUP_ENCRYPTION_KEY is not configured")
272
-
273
- try:
274
- # Safety backup first
275
- safety = await run_backup(label="pre-restore-safety")
276
- if not safety.ok:
277
- return BackupResult(ok=False, size_bytes=0, error=f"Safety backup failed: {safety.error}")
278
-
279
- key = _parse_key(settings.backup_encryption_key)
280
- encrypted = await download_from_relay(backup_id)
281
- dump = decrypt(encrypted, key)
282
- restore_database(dump, settings.database_url)
283
- return BackupResult(ok=True, size_bytes=len(dump))
284
- except Exception as exc:
285
- return BackupResult(ok=False, size_bytes=0, error=str(exc))
@@ -1,11 +1,10 @@
1
1
  # Copyright (c) 2026 Noah Severs
2
2
  # SPDX-License-Identifier: BUSL-1.1
3
3
 
4
- """Export full backup as .celerp-backup (unencrypted tar.gz).
4
+ """Export a full local backup as .celerp-backup (unencrypted tar.gz).
5
5
 
6
- Two sources:
7
- - export_full(): local pg_dump + attachments + meta.json
8
- - export_from_cloud(backup_id): download encrypted → decrypt → repackage
6
+ ``export_full()`` bundles a local pg_dump + attachments + meta.json. Cloud snapshots
7
+ are rebuilt into the same format by ``backup_repo.reassemble_snapshot``.
9
8
  """
10
9
 
11
10
  from __future__ import annotations
@@ -135,25 +134,3 @@ async def export_full() -> Path:
135
134
  [settings.data_dir / "static" / "attachments", settings.data_dir / "ai_uploads"],
136
135
  meta,
137
136
  )
138
-
139
-
140
- async def export_from_cloud(backup_id: str) -> Path:
141
- """Download encrypted backup from relay, decrypt, repackage as .celerp-backup.
142
-
143
- The decrypted blob is itself a complete .celerp-backup (built by
144
- export_full when the cloud backup was first uploaded), so it already
145
- carries the original meta.json with enabled_modules. We pass it through
146
- unchanged — the import side reads meta.json directly.
147
- """
148
- from celerp.config import settings
149
- from celerp.services.backup import _parse_key, decrypt, download_from_relay
150
-
151
- key = _parse_key(settings.backup_encryption_key)
152
- encrypted = await download_from_relay(backup_id)
153
- decrypted = decrypt(encrypted, key)
154
-
155
- # Write decrypted blob as .celerp-backup
156
- tmp = tempfile.NamedTemporaryFile(suffix=".celerp-backup", delete=False)
157
- tmp.write(decrypted)
158
- tmp.close()
159
- return Path(tmp.name)
@@ -194,11 +194,11 @@ async def _safety_backup(label: str):
194
194
  Module-level helper so tests can stub it cleanly.
195
195
  """
196
196
  from celerp.config import settings
197
- from celerp.services.backup import run_backup
197
+ from celerp.services.backup import BackupResult
198
198
  if not settings.backup_encryption_key:
199
- from celerp.services.backup import BackupResult
200
199
  return BackupResult(ok=True, size_bytes=0)
201
- return await run_backup(label=label)
200
+ from celerp.services.backup_repo import run_snapshot
201
+ return await run_snapshot(label=label)
202
202
 
203
203
 
204
204
  async def _read_modules_from_restored_db() -> list[str]:
@@ -0,0 +1,241 @@
1
+ # Copyright (c) 2026 Noah Severs
2
+ # SPDX-License-Identifier: BUSL-1.1
3
+
4
+ """Content-addressed cloud snapshot client.
5
+
6
+ One cloud backup path for both database and files. Every member of a backup (the
7
+ pg_dump and each attachment/upload file) is a content-addressed *blob* keyed by the
8
+ SHA-256 of its plaintext, encrypted client-side and stored once on the relay. A
9
+ *snapshot* is a small manifest referencing the blobs needed to rebuild a
10
+ ``.celerp-backup``. Unchanged files share a hash and are never re-uploaded, so a
11
+ daily backup sends only what changed.
12
+
13
+ Restore downloads the manifest, fetches its blobs, reassembles a ``.celerp-backup``
14
+ and feeds the canonical ``run_import`` engine — the same importer as a local restore.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import asyncio
20
+ import hashlib
21
+ import io
22
+ import json
23
+ import logging
24
+ import tarfile
25
+ import tempfile
26
+ from pathlib import Path
27
+
28
+ import httpx
29
+
30
+ from celerp.config import settings
31
+ from celerp.gateway.state import get_session_token, relay_http_url, relay_session_headers
32
+ from celerp.services.backup import BackupResult, _parse_key, decrypt, dump_database, encrypt
33
+
34
+ log = logging.getLogger(__name__)
35
+
36
+ _CHUNK = 1024 * 1024 # 1 MiB read window for streaming hashes
37
+ # Each AES-256-GCM blob carries a 12-byte nonce + 16-byte tag over the plaintext.
38
+ _ENC_OVERHEAD = 28
39
+
40
+
41
+ def _attachment_dirs() -> list[Path]:
42
+ return [settings.data_dir / "static" / "attachments", settings.data_dir / "ai_uploads"]
43
+
44
+
45
+ def _members() -> list[tuple[str, Path]]:
46
+ """(arcname, path) for every backed-up file, arcname relative to the dir's parent
47
+ so it round-trips through the same ``.celerp-backup`` layout as a local export."""
48
+ out: list[tuple[str, Path]] = []
49
+ for d in _attachment_dirs():
50
+ if not d.exists():
51
+ continue
52
+ for p in sorted(d.rglob("*")):
53
+ if p.is_file():
54
+ try:
55
+ rel = str(p.relative_to(d.parent))
56
+ except ValueError:
57
+ rel = p.name
58
+ out.append((rel, p))
59
+ return out
60
+
61
+
62
+ def _hash_file(path: Path) -> tuple[str, int]:
63
+ h = hashlib.sha256()
64
+ size = 0
65
+ with path.open("rb") as fh:
66
+ while chunk := fh.read(_CHUNK):
67
+ h.update(chunk)
68
+ size += len(chunk)
69
+ return h.hexdigest(), size
70
+
71
+
72
+ async def _build_meta() -> dict:
73
+ from celerp.services.backup_export import _pg_version, _read_company_enabled_modules, _version
74
+ import datetime as _dt
75
+
76
+ from celerp.config import read_config
77
+ cfg = read_config()
78
+ return {
79
+ "celerp_version": _version(),
80
+ "pg_version": _pg_version(),
81
+ "created_at": _dt.datetime.now(_dt.timezone.utc).isoformat(),
82
+ "company_name": cfg.get("company", {}).get("name", "unknown"),
83
+ "enabled_modules": await _read_company_enabled_modules(),
84
+ }
85
+
86
+
87
+ # ── Relay API ─────────────────────────────────────────────────────────────────
88
+
89
+ def _relay() -> httpx.AsyncClient:
90
+ return httpx.AsyncClient(
91
+ base_url=relay_http_url(), headers=relay_session_headers(), timeout=60
92
+ )
93
+
94
+
95
+ async def _missing(client: httpx.AsyncClient, hashes: set[str]) -> set[str]:
96
+ r = await client.post("/repo/missing", json={"hashes": sorted(hashes)})
97
+ r.raise_for_status()
98
+ return set(r.json()["missing"])
99
+
100
+
101
+ async def _put_blob(client: httpx.AsyncClient, blob_hash: str, plaintext: bytes, key: bytes) -> int:
102
+ """Encrypt and upload one blob via a presigned PUT. Returns stored (encrypted) size."""
103
+ r = await client.post(f"/repo/blob/{blob_hash}/upload-url")
104
+ r.raise_for_status()
105
+ encrypted = await asyncio.to_thread(encrypt, plaintext, key)
106
+ async with httpx.AsyncClient(timeout=300) as s3:
107
+ put = await s3.put(r.json()["url"], content=encrypted)
108
+ put.raise_for_status()
109
+ return len(encrypted)
110
+
111
+
112
+ async def _get_blob(client: httpx.AsyncClient, blob_hash: str, key: bytes) -> bytes:
113
+ """Download, decrypt and integrity-check one blob against its content hash."""
114
+ r = await client.get(f"/repo/blob/{blob_hash}/download-url")
115
+ r.raise_for_status()
116
+ async with httpx.AsyncClient(timeout=300) as s3:
117
+ dl = await s3.get(r.json()["url"])
118
+ dl.raise_for_status()
119
+ plaintext = await asyncio.to_thread(decrypt, dl.content, key)
120
+ if hashlib.sha256(plaintext).hexdigest() != blob_hash:
121
+ raise RuntimeError(f"Blob {blob_hash[:12]} failed integrity check")
122
+ return plaintext
123
+
124
+
125
+ # ── Public API ────────────────────────────────────────────────────────────────
126
+
127
+ async def run_snapshot(label: str | None = None) -> BackupResult:
128
+ """Back up the database + files as a deduplicated snapshot. Never raises."""
129
+ if not settings.backup_encryption_key:
130
+ return BackupResult(ok=False, size_bytes=0, error="BACKUP_ENCRYPTION_KEY is not configured")
131
+ if not get_session_token():
132
+ return BackupResult(ok=False, size_bytes=0, error="Relay not connected - skipping backup")
133
+
134
+ try:
135
+ from celerp.services.backup_state import writes_paused
136
+
137
+ key = _parse_key(settings.backup_encryption_key)
138
+
139
+ # Pause writes for the clean point; blocking work runs off the event loop so
140
+ # reads stay served throughout.
141
+ with writes_paused():
142
+ # Hash every member first (streamed) so we only ever upload what's missing.
143
+ dump = await asyncio.to_thread(dump_database, settings.database_url)
144
+ db_hash = hashlib.sha256(dump).hexdigest()
145
+ files = [] # manifest entries
146
+ by_hash: dict[str, tuple[str, Path] | None] = {db_hash: None} # None ⇒ db dump
147
+ for arcname, path in _members():
148
+ fhash, size = await asyncio.to_thread(_hash_file, path)
149
+ files.append({"path": arcname, "hash": fhash, "size": size})
150
+ by_hash.setdefault(fhash, (arcname, path))
151
+
152
+ manifest = {"meta": await _build_meta(), "db_dump": db_hash, "files": files}
153
+ manifest_bytes = json.dumps(manifest, indent=2).encode()
154
+ manifest_hash = hashlib.sha256(manifest_bytes).hexdigest()
155
+
156
+ referenced = set(by_hash) | {manifest_hash}
157
+ uploaded = 0
158
+ async with _relay() as client:
159
+ missing = await _missing(client, referenced)
160
+ sizes: dict[str, int] = {}
161
+ for h in missing:
162
+ if h == manifest_hash:
163
+ plaintext = manifest_bytes
164
+ elif h == db_hash:
165
+ plaintext = dump
166
+ else:
167
+ plaintext = await asyncio.to_thread(by_hash[h][1].read_bytes) # type: ignore[index]
168
+ sizes[h] = await _put_blob(client, h, plaintext, key)
169
+ uploaded += sizes[h]
170
+
171
+ # size matters only for newly-uploaded blobs (quota); the relay keeps
172
+ # the stored size for blobs it already has, so 1 is a harmless placeholder.
173
+ blobs = [{"hash": h, "size": sizes.get(h, 1)} for h in referenced]
174
+ r = await client.post(
175
+ "/repo/snapshot",
176
+ json={"manifest_hash": manifest_hash, "blobs": blobs, "label": label},
177
+ )
178
+ r.raise_for_status()
179
+
180
+ log.info("Snapshot committed: %d blobs referenced, %d bytes uploaded", len(referenced), uploaded)
181
+ return BackupResult(ok=True, size_bytes=uploaded)
182
+ except Exception as exc: # never raise — surfaced in result
183
+ return BackupResult(ok=False, size_bytes=0, error=str(exc))
184
+
185
+
186
+ async def list_snapshots() -> dict:
187
+ """Return the relay's snapshot list payload (items + totals). Raises on error."""
188
+ async with _relay() as client:
189
+ r = await client.get("/repo/snapshots")
190
+ r.raise_for_status()
191
+ return r.json()
192
+
193
+
194
+ async def reassemble_snapshot(snapshot_id: str) -> Path:
195
+ """Download a snapshot and rebuild it as a ``.celerp-backup`` temp file."""
196
+ key = _parse_key(settings.backup_encryption_key)
197
+ async with _relay() as client:
198
+ r = await client.get("/repo/snapshots")
199
+ r.raise_for_status()
200
+ snap = next((s for s in r.json()["items"] if s["id"] == snapshot_id), None)
201
+ if snap is None:
202
+ raise RuntimeError(f"Snapshot {snapshot_id} not found")
203
+
204
+ manifest = json.loads(await _get_blob(client, snap["manifest_hash"], key))
205
+
206
+ tmp = tempfile.NamedTemporaryFile(suffix=".celerp-backup", delete=False)
207
+ tmp.close()
208
+ with tarfile.open(tmp.name, "w:gz") as tar:
209
+ dump = await _get_blob(client, manifest["db_dump"], key)
210
+ info = tarfile.TarInfo(name="database.dump")
211
+ info.size = len(dump)
212
+ tar.addfile(info, io.BytesIO(dump))
213
+
214
+ meta_bytes = json.dumps(manifest["meta"], indent=2).encode()
215
+ info = tarfile.TarInfo(name="meta.json")
216
+ info.size = len(meta_bytes)
217
+ tar.addfile(info, io.BytesIO(meta_bytes))
218
+
219
+ for entry in manifest["files"]:
220
+ data = await _get_blob(client, entry["hash"], key)
221
+ info = tarfile.TarInfo(name=entry["path"])
222
+ info.size = len(data)
223
+ tar.addfile(info, io.BytesIO(data))
224
+
225
+ return Path(tmp.name)
226
+
227
+
228
+ async def restore_snapshot(snapshot_id: str) -> BackupResult:
229
+ """Reassemble a cloud snapshot and restore it through the canonical importer."""
230
+ if not settings.backup_encryption_key:
231
+ return BackupResult(ok=False, size_bytes=0, error="BACKUP_ENCRYPTION_KEY is not configured")
232
+ try:
233
+ from celerp.services.backup_import import run_import
234
+ path = await reassemble_snapshot(snapshot_id)
235
+ try:
236
+ await run_import(path)
237
+ finally:
238
+ path.unlink(missing_ok=True)
239
+ return BackupResult(ok=True, size_bytes=0)
240
+ except Exception as exc:
241
+ return BackupResult(ok=False, size_bytes=0, error=str(exc))