kamau1 commited on
Commit
8d20770
·
1 Parent(s): a963b0d

fix: convert Decimals to float in invoice generation additional_metadata for JSON serialization

Browse files
docs/devlogs/browser/browserconsole.txt CHANGED
@@ -32,23 +32,41 @@ flushPassiveEffects @ chunk-276SZO74.js?v=02c37274:19447
32
  workLoop @ chunk-276SZO74.js?v=02c37274:197
33
  flushWork @ chunk-276SZO74.js?v=02c37274:176
34
  performWorkUntilDeadline @ chunk-276SZO74.js?v=02c37274:384
35
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me → 200 (756ms)
36
  core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences
37
  Index.tsx:37 ProjectOverview Page Loaded (New Implementation)
38
- core.ts:119 ℹ️ [11:28:23] [COMPONENT] ProjectOverview: Fetching project overview data {projectId: '0ade6bd1-e492-4e25-b681-59f42058d29a'}
39
  core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/overview?
40
  Index.tsx:37 ProjectOverview Page Loaded (New Implementation)
41
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences → 200 (617ms)
42
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/overview? → 200 (585ms)
43
- core.ts:119 ℹ️ [11:28:23] [COMPONENT] ProjectOverview: Project overview data loaded {regionsCount: 3, hasInvolvement: false}
44
  Index.tsx:37 ProjectOverview Page Loaded (New Implementation)
45
  Index.tsx:37 ProjectOverview Page Loaded (New Implementation)
46
  Index.tsx:37 ProjectOverview Page Loaded (New Implementation)
47
  Index.tsx:37 ProjectOverview Page Loaded (New Implementation)
48
- core.ts:169 %cPATCH%c https://kamau1-swiftops-backend.hf.space/api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a
49
- project-setup.service.ts:212 PATCH https://kamau1-swiftops-backend.hf.space/api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a 500 (Internal Server Error)
50
- updateProject @ project-setup.service.ts:212
51
- handleSubmit @ InvoicePricingModal.tsx:142
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  callCallback2 @ chunk-276SZO74.js?v=02c37274:3674
53
  invokeGuardedCallbackDev @ chunk-276SZO74.js?v=02c37274:3699
54
  invokeGuardedCallback @ chunk-276SZO74.js?v=02c37274:3733
@@ -64,12 +82,46 @@ dispatchEventForPluginEventSystem @ chunk-276SZO74.js?v=02c37274:7173
64
  dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ chunk-276SZO74.js?v=02c37274:5478
65
  dispatchEvent @ chunk-276SZO74.js?v=02c37274:5472
66
  dispatchDiscreteEvent @ chunk-276SZO74.js?v=02c37274:5449
67
- core.ts:169 PATCH https://kamau1-swiftops-backend.hf.space/api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a → 500 (587ms)
68
- InvoicePricingModal.tsx:150 Error: An error occurred while updating the project
69
- at handleResponse (project-setup.service.ts:22:15)
70
- at async handleSubmit (InvoicePricingModal.tsx:142:13)
71
- handleSubmit @ InvoicePricingModal.tsx:150
72
- await in handleSubmit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  callCallback2 @ chunk-276SZO74.js?v=02c37274:3674
74
  invokeGuardedCallbackDev @ chunk-276SZO74.js?v=02c37274:3699
75
  invokeGuardedCallback @ chunk-276SZO74.js?v=02c37274:3733
 
32
  workLoop @ chunk-276SZO74.js?v=02c37274:197
33
  flushWork @ chunk-276SZO74.js?v=02c37274:176
34
  performWorkUntilDeadline @ chunk-276SZO74.js?v=02c37274:384
35
+ core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me → 200 (967ms)
36
  core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences
37
  Index.tsx:37 ProjectOverview Page Loaded (New Implementation)
38
+ core.ts:119 ℹ️ [11:41:55] [COMPONENT] ProjectOverview: Fetching project overview data {projectId: '0ade6bd1-e492-4e25-b681-59f42058d29a'}
39
  core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/overview?
40
  Index.tsx:37 ProjectOverview Page Loaded (New Implementation)
41
+ core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences → 200 (591ms)
42
+ core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/overview? → 200 (664ms)
43
+ core.ts:119 ℹ️ [11:41:56] [COMPONENT] ProjectOverview: Project overview data loaded {regionsCount: 3, hasInvolvement: false}
44
  Index.tsx:37 ProjectOverview Page Loaded (New Implementation)
45
  Index.tsx:37 ProjectOverview Page Loaded (New Implementation)
46
  Index.tsx:37 ProjectOverview Page Loaded (New Implementation)
47
  Index.tsx:37 ProjectOverview Page Loaded (New Implementation)
48
+ core.ts:119 ℹ️ [11:45:07] [COMPONENT] AppLauncher: App clicked {appCode: 'invoicing', route: '/invoicing', primaryProject: '0ade6bd1-e492-4e25-b681-59f42058d29a', currentPath: '/project/0ade6bd1-e492-4e25-b681-59f42058d29a/overview', metaApps: Array(6)}
49
+ core.ts:119 ℹ️ [11:45:07] [COMPONENT] AppLauncher: Navigation decision {hasProject: true, isInProjectContext: true, isMetaApp: false, appCode: 'invoicing', metaApps: Array(6)}
50
+ core.ts:119 ℹ️ [11:45:07] [COMPONENT] AppLauncher: Navigating to project-scoped route {projectRoute: '/project/0ade6bd1-e492-4e25-b681-59f42058d29a/invoicing', appCode: 'invoicing'}
51
+ core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a
52
+ core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a
53
+ core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a → 200 (1.60s)
54
+ core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a → 200 (1.64s)
55
+ core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/invoices/available-tickets?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&contractor_id=auto
56
+ core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/invoices/available-tickets?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&contractor_id=auto → 200 (698ms)
57
+ core.ts:169 %cPOST%c https://kamau1-swiftops-backend.hf.space/api/v1/invoices/generate
58
+ api-client.ts:124 POST https://kamau1-swiftops-backend.hf.space/api/v1/invoices/generate 500 (Internal Server Error)
59
+ request @ api-client.ts:124
60
+ post @ api-client.ts:213
61
+ generateInvoice @ invoice.service.ts:40
62
+ mutationFn @ useInvoices.ts:44
63
+ fn @ @tanstack_react-query.js?v=02c37274:1236
64
+ run @ @tanstack_react-query.js?v=02c37274:513
65
+ start @ @tanstack_react-query.js?v=02c37274:555
66
+ execute @ @tanstack_react-query.js?v=02c37274:1272
67
+ await in execute
68
+ mutate @ @tanstack_react-query.js?v=02c37274:2692
69
+ handleCreate @ GenerateInvoicePage.tsx:52
70
  callCallback2 @ chunk-276SZO74.js?v=02c37274:3674
71
  invokeGuardedCallbackDev @ chunk-276SZO74.js?v=02c37274:3699
72
  invokeGuardedCallback @ chunk-276SZO74.js?v=02c37274:3733
 
82
  dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ chunk-276SZO74.js?v=02c37274:5478
83
  dispatchEvent @ chunk-276SZO74.js?v=02c37274:5472
84
  dispatchDiscreteEvent @ chunk-276SZO74.js?v=02c37274:5449
85
+ core.ts:169 POST https://kamau1-swiftops-backend.hf.space/api/v1/invoices/generate → 500 (1.27s)
86
+ core.ts:169 %cPOST%c https://kamau1-swiftops-backend.hf.space/api/v1/invoices/generate
87
+ api-client.ts:124 POST https://kamau1-swiftops-backend.hf.space/api/v1/invoices/generate 500 (Internal Server Error)
88
+ request @ api-client.ts:124
89
+ post @ api-client.ts:213
90
+ generateInvoice @ invoice.service.ts:40
91
+ mutationFn @ useInvoices.ts:44
92
+ fn @ @tanstack_react-query.js?v=02c37274:1236
93
+ run @ @tanstack_react-query.js?v=02c37274:513
94
+ (anonymous) @ @tanstack_react-query.js?v=02c37274:538
95
+ Promise.then
96
+ (anonymous) @ @tanstack_react-query.js?v=02c37274:534
97
+ Promise.catch
98
+ run @ @tanstack_react-query.js?v=02c37274:517
99
+ start @ @tanstack_react-query.js?v=02c37274:555
100
+ execute @ @tanstack_react-query.js?v=02c37274:1272
101
+ await in execute
102
+ mutate @ @tanstack_react-query.js?v=02c37274:2692
103
+ handleCreate @ GenerateInvoicePage.tsx:52
104
+ callCallback2 @ chunk-276SZO74.js?v=02c37274:3674
105
+ invokeGuardedCallbackDev @ chunk-276SZO74.js?v=02c37274:3699
106
+ invokeGuardedCallback @ chunk-276SZO74.js?v=02c37274:3733
107
+ invokeGuardedCallbackAndCatchFirstError @ chunk-276SZO74.js?v=02c37274:3736
108
+ executeDispatch @ chunk-276SZO74.js?v=02c37274:7014
109
+ processDispatchQueueItemsInOrder @ chunk-276SZO74.js?v=02c37274:7034
110
+ processDispatchQueue @ chunk-276SZO74.js?v=02c37274:7043
111
+ dispatchEventsForPlugins @ chunk-276SZO74.js?v=02c37274:7051
112
+ (anonymous) @ chunk-276SZO74.js?v=02c37274:7174
113
+ batchedUpdates$1 @ chunk-276SZO74.js?v=02c37274:18913
114
+ batchedUpdates @ chunk-276SZO74.js?v=02c37274:3579
115
+ dispatchEventForPluginEventSystem @ chunk-276SZO74.js?v=02c37274:7173
116
+ dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ chunk-276SZO74.js?v=02c37274:5478
117
+ dispatchEvent @ chunk-276SZO74.js?v=02c37274:5472
118
+ dispatchDiscreteEvent @ chunk-276SZO74.js?v=02c37274:5449
119
+ core.ts:169 POST https://kamau1-swiftops-backend.hf.space/api/v1/invoices/generate → 500 (377ms)
120
+ GenerateInvoicePage.tsx:61 APIError: Request failed
121
+ at APIClient.request (api-client.ts:158:15)
122
+ at async Object.generateInvoice (invoice.service.ts:40:22)
123
+ handleCreate @ GenerateInvoicePage.tsx:61
124
+ await in handleCreate
125
  callCallback2 @ chunk-276SZO74.js?v=02c37274:3674
126
  invokeGuardedCallbackDev @ chunk-276SZO74.js?v=02c37274:3699
127
  invokeGuardedCallback @ chunk-276SZO74.js?v=02c37274:3733
docs/devlogs/server/runtimeerror.txt CHANGED
@@ -1,48 +1,339 @@
1
- ===== Application Startup at 2025-12-15 11:34:54 =====
2
 
3
  INFO: Started server process [7]
4
  INFO: Waiting for application startup.
5
- INFO: 2025-12-15T11:35:06 - app.main: ============================================================
6
- INFO: 2025-12-15T11:35:06 - app.main: 🚀 SwiftOps API v1.0.0 | PRODUCTION
7
- INFO: 2025-12-15T11:35:06 - app.main: 📊 Dashboard: Enabled
8
- INFO: 2025-12-15T11:35:06 - app.main: ============================================================
9
- INFO: 2025-12-15T11:35:06 - app.main: 📦 Database:
10
- INFO: 2025-12-15T11:35:06 - app.main: ✓ Connected | 45 tables | 6 users
11
- INFO: 2025-12-15T11:35:06 - app.main: 💾 Cache & Sessions:
12
- INFO: 2025-12-15T11:35:07 - app.services.otp_service: ✅ OTP Service initialized with Redis storage
13
- INFO: 2025-12-15T11:35:08 - app.main: ✓ Redis: Connected
14
- INFO: 2025-12-15T11:35:08 - app.main: 🔌 External Services:
15
- INFO: 2025-12-15T11:35:08 - app.main: ✓ Cloudinary: Connected
16
- INFO: 2025-12-15T11:35:08 - app.main: ✓ Resend: Configured
17
- INFO: 2025-12-15T11:35:08 - app.main: ○ WASender: Disconnected
18
- INFO: 2025-12-15T11:35:08 - app.main: ✓ Supabase: Connected | 6 buckets
19
- INFO: 2025-12-15T11:35:08 - app.main: ============================================================
20
- INFO: 2025-12-15T11:35:08 - app.main: ✅ Startup complete | Ready to serve requests
21
- INFO: 2025-12-15T11:35:08 - app.main: ============================================================
22
  INFO: Application startup complete.
23
  INFO: Uvicorn running on http://0.0.0.0:7860 (Press CTRL+C to quit)
24
- INFO: 10.16.13.79:36199 - "GET /health HTTP/1.1" 200 OK
25
- INFO: 2025-12-15T11:35:14 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
26
- INFO: 2025-12-15T11:35:14 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
27
- INFO: 2025-12-15T11:35:14 - app.services.project_service: Project updated: 0ade6bd1-e492-4e25-b681-59f42058d29a by user c5cf92be-4172-4fe2-af5c-f05d83b3a938
28
- INFO: 2025-12-15T11:35:14 - app.services.audit_service: Audit log created: update on project by nadina73@nembors.com
29
- INFO: 10.16.25.209:47072 - "PATCH /api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 200 OK
30
- INFO: 2025-12-15T11:35:15 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
31
- INFO: 2025-12-15T11:35:15 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
32
- INFO: 2025-12-15T11:35:15 - app.services.dashboard_service: Overview cache MISS for project 0ade6bd1-e492-4e25-b681-59f42058d29a, user c5cf92be-4172-4fe2-af5c-f05d83b3a938 - building fresh data
33
- INFO: 2025-12-15T11:35:15 - app.services.dashboard_service: Built and cached overview for project 0ade6bd1-e492-4e25-b681-59f42058d29a
34
- INFO: 10.16.25.209:47072 - "GET /api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/overview?refresh=true HTTP/1.1" 200 OK
35
- INFO: 10.16.13.79:27293 - "GET /health HTTP/1.1" 200 OK
36
- INFO: 2025-12-15T11:35:35 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
37
- INFO: 2025-12-15T11:35:35 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
38
- INFO: 10.16.25.209:11742 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
39
- INFO: 2025-12-15T11:35:35 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
40
- INFO: 2025-12-15T11:35:35 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
41
- INFO: 10.16.25.209:11742 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
42
- INFO: 2025-12-15T11:35:35 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
43
- INFO: 2025-12-15T11:35:35 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
44
- INFO: 10.16.13.79:27293 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
45
- INFO: 2025-12-15T11:35:35 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
46
- INFO: 2025-12-15T11:35:35 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
47
- INFO: 2025-12-15T11:35:35 - app.services.dashboard_service: Overview cache HIT for project 0ade6bd1-e492-4e25-b681-59f42058d29a, user c5cf92be-4172-4fe2-af5c-f05d83b3a938
48
- INFO: 10.16.13.79:27293 - "GET /api/v1/projects/0ade6bd1-e492-4e25-b681-59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ===== Application Startup at 2025-12-15 11:41:31 =====
2
 
3
  INFO: Started server process [7]
4
  INFO: Waiting for application startup.
5
+ INFO: 2025-12-15T11:41:43 - app.main: ============================================================
6
+ INFO: 2025-12-15T11:41:43 - app.main: 🚀 SwiftOps API v1.0.0 | PRODUCTION
7
+ INFO: 2025-12-15T11:41:43 - app.main: 📊 Dashboard: Enabled
8
+ INFO: 2025-12-15T11:41:43 - app.main: ============================================================
9
+ INFO: 2025-12-15T11:41:43 - app.main: 📦 Database:
10
+ INFO: 2025-12-15T11:41:43 - app.main: ✓ Connected | 45 tables | 6 users
11
+ INFO: 2025-12-15T11:41:43 - app.main: 💾 Cache & Sessions:
12
+ INFO: 2025-12-15T11:41:44 - app.services.otp_service: ✅ OTP Service initialized with Redis storage
13
+ INFO: 2025-12-15T11:41:45 - app.main: ✓ Redis: Connected
14
+ INFO: 2025-12-15T11:41:45 - app.main: 🔌 External Services:
15
+ INFO: 2025-12-15T11:41:45 - app.main: ✓ Cloudinary: Connected
16
+ INFO: 2025-12-15T11:41:45 - app.main: ✓ Resend: Configured
17
+ INFO: 2025-12-15T11:41:45 - app.main: ○ WASender: Disconnected
18
+ INFO: 2025-12-15T11:41:45 - app.main: ✓ Supabase: Connected | 6 buckets
19
+ INFO: 2025-12-15T11:41:45 - app.main: ============================================================
20
+ INFO: 2025-12-15T11:41:45 - app.main: ✅ Startup complete | Ready to serve requests
21
+ INFO: 2025-12-15T11:41:45 - app.main: ============================================================
22
  INFO: Application startup complete.
23
  INFO: Uvicorn running on http://0.0.0.0:7860 (Press CTRL+C to quit)
24
+ INFO: 10.16.13.79:61786 - "GET /health HTTP/1.1" 200 OK
25
+ INFO: 10.16.13.79:49110 - "GET /health HTTP/1.1" 200 OK
26
+ INFO: 2025-12-15T11:41:54 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
27
+ INFO: 2025-12-15T11:41:54 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
28
+ INFO: 10.16.13.79:49110 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
29
+ INFO: 2025-12-15T11:41:55 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
30
+ INFO: 2025-12-15T11:41:55 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
31
+ INFO: 10.16.13.79:49110 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
32
+ INFO: 2025-12-15T11:41:55 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
33
+ INFO: 2025-12-15T11:41:55 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
34
+ INFO: 10.16.25.209:46824 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
35
+ INFO: 2025-12-15T11:41:55 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
36
+ INFO: 2025-12-15T11:41:55 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
37
+ INFO: 2025-12-15T11:41:55 - app.services.dashboard_service: Overview cache MISS for project 0ade6bd1-e492-4e25-b681-59f42058d29a, user c5cf92be-4172-4fe2-af5c-f05d83b3a938 - building fresh data
38
+ INFO: 2025-12-15T11:41:55 - app.services.dashboard_service: Built and cached overview for project 0ade6bd1-e492-4e25-b681-59f42058d29a
39
+ INFO: 10.16.13.79:49110 - "GET /api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/overview HTTP/1.1" 200 OK
40
+ INFO: 10.16.25.209:40661 - "GET /health HTTP/1.1" 200 OK
41
+ INFO: 10.16.25.209:25044 - "GET /health HTTP/1.1" 200 OK
42
+ INFO: 10.16.13.79:33349 - "GET /health HTTP/1.1" 200 OK
43
+ INFO: 10.16.25.209:39129 - "GET /health HTTP/1.1" 200 OK
44
+ INFO: 10.16.25.209:5922 - "GET /health HTTP/1.1" 200 OK
45
+ INFO: 10.16.13.79:1316 - "GET /health HTTP/1.1" 200 OK
46
+ INFO: 10.16.13.79:35220 - "GET /api/v1/contractor-invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 200 OK
47
+ INFO: 10.16.25.209:42618 - "GET /api/v1/contractor-invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 200 OK
48
+ INFO: 10.16.25.209:42618 - "GET /api/v1/invoices/available-tickets?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&contractor_id=auto HTTP/1.1" 200 OK
49
+ INFO: 2025-12-15T11:45:20 - app.services.invoice_generation_service: Applying tiered pricing for 1 tickets
50
+ INFO: 10.16.25.209:40744 - "POST /api/v1/invoices/generate HTTP/1.1" 500 Internal Server Error
51
+ ERROR: Exception in ASGI application
52
+ Traceback (most recent call last):
53
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 1814, in _execute_context
54
+ context = constructor(
55
+ ^^^^^^^^^^^^
56
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/default.py", line 1487, in _init_compiled
57
+ d_param = {
58
+ ^
59
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/default.py", line 1488, in <dictcomp>
60
+ key: flattened_processors[key](compiled_params[key])
61
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
62
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/sql/sqltypes.py", line 2717, in process
63
+ return json_serializer(value)
64
+ ^^^^^^^^^^^^^^^^^^^^^^
65
+ File "/usr/local/lib/python3.11/json/__init__.py", line 231, in dumps
66
+ return _default_encoder.encode(obj)
67
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
68
+ File "/usr/local/lib/python3.11/json/encoder.py", line 200, in encode
69
+ chunks = self.iterencode(o, _one_shot=True)
70
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
71
+ File "/usr/local/lib/python3.11/json/encoder.py", line 258, in iterencode
72
+ return _iterencode(o, 0)
73
+ ^^^^^^^^^^^^^^^^^
74
+ File "/usr/local/lib/python3.11/json/encoder.py", line 180, in default
75
+ raise TypeError(f'Object of type {o.__class__.__name__} '
76
+ TypeError: Object of type Decimal is not JSON serializable
77
+
78
+ The above exception was the direct cause of the following exception:
79
+
80
+ Traceback (most recent call last):
81
+ File "/usr/local/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py", line 426, in run_asgi
82
+ result = await app( # type: ignore[func-returns-value]
83
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
84
+ File "/usr/local/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
85
+ return await self.app(scope, receive, send)
86
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
87
+ File "/usr/local/lib/python3.11/site-packages/fastapi/applications.py", line 1106, in __call__
88
+ await super().__call__(scope, receive, send)
89
+ File "/usr/local/lib/python3.11/site-packages/starlette/applications.py", line 122, in __call__
90
+ await self.middleware_stack(scope, receive, send)
91
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 184, in __call__
92
+ raise exc
93
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in __call__
94
+ await self.app(scope, receive, _send)
95
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/cors.py", line 91, in __call__
96
+ await self.simple_response(scope, receive, send, request_headers=headers)
97
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/cors.py", line 146, in simple_response
98
+ await self.app(scope, receive, send)
99
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
100
+ raise exc
101
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
102
+ await self.app(scope, receive, sender)
103
+ File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
104
+ raise e
105
+ File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
106
+ await self.app(scope, receive, send)
107
+ File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 718, in __call__
108
+ await route.handle(scope, receive, send)
109
+ File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 276, in handle
110
+ await self.app(scope, receive, send)
111
+ File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 66, in app
112
+ response = await func(request)
113
+ ^^^^^^^^^^^^^^^^^^^
114
+ File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 274, in app
115
+ raw_response = await run_endpoint_function(
116
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
117
+ File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 193, in run_endpoint_function
118
+ return await run_in_threadpool(dependant.call, **values)
119
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
120
+ File "/usr/local/lib/python3.11/site-packages/starlette/concurrency.py", line 41, in run_in_threadpool
121
+ return await anyio.to_thread.run_sync(func, *args)
122
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
123
+ File "/usr/local/lib/python3.11/site-packages/anyio/to_thread.py", line 33, in run_sync
124
+ return await get_asynclib().run_sync_in_worker_thread(
125
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
126
+ File "/usr/local/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 877, in run_sync_in_worker_thread
127
+ return await future
128
+ ^^^^^^^^^^^^
129
+ File "/usr/local/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 807, in run
130
+ result = context.run(func, *args)
131
+ ^^^^^^^^^^^^^^^^^^^^^^^^
132
+ File "/app/src/app/api/v1/invoice_generation.py", line 187, in generate_invoice
133
+ invoice, viewing_link, csv_link, notification_ids = InvoiceGenerationService.generate_invoice_from_tickets(
134
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
135
+ File "/app/src/app/services/invoice_generation_service.py", line 278, in generate_invoice_from_tickets
136
+ db.flush()
137
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/session.py", line 4312, in flush
138
+ self._flush(objects)
139
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/session.py", line 4447, in _flush
140
+ with util.safe_reraise():
141
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__
142
+ raise exc_value.with_traceback(exc_tb)
143
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/session.py", line 4408, in _flush
144
+ flush_context.execute()
145
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/unitofwork.py", line 466, in execute
146
+ rec.execute(self)
147
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/unitofwork.py", line 642, in execute
148
+ util.preloaded.orm_persistence.save_obj(
149
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/persistence.py", line 93, in save_obj
150
+ _emit_insert_statements(
151
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/persistence.py", line 1226, in _emit_insert_statements
152
+ result = connection.execute(
153
+ ^^^^^^^^^^^^^^^^^^^
154
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 1416, in execute
155
+ return meth(
156
+ ^^^^^
157
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/sql/elements.py", line 516, in _execute_on_connection
158
+ return connection._execute_clauseelement(
159
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
160
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 1639, in _execute_clauseelement
161
+ ret = self._execute_context(
162
+ ^^^^^^^^^^^^^^^^^^^^^^
163
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 1820, in _execute_context
164
+ self._handle_dbapi_exception(
165
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 2343, in _handle_dbapi_exception
166
+ raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
167
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 1814, in _execute_context
168
+ context = constructor(
169
+ ^^^^^^^^^^^^
170
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/default.py", line 1487, in _init_compiled
171
+ d_param = {
172
+ ^
173
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/default.py", line 1488, in <dictcomp>
174
+ key: flattened_processors[key](compiled_params[key])
175
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
176
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/sql/sqltypes.py", line 2717, in process
177
+ return json_serializer(value)
178
+ ^^^^^^^^^^^^^^^^^^^^^^
179
+ File "/usr/local/lib/python3.11/json/__init__.py", line 231, in dumps
180
+ return _default_encoder.encode(obj)
181
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
182
+ File "/usr/local/lib/python3.11/json/encoder.py", line 200, in encode
183
+ chunks = self.iterencode(o, _one_shot=True)
184
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
185
+ File "/usr/local/lib/python3.11/json/encoder.py", line 258, in iterencode
186
+ return _iterencode(o, 0)
187
+ ^^^^^^^^^^^^^^^^^
188
+ File "/usr/local/lib/python3.11/json/encoder.py", line 180, in default
189
+ raise TypeError(f'Object of type {o.__class__.__name__} '
190
+ sqlalchemy.exc.StatementError: (builtins.TypeError) Object of type Decimal is not JSON serializable
191
+ [SQL: INSERT INTO contractor_invoices (contractor_id, client_id, project_id, invoice_number, invoice_title, billing_period_start, billing_period_end, subtotal, tax_rate, tax_amount, discount_amount, total_amount, amount_paid, currency, line_items, status, issue_date, due_date, sent_date, paid_date, payment_method, payment_reference, payment_notes, notes, terms_and_conditions, additional_metadata, created_by_user_id, version, previous_version_id, is_latest_version, revision_notes, viewing_token, viewing_token_expires_at, viewing_token_created_by, times_viewed, last_viewed_at, csv_exported, csv_exported_at, csv_exported_by_user_id, client_comments, client_viewed_at, id, created_at, updated_at, deleted_at) VALUES (%(contractor_id)s::UUID, %(client_id)s::UUID, %(project_id)s::UUID, %(invoice_number)s, %(invoice_title)s, %(billing_period_start)s, %(billing_period_end)s, %(subtotal)s, %(tax_rate)s, %(tax_amount)s, %(discount_amount)s, %(total_amount)s, %(amount_paid)s, %(currency)s, %(line_items)s, %(status)s, %(issue_date)s, %(due_date)s, %(sent_date)s, %(paid_date)s, %(payment_method)s, %(payment_reference)s, %(payment_notes)s, %(notes)s, %(terms_and_conditions)s, %(additional_metadata)s, %(created_by_user_id)s::UUID, %(version)s, %(previous_version_id)s::UUID, %(is_latest_version)s, %(revision_notes)s, %(viewing_token)s, %(viewing_token_expires_at)s, %(viewing_token_created_by)s::UUID, %(times_viewed)s, %(last_viewed_at)s, %(csv_exported)s, %(csv_exported_at)s, %(csv_exported_by_user_id)s::UUID, %(client_comments)s, %(client_viewed_at)s, %(id)s::UUID, %(created_at)s, %(updated_at)s, %(deleted_at)s)]
192
+ [parameters: [{'status': 'draft', 'discount_amount': Decimal('0.00'), 'version': 1, 'amount_paid': Decimal('0.00'), 'billing_period_start': datetime.date(2025, 12, ... (2074 characters truncated) ... id': None, 'paid_date': None, 'client_viewed_at': None, 'terms_and_conditions': None, 'viewing_token': None, 'payment_notes': None, 'sent_date': None}]]
193
+ INFO: 10.16.13.79:19719 - "GET /health HTTP/1.1" 200 OK
194
+ INFO: 2025-12-15T11:45:21 - app.services.invoice_generation_service: Applying tiered pricing for 1 tickets
195
+ INFO: 10.16.25.209:13928 - "POST /api/v1/invoices/generate HTTP/1.1" 500 Internal Server Error
196
+ ERROR: Exception in ASGI application
197
+ Traceback (most recent call last):
198
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 1814, in _execute_context
199
+ context = constructor(
200
+ ^^^^^^^^^^^^
201
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/default.py", line 1487, in _init_compiled
202
+ d_param = {
203
+ ^
204
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/default.py", line 1488, in <dictcomp>
205
+ key: flattened_processors[key](compiled_params[key])
206
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
207
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/sql/sqltypes.py", line 2717, in process
208
+ return json_serializer(value)
209
+ ^^^^^^^^^^^^^^^^^^^^^^
210
+ File "/usr/local/lib/python3.11/json/__init__.py", line 231, in dumps
211
+ return _default_encoder.encode(obj)
212
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
213
+ File "/usr/local/lib/python3.11/json/encoder.py", line 200, in encode
214
+ chunks = self.iterencode(o, _one_shot=True)
215
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
216
+ File "/usr/local/lib/python3.11/json/encoder.py", line 258, in iterencode
217
+ return _iterencode(o, 0)
218
+ ^^^^^^^^^^^^^^^^^
219
+ File "/usr/local/lib/python3.11/json/encoder.py", line 180, in default
220
+ raise TypeError(f'Object of type {o.__class__.__name__} '
221
+ TypeError: Object of type Decimal is not JSON serializable
222
+
223
+ The above exception was the direct cause of the following exception:
224
+
225
+ Traceback (most recent call last):
226
+ File "/usr/local/lib/python3.11/site-packages/uvicorn/protocols/http/httptools_impl.py", line 426, in run_asgi
227
+ result = await app( # type: ignore[func-returns-value]
228
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
229
+ File "/usr/local/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
230
+ return await self.app(scope, receive, send)
231
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
232
+ File "/usr/local/lib/python3.11/site-packages/fastapi/applications.py", line 1106, in __call__
233
+ await super().__call__(scope, receive, send)
234
+ File "/usr/local/lib/python3.11/site-packages/starlette/applications.py", line 122, in __call__
235
+ await self.middleware_stack(scope, receive, send)
236
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 184, in __call__
237
+ raise exc
238
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in __call__
239
+ await self.app(scope, receive, _send)
240
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/cors.py", line 91, in __call__
241
+ await self.simple_response(scope, receive, send, request_headers=headers)
242
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/cors.py", line 146, in simple_response
243
+ await self.app(scope, receive, send)
244
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
245
+ raise exc
246
+ File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
247
+ await self.app(scope, receive, sender)
248
+ File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
249
+ raise e
250
+ File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
251
+ await self.app(scope, receive, send)
252
+ File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 718, in __call__
253
+ await route.handle(scope, receive, send)
254
+ File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 276, in handle
255
+ await self.app(scope, receive, send)
256
+ File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 66, in app
257
+ response = await func(request)
258
+ ^^^^^^^^^^^^^^^^^^^
259
+ File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 274, in app
260
+ raw_response = await run_endpoint_function(
261
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
262
+ File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 193, in run_endpoint_function
263
+ return await run_in_threadpool(dependant.call, **values)
264
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
265
+ File "/usr/local/lib/python3.11/site-packages/starlette/concurrency.py", line 41, in run_in_threadpool
266
+ return await anyio.to_thread.run_sync(func, *args)
267
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
268
+ File "/usr/local/lib/python3.11/site-packages/anyio/to_thread.py", line 33, in run_sync
269
+ return await get_asynclib().run_sync_in_worker_thread(
270
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
271
+ File "/usr/local/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 877, in run_sync_in_worker_thread
272
+ return await future
273
+ ^^^^^^^^^^^^
274
+ File "/usr/local/lib/python3.11/site-packages/anyio/_backends/_asyncio.py", line 807, in run
275
+ result = context.run(func, *args)
276
+ ^^^^^^^^^^^^^^^^^^^^^^^^
277
+ File "/app/src/app/api/v1/invoice_generation.py", line 187, in generate_invoice
278
+ invoice, viewing_link, csv_link, notification_ids = InvoiceGenerationService.generate_invoice_from_tickets(
279
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
280
+ File "/app/src/app/services/invoice_generation_service.py", line 278, in generate_invoice_from_tickets
281
+ db.flush()
282
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/session.py", line 4312, in flush
283
+ self._flush(objects)
284
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/session.py", line 4447, in _flush
285
+ with util.safe_reraise():
286
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/util/langhelpers.py", line 146, in __exit__
287
+ raise exc_value.with_traceback(exc_tb)
288
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/session.py", line 4408, in _flush
289
+ flush_context.execute()
290
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/unitofwork.py", line 466, in execute
291
+ rec.execute(self)
292
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/unitofwork.py", line 642, in execute
293
+ util.preloaded.orm_persistence.save_obj(
294
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/persistence.py", line 93, in save_obj
295
+ _emit_insert_statements(
296
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/orm/persistence.py", line 1226, in _emit_insert_statements
297
+ result = connection.execute(
298
+ ^^^^^^^^^^^^^^^^^^^
299
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 1416, in execute
300
+ return meth(
301
+ ^^^^^
302
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/sql/elements.py", line 516, in _execute_on_connection
303
+ return connection._execute_clauseelement(
304
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
305
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 1639, in _execute_clauseelement
306
+ ret = self._execute_context(
307
+ ^^^^^^^^^^^^^^^^^^^^^^
308
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 1820, in _execute_context
309
+ self._handle_dbapi_exception(
310
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 2343, in _handle_dbapi_exception
311
+ raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
312
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/base.py", line 1814, in _execute_context
313
+ context = constructor(
314
+ ^^^^^^^^^^^^
315
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/default.py", line 1487, in _init_compiled
316
+ d_param = {
317
+ ^
318
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/engine/default.py", line 1488, in <dictcomp>
319
+ key: flattened_processors[key](compiled_params[key])
320
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
321
+ File "/usr/local/lib/python3.11/site-packages/sqlalchemy/sql/sqltypes.py", line 2717, in process
322
+ return json_serializer(value)
323
+ ^^^^^^^^^^^^^^^^^^^^^^
324
+ File "/usr/local/lib/python3.11/json/__init__.py", line 231, in dumps
325
+ return _default_encoder.encode(obj)
326
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
327
+ File "/usr/local/lib/python3.11/json/encoder.py", line 200, in encode
328
+ chunks = self.iterencode(o, _one_shot=True)
329
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
330
+ File "/usr/local/lib/python3.11/json/encoder.py", line 258, in iterencode
331
+ return _iterencode(o, 0)
332
+ ^^^^^^^^^^^^^^^^^
333
+ File "/usr/local/lib/python3.11/json/encoder.py", line 180, in default
334
+ raise TypeError(f'Object of type {o.__class__.__name__} '
335
+ sqlalchemy.exc.StatementError: (builtins.TypeError) Object of type Decimal is not JSON serializable
336
+ [SQL: INSERT INTO contractor_invoices (contractor_id, client_id, project_id, invoice_number, invoice_title, billing_period_start, billing_period_end, subtotal, tax_rate, tax_amount, discount_amount, total_amount, amount_paid, currency, line_items, status, issue_date, due_date, sent_date, paid_date, payment_method, payment_reference, payment_notes, notes, terms_and_conditions, additional_metadata, created_by_user_id, version, previous_version_id, is_latest_version, revision_notes, viewing_token, viewing_token_expires_at, viewing_token_created_by, times_viewed, last_viewed_at, csv_exported, csv_exported_at, csv_exported_by_user_id, client_comments, client_viewed_at, id, created_at, updated_at, deleted_at) VALUES (%(contractor_id)s::UUID, %(client_id)s::UUID, %(project_id)s::UUID, %(invoice_number)s, %(invoice_title)s, %(billing_period_start)s, %(billing_period_end)s, %(subtotal)s, %(tax_rate)s, %(tax_amount)s, %(discount_amount)s, %(total_amount)s, %(amount_paid)s, %(currency)s, %(line_items)s, %(status)s, %(issue_date)s, %(due_date)s, %(sent_date)s, %(paid_date)s, %(payment_method)s, %(payment_reference)s, %(payment_notes)s, %(notes)s, %(terms_and_conditions)s, %(additional_metadata)s, %(created_by_user_id)s::UUID, %(version)s, %(previous_version_id)s::UUID, %(is_latest_version)s, %(revision_notes)s, %(viewing_token)s, %(viewing_token_expires_at)s, %(viewing_token_created_by)s::UUID, %(times_viewed)s, %(last_viewed_at)s, %(csv_exported)s, %(csv_exported_at)s, %(csv_exported_by_user_id)s::UUID, %(client_comments)s, %(client_viewed_at)s, %(id)s::UUID, %(created_at)s, %(updated_at)s, %(deleted_at)s)]
337
+ [parameters: [{'status': 'draft', 'discount_amount': Decimal('0.00'), 'version': 1, 'amount_paid': Decimal('0.00'), 'billing_period_start': datetime.date(2025, 12, ... (2074 characters truncated) ... id': None, 'paid_date': None, 'client_viewed_at': None, 'terms_and_conditions': None, 'viewing_token': None, 'payment_notes': None, 'sent_date': None}]]
338
+ INFO: 10.16.13.79:57926 - "GET /health HTTP/1.1" 200 OK
339
+ INFO: 10.16.13.79:45014 - "GET /health HTTP/1.1" 200 OK
src/app/services/invoice_generation_service.py CHANGED
@@ -36,6 +36,27 @@ from app.services.invoice_pricing_service import InvoicePricingService
36
  logger = logging.getLogger(__name__)
37
 
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  class InvoiceGenerationService:
40
  """Service for generating invoices from completed tickets"""
41
 
@@ -270,7 +291,7 @@ class InvoiceGenerationService:
270
  previous_version_id=None,
271
  revision_notes="Initial version" + (f" - {pricing_result.pricing_model} pricing applied" if pricing_result else " - Proof of work invoice"),
272
  additional_metadata={
273
- "pricing_calculation": pricing_result.model_dump() if pricing_result else None
274
  }
275
  )
276
 
 
36
  logger = logging.getLogger(__name__)
37
 
38
 
39
+ def _convert_decimals_to_float(obj):
40
+ """
41
+ Recursively convert Decimal objects to float for JSON serialization
42
+
43
+ Args:
44
+ obj: Object to convert (dict, list, or primitive)
45
+
46
+ Returns:
47
+ Object with all Decimals converted to float
48
+ """
49
+ from decimal import Decimal
50
+ if isinstance(obj, Decimal):
51
+ return float(obj)
52
+ elif isinstance(obj, dict):
53
+ return {k: _convert_decimals_to_float(v) for k, v in obj.items()}
54
+ elif isinstance(obj, list):
55
+ return [_convert_decimals_to_float(item) for item in obj]
56
+ else:
57
+ return obj
58
+
59
+
60
  class InvoiceGenerationService:
61
  """Service for generating invoices from completed tickets"""
62
 
 
291
  previous_version_id=None,
292
  revision_notes="Initial version" + (f" - {pricing_result.pricing_model} pricing applied" if pricing_result else " - Proof of work invoice"),
293
  additional_metadata={
294
+ "pricing_calculation": _convert_decimals_to_float(pricing_result.model_dump()) if pricing_result else None
295
  }
296
  )
297