celerp 1.0.3__py3-none-any.whl

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 (392) hide show
  1. celerp/__init__.py +6 -0
  2. celerp/ai/__init__.py +2 -0
  3. celerp/ai/batch.py +228 -0
  4. celerp/ai/cleanup.py +84 -0
  5. celerp/ai/commands.py +184 -0
  6. celerp/ai/conversations.py +234 -0
  7. celerp/ai/files.py +49 -0
  8. celerp/ai/intent.py +92 -0
  9. celerp/ai/llm.py +126 -0
  10. celerp/ai/memory.py +102 -0
  11. celerp/ai/models.py +43 -0
  12. celerp/ai/page_count.py +67 -0
  13. celerp/ai/quota.py +153 -0
  14. celerp/ai/service.py +265 -0
  15. celerp/ai/tools.py +286 -0
  16. celerp/alembic.ini +39 -0
  17. celerp/cli.py +763 -0
  18. celerp/compute/__init__.py +3 -0
  19. celerp/compute/aggregations.py +25 -0
  20. celerp/compute/valuation.py +38 -0
  21. celerp/config.py +293 -0
  22. celerp/connectors/__init__.py +26 -0
  23. celerp/connectors/base.py +149 -0
  24. celerp/connectors/daily_scheduler.py +120 -0
  25. celerp/connectors/http.py +65 -0
  26. celerp/connectors/outbound_queue.py +207 -0
  27. celerp/connectors/quickbooks.py +296 -0
  28. celerp/connectors/registry.py +32 -0
  29. celerp/connectors/shopify.py +356 -0
  30. celerp/connectors/sync_runner.py +126 -0
  31. celerp/connectors/upsert.py +64 -0
  32. celerp/connectors/webhooks.py +76 -0
  33. celerp/connectors/woocommerce.py +319 -0
  34. celerp/connectors/xero.py +266 -0
  35. celerp/db.py +23 -0
  36. celerp/events/__init__.py +3 -0
  37. celerp/events/engine.py +83 -0
  38. celerp/events/schemas.py +825 -0
  39. celerp/events/types.py +113 -0
  40. celerp/gateway/__init__.py +3 -0
  41. celerp/gateway/client.py +337 -0
  42. celerp/gateway/state.py +48 -0
  43. celerp/importers/__init__.py +2 -0
  44. celerp/importers/importer.py +384 -0
  45. celerp/importers/schema.py +199 -0
  46. celerp/main.py +255 -0
  47. celerp/middleware.py +131 -0
  48. celerp/migrations/README.md +47 -0
  49. celerp/migrations/env.py +83 -0
  50. celerp/migrations/script.py.mako +31 -0
  51. celerp/migrations/versions/a1b2c3d4e5f6_add_doc_share_tokens.py +45 -0
  52. celerp/migrations/versions/b2c3d4e5f6a7_add_import_batches.py +51 -0
  53. celerp/migrations/versions/c1d2e3f4a5b6_add_marketplace.py +52 -0
  54. celerp/migrations/versions/d2e3f4a5b6c7_add_password_reset_token.py +35 -0
  55. celerp/migrations/versions/e3f4a5b6c7d8_add_company_is_active.py +37 -0
  56. celerp/migrations/versions/f1a2b3c4d5e6_move_accounts_marketplace_to_modules.py +31 -0
  57. celerp/migrations/versions/fd5de461e14e_initial_schema.py +125 -0
  58. celerp/migrations/versions/g1h2i3j4k5l6_add_consignment_flag.py +35 -0
  59. celerp/migrations/versions/h2i3j4k5l6m7_add_bank_accounts_and_reconciliation.py +56 -0
  60. celerp/migrations/versions/j4k5l6m7n8o9_labels_db_persistence.py +42 -0
  61. celerp/migrations/versions/k5l6m7n8o9p0_add_reconciliation_v2.py +82 -0
  62. celerp/migrations/versions/l6m7n8o9p0q1_add_sync_runs_table.py +43 -0
  63. celerp/migrations/versions/m7n8o9p0q1r2_add_connector_configs_and_outbound_queue.py +60 -0
  64. celerp/models/__init__.py +9 -0
  65. celerp/models/accounting.py +25 -0
  66. celerp/models/ai.py +114 -0
  67. celerp/models/base.py +8 -0
  68. celerp/models/company.py +55 -0
  69. celerp/models/connector_config.py +60 -0
  70. celerp/models/import_batch.py +38 -0
  71. celerp/models/ledger.py +36 -0
  72. celerp/models/marketplace.py +8 -0
  73. celerp/models/notification.py +46 -0
  74. celerp/models/projections.py +32 -0
  75. celerp/models/share.py +32 -0
  76. celerp/models/sync_run.py +36 -0
  77. celerp/modules/__init__.py +25 -0
  78. celerp/modules/api.py +116 -0
  79. celerp/modules/license.py +139 -0
  80. celerp/modules/loader.py +440 -0
  81. celerp/modules/references.py +35 -0
  82. celerp/modules/registry.py +57 -0
  83. celerp/modules/slots.py +83 -0
  84. celerp/notifications/__init__.py +2 -0
  85. celerp/notifications/service.py +160 -0
  86. celerp/notifications/sse.py +139 -0
  87. celerp/projections/__init__.py +3 -0
  88. celerp/projections/engine.py +120 -0
  89. celerp/projections/handlers/__init__.py +3 -0
  90. celerp/projections/handlers/marketplace.py +42 -0
  91. celerp/projections/handlers/scanning.py +32 -0
  92. celerp/projections/handlers/system.py +30 -0
  93. celerp/routers/__init__.py +3 -0
  94. celerp/routers/auth.py +395 -0
  95. celerp/routers/companies.py +1657 -0
  96. celerp/routers/doctor.py +528 -0
  97. celerp/routers/health.py +81 -0
  98. celerp/routers/ledger.py +103 -0
  99. celerp/routers/notifications.py +121 -0
  100. celerp/routers/system.py +331 -0
  101. celerp/schemas/__init__.py +2 -0
  102. celerp/services/__init__.py +3 -0
  103. celerp/services/attachments.py +244 -0
  104. celerp/services/auth.py +156 -0
  105. celerp/services/auto_je.py +380 -0
  106. celerp/services/backup.py +215 -0
  107. celerp/services/backup_export.py +117 -0
  108. celerp/services/backup_files.py +173 -0
  109. celerp/services/backup_import.py +132 -0
  110. celerp/services/backup_scheduler.py +177 -0
  111. celerp/services/demo.py +1283 -0
  112. celerp/services/email.py +83 -0
  113. celerp/services/field_schema.py +105 -0
  114. celerp/services/fulfill.py +293 -0
  115. celerp/services/je_keys.py +18 -0
  116. celerp/services/pick.py +149 -0
  117. celerp/services/session_tracker.py +37 -0
  118. celerp/services/system_health.py +79 -0
  119. celerp/session_gate.py +83 -0
  120. celerp/tax_regimes.py +218 -0
  121. celerp-1.0.3.dist-info/METADATA +256 -0
  122. celerp-1.0.3.dist-info/RECORD +392 -0
  123. celerp-1.0.3.dist-info/WHEEL +5 -0
  124. celerp-1.0.3.dist-info/entry_points.txt +2 -0
  125. celerp-1.0.3.dist-info/licenses/LICENSE +77 -0
  126. celerp-1.0.3.dist-info/licenses/NOTICE +25 -0
  127. celerp-1.0.3.dist-info/top_level.txt +3 -0
  128. default_modules/__init__.py +8 -0
  129. default_modules/celerp-accounting/__init__.py +26 -0
  130. default_modules/celerp-accounting/celerp_accounting/__init__.py +2 -0
  131. default_modules/celerp-accounting/celerp_accounting/api_setup.py +9 -0
  132. default_modules/celerp-accounting/celerp_accounting/csv_parser.py +145 -0
  133. default_modules/celerp-accounting/celerp_accounting/matcher.py +196 -0
  134. default_modules/celerp-accounting/celerp_accounting/models.py +126 -0
  135. default_modules/celerp-accounting/celerp_accounting/projections.py +31 -0
  136. default_modules/celerp-accounting/celerp_accounting/routes.py +2048 -0
  137. default_modules/celerp-accounting/celerp_accounting/ui_routes.py +288 -0
  138. default_modules/celerp-admin/__init__.py +17 -0
  139. default_modules/celerp-admin/celerp_admin/__init__.py +2 -0
  140. default_modules/celerp-admin/celerp_admin/routes.py +528 -0
  141. default_modules/celerp-admin/celerp_admin/setup.py +7 -0
  142. default_modules/celerp-ai/__init__.py +22 -0
  143. default_modules/celerp-ai/celerp_ai/__init__.py +2 -0
  144. default_modules/celerp-ai/celerp_ai/routes.py +753 -0
  145. default_modules/celerp-ai/celerp_ai/setup.py +8 -0
  146. default_modules/celerp-ai/celerp_ai/ui_routes.py +1076 -0
  147. default_modules/celerp-backup/__init__.py +20 -0
  148. default_modules/celerp-backup/celerp_backup/__init__.py +2 -0
  149. default_modules/celerp-backup/celerp_backup/routes.py +261 -0
  150. default_modules/celerp-backup/celerp_backup/setup.py +7 -0
  151. default_modules/celerp-connectors/__init__.py +42 -0
  152. default_modules/celerp-connectors/celerp_connectors/__init__.py +2 -0
  153. default_modules/celerp-connectors/celerp_connectors/models.py +26 -0
  154. default_modules/celerp-connectors/celerp_connectors/routes.py +146 -0
  155. default_modules/celerp-contacts/__init__.py +36 -0
  156. default_modules/celerp-contacts/celerp_contacts/__init__.py +3 -0
  157. default_modules/celerp-contacts/celerp_contacts/projections.py +159 -0
  158. default_modules/celerp-contacts/celerp_contacts/routes.py +1082 -0
  159. default_modules/celerp-contacts/celerp_contacts/services.py +80 -0
  160. default_modules/celerp-contacts/celerp_contacts/ui_routes.py +15 -0
  161. default_modules/celerp-dashboard/__init__.py +19 -0
  162. default_modules/celerp-dashboard/celerp_dashboard/__init__.py +2 -0
  163. default_modules/celerp-dashboard/celerp_dashboard/routes.py +112 -0
  164. default_modules/celerp-dashboard/celerp_dashboard/setup.py +7 -0
  165. default_modules/celerp-docs/__init__.py +37 -0
  166. default_modules/celerp-docs/celerp_docs/__init__.py +3 -0
  167. default_modules/celerp-docs/celerp_docs/_ui_documents.py +1250 -0
  168. default_modules/celerp-docs/celerp_docs/api_setup.py +14 -0
  169. default_modules/celerp-docs/celerp_docs/doc_constants.py +6 -0
  170. default_modules/celerp-docs/celerp_docs/doc_projections.py +257 -0
  171. default_modules/celerp-docs/celerp_docs/doc_service.py +79 -0
  172. default_modules/celerp-docs/celerp_docs/models_share.py +4 -0
  173. default_modules/celerp-docs/celerp_docs/pdf.py +442 -0
  174. default_modules/celerp-docs/celerp_docs/routes.py +2020 -0
  175. default_modules/celerp-docs/celerp_docs/routes_share.py +619 -0
  176. default_modules/celerp-docs/celerp_docs/sequences.py +164 -0
  177. default_modules/celerp-docs/celerp_docs/taxes.py +40 -0
  178. default_modules/celerp-docs/celerp_docs/ui_routes.py +9 -0
  179. default_modules/celerp-inventory/__init__.py +35 -0
  180. default_modules/celerp-inventory/celerp_inventory/__init__.py +22 -0
  181. default_modules/celerp-inventory/celerp_inventory/models_import_batch.py +4 -0
  182. default_modules/celerp-inventory/celerp_inventory/projections.py +122 -0
  183. default_modules/celerp-inventory/celerp_inventory/routes.py +1683 -0
  184. default_modules/celerp-inventory/celerp_inventory/routes_attachments.py +264 -0
  185. default_modules/celerp-inventory/celerp_inventory/routes_scanning.py +107 -0
  186. default_modules/celerp-inventory/celerp_inventory/services.py +80 -0
  187. default_modules/celerp-inventory/celerp_inventory/ui_routes.py +20 -0
  188. default_modules/celerp-labels/LICENSE +21 -0
  189. default_modules/celerp-labels/__init__.py +64 -0
  190. default_modules/celerp-labels/celerp_labels/__init__.py +2 -0
  191. default_modules/celerp-labels/celerp_labels/migrations/__init__.py +7 -0
  192. default_modules/celerp-labels/celerp_labels/migrations/labels_001_create_label_templates.py +38 -0
  193. default_modules/celerp-labels/celerp_labels/models.py +71 -0
  194. default_modules/celerp-labels/celerp_labels/routes.py +264 -0
  195. default_modules/celerp-labels/celerp_labels/service.py +263 -0
  196. default_modules/celerp-labels/celerp_labels/ui_routes.py +1415 -0
  197. default_modules/celerp-labels/requirements.txt +4 -0
  198. default_modules/celerp-manufacturing/LICENSE +21 -0
  199. default_modules/celerp-manufacturing/__init__.py +53 -0
  200. default_modules/celerp-manufacturing/celerp_manufacturing/__init__.py +2 -0
  201. default_modules/celerp-manufacturing/celerp_manufacturing/projection_handler.py +49 -0
  202. default_modules/celerp-manufacturing/celerp_manufacturing/routes.py +621 -0
  203. default_modules/celerp-manufacturing/celerp_manufacturing/ui_routes.py +22 -0
  204. default_modules/celerp-manufacturing/requirements.txt +3 -0
  205. default_modules/celerp-reports/__init__.py +17 -0
  206. default_modules/celerp-reports/celerp_reports/__init__.py +2 -0
  207. default_modules/celerp-reports/celerp_reports/api_setup.py +9 -0
  208. default_modules/celerp-reports/celerp_reports/routes.py +554 -0
  209. default_modules/celerp-reports/celerp_reports/ui_routes.py +561 -0
  210. default_modules/celerp-subscriptions/__init__.py +26 -0
  211. default_modules/celerp-subscriptions/celerp_subscriptions/__init__.py +22 -0
  212. default_modules/celerp-subscriptions/celerp_subscriptions/projection_handler.py +34 -0
  213. default_modules/celerp-subscriptions/celerp_subscriptions/routes.py +412 -0
  214. default_modules/celerp-subscriptions/celerp_subscriptions/ui_routes.py +482 -0
  215. default_modules/celerp-subscriptions/celerp_subscriptions/ui_routes_import.py +189 -0
  216. default_modules/celerp-verticals/__init__.py +23 -0
  217. default_modules/celerp-verticals/celerp_verticals/__init__.py +19 -0
  218. default_modules/celerp-verticals/celerp_verticals/categories/accessory_fashion.json +66 -0
  219. default_modules/celerp-verticals/celerp_verticals/categories/activewear.json +72 -0
  220. default_modules/celerp-verticals/celerp_verticals/categories/art_photography.json +121 -0
  221. default_modules/celerp-verticals/celerp_verticals/categories/audio_equipment.json +89 -0
  222. default_modules/celerp-verticals/celerp_verticals/categories/bag_handbag.json +88 -0
  223. default_modules/celerp-verticals/celerp_verticals/categories/banknote.json +78 -0
  224. default_modules/celerp-verticals/celerp_verticals/categories/beauty_tool.json +53 -0
  225. default_modules/celerp-verticals/celerp_verticals/categories/bed_bedroom.json +97 -0
  226. default_modules/celerp-verticals/celerp_verticals/categories/beer.json +85 -0
  227. default_modules/celerp-verticals/celerp_verticals/categories/beverage_nonalc.json +81 -0
  228. default_modules/celerp-verticals/celerp_verticals/categories/body_part_auto.json +97 -0
  229. default_modules/celerp-verticals/celerp_verticals/categories/book.json +79 -0
  230. default_modules/celerp-verticals/celerp_verticals/categories/bottoms.json +86 -0
  231. default_modules/celerp-verticals/celerp_verticals/categories/brake_suspension.json +99 -0
  232. default_modules/celerp-verticals/celerp_verticals/categories/bullion_coin.json +85 -0
  233. default_modules/celerp-verticals/celerp_verticals/categories/camera.json +96 -0
  234. default_modules/celerp-verticals/celerp_verticals/categories/colored_stone.json +211 -0
  235. default_modules/celerp-verticals/celerp_verticals/categories/comic.json +71 -0
  236. default_modules/celerp-verticals/celerp_verticals/categories/commercial_space.json +131 -0
  237. default_modules/celerp-verticals/celerp_verticals/categories/component_part.json +63 -0
  238. default_modules/celerp-verticals/celerp_verticals/categories/confectionery.json +68 -0
  239. default_modules/celerp-verticals/celerp_verticals/categories/consulting_service.json +88 -0
  240. default_modules/celerp-verticals/celerp_verticals/categories/decorative_art.json +115 -0
  241. default_modules/celerp-verticals/celerp_verticals/categories/diamond.json +175 -0
  242. default_modules/celerp-verticals/celerp_verticals/categories/drawing.json +114 -0
  243. default_modules/celerp-verticals/celerp_verticals/categories/dress_jumpsuit.json +81 -0
  244. default_modules/celerp-verticals/celerp_verticals/categories/electrical_auto.json +76 -0
  245. default_modules/celerp-verticals/celerp_verticals/categories/electrical_component.json +63 -0
  246. default_modules/celerp-verticals/celerp_verticals/categories/emerald.json +141 -0
  247. default_modules/celerp-verticals/celerp_verticals/categories/engine_part.json +80 -0
  248. default_modules/celerp-verticals/celerp_verticals/categories/fastener.json +79 -0
  249. default_modules/celerp-verticals/celerp_verticals/categories/fertilizer_chemical.json +83 -0
  250. default_modules/celerp-verticals/celerp_verticals/categories/film_video.json +91 -0
  251. default_modules/celerp-verticals/celerp_verticals/categories/fine_writing_instrument.json +117 -0
  252. default_modules/celerp-verticals/celerp_verticals/categories/fluid_lubricant.json +56 -0
  253. default_modules/celerp-verticals/celerp_verticals/categories/footwear.json +75 -0
  254. default_modules/celerp-verticals/celerp_verticals/categories/fragrance.json +63 -0
  255. default_modules/celerp-verticals/celerp_verticals/categories/fresh_food.json +67 -0
  256. default_modules/celerp-verticals/celerp_verticals/categories/fresh_produce.json +82 -0
  257. default_modules/celerp-verticals/celerp_verticals/categories/frozen_food.json +78 -0
  258. default_modules/celerp-verticals/celerp_verticals/categories/gaming_console.json +65 -0
  259. default_modules/celerp-verticals/celerp_verticals/categories/gold_bullion.json +86 -0
  260. default_modules/celerp-verticals/celerp_verticals/categories/grain_cereal.json +84 -0
  261. default_modules/celerp-verticals/celerp_verticals/categories/haircare.json +74 -0
  262. default_modules/celerp-verticals/celerp_verticals/categories/hand_tool.json +61 -0
  263. default_modules/celerp-verticals/celerp_verticals/categories/ingredient_bulk.json +63 -0
  264. default_modules/celerp-verticals/celerp_verticals/categories/interior_part.json +83 -0
  265. default_modules/celerp-verticals/celerp_verticals/categories/jewelry.json +91 -0
  266. default_modules/celerp-verticals/celerp_verticals/categories/kitchen_dining.json +60 -0
  267. default_modules/celerp-verticals/celerp_verticals/categories/laptop.json +105 -0
  268. default_modules/celerp-verticals/celerp_verticals/categories/lighting.json +89 -0
  269. default_modules/celerp-verticals/celerp_verticals/categories/livestock_feed.json +81 -0
  270. default_modules/celerp-verticals/celerp_verticals/categories/makeup.json +75 -0
  271. default_modules/celerp-verticals/celerp_verticals/categories/measuring_instrument.json +68 -0
  272. default_modules/celerp-verticals/celerp_verticals/categories/medal_token.json +80 -0
  273. default_modules/celerp-verticals/celerp_verticals/categories/mineral_specimen.json +118 -0
  274. default_modules/celerp-verticals/celerp_verticals/categories/mobile_phone.json +79 -0
  275. default_modules/celerp-verticals/celerp_verticals/categories/music_cd.json +74 -0
  276. default_modules/celerp-verticals/celerp_verticals/categories/music_vinyl.json +115 -0
  277. default_modules/celerp-verticals/celerp_verticals/categories/nail.json +63 -0
  278. default_modules/celerp-verticals/celerp_verticals/categories/numismatic_coin.json +102 -0
  279. default_modules/celerp-verticals/celerp_verticals/categories/outdoor_furniture.json +86 -0
  280. default_modules/celerp-verticals/celerp_verticals/categories/outerwear.json +86 -0
  281. default_modules/celerp-verticals/celerp_verticals/categories/packaged_food.json +82 -0
  282. default_modules/celerp-verticals/celerp_verticals/categories/painting.json +138 -0
  283. default_modules/celerp-verticals/celerp_verticals/categories/parking_bay.json +79 -0
  284. default_modules/celerp-verticals/celerp_verticals/categories/pearl.json +122 -0
  285. default_modules/celerp-verticals/celerp_verticals/categories/personal_care.json +56 -0
  286. default_modules/celerp-verticals/celerp_verticals/categories/pipe_plumbing.json +65 -0
  287. default_modules/celerp-verticals/celerp_verticals/categories/platinum_bullion.json +92 -0
  288. default_modules/celerp-verticals/celerp_verticals/categories/power_tool.json +83 -0
  289. default_modules/celerp-verticals/celerp_verticals/categories/print_edition.json +142 -0
  290. default_modules/celerp-verticals/celerp_verticals/categories/residential_unit.json +110 -0
  291. default_modules/celerp-verticals/celerp_verticals/categories/rough_gemstone.json +124 -0
  292. default_modules/celerp-verticals/celerp_verticals/categories/ruby.json +142 -0
  293. default_modules/celerp-verticals/celerp_verticals/categories/saas_plan.json +86 -0
  294. default_modules/celerp-verticals/celerp_verticals/categories/safety_ppe.json +59 -0
  295. default_modules/celerp-verticals/celerp_verticals/categories/sapphire.json +148 -0
  296. default_modules/celerp-verticals/celerp_verticals/categories/sculpture.json +140 -0
  297. default_modules/celerp-verticals/celerp_verticals/categories/seating.json +98 -0
  298. default_modules/celerp-verticals/celerp_verticals/categories/seeds.json +72 -0
  299. default_modules/celerp-verticals/celerp_verticals/categories/silver_bullion.json +85 -0
  300. default_modules/celerp-verticals/celerp_verticals/categories/skincare.json +72 -0
  301. default_modules/celerp-verticals/celerp_verticals/categories/soft_furnishing.json +60 -0
  302. default_modules/celerp-verticals/celerp_verticals/categories/software_addon.json +56 -0
  303. default_modules/celerp-verticals/celerp_verticals/categories/software_license.json +85 -0
  304. default_modules/celerp-verticals/celerp_verticals/categories/spirit.json +91 -0
  305. default_modules/celerp-verticals/celerp_verticals/categories/storage_furniture.json +77 -0
  306. default_modules/celerp-verticals/celerp_verticals/categories/swimwear.json +75 -0
  307. default_modules/celerp-verticals/celerp_verticals/categories/table_desk.json +90 -0
  308. default_modules/celerp-verticals/celerp_verticals/categories/tablet.json +81 -0
  309. default_modules/celerp-verticals/celerp_verticals/categories/tire_wheel.json +83 -0
  310. default_modules/celerp-verticals/celerp_verticals/categories/tops.json +71 -0
  311. default_modules/celerp-verticals/celerp_verticals/categories/trading_card.json +80 -0
  312. default_modules/celerp-verticals/celerp_verticals/categories/tv_display.json +86 -0
  313. default_modules/celerp-verticals/celerp_verticals/categories/video_game.json +84 -0
  314. default_modules/celerp-verticals/celerp_verticals/categories/watch.json +131 -0
  315. default_modules/celerp-verticals/celerp_verticals/categories/watch_strap.json +92 -0
  316. default_modules/celerp-verticals/celerp_verticals/categories/wine.json +111 -0
  317. default_modules/celerp-verticals/celerp_verticals/presets/agricultural.json +27 -0
  318. default_modules/celerp-verticals/celerp_verticals/presets/artwork.json +25 -0
  319. default_modules/celerp-verticals/celerp_verticals/presets/automotive.json +26 -0
  320. default_modules/celerp-verticals/celerp_verticals/presets/blank.json +12 -0
  321. default_modules/celerp-verticals/celerp_verticals/presets/books_media.json +26 -0
  322. default_modules/celerp-verticals/celerp_verticals/presets/coins_precious_metals.json +26 -0
  323. default_modules/celerp-verticals/celerp_verticals/presets/consulting.json +22 -0
  324. default_modules/celerp-verticals/celerp_verticals/presets/cosmetics.json +26 -0
  325. default_modules/celerp-verticals/celerp_verticals/presets/electronics.json +27 -0
  326. default_modules/celerp-verticals/celerp_verticals/presets/fashion.json +28 -0
  327. default_modules/celerp-verticals/celerp_verticals/presets/food_beverage.json +28 -0
  328. default_modules/celerp-verticals/celerp_verticals/presets/furniture.json +27 -0
  329. default_modules/celerp-verticals/celerp_verticals/presets/gemstones.json +28 -0
  330. default_modules/celerp-verticals/celerp_verticals/presets/hardware.json +26 -0
  331. default_modules/celerp-verticals/celerp_verticals/presets/property_rental.json +24 -0
  332. default_modules/celerp-verticals/celerp_verticals/presets/saas.json +24 -0
  333. default_modules/celerp-verticals/celerp_verticals/presets/watches.json +23 -0
  334. default_modules/celerp-verticals/celerp_verticals/presets/wine_spirits.json +25 -0
  335. default_modules/celerp-verticals/celerp_verticals/routes.py +237 -0
  336. default_modules/celerp-verticals/celerp_verticals/ui_routes.py +8 -0
  337. ui/__init__.py +4 -0
  338. ui/api_client.py +1627 -0
  339. ui/app.py +264 -0
  340. ui/components/__init__.py +2 -0
  341. ui/components/activity.py +356 -0
  342. ui/components/backup.py +87 -0
  343. ui/components/cloud_gate.py +90 -0
  344. ui/components/shell.py +647 -0
  345. ui/components/table.py +1099 -0
  346. ui/config.py +54 -0
  347. ui/i18n.py +71 -0
  348. ui/locales/ar.json +1146 -0
  349. ui/locales/de.json +1146 -0
  350. ui/locales/en.json +1146 -0
  351. ui/locales/es.json +1146 -0
  352. ui/locales/fr.json +1146 -0
  353. ui/locales/id.json +1146 -0
  354. ui/locales/it.json +1146 -0
  355. ui/locales/ja.json +1146 -0
  356. ui/locales/pt.json +1146 -0
  357. ui/locales/th.json +1146 -0
  358. ui/locales/vi.json +1146 -0
  359. ui/routes/__init__.py +2 -0
  360. ui/routes/accounting.py +248 -0
  361. ui/routes/accounting_import.py +272 -0
  362. ui/routes/auth.py +650 -0
  363. ui/routes/contacts.py +2289 -0
  364. ui/routes/csv_import.py +1342 -0
  365. ui/routes/dashboard.py +813 -0
  366. ui/routes/docs_import.py +356 -0
  367. ui/routes/documents.py +4620 -0
  368. ui/routes/inventory.py +2959 -0
  369. ui/routes/lists_import.py +296 -0
  370. ui/routes/manufacturing.py +814 -0
  371. ui/routes/manufacturing_import.py +568 -0
  372. ui/routes/notifications.py +100 -0
  373. ui/routes/reconciliation.py +885 -0
  374. ui/routes/reports.py +561 -0
  375. ui/routes/search.py +72 -0
  376. ui/routes/settings.py +4071 -0
  377. ui/routes/settings_accounting.py +643 -0
  378. ui/routes/settings_cloud.py +710 -0
  379. ui/routes/settings_connectors.py +711 -0
  380. ui/routes/settings_contacts.py +298 -0
  381. ui/routes/settings_general.py +150 -0
  382. ui/routes/settings_import.py +644 -0
  383. ui/routes/settings_inventory.py +513 -0
  384. ui/routes/settings_purchasing.py +86 -0
  385. ui/routes/settings_sales.py +291 -0
  386. ui/routes/setup.py +647 -0
  387. ui/routes/subscriptions.py +483 -0
  388. ui/routes/subscriptions_import.py +319 -0
  389. ui/static/app.css +1901 -0
  390. ui/static/htmx.min.js +1 -0
  391. ui/static/icon.png +0 -0
  392. ui/static/logo.png +0 -0
celerp/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ # Copyright (c) 2026 Noah Severs
2
+ # SPDX-License-Identifier: BSL-1.1
3
+
4
+ from __future__ import annotations
5
+
6
+ __version__ = "1.0.0"
celerp/ai/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ # Copyright (c) 2026 Noah Severs
2
+ # SPDX-License-Identifier: BSL-1.1
celerp/ai/batch.py ADDED
@@ -0,0 +1,228 @@
1
+ # Copyright (c) 2026 Noah Severs
2
+ # SPDX-License-Identifier: BSL-1.1
3
+
4
+ """AI batch processing - parallel multi-file processing via OpenRouter.
5
+
6
+ Processes 2-100 files in parallel (up to BATCH_CONCURRENCY concurrent LLM calls).
7
+ Each file gets its own API call with the bulk extraction model.
8
+
9
+ Usage:
10
+ job = await start_batch(session, company_id, user_id, query, file_ids, credits)
11
+ # Background task runs the batch
12
+ # SSE events emitted per-file completion
13
+ # Notification created on finish
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import asyncio
19
+ import base64
20
+ import logging
21
+ import uuid
22
+ from datetime import datetime, timezone
23
+
24
+ from sqlalchemy.ext.asyncio import AsyncSession
25
+
26
+ from celerp.ai.files import load_file, load_file_for_llm
27
+ from celerp.ai.llm import call_llm
28
+ from celerp.ai.models import BULK_EXTRACTION
29
+ from celerp.models.ai import AIBatchJob
30
+
31
+ log = logging.getLogger(__name__)
32
+
33
+ BATCH_CONCURRENCY = 10
34
+ MAX_BATCH_FILES = 100
35
+
36
+ _BATCH_SYSTEM_PROMPT = """\
37
+ You are analyzing a business document (receipt, invoice, or contract).
38
+ Extract structured data: vendor name, date, total amount, line items with description/quantity/unit price.
39
+
40
+ Output a JSON block:
41
+ ```json
42
+ {
43
+ "vendor_name": "string",
44
+ "date": "YYYY-MM-DD",
45
+ "total": 0.00,
46
+ "line_items": [
47
+ {"description": "string", "quantity": 1, "unit_price": 0.00}
48
+ ]
49
+ }
50
+ ```
51
+
52
+ If you cannot extract structured data, return a brief text summary instead (no JSON block).
53
+ """
54
+
55
+
56
+ async def _process_single_file(
57
+ file_id: str,
58
+ query: str,
59
+ company_id: uuid.UUID,
60
+ semaphore: asyncio.Semaphore,
61
+ ) -> dict:
62
+ """Process a single file through the LLM. Returns result dict."""
63
+ try:
64
+ data_bytes, meta = load_file(file_id, company_id)
65
+ except (FileNotFoundError, PermissionError):
66
+ return {"file_id": file_id, "status": "error", "error": f"File {file_id} not found"}
67
+
68
+ b64 = base64.b64encode(data_bytes).decode("utf-8")
69
+ files = [{"media_type": meta.get("content_type", "image/jpeg"), "data": b64}]
70
+
71
+ prompt = f"{query}\n\nAnalyze the attached document." if query else "Analyze the attached document."
72
+
73
+ async with semaphore:
74
+ try:
75
+ answer = await call_llm(BULK_EXTRACTION, _BATCH_SYSTEM_PROMPT, prompt, files=files)
76
+ return {
77
+ "file_id": file_id,
78
+ "filename": meta.get("filename", file_id),
79
+ "status": "success",
80
+ "answer": answer,
81
+ }
82
+ except Exception as exc:
83
+ log.warning("Batch file %s failed: %s", file_id, exc)
84
+ return {
85
+ "file_id": file_id,
86
+ "filename": meta.get("filename", file_id),
87
+ "status": "error",
88
+ "error": "Processing failed for this file",
89
+ }
90
+
91
+
92
+ async def create_batch_job(
93
+ session: AsyncSession,
94
+ company_id: uuid.UUID,
95
+ user_id: uuid.UUID,
96
+ query: str,
97
+ file_ids: list[str],
98
+ credits: int,
99
+ conversation_id: uuid.UUID | None = None,
100
+ ) -> AIBatchJob:
101
+ """Create a pending batch job record."""
102
+ if len(file_ids) > MAX_BATCH_FILES:
103
+ raise ValueError(f"Maximum {MAX_BATCH_FILES} files per batch")
104
+ if len(file_ids) < 2:
105
+ raise ValueError("Batch requires at least 2 files")
106
+
107
+ job = AIBatchJob(
108
+ company_id=company_id,
109
+ user_id=user_id,
110
+ conversation_id=conversation_id,
111
+ query=query,
112
+ file_ids=file_ids,
113
+ total_files=len(file_ids),
114
+ credits_consumed=credits,
115
+ status="pending",
116
+ )
117
+ session.add(job)
118
+ await session.flush()
119
+ return job
120
+
121
+
122
+ async def run_batch(
123
+ job_id: uuid.UUID,
124
+ company_id: uuid.UUID,
125
+ user_id: uuid.UUID,
126
+ query: str,
127
+ file_ids: list[str],
128
+ db_factory,
129
+ on_progress=None,
130
+ ) -> None:
131
+ """Execute a batch job: parallel file processing.
132
+
133
+ Args:
134
+ db_factory: Callable that returns an AsyncSession context manager.
135
+ on_progress: Optional async callback(job_id, completed, failed, total, result).
136
+ """
137
+ semaphore = asyncio.Semaphore(BATCH_CONCURRENCY)
138
+ results: list[dict] = []
139
+ completed = 0
140
+ failed = 0
141
+
142
+ # Update status to running
143
+ async with db_factory() as session:
144
+ job = await session.get(AIBatchJob, job_id)
145
+ if job:
146
+ job.status = "running"
147
+ session.add(job)
148
+ await session.commit()
149
+
150
+ # Fan out: process all files concurrently (bounded by semaphore)
151
+ tasks = [
152
+ _process_single_file(fid, query, company_id, semaphore)
153
+ for fid in file_ids
154
+ ]
155
+
156
+ for coro in asyncio.as_completed(tasks):
157
+ result = await coro
158
+ results.append(result)
159
+
160
+ if result["status"] == "success":
161
+ completed += 1
162
+ else:
163
+ failed += 1
164
+
165
+ # Update DB progress
166
+ async with db_factory() as session:
167
+ job = await session.get(AIBatchJob, job_id)
168
+ if job:
169
+ job.completed_files = completed
170
+ job.failed_files = failed
171
+ session.add(job)
172
+ await session.commit()
173
+
174
+ # Notify progress
175
+ if on_progress:
176
+ try:
177
+ await on_progress(job_id, completed, failed, len(file_ids), result)
178
+ except Exception:
179
+ log.debug("on_progress callback failed", exc_info=True)
180
+
181
+ # Finalize
182
+ final_status = "failed" if failed == len(file_ids) else "completed"
183
+ async with db_factory() as session:
184
+ job = await session.get(AIBatchJob, job_id)
185
+ if job:
186
+ job.status = final_status
187
+ job.results = {"files": results}
188
+ job.completed_at = datetime.now(timezone.utc)
189
+ session.add(job)
190
+ await session.commit()
191
+
192
+ # Create notification
193
+ try:
194
+ from celerp.notifications.service import create as create_notification
195
+ async with db_factory() as session:
196
+ if final_status == "completed":
197
+ await create_notification(
198
+ session, company_id, "ai",
199
+ f"Batch complete: {completed}/{len(file_ids)} files processed",
200
+ f"{completed} files processed successfully, {failed} failed.",
201
+ user_id=user_id,
202
+ action_url="/ai",
203
+ priority="high",
204
+ )
205
+ else:
206
+ await create_notification(
207
+ session, company_id, "ai",
208
+ f"Batch failed: {failed}/{len(file_ids)} files",
209
+ "All files failed to process. Please try again.",
210
+ user_id=user_id,
211
+ action_url="/ai",
212
+ priority="high",
213
+ )
214
+ await session.commit()
215
+ except Exception:
216
+ log.warning("Failed to create batch notification", exc_info=True)
217
+
218
+
219
+ async def get_batch_job(
220
+ session: AsyncSession,
221
+ job_id: uuid.UUID,
222
+ company_id: uuid.UUID,
223
+ ) -> AIBatchJob | None:
224
+ """Get a batch job by ID, scoped to company."""
225
+ job = await session.get(AIBatchJob, job_id)
226
+ if job is None or job.company_id != company_id:
227
+ return None
228
+ return job
celerp/ai/cleanup.py ADDED
@@ -0,0 +1,84 @@
1
+ # Copyright (c) 2026 Noah Severs
2
+ # SPDX-License-Identifier: BSL-1.1
3
+
4
+ """AI file cleanup - periodic removal of old upload files.
5
+
6
+ All files older than 30 days are deleted unconditionally.
7
+ Runs every 6 hours via background task.
8
+
9
+ Does NOT require a database session - operates purely on filesystem.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import asyncio
15
+ import logging
16
+ import time
17
+ from pathlib import Path
18
+
19
+ from celerp.ai.files import upload_dir
20
+
21
+ log = logging.getLogger(__name__)
22
+
23
+ CLEANUP_INTERVAL_SECONDS = 6 * 3600 # 6 hours
24
+ MAX_AGE_DAYS = 30
25
+
26
+
27
+ def _delete_file_pair(meta_path: Path) -> None:
28
+ """Delete both .meta and .bin files."""
29
+ bin_path = meta_path.with_suffix(".bin")
30
+ try:
31
+ if bin_path.exists():
32
+ bin_path.unlink()
33
+ if meta_path.exists():
34
+ meta_path.unlink()
35
+ except OSError:
36
+ log.warning("Failed to delete %s", meta_path.stem, exc_info=True)
37
+
38
+
39
+ def cleanup_uploads() -> int:
40
+ """Remove AI upload files older than 30 days. Returns count deleted."""
41
+ try:
42
+ ud = upload_dir()
43
+ except (PermissionError, OSError) as exc:
44
+ log.debug("AI upload dir unavailable, skipping cleanup: %s", exc)
45
+ return 0
46
+ if not ud.exists():
47
+ return 0
48
+
49
+ now = time.time()
50
+ deleted = 0
51
+
52
+ for meta_path in list(ud.glob("*.meta")):
53
+ try:
54
+ age_days = (now - meta_path.stat().st_mtime) / 86400
55
+ except OSError:
56
+ continue
57
+
58
+ if age_days > MAX_AGE_DAYS:
59
+ _delete_file_pair(meta_path)
60
+ deleted += 1
61
+ log.debug("Deleted old file %s (%.0f days)", meta_path.stem, age_days)
62
+
63
+ # Clean up orphaned .bin files (no matching .meta)
64
+ for bin_path in list(ud.glob("*.bin")):
65
+ if not bin_path.with_suffix(".meta").exists():
66
+ try:
67
+ bin_path.unlink()
68
+ deleted += 1
69
+ except OSError:
70
+ pass
71
+
72
+ if deleted:
73
+ log.info("AI file cleanup: removed %d files", deleted)
74
+ return deleted
75
+
76
+
77
+ async def run_cleanup_loop() -> None:
78
+ """Background task: run cleanup every CLEANUP_INTERVAL_SECONDS."""
79
+ while True:
80
+ await asyncio.sleep(CLEANUP_INTERVAL_SECONDS)
81
+ try:
82
+ cleanup_uploads()
83
+ except Exception:
84
+ log.warning("AI file cleanup failed", exc_info=True)
celerp/ai/commands.py ADDED
@@ -0,0 +1,184 @@
1
+ # Copyright (c) 2026 Noah Severs
2
+ # SPDX-License-Identifier: BSL-1.1
3
+
4
+ """AI command parsing and execution - structured bill creation from LLM output.
5
+
6
+ Two-phase flow:
7
+ 1. parse_bill_commands() - validate LLM JSON, return structured data
8
+ 2. create_bills() - execute against event store (only after user confirms)
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import hashlib
14
+ import logging
15
+ import re
16
+ import uuid
17
+
18
+ from pydantic import BaseModel, field_validator
19
+ from sqlalchemy import cast, select, String
20
+ from sqlalchemy.ext.asyncio import AsyncSession
21
+
22
+ log = logging.getLogger(__name__)
23
+
24
+
25
+ # -- Pydantic models -------------------------------------------------------
26
+
27
+ class LineItem(BaseModel):
28
+ description: str
29
+ quantity: float
30
+ unit_price: float
31
+
32
+ @field_validator("quantity")
33
+ @classmethod
34
+ def qty_positive(cls, v: float) -> float:
35
+ if v <= 0:
36
+ raise ValueError("quantity must be > 0")
37
+ return v
38
+
39
+ @field_validator("unit_price")
40
+ @classmethod
41
+ def price_non_negative(cls, v: float) -> float:
42
+ if v < 0:
43
+ raise ValueError("unit_price must be >= 0")
44
+ return v
45
+
46
+
47
+ class DraftBill(BaseModel):
48
+ vendor_name: str
49
+ date: str
50
+ total: float
51
+ source_file_id: str | None = None
52
+ line_items: list[LineItem]
53
+
54
+
55
+ # -- Phase 1: Parse + validate ---------------------------------------------
56
+
57
+ def parse_bill_commands(raw_json: dict) -> list[DraftBill]:
58
+ """Validate LLM JSON output into structured bill data.
59
+
60
+ Raises ValueError with details on validation failure.
61
+ """
62
+ bills_data = raw_json.get("create_draft_bills", [])
63
+ if not bills_data:
64
+ return []
65
+ bills: list[DraftBill] = []
66
+ for i, entry in enumerate(bills_data):
67
+ try:
68
+ bills.append(DraftBill.model_validate(entry))
69
+ except Exception as exc:
70
+ raise ValueError(f"Bill #{i + 1} validation failed: {exc}") from exc
71
+ return bills
72
+
73
+
74
+ # -- Phase 2: Execute (after user confirmation) ----------------------------
75
+
76
+ async def create_bills(
77
+ session: AsyncSession,
78
+ company_id: uuid.UUID,
79
+ user_id: uuid.UUID,
80
+ bills: list[DraftBill],
81
+ ) -> str:
82
+ """Create draft bills and contacts in the event store. Returns feedback text."""
83
+ from celerp.events.engine import emit_event
84
+ from celerp.models.company import Company
85
+ from celerp.models.projections import Projection
86
+
87
+ company = await session.get(Company, company_id)
88
+ if not company:
89
+ return ""
90
+
91
+ feedback_lines: list[str] = []
92
+ currency = company.settings.get("currency", "USD")
93
+
94
+ for bill in bills:
95
+ # Find vendor in projection
96
+ vendor_row = (await session.execute(
97
+ select(Projection).where(
98
+ Projection.company_id == company_id,
99
+ Projection.entity_type == "contact",
100
+ cast(Projection.state["name"], String).ilike(f"%{bill.vendor_name}%"),
101
+ )
102
+ )).scalars().first()
103
+
104
+ if vendor_row:
105
+ contact_id = str(vendor_row.entity_id)
106
+ else:
107
+ slug = re.sub(r"[^a-zA-Z0-9]+", "-", bill.vendor_name.lower()) or "vendor"
108
+ ref_id = f"{slug}-{str(uuid.uuid4())[:4]}"
109
+ contact_id = f"contact:{ref_id}"
110
+ idem_key = _idempotency_key(company_id, "contact", bill.vendor_name, bill.date)
111
+ await emit_event(
112
+ session,
113
+ company_id=company_id,
114
+ entity_id=contact_id,
115
+ entity_type="contact",
116
+ event_type="contact.created",
117
+ data={
118
+ "name": bill.vendor_name,
119
+ "contact_type": "vendor",
120
+ "status": "draft",
121
+ "ref_id": ref_id,
122
+ "currency": currency,
123
+ },
124
+ actor_id=user_id,
125
+ location_id=None,
126
+ source="ai",
127
+ idempotency_key=idem_key,
128
+ metadata_={},
129
+ )
130
+
131
+ try:
132
+ from celerp_docs.sequences import next_doc_ref
133
+ bill_ref = next_doc_ref(company, "bill")
134
+ except ImportError:
135
+ bill_ref = f"BIL-{str(uuid.uuid4())[:6].upper()}"
136
+
137
+ entity_id = f"doc:{bill_ref}"
138
+ line_items = [
139
+ {
140
+ "description": li.description,
141
+ "quantity": li.quantity,
142
+ "unit_price": li.unit_price,
143
+ "line_total": li.quantity * li.unit_price,
144
+ }
145
+ for li in bill.line_items
146
+ ]
147
+ idem_key = _idempotency_key(company_id, "bill", bill.vendor_name, bill.date, str(bill.total))
148
+
149
+ await emit_event(
150
+ session,
151
+ company_id=company_id,
152
+ entity_id=entity_id,
153
+ entity_type="doc",
154
+ event_type="doc.created",
155
+ data={
156
+ "doc_type": "bill",
157
+ "status": "draft",
158
+ "ref_id": bill_ref,
159
+ "date": bill.date,
160
+ "contact_id": contact_id,
161
+ "location_id": "loc:default",
162
+ "total": bill.total,
163
+ "subtotal": bill.total,
164
+ "currency": currency,
165
+ "amount_outstanding": bill.total,
166
+ "line_items": line_items,
167
+ },
168
+ actor_id=user_id,
169
+ location_id=None,
170
+ source="ai",
171
+ idempotency_key=idem_key,
172
+ metadata_={"ai_source_file_id": bill.source_file_id} if bill.source_file_id else {},
173
+ )
174
+ feedback_lines.append(
175
+ f"Created Draft Bill {bill_ref} for {bill.vendor_name} ({currency} {bill.total:.2f})"
176
+ )
177
+
178
+ return "\n".join(feedback_lines)
179
+
180
+
181
+ def _idempotency_key(company_id: uuid.UUID, entity: str, *parts: str) -> str:
182
+ """Deterministic idempotency key from company + entity + parts."""
183
+ raw = f"{company_id}:{entity}:" + ":".join(parts)
184
+ return f"ai_{entity}_{hashlib.sha256(raw.encode()).hexdigest()[:12]}"