pharmacy-erp 1.0.0

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 (137) hide show
  1. package/.env.example +34 -0
  2. package/LICENSE +21 -0
  3. package/README.md +479 -0
  4. package/backend/Dockerfile +44 -0
  5. package/backend/app/__init__.py +1 -0
  6. package/backend/app/core/__init__.py +1 -0
  7. package/backend/app/core/audit.py +33 -0
  8. package/backend/app/core/config.py +16 -0
  9. package/backend/app/core/database.py +26 -0
  10. package/backend/app/core/deps.py +49 -0
  11. package/backend/app/core/exceptions.py +43 -0
  12. package/backend/app/core/security.py +32 -0
  13. package/backend/app/main.py +54 -0
  14. package/backend/app/modules/__init__.py +0 -0
  15. package/backend/app/modules/admin/__init__.py +1 -0
  16. package/backend/app/modules/admin/models.py +15 -0
  17. package/backend/app/modules/admin/router.py +353 -0
  18. package/backend/app/modules/auth/__init__.py +0 -0
  19. package/backend/app/modules/auth/models.py +16 -0
  20. package/backend/app/modules/auth/router.py +73 -0
  21. package/backend/app/modules/auth/schemas.py +29 -0
  22. package/backend/app/modules/cash_sessions/__init__.py +0 -0
  23. package/backend/app/modules/cash_sessions/models.py +19 -0
  24. package/backend/app/modules/cash_sessions/router.py +85 -0
  25. package/backend/app/modules/cash_sessions/schemas.py +31 -0
  26. package/backend/app/modules/customers/__init__.py +0 -0
  27. package/backend/app/modules/customers/models.py +37 -0
  28. package/backend/app/modules/customers/router.py +296 -0
  29. package/backend/app/modules/customers/schemas.py +72 -0
  30. package/backend/app/modules/inventory/__init__.py +0 -0
  31. package/backend/app/modules/inventory/models.py +16 -0
  32. package/backend/app/modules/inventory/router.py +150 -0
  33. package/backend/app/modules/inventory/schemas.py +24 -0
  34. package/backend/app/modules/medicines/__init__.py +0 -0
  35. package/backend/app/modules/medicines/models.py +54 -0
  36. package/backend/app/modules/medicines/router.py +631 -0
  37. package/backend/app/modules/medicines/schemas.py +153 -0
  38. package/backend/app/modules/medicines/template_generator.py +118 -0
  39. package/backend/app/modules/notifications/__init__.py +1 -0
  40. package/backend/app/modules/notifications/models.py +15 -0
  41. package/backend/app/modules/notifications/router.py +89 -0
  42. package/backend/app/modules/notifications/schemas.py +22 -0
  43. package/backend/app/modules/organizations/__init__.py +0 -0
  44. package/backend/app/modules/organizations/models.py +16 -0
  45. package/backend/app/modules/organizations/router.py +49 -0
  46. package/backend/app/modules/organizations/schemas.py +31 -0
  47. package/backend/app/modules/reports/__init__.py +0 -0
  48. package/backend/app/modules/reports/router.py +409 -0
  49. package/backend/app/modules/roles/__init__.py +1 -0
  50. package/backend/app/modules/roles/models.py +43 -0
  51. package/backend/app/modules/roles/router.py +89 -0
  52. package/backend/app/modules/roles/schemas.py +55 -0
  53. package/backend/app/modules/sales/__init__.py +0 -0
  54. package/backend/app/modules/sales/models.py +44 -0
  55. package/backend/app/modules/sales/router.py +63 -0
  56. package/backend/app/modules/sales/schemas.py +42 -0
  57. package/backend/app/modules/sales/service.py +128 -0
  58. package/backend/app/modules/suppliers/__init__.py +0 -0
  59. package/backend/app/modules/suppliers/models.py +14 -0
  60. package/backend/app/modules/suppliers/router.py +56 -0
  61. package/backend/app/modules/suppliers/schemas.py +27 -0
  62. package/backend/app/modules/users/__init__.py +0 -0
  63. package/backend/app/modules/users/router.py +74 -0
  64. package/backend/app/seed.py +275 -0
  65. package/backend/data/.gitkeep +1 -0
  66. package/backend/requirements.txt +17 -0
  67. package/bin/cli.js +288 -0
  68. package/docker-compose.dev.yml +42 -0
  69. package/docker-compose.yml +59 -0
  70. package/frontend/Dockerfile +56 -0
  71. package/frontend/next.config.ts +19 -0
  72. package/frontend/package.json +60 -0
  73. package/frontend/pnpm-lock.yaml +5678 -0
  74. package/frontend/pnpm-workspace.yaml +6 -0
  75. package/frontend/postcss.config.mjs +6 -0
  76. package/frontend/public/logo.png +0 -0
  77. package/frontend/src/app/[locale]/(app)/admin/page.tsx +1426 -0
  78. package/frontend/src/app/[locale]/(app)/catalog/products/[id]/page.tsx +505 -0
  79. package/frontend/src/app/[locale]/(app)/catalog/products/page.tsx +753 -0
  80. package/frontend/src/app/[locale]/(app)/customers/[id]/page.tsx +500 -0
  81. package/frontend/src/app/[locale]/(app)/customers/page.tsx +538 -0
  82. package/frontend/src/app/[locale]/(app)/dashboard/page.tsx +175 -0
  83. package/frontend/src/app/[locale]/(app)/inventory/page.tsx +765 -0
  84. package/frontend/src/app/[locale]/(app)/layout.tsx +60 -0
  85. package/frontend/src/app/[locale]/(app)/purchasing/page.tsx +1 -0
  86. package/frontend/src/app/[locale]/(app)/reports/page.tsx +794 -0
  87. package/frontend/src/app/[locale]/(app)/sales/page.tsx +296 -0
  88. package/frontend/src/app/[locale]/(auth)/login/page.tsx +100 -0
  89. package/frontend/src/app/[locale]/(pos)/layout.tsx +33 -0
  90. package/frontend/src/app/[locale]/(pos)/pos/page.tsx +463 -0
  91. package/frontend/src/app/[locale]/(pos)/pos/pos-data.ts +89 -0
  92. package/frontend/src/app/[locale]/layout.tsx +30 -0
  93. package/frontend/src/app/[locale]/page.tsx +6 -0
  94. package/frontend/src/app/globals.css +77 -0
  95. package/frontend/src/app/layout.tsx +23 -0
  96. package/frontend/src/app/print.css +18 -0
  97. package/frontend/src/components/pos/CartPanel.tsx +525 -0
  98. package/frontend/src/components/pos/CashSessionGuard.tsx +255 -0
  99. package/frontend/src/components/pos/CloseSessionModal.tsx +160 -0
  100. package/frontend/src/components/pos/PaymentModal.tsx +266 -0
  101. package/frontend/src/components/pos/PaymentSettingsModal.tsx +472 -0
  102. package/frontend/src/components/pos/ProductCatalog.tsx +140 -0
  103. package/frontend/src/components/pos/SaleReceipt.tsx +133 -0
  104. package/frontend/src/components/ui/badge.tsx +28 -0
  105. package/frontend/src/components/ui/bulk-import-modal.tsx +400 -0
  106. package/frontend/src/components/ui/button.tsx +60 -0
  107. package/frontend/src/components/ui/card.tsx +13 -0
  108. package/frontend/src/components/ui/confirm-dialog.tsx +50 -0
  109. package/frontend/src/components/ui/input.tsx +32 -0
  110. package/frontend/src/components/ui/notification-center.tsx +228 -0
  111. package/frontend/src/components/ui/select.tsx +59 -0
  112. package/frontend/src/components/ui/sidebar.tsx +91 -0
  113. package/frontend/src/components/ui/slide-over.tsx +43 -0
  114. package/frontend/src/components/ui/stat-card.tsx +40 -0
  115. package/frontend/src/components/ui/switch.tsx +38 -0
  116. package/frontend/src/components/ui/topbar.tsx +97 -0
  117. package/frontend/src/i18n/request.ts +13 -0
  118. package/frontend/src/i18n/routing.ts +9 -0
  119. package/frontend/src/lib/api.ts +240 -0
  120. package/frontend/src/lib/constants.ts +30 -0
  121. package/frontend/src/lib/utils.ts +32 -0
  122. package/frontend/src/messages/ar.json +106 -0
  123. package/frontend/src/messages/en.json +106 -0
  124. package/frontend/src/middleware.ts +8 -0
  125. package/frontend/src/store/app-store.ts +37 -0
  126. package/frontend/src/store/auth-store.ts +52 -0
  127. package/frontend/src/store/payment-methods-store.ts +144 -0
  128. package/frontend/src/store/pos-store.ts +344 -0
  129. package/frontend/tailwind.config.ts +85 -0
  130. package/frontend/tsconfig.json +27 -0
  131. package/img/backgraund-logo.png +0 -0
  132. package/img/full-logo.png +0 -0
  133. package/img/logo.png +0 -0
  134. package/nginx/nginx.conf +67 -0
  135. package/package.json +88 -0
  136. package/start.bat +90 -0
  137. package/start.sh +64 -0
package/.env.example ADDED
@@ -0,0 +1,34 @@
1
+ # ============================================================
2
+ # Pharmacy ERP & POS โ€” Environment Variables
3
+ # Copy this to .env and update values
4
+ # ============================================================
5
+
6
+ # Application
7
+ APP_NAME=Pharmacy ERP
8
+ APP_ENV=development
9
+ DEBUG=true
10
+
11
+ # Database
12
+ # For local development (SQLite โ€” no setup needed):
13
+ DATABASE_URL=sqlite+aiosqlite:///./data/pharmacy.db
14
+
15
+ # For production (PostgreSQL):
16
+ # DATABASE_URL=postgresql+asyncpg://user:password@localhost:5432/pharmacy_erp
17
+
18
+ # Security
19
+ SECRET_KEY=your-secret-key-change-this-in-production-min-32-chars
20
+ ACCESS_TOKEN_EXPIRE_MINUTES=30
21
+ REFRESH_TOKEN_EXPIRE_DAYS=7
22
+
23
+ # CORS
24
+ CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
25
+
26
+ # Frontend
27
+ NEXT_PUBLIC_API_URL=http://localhost:8000/api/v1
28
+
29
+ # Redis (optional โ€” for production)
30
+ # REDIS_URL=redis://localhost:6379/0
31
+
32
+ # File Storage
33
+ UPLOAD_DIR=./data/uploads
34
+ MAX_UPLOAD_SIZE_MB=10
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pharmacy ERP Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,479 @@
1
+ <div align="center">
2
+
3
+ <img src="img/logo.png" alt="Pharmacy ERP Logo" width="120" />
4
+
5
+ # Pharmacy ERP & POS System
6
+
7
+ **A modern, open-source Pharmacy ERP & Point of Sale system built for independent pharmacies, chains, and hospitals.**
8
+
9
+ *Full Arabic (RTL) & English support ยท Designed for the Gulf/MENA market*
10
+
11
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
12
+ [![CI](https://github.com/omersx/pharmacy-erp/actions/workflows/ci.yml/badge.svg)](https://github.com/omersx/pharmacy-erp/actions/workflows/ci.yml)
13
+ [![Docker](https://img.shields.io/badge/Docker_Hub-images-2496ED?logo=docker&logoColor=white)](https://hub.docker.com/u/omersx)
14
+ [![npm](https://img.shields.io/npm/v/pharmacy-erp?color=CB3837&logo=npm)](https://www.npmjs.com/package/pharmacy-erp)
15
+ [![Python 3.12+](https://img.shields.io/badge/Python-3.12+-3776AB?logo=python&logoColor=white)](https://python.org)
16
+ [![Node.js 18+](https://img.shields.io/badge/Node.js-18+-339933?logo=node.js&logoColor=white)](https://nodejs.org)
17
+ [![FastAPI](https://img.shields.io/badge/FastAPI-0.115+-009688?logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com)
18
+ [![Next.js 15](https://img.shields.io/badge/Next.js-15-000000?logo=next.js&logoColor=white)](https://nextjs.org)
19
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
20
+
21
+ [Features](#-features) ยท [Quick Start](#-quick-start) ยท [Screenshots](#-screenshots) ยท [Architecture](#-architecture) ยท [API Docs](#-api-documentation) ยท [Docker](#-docker-deployment) ยท [Contributing](#-contributing)
22
+
23
+ </div>
24
+
25
+ ---
26
+
27
+ ## โœจ Features
28
+
29
+ <table>
30
+ <tr>
31
+ <td width="50%">
32
+
33
+ ### ๐Ÿช Point of Sale
34
+ - Fullscreen, keyboard-first, touch-friendly POS
35
+ - Barcode/search product lookup
36
+ - Hold & recall sales
37
+ - Split payments (cash, card, credit)
38
+ - Receipt printing (PDF export)
39
+
40
+ </td>
41
+ <td width="50%">
42
+
43
+ ### ๐Ÿ’Š Medicine Management
44
+ - Complete product catalog with categories
45
+ - Batch tracking with expiry dates
46
+ - FEFO (First Expiry, First Out) allocation
47
+ - CSV/Excel bulk import
48
+ - Low stock & expiry alerts
49
+
50
+ </td>
51
+ </tr>
52
+ <tr>
53
+ <td width="50%">
54
+
55
+ ### ๐Ÿ“ฆ Inventory & Purchasing
56
+ - Append-only inventory ledger
57
+ - Real-time stock levels per branch
58
+ - Purchase orders & goods receipt
59
+ - Supplier management & tracking
60
+ - Automated stock alerts
61
+
62
+ </td>
63
+ <td width="50%">
64
+
65
+ ### ๐Ÿ’ฐ Sales & Cash Management
66
+ - Sales invoices & returns
67
+ - Cash session management (open/close)
68
+ - Opening float & blind close
69
+ - X-Report & Z-Report generation
70
+ - Customer credit tracking
71
+
72
+ </td>
73
+ </tr>
74
+ <tr>
75
+ <td width="50%">
76
+
77
+ ### ๐Ÿ“Š Reports & Analytics
78
+ - Sales reports (daily, weekly, monthly)
79
+ - Inventory valuation reports
80
+ - Profit & margin analysis
81
+ - Top-selling products
82
+ - Exportable to Excel/PDF
83
+
84
+ </td>
85
+ <td width="50%">
86
+
87
+ ### ๐ŸŒ Enterprise Features
88
+ - **Bilingual**: Full Arabic (RTL) + English
89
+ - **Dark/Light Theme**: Premium UI design
90
+ - **RBAC**: Role-based access control
91
+ - **Multi-branch**: Branch management
92
+ - **Responsive**: Desktop, tablet, & mobile
93
+
94
+ </td>
95
+ </tr>
96
+ </table>
97
+
98
+ ---
99
+
100
+ ## ๐Ÿ“ธ Screenshots
101
+
102
+ > **Coming soon** โ€” Screenshots of the Dashboard, POS, Inventory, and Reports pages will be added here.
103
+ >
104
+ > Want to see the app in action? Follow the [Quick Start](#-quick-start) guide to run it locally in under 5 minutes!
105
+
106
+ <!-- Uncomment and add your screenshots:
107
+ <div align="center">
108
+
109
+ | Dashboard | Point of Sale |
110
+ |:---------:|:------------:|
111
+ | ![Dashboard](img/screenshots/dashboard.png) | ![POS](img/screenshots/pos.png) |
112
+
113
+ | Inventory | Reports |
114
+ |:---------:|:-------:|
115
+ | ![Inventory](img/screenshots/inventory.png) | ![Reports](img/screenshots/reports.png) |
116
+
117
+ </div>
118
+ -->
119
+
120
+ ---
121
+
122
+ ## ๐Ÿš€ Quick Start
123
+
124
+ ### Prerequisites
125
+
126
+ | Tool | Version | Download |
127
+ |------|---------|----------|
128
+ | **Node.js** | 18+ | [nodejs.org](https://nodejs.org) |
129
+ | **pnpm** | 9+ | `npm install -g pnpm` |
130
+ | **Python** | 3.12+ | [python.org](https://python.org) |
131
+
132
+ ### Option A: One-Command Setup
133
+
134
+ <details>
135
+ <summary><b>๐ŸชŸ Windows</b></summary>
136
+
137
+ ```batch
138
+ git clone https://github.com/omersx/pharmacy-erp.git
139
+ cd pharmacy-erp
140
+ start.bat
141
+ ```
142
+
143
+ This will automatically:
144
+ 1. Create the `.env` config file
145
+ 2. Install all frontend & backend dependencies
146
+ 3. Seed the database with demo data
147
+ 4. Start both servers
148
+
149
+ </details>
150
+
151
+ <details>
152
+ <summary><b>๐Ÿง Linux / ๐ŸŽ macOS</b></summary>
153
+
154
+ ```bash
155
+ git clone https://github.com/omersx/pharmacy-erp.git
156
+ cd pharmacy-erp
157
+ chmod +x start.sh
158
+ ./start.sh
159
+ ```
160
+
161
+ </details>
162
+
163
+ ### Option B: Step-by-Step
164
+
165
+ ```bash
166
+ # 1. Clone the repository
167
+ git clone https://github.com/omersx/pharmacy-erp.git
168
+ cd pharmacy-erp
169
+
170
+ # 2. Install root dependencies (concurrently)
171
+ pnpm install
172
+
173
+ # 3. Setup frontend
174
+ pnpm run setup:frontend
175
+
176
+ # 4. Setup backend (auto-detects Windows/Linux/macOS)
177
+ pnpm run setup:backend
178
+
179
+ # 5. Configure environment
180
+ cp .env.example .env # Linux/macOS
181
+ # copy .env.example .env # Windows
182
+
183
+ # 6. Seed demo data
184
+ pnpm run seed
185
+
186
+ # 7. Start development servers
187
+ pnpm dev
188
+ ```
189
+
190
+ ### ๐ŸŽ‰ You're Ready!
191
+
192
+ | Service | URL |
193
+ |---------|-----|
194
+ | ๐ŸŒ **Frontend** | [http://localhost:3000](http://localhost:3000) |
195
+ | ๐Ÿ”ง **Backend API** | [http://localhost:8000](http://localhost:8000) |
196
+ | ๐Ÿ“š **API Docs (Swagger)** | [http://localhost:8000/docs](http://localhost:8000/docs) |
197
+
198
+ ### Default Login
199
+
200
+ | Role | Email | Password |
201
+ |------|-------|----------|
202
+ | Super Admin | `admin@pharmacy.com` | `admin123` |
203
+
204
+ > โš ๏ธ **Change the default credentials** before deploying to production!
205
+
206
+ ---
207
+
208
+ ## ๐Ÿ—๏ธ Architecture
209
+
210
+ ```mermaid
211
+ graph TB
212
+ subgraph Client
213
+ A[Browser] -->|HTTP/HTTPS| B[Next.js Frontend]
214
+ end
215
+
216
+ subgraph Frontend["Frontend โ€” Next.js 15"]
217
+ B --> C[App Router]
218
+ C --> D[POS Module]
219
+ C --> E[ERP Dashboard]
220
+ C --> F[Auth Pages]
221
+ B --> G[Zustand Store]
222
+ B --> H[next-intl i18n]
223
+ end
224
+
225
+ subgraph Backend["Backend โ€” FastAPI"]
226
+ I[API Gateway] --> J[Auth & RBAC]
227
+ I --> K[Medicines]
228
+ I --> L[Inventory]
229
+ I --> M[Sales & POS]
230
+ I --> N[Purchases]
231
+ I --> O[Customers]
232
+ I --> P[Cash Sessions]
233
+ I --> Q[Reports]
234
+ I --> R[Admin & Audit]
235
+ end
236
+
237
+ subgraph Data["Data Layer"]
238
+ S[(SQLite / PostgreSQL)]
239
+ end
240
+
241
+ B -->|REST API| I
242
+ J --> S
243
+ K --> S
244
+ L --> S
245
+ M --> S
246
+ N --> S
247
+ O --> S
248
+ P --> S
249
+ Q --> S
250
+ R --> S
251
+ ```
252
+
253
+ ### Project Structure
254
+
255
+ ```
256
+ pharmacy-erp/
257
+ โ”œโ”€โ”€ frontend/ # Next.js 15 (App Router)
258
+ โ”‚ โ”œโ”€โ”€ src/
259
+ โ”‚ โ”‚ โ”œโ”€โ”€ app/ # Routes & pages
260
+ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ [locale]/ # i18n routing (en, ar)
261
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ (app)/ # ERP dashboard pages
262
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ (auth)/ # Login / register
263
+ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ (pos)/ # Point of Sale
264
+ โ”‚ โ”‚ โ”œโ”€โ”€ components/ # Reusable UI components
265
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ ui/ # Base components (Radix UI)
266
+ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ pos/ # POS-specific components
267
+ โ”‚ โ”‚ โ”œโ”€โ”€ lib/ # API client, utilities
268
+ โ”‚ โ”‚ โ”œโ”€โ”€ store/ # Zustand state stores
269
+ โ”‚ โ”‚ โ”œโ”€โ”€ messages/ # i18n translations (en.json, ar.json)
270
+ โ”‚ โ”‚ โ””โ”€โ”€ i18n/ # i18n configuration
271
+ โ”‚ โ”œโ”€โ”€ Dockerfile
272
+ โ”‚ โ””โ”€โ”€ package.json
273
+ โ”‚
274
+ โ”œโ”€โ”€ backend/ # FastAPI (Python 3.12)
275
+ โ”‚ โ”œโ”€โ”€ app/
276
+ โ”‚ โ”‚ โ”œโ”€โ”€ core/ # Config, database, security, exceptions
277
+ โ”‚ โ”‚ โ”œโ”€โ”€ modules/ # Business logic modules
278
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ auth/ # Authentication & JWT
279
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ users/ # User management
280
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ roles/ # RBAC roles & permissions
281
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ organizations/# Branch management
282
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ medicines/ # Product catalog & batches
283
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ inventory/ # Stock movements & ledger
284
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ sales/ # Invoices, returns, held sales
285
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ purchases/ # Purchase orders
286
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ suppliers/ # Supplier management
287
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ customers/ # Customer & credit management
288
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ cash_sessions/# Cash register sessions
289
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ reports/ # Analytics & reporting
290
+ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ notifications/# System notifications
291
+ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ admin/ # Audit logs & admin tools
292
+ โ”‚ โ”‚ โ”œโ”€โ”€ main.py # FastAPI application entry
293
+ โ”‚ โ”‚ โ””โ”€โ”€ seed.py # Demo data seeder
294
+ โ”‚ โ”œโ”€โ”€ Dockerfile
295
+ โ”‚ โ””โ”€โ”€ requirements.txt
296
+ โ”‚
297
+ โ”œโ”€โ”€ nginx/ # Nginx reverse proxy config
298
+ โ”œโ”€โ”€ img/ # Logo and brand assets
299
+ โ”œโ”€โ”€ docker-compose.yml # Production deployment
300
+ โ”œโ”€โ”€ package.json # Root orchestration scripts
301
+ โ”œโ”€โ”€ start.bat # One-click setup (Windows)
302
+ โ”œโ”€โ”€ start.sh # One-click setup (Linux/macOS)
303
+ โ”œโ”€โ”€ .env.example # Environment template
304
+ โ””โ”€โ”€ README.md
305
+ ```
306
+
307
+ ---
308
+
309
+ ## ๐Ÿ–ฅ๏ธ Tech Stack
310
+
311
+ | Layer | Technologies |
312
+ |-------|-------------|
313
+ | **Frontend** | [Next.js 15](https://nextjs.org) ยท [React 19](https://react.dev) ยท [TypeScript](https://typescriptlang.org) ยท [Tailwind CSS](https://tailwindcss.com) |
314
+ | **UI Components** | [Radix UI](https://radix-ui.com) ยท [Lucide Icons](https://lucide.dev) ยท [Framer Motion](https://framer.com/motion) ยท [Recharts](https://recharts.org) |
315
+ | **State & i18n** | [Zustand](https://zustand-demo.pmnd.rs) ยท [next-intl](https://next-intl-docs.vercel.app) |
316
+ | **Backend** | [FastAPI](https://fastapi.tiangolo.com) ยท [Python 3.12](https://python.org) ยท [Pydantic v2](https://docs.pydantic.dev) ยท [SQLAlchemy 2](https://sqlalchemy.org) |
317
+ | **Database** | [SQLite](https://sqlite.org) (dev) ยท [PostgreSQL](https://postgresql.org) (production) |
318
+ | **Auth** | JWT (httpOnly cookies) ยท [Argon2](https://github.com/P-H-C/phc-winner-argon2) password hashing |
319
+ | **DevOps** | [Docker](https://docker.com) ยท [Nginx](https://nginx.org) ยท [Uvicorn](https://uvicorn.org) |
320
+
321
+ ---
322
+
323
+ ## ๐Ÿ“– API Documentation
324
+
325
+ Once the backend is running, interactive API documentation is available at:
326
+
327
+ | Format | URL |
328
+ |--------|-----|
329
+ | **Swagger UI** | [http://localhost:8000/docs](http://localhost:8000/docs) |
330
+ | **ReDoc** | [http://localhost:8000/redoc](http://localhost:8000/redoc) |
331
+
332
+ ### API Modules
333
+
334
+ | Endpoint Prefix | Module | Description |
335
+ |----------------|--------|-------------|
336
+ | `/api/v1/auth` | Authentication | Login, register, refresh tokens |
337
+ | `/api/v1/medicines` | Medicines | CRUD, batches, categories, import |
338
+ | `/api/v1/inventory` | Inventory | Stock movements, alerts, ledger |
339
+ | `/api/v1/sales` | Sales | Invoices, returns, held sales |
340
+ | `/api/v1/cash-sessions` | Cash Sessions | Open, close, X/Z reports |
341
+ | `/api/v1/customers` | Customers | Customer management, credit |
342
+ | `/api/v1/suppliers` | Suppliers | Supplier directory |
343
+ | `/api/v1/branches` | Branches | Multi-branch management |
344
+ | `/api/v1/reports` | Reports | Sales, inventory, profit analytics |
345
+ | `/api/v1/users` | Users | User management |
346
+ | `/api/v1/roles` | Roles | RBAC roles & permissions |
347
+ | `/api/v1/admin` | Admin | Audit logs, system admin |
348
+ | `/api/v1/notifications` | Notifications | System notifications |
349
+
350
+ ---
351
+
352
+ ## ๐Ÿณ Docker Deployment
353
+
354
+ ### Quick Deploy (from Docker Hub)
355
+
356
+ ```bash
357
+ # Pull pre-built images and start
358
+ docker compose up -d
359
+
360
+ # This starts:
361
+ # - FastAPI backend โ†’ port 8000
362
+ # - Next.js frontend โ†’ port 3000
363
+ # - Nginx proxy โ†’ port 80
364
+ ```
365
+
366
+ Or pull images individually:
367
+
368
+ ```bash
369
+ docker pull omersx/pharmacy-erp-backend:latest
370
+ docker pull omersx/pharmacy-erp-frontend:latest
371
+ ```
372
+
373
+ ### Build from Source (for contributors)
374
+
375
+ ```bash
376
+ docker compose -f docker-compose.dev.yml up --build
377
+ ```
378
+
379
+ ### Production Checklist
380
+
381
+ - [ ] Change `SECRET_KEY` to a strong random value (32+ characters)
382
+ - [ ] Change default admin credentials
383
+ - [ ] Set `APP_ENV=production` and `DEBUG=false`
384
+ - [ ] Switch database to PostgreSQL
385
+ - [ ] Configure proper `CORS_ORIGINS`
386
+ - [ ] Enable HTTPS via reverse proxy
387
+ - [ ] Set up automated backups
388
+
389
+ ---
390
+
391
+ ## โš™๏ธ Environment Variables
392
+
393
+ | Variable | Description | Default |
394
+ |----------|-------------|---------|
395
+ | `APP_NAME` | Application name | `Pharmacy ERP` |
396
+ | `APP_ENV` | Environment (`development` / `production`) | `development` |
397
+ | `DEBUG` | Enable debug mode | `true` |
398
+ | `DATABASE_URL` | Database connection string | `sqlite+aiosqlite:///./data/pharmacy.db` |
399
+ | `SECRET_KEY` | JWT signing key (change in production!) | `dev-secret-key-...` |
400
+ | `ACCESS_TOKEN_EXPIRE_MINUTES` | Access token TTL | `30` |
401
+ | `REFRESH_TOKEN_EXPIRE_DAYS` | Refresh token TTL | `7` |
402
+ | `CORS_ORIGINS` | Allowed CORS origins (comma-separated) | `http://localhost:3000` |
403
+ | `NEXT_PUBLIC_API_URL` | API URL for the frontend | `http://localhost:8000/api/v1` |
404
+ | `REDIS_URL` | Redis URL (optional, for production) | โ€” |
405
+ | `UPLOAD_DIR` | File upload directory | `./data/uploads` |
406
+ | `MAX_UPLOAD_SIZE_MB` | Max upload file size | `10` |
407
+
408
+ See [`.env.example`](.env.example) for the full template.
409
+
410
+ ---
411
+
412
+ ## ๐ŸŒ Internationalization
413
+
414
+ Pharmacy ERP ships with complete support for:
415
+
416
+ | Language | Direction | Status |
417
+ |----------|-----------|--------|
418
+ | ๐Ÿ‡ฌ๐Ÿ‡ง English | LTR (Left-to-Right) | โœ… Complete |
419
+ | ๐Ÿ‡ธ๐Ÿ‡ฆ ุงู„ุนุฑุจูŠุฉ (Arabic) | RTL (Right-to-Left) | โœ… Complete |
420
+
421
+ Switch languages from any page โ€” the entire UI, including layout direction, updates instantly.
422
+
423
+ **Adding a new language:**
424
+
425
+ 1. Create a new translation file: `frontend/src/messages/<locale>.json`
426
+ 2. Add the locale to `frontend/src/i18n/` configuration
427
+ 3. All strings are externalized โ€” no hardcoded text in components
428
+
429
+ ---
430
+
431
+ ## ๐Ÿค Contributing
432
+
433
+ We love contributions! Whether it's fixing bugs, adding features, improving docs, or suggesting ideas โ€” all contributions are welcome.
434
+
435
+ 1. **Fork** the repository
436
+ 2. **Create** a feature branch: `git checkout -b feature/amazing-feature`
437
+ 3. **Commit** your changes: `git commit -m 'feat: add amazing feature'`
438
+ 4. **Push** to the branch: `git push origin feature/amazing-feature`
439
+ 5. **Open** a Pull Request
440
+
441
+ Please read our [Contributing Guide](CONTRIBUTING.md) and [Code of Conduct](CODE_OF_CONDUCT.md) before getting started.
442
+
443
+ ---
444
+
445
+ ## ๐Ÿ—บ๏ธ Roadmap
446
+
447
+ - [ ] ๐Ÿ“ฑ Mobile app (React Native)
448
+ - [ ] ๐Ÿ”Œ Barcode scanner hardware integration
449
+ - [ ] ๐Ÿ“Š Advanced analytics dashboard
450
+ - [ ] ๐Ÿฅ Insurance claims module
451
+ - [ ] ๐Ÿ’ณ Payment gateway integration
452
+ - [ ] ๐Ÿ“ง Email notifications & alerts
453
+ - [ ] ๐Ÿ”„ Real-time sync across branches
454
+ - [ ] ๐Ÿ“‹ Prescription management
455
+ - [ ] ๐Ÿงช Lab integration module
456
+
457
+ Have a feature idea? [Open a feature request!](../../issues/new?template=feature_request.md)
458
+
459
+ ---
460
+
461
+ ## โญ Show Your Support
462
+
463
+ If this project helps you, give it a โญ on GitHub โ€” it means a lot and helps others discover it!
464
+
465
+ ---
466
+
467
+ ## ๐Ÿ“„ License
468
+
469
+ This project is licensed under the **MIT License** โ€” see the [LICENSE](LICENSE) file for details.
470
+
471
+ ---
472
+
473
+ <div align="center">
474
+
475
+ **Built with โค๏ธ for pharmacies everywhere**
476
+
477
+ [Report Bug](../../issues/new?template=bug_report.md) ยท [Request Feature](../../issues/new?template=feature_request.md) ยท [Contribute](CONTRIBUTING.md)
478
+
479
+ </div>
@@ -0,0 +1,44 @@
1
+ FROM python:3.12-slim AS base
2
+
3
+ LABEL org.opencontainers.image.title="Pharmacy ERP Backend"
4
+ LABEL org.opencontainers.image.description="FastAPI backend for Pharmacy ERP & POS System"
5
+ LABEL org.opencontainers.image.source="https://github.com/omersx/pharmacy-erp"
6
+ LABEL org.opencontainers.image.licenses="MIT"
7
+
8
+ # โ”€โ”€ Dependencies stage โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
9
+ FROM base AS deps
10
+
11
+ WORKDIR /app
12
+
13
+ COPY requirements.txt .
14
+ RUN pip install --no-cache-dir -r requirements.txt
15
+
16
+ # โ”€โ”€ Production stage โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
17
+ FROM base AS runner
18
+
19
+ WORKDIR /app
20
+
21
+ # Create non-root user
22
+ RUN groupadd --system --gid 1001 appuser && \
23
+ useradd --system --uid 1001 --gid appuser appuser
24
+
25
+ # Copy installed packages from deps stage
26
+ COPY --from=deps /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
27
+ COPY --from=deps /usr/local/bin /usr/local/bin
28
+
29
+ # Copy application code
30
+ COPY . .
31
+
32
+ # Create data directory
33
+ RUN mkdir -p /app/data && chown -R appuser:appuser /app/data
34
+
35
+ # Switch to non-root user
36
+ USER appuser
37
+
38
+ EXPOSE 8000
39
+
40
+ # Health check
41
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
42
+ CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/docs')" || exit 1
43
+
44
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,33 @@
1
+ from sqlalchemy.ext.asyncio import AsyncSession
2
+ from app.modules.admin.models import AuditLog
3
+ from app.modules.auth.models import User
4
+ from typing import Optional
5
+
6
+ async def log_action(
7
+ db: AsyncSession,
8
+ action: str,
9
+ module: str,
10
+ details: str,
11
+ user: Optional[User] = None,
12
+ entity_type: Optional[str] = None,
13
+ entity_id: Optional[str] = None,
14
+ ip_address: Optional[str] = None
15
+ ):
16
+ """Log an audit action to the database."""
17
+ log = AuditLog(
18
+ user_id=user.id if user else None,
19
+ user_email=user.email if user else "System",
20
+ action=action,
21
+ module=module,
22
+ entity_type=entity_type,
23
+ entity_id=str(entity_id) if entity_id else None,
24
+ details=details,
25
+ ip_address=ip_address
26
+ )
27
+ db.add(log)
28
+ # Don't commit here โ€” let the caller's transaction handle it
29
+ # But for standalone audit logs (like login), we flush
30
+ try:
31
+ await db.flush()
32
+ except Exception:
33
+ pass
@@ -0,0 +1,16 @@
1
+ from pydantic_settings import BaseSettings, SettingsConfigDict
2
+ from typing import List
3
+
4
+ class Settings(BaseSettings):
5
+ APP_NAME: str = "Pharma ERP"
6
+ APP_ENV: str = "development"
7
+ DEBUG: bool = True
8
+ DATABASE_URL: str = "sqlite+aiosqlite:///./data/pharmacy.db"
9
+ SECRET_KEY: str = "supersecretkey_change_in_production"
10
+ ACCESS_TOKEN_EXPIRE_MINUTES: int = 120
11
+ REFRESH_TOKEN_EXPIRE_DAYS: int = 7
12
+ CORS_ORIGINS: List[str] = ["*"]
13
+
14
+ model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
15
+
16
+ settings = Settings()
@@ -0,0 +1,26 @@
1
+ import uuid
2
+ from datetime import datetime
3
+ from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
4
+ from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
5
+ from app.core.config import settings
6
+
7
+ engine = create_async_engine(
8
+ settings.DATABASE_URL,
9
+ echo=settings.DEBUG,
10
+ connect_args={"check_same_thread": False} if settings.DATABASE_URL.startswith("sqlite") else {}
11
+ )
12
+
13
+ AsyncSessionLocal = async_sessionmaker(bind=engine, class_=AsyncSession, expire_on_commit=False)
14
+
15
+ class Base(DeclarativeBase):
16
+ id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4)
17
+ created_at: Mapped[datetime] = mapped_column(default=datetime.utcnow)
18
+ updated_at: Mapped[datetime] = mapped_column(default=datetime.utcnow, onupdate=datetime.utcnow)
19
+
20
+ async def get_db():
21
+ async with AsyncSessionLocal() as session:
22
+ yield session
23
+
24
+ async def init_db():
25
+ async with engine.begin() as conn:
26
+ await conn.run_sync(Base.metadata.create_all)