dao-treasury 0.0.35__cp311-cp311-win_amd64.whl → 0.1.1__cp311-cp311-win_amd64.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.

Potentially problematic release.


This version of dao-treasury might be problematic. Click here for more details.

Files changed (49) hide show
  1. dao_treasury/.grafana/provisioning/dashboards/breakdowns/Expenses.json +567 -0
  2. dao_treasury/.grafana/provisioning/dashboards/breakdowns/Revenue.json +569 -0
  3. dao_treasury/.grafana/provisioning/dashboards/dashboards.yaml +7 -57
  4. dao_treasury/.grafana/provisioning/dashboards/streams/LlamaPay.json +15 -27
  5. dao_treasury/.grafana/provisioning/dashboards/summary/Monthly.json +286 -25
  6. dao_treasury/.grafana/provisioning/dashboards/transactions/Treasury Transactions.json +54 -71
  7. dao_treasury/.grafana/provisioning/dashboards/transactions/Unsorted Transactions.json +367 -0
  8. dao_treasury/.grafana/provisioning/dashboards/treasury/Cashflow (Including Unsorted).json +172 -209
  9. dao_treasury/.grafana/provisioning/dashboards/treasury/Cashflow.json +122 -142
  10. dao_treasury/.grafana/provisioning/dashboards/treasury/Current Treasury Assets.json +941 -0
  11. dao_treasury/.grafana/provisioning/dashboards/treasury/Historical Treasury Balances.json +3931 -0
  12. dao_treasury/.grafana/provisioning/dashboards/treasury/Operating Cashflow.json +89 -108
  13. dao_treasury/.grafana/provisioning/datasources/datasources.yaml +9 -4
  14. dao_treasury/ENVIRONMENT_VARIABLES.py +12 -0
  15. dao_treasury/__init__.py +14 -4
  16. dao_treasury/_docker.cp311-win_amd64.pyd +0 -0
  17. dao_treasury/_docker.py +44 -23
  18. dao_treasury/_nicknames.cp311-win_amd64.pyd +0 -0
  19. dao_treasury/_nicknames.py +18 -2
  20. dao_treasury/_wallet.cp311-win_amd64.pyd +0 -0
  21. dao_treasury/constants.cp311-win_amd64.pyd +0 -0
  22. dao_treasury/constants.py +24 -0
  23. dao_treasury/db.py +409 -119
  24. dao_treasury/docker-compose.yaml +19 -3
  25. dao_treasury/main.py +44 -3
  26. dao_treasury/sorting/__init__.cp311-win_amd64.pyd +0 -0
  27. dao_treasury/sorting/__init__.py +38 -21
  28. dao_treasury/sorting/_matchers.cp311-win_amd64.pyd +0 -0
  29. dao_treasury/sorting/_rules.cp311-win_amd64.pyd +0 -0
  30. dao_treasury/sorting/factory.cp311-win_amd64.pyd +0 -0
  31. dao_treasury/sorting/rule.cp311-win_amd64.pyd +0 -0
  32. dao_treasury/sorting/rule.py +8 -10
  33. dao_treasury/sorting/rules/__init__.cp311-win_amd64.pyd +0 -0
  34. dao_treasury/sorting/rules/ignore/__init__.cp311-win_amd64.pyd +0 -0
  35. dao_treasury/sorting/rules/ignore/llamapay.cp311-win_amd64.pyd +0 -0
  36. dao_treasury/streams/llamapay.py +14 -2
  37. dao_treasury/treasury.py +37 -16
  38. dao_treasury/types.cp311-win_amd64.pyd +0 -0
  39. {dao_treasury-0.0.35.dist-info → dao_treasury-0.1.1.dist-info}/METADATA +19 -3
  40. dao_treasury-0.1.1.dist-info/RECORD +53 -0
  41. dao_treasury-0.1.1.dist-info/top_level.txt +2 -0
  42. dao_treasury__mypyc.cp311-win_amd64.pyd +0 -0
  43. bf2b4fe1f86ad2ea158b__mypyc.cp311-win_amd64.pyd +0 -0
  44. dao_treasury/.grafana/provisioning/dashboards/treasury/Treasury.json +0 -2018
  45. dao_treasury/streams/__init__.cp311-win_amd64.pyd +0 -0
  46. dao_treasury/streams/llamapay.cp311-win_amd64.pyd +0 -0
  47. dao_treasury-0.0.35.dist-info/RECORD +0 -51
  48. dao_treasury-0.0.35.dist-info/top_level.txt +0 -2
  49. {dao_treasury-0.0.35.dist-info → dao_treasury-0.1.1.dist-info}/WHEEL +0 -0
@@ -18,16 +18,12 @@
18
18
  "editable": true,
19
19
  "fiscalYearStartMonth": 0,
20
20
  "graphTooltip": 0,
21
- "id": 7,
21
+ "id": 11,
22
22
  "links": [],
23
- "liveNow": false,
24
23
  "panels": [
25
24
  {
26
- "datasource": {
27
- "type": "frser-sqlite-datasource",
28
- "uid": "P2D2EEF3E092AF52B"
29
- },
30
- "description": "",
25
+ "datasource": "PostgreSQL",
26
+ "description": "Displays all LlamaPay payment streams managed by the DAO, including stream ID, factory, start/end block, token, sender, recipient, reason, budget request, amount per second, status, and transaction group.\n\nData Links: Click on addresses or blocks to view them on Etherscan. Click on a budget request to view the related Github issue.",
31
27
  "fieldConfig": {
32
28
  "defaults": {
33
29
  "color": {
@@ -46,7 +42,7 @@
46
42
  "steps": [
47
43
  {
48
44
  "color": "green",
49
- "value": null
45
+ "value": 0
50
46
  },
51
47
  {
52
48
  "color": "red",
@@ -178,37 +174,29 @@
178
174
  "footer": {
179
175
  "countRows": false,
180
176
  "fields": "",
181
- "reducer": [
182
- "sum"
183
- ],
177
+ "reducer": ["sum"],
184
178
  "show": false
185
179
  },
186
180
  "showHeader": true
187
181
  },
188
- "pluginVersion": "10.2.0",
182
+ "pluginVersion": "12.1.1",
189
183
  "targets": [
190
184
  {
191
- "datasource": {
192
- "type": "frser-sqlite-datasource",
193
- "uid": "P2D2EEF3E092AF52B"
194
- },
195
- "queryText": "SELECT\n stream_id as \"Stream ID\",\n b.address as \"Factory\",\n start_block as \"Start Block\",\n end_block as \"End Block\",\n c.symbol as \"Token\",\n d.address as \"From\",\n e.address as \"To\",\n reason as \"Reason\",\n CASE\n WHEN reason LIKE 'gh-%' AND\n -- ensures all after \"gh-\" is digits\n REPLACE(SUBSTR(reason, 4), '0', '') >= '' AND\n CAST(SUBSTR(reason, 4) AS INTEGER) || '' = SUBSTR(reason, 4)\n THEN CAST(SUBSTR(reason, 4) AS INTEGER)\n ELSE NULL\n END AS \"Budget Request\",\n amount_per_second as \"Amount Per Second\",\n status as \"Status\",\n txgroup as \"TxGroup\"\n\nFROM streams a\nLEFT JOIN addresses b ON a.contract = b.address_id\nLEFT JOIN tokens c ON a.token = c.token_id\nLEFT JOIN addresses d ON a.from_address = d.address_id\nLEFT JOIN addresses e ON a.to_address = e.address_id",
196
- "queryType": "table",
197
- "rawQueryText": "SELECT\n stream_id as \"Stream ID\",\n b.address as \"Factory\",\n start_block as \"Start Block\",\n end_block as \"End Block\",\n c.symbol as \"Token\",\n d.address as \"From\",\n e.address as \"To\",\n reason as \"Reason\",\n CASE\n WHEN reason LIKE 'gh-%' AND\n -- ensures all after \"gh-\" is digits\n REPLACE(SUBSTR(reason, 4), '0', '') >= '' AND\n CAST(SUBSTR(reason, 4) AS INTEGER) || '' = SUBSTR(reason, 4)\n THEN CAST(SUBSTR(reason, 4) AS INTEGER)\n ELSE NULL\n END AS \"Budget Request\",\n amount_per_second as \"Amount Per Second\",\n status as \"Status\",\n txgroup as \"TxGroup\"\n\nFROM streams a\nLEFT JOIN addresses b ON a.contract = b.address_id\nLEFT JOIN tokens c ON a.token = c.token_id\nLEFT JOIN addresses d ON a.from_address = d.address_id\nLEFT JOIN addresses e ON a.to_address = e.address_id",
185
+ "datasource": "PostgreSQL",
186
+ "format": "table",
187
+ "rawSql": "SELECT\n stream_id as \"Stream ID\",\n b.address as \"Factory\",\n start_block as \"Start Block\",\n end_block as \"End Block\",\n c.symbol as \"Token\",\n d.address as \"From\",\n e.address as \"To\",\n reason as \"Reason\",\n CASE\n WHEN reason LIKE 'gh-%' AND\n -- ensures all after \"gh-\" is digits\n REPLACE(SUBSTR(reason, 4), '0', '') >= '' AND\n CAST(SUBSTR(reason, 4) AS INTEGER) || '' = SUBSTR(reason, 4)\n THEN CAST(SUBSTR(reason, 4) AS INTEGER)\n ELSE NULL\n END AS \"Budget Request\",\n amount_per_second as \"Amount Per Second\",\n status as \"Status\",\n txgroup as \"TxGroup\"\n\nFROM streams a\nLEFT JOIN addresses b ON a.contract = b.address_id\nLEFT JOIN tokens c ON a.token = c.token_id\nLEFT JOIN addresses d ON a.from_address = d.address_id\nLEFT JOIN addresses e ON a.to_address = e.address_id",
198
188
  "refId": "A",
199
- "timeColumns": [
200
- "time",
201
- "ts"
202
- ]
189
+ "timeColumns": ["time", "ts"]
203
190
  }
204
191
  ],
205
192
  "title": "LlamaPay Streams",
206
193
  "type": "table"
207
194
  }
208
195
  ],
196
+ "preload": false,
209
197
  "refresh": "",
210
- "schemaVersion": 38,
211
- "tags": [],
198
+ "schemaVersion": 41,
199
+ "tags": ["streams", "llamapay", "payments"],
212
200
  "templating": {
213
201
  "list": []
214
202
  },
@@ -219,7 +207,7 @@
219
207
  "timepicker": {},
220
208
  "timezone": "",
221
209
  "title": "LlamaPay",
210
+ "description": "A simple dashboard with a comprehensive view of all LlamaPay payment streams managed by the DAO, including stream status, participants, configuration, and transaction group.",
222
211
  "uid": "aa4d62a2-9e52-4acc-8f38-a96c77810aca",
223
- "version": 2,
224
- "weekStart": ""
212
+ "version": 5
225
213
  }
@@ -12,46 +12,314 @@
12
12
  }
13
13
  ]
14
14
  },
15
+ "description": "Summarizes the DAO's monthly profit and loss, providing a breakdown of sorted and unsorted financial activity for each month. Supports financial reporting and tracking the progress of transaction categorization.",
15
16
  "editable": true,
16
17
  "fiscalYearStartMonth": 0,
17
18
  "graphTooltip": 0,
18
19
  "id": 2,
19
20
  "links": [],
20
- "liveNow": false,
21
21
  "panels": [
22
22
  {
23
- "datasource": "SQLite",
23
+ "datasource": "PostgreSQL",
24
+ "description": "Displays a table of monthly profit and loss for the DAO, including Revenue, Cost of Revenue, Expenses, Other Income, Other Expense, Sorted Net, Unsorted Income, Unsorted Expense.\n\nUseful for high-level financial reporting and tracking the progress of transaction categorization.\n\nClick on any underlined cell value to see all transactions for that transaction group and time period.\n\nYou can download this table as a CSV. Click on the three dots in the upper right corner, navigate \"Inspect\" -> \"Data\", select your desired options and click \"Download CSV\".",
24
25
  "fieldConfig": {
25
26
  "defaults": {
26
27
  "color": {
27
- "mode": "thresholds"
28
+ "mode": "continuous-RdYlGr"
28
29
  },
29
30
  "custom": {
30
31
  "align": "auto",
31
32
  "cellOptions": {
32
33
  "type": "auto"
33
34
  },
34
- "inspect": false
35
+ "footer": {
36
+ "reducers": ["sum", "max", "mean", "median"]
37
+ },
38
+ "inspect": true
35
39
  },
40
+ "fieldMinMax": true,
41
+ "links": [
42
+ {
43
+ "targetBlank": true,
44
+ "title": "View ${__field.name} transactions for this period",
45
+ "url": "/d/b21f1092-66a4-4fb0-90ef-ed77d2becaa4/treasury-transactions?var-Top=${__field.name}&from=${__data.fields.month_start}&to=${__data.fields.month_end}"
46
+ }
47
+ ],
36
48
  "mappings": [],
37
49
  "thresholds": {
38
50
  "mode": "absolute",
39
51
  "steps": [
40
52
  {
41
53
  "color": "green",
42
- "value": null
54
+ "value": 0
43
55
  },
44
56
  {
45
57
  "color": "red",
46
58
  "value": 80
47
59
  }
48
60
  ]
49
- }
61
+ },
62
+ "unit": "currencyUSD"
50
63
  },
51
- "overrides": []
64
+ "overrides": [
65
+ {
66
+ "matcher": {
67
+ "id": "byName",
68
+ "options": "Sorted Net"
69
+ },
70
+ "properties": [
71
+ {
72
+ "id": "custom.cellOptions",
73
+ "value": {
74
+ "type": "color-text"
75
+ }
76
+ },
77
+ {
78
+ "id": "links"
79
+ }
80
+ ]
81
+ },
82
+ {
83
+ "matcher": {
84
+ "id": "byName",
85
+ "options": "Net"
86
+ },
87
+ "properties": [
88
+ {
89
+ "id": "custom.cellOptions",
90
+ "value": {
91
+ "type": "color-text"
92
+ }
93
+ },
94
+ {
95
+ "id": "links"
96
+ }
97
+ ]
98
+ },
99
+ {
100
+ "matcher": {
101
+ "id": "byName",
102
+ "options": "Unsorted Income"
103
+ },
104
+ "properties": [
105
+ {
106
+ "id": "custom.cellOptions",
107
+ "value": {
108
+ "type": "color-text"
109
+ }
110
+ },
111
+ {
112
+ "id": "color",
113
+ "value": {
114
+ "mode": "fixed"
115
+ }
116
+ }
117
+ ]
118
+ },
119
+ {
120
+ "matcher": {
121
+ "id": "byName",
122
+ "options": "Unsorted Expenses"
123
+ },
124
+ "properties": [
125
+ {
126
+ "id": "custom.cellOptions",
127
+ "value": {
128
+ "type": "color-text"
129
+ }
130
+ },
131
+ {
132
+ "id": "color",
133
+ "value": {
134
+ "mode": "fixed"
135
+ }
136
+ }
137
+ ]
138
+ },
139
+ {
140
+ "matcher": {
141
+ "id": "byName",
142
+ "options": "Other Income"
143
+ },
144
+ "properties": [
145
+ {
146
+ "id": "custom.cellOptions",
147
+ "value": {
148
+ "type": "color-text"
149
+ }
150
+ },
151
+ {
152
+ "id": "color",
153
+ "value": {
154
+ "mode": "fixed"
155
+ }
156
+ }
157
+ ]
158
+ },
159
+ {
160
+ "matcher": {
161
+ "id": "byName",
162
+ "options": "Other Expenses"
163
+ },
164
+ "properties": [
165
+ {
166
+ "id": "custom.cellOptions",
167
+ "value": {
168
+ "type": "color-text"
169
+ }
170
+ },
171
+ {
172
+ "id": "color",
173
+ "value": {
174
+ "mode": "fixed"
175
+ }
176
+ }
177
+ ]
178
+ },
179
+ {
180
+ "matcher": {
181
+ "id": "byName",
182
+ "options": "Operating Net"
183
+ },
184
+ "properties": [
185
+ {
186
+ "id": "custom.cellOptions",
187
+ "value": {
188
+ "type": "color-text"
189
+ }
190
+ },
191
+ {
192
+ "id": "color",
193
+ "value": {
194
+ "mode": "continuous-RdYlGr"
195
+ }
196
+ },
197
+ {
198
+ "id": "links"
199
+ }
200
+ ]
201
+ },
202
+ {
203
+ "matcher": {
204
+ "id": "byName",
205
+ "options": "month_start"
206
+ },
207
+ "properties": [
208
+ {
209
+ "id": "unit"
210
+ },
211
+ {
212
+ "id": "custom.hideFrom.viz",
213
+ "value": true
214
+ }
215
+ ]
216
+ },
217
+ {
218
+ "matcher": {
219
+ "id": "byName",
220
+ "options": "month_end"
221
+ },
222
+ "properties": [
223
+ {
224
+ "id": "unit"
225
+ },
226
+ {
227
+ "id": "custom.hideFrom.viz",
228
+ "value": true
229
+ }
230
+ ]
231
+ },
232
+ {
233
+ "matcher": {
234
+ "id": "byName",
235
+ "options": "Revenue"
236
+ },
237
+ "properties": [
238
+ {
239
+ "id": "custom.cellOptions",
240
+ "value": {
241
+ "type": "color-text"
242
+ }
243
+ },
244
+ {
245
+ "id": "color",
246
+ "value": {
247
+ "fixedColor": "#ffffff",
248
+ "mode": "fixed"
249
+ }
250
+ }
251
+ ]
252
+ },
253
+ {
254
+ "matcher": {
255
+ "id": "byName",
256
+ "options": "Expenses"
257
+ },
258
+ "properties": [
259
+ {
260
+ "id": "custom.cellOptions",
261
+ "value": {
262
+ "type": "color-text"
263
+ }
264
+ },
265
+ {
266
+ "id": "color",
267
+ "value": {
268
+ "fixedColor": "#ffffff",
269
+ "mode": "fixed"
270
+ }
271
+ }
272
+ ]
273
+ },
274
+ {
275
+ "matcher": {
276
+ "id": "byName",
277
+ "options": "Cost of Revenue"
278
+ },
279
+ "properties": [
280
+ {
281
+ "id": "color",
282
+ "value": {
283
+ "fixedColor": "#ffffff",
284
+ "mode": "fixed"
285
+ }
286
+ },
287
+ {
288
+ "id": "custom.cellOptions",
289
+ "value": {
290
+ "type": "color-text"
291
+ }
292
+ }
293
+ ]
294
+ },
295
+ {
296
+ "matcher": {
297
+ "id": "byName",
298
+ "options": "Month"
299
+ },
300
+ "properties": [
301
+ {
302
+ "id": "color",
303
+ "value": {
304
+ "fixedColor": "#ffffff",
305
+ "mode": "fixed"
306
+ }
307
+ },
308
+ {
309
+ "id": "custom.cellOptions",
310
+ "value": {
311
+ "type": "color-text"
312
+ }
313
+ },
314
+ {
315
+ "id": "links"
316
+ }
317
+ ]
318
+ }
319
+ ]
52
320
  },
53
321
  "gridPos": {
54
- "h": 9,
322
+ "h": 20,
55
323
  "w": 24,
56
324
  "x": 0,
57
325
  "y": 0
@@ -59,14 +327,6 @@
59
327
  "id": 1,
60
328
  "options": {
61
329
  "cellHeight": "sm",
62
- "footer": {
63
- "countRows": false,
64
- "fields": "",
65
- "reducer": [
66
- "sum"
67
- ],
68
- "show": false
69
- },
70
330
  "showHeader": true,
71
331
  "sortBy": [
72
332
  {
@@ -75,33 +335,34 @@
75
335
  }
76
336
  ]
77
337
  },
78
- "pluginVersion": "10.2.0",
338
+ "pluginVersion": "12.2.1",
79
339
  "targets": [
80
340
  {
81
- "datasource": "SQLite",
82
- "queryText": "SELECT\n month AS \"Month\",\n SUM(CASE WHEN s.top_category = 'Revenue' THEN value_usd ELSE 0 END) AS \"Revenue\",\n SUM(CASE WHEN s.top_category = 'Cost of Revenue' THEN value_usd ELSE 0 END) AS \"Cost of Revenue\",\n SUM(CASE WHEN s.top_category = 'Expenses' THEN value_usd ELSE 0 END) AS \"Expenses\",\n SUM(CASE WHEN s.top_category = 'Other Income' THEN value_usd ELSE 0 END) AS \"Other Income\",\n SUM(CASE WHEN s.top_category = 'Other Expenses' THEN value_usd ELSE 0 END) AS \"Other Expense\",\n (\n SUM(CASE WHEN s.top_category = 'Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Cost of Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Expenses' THEN value_usd ELSE 0 END)\n + SUM(CASE WHEN s.top_category = 'Other Income' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Other Expenses' THEN value_usd ELSE 0 END)\n ) AS \"Sorted Net\",\n SUM(CASE WHEN s.top_category = 'Sort Me (Inbound)' THEN value_usd ELSE 0 END) AS \"Unsorted Income\",\n SUM(CASE WHEN s.top_category = 'Sort Me (Outbound)' THEN value_usd ELSE 0 END) AS \"Unsorted Expense\",\n (\n SUM(CASE WHEN s.top_category = 'Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Cost of Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Expenses' THEN value_usd ELSE 0 END)\n + SUM(CASE WHEN s.top_category = 'Other Income' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Other Expenses' THEN value_usd ELSE 0 END)\n + SUM(CASE WHEN s.top_category = 'Sort Me (Inbound)' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Sort Me (Outbound)' THEN value_usd ELSE 0 END)\n ) AS \"Net\"\nFROM (\n SELECT\n strftime('%Y-%m', datetime(t.timestamp, 'unixepoch')) AS month,\n gh.top_category,\n COALESCE(t.value_usd, 0) AS value_usd\n FROM treasury_txs AS t\n JOIN txgroups AS tg ON t.txgroup_id = tg.txgroup_id\n JOIN txgroup_hierarchy AS gh ON tg.txgroup_id = gh.txgroup_id\n WHERE t.timestamp >= strftime('%s', '2025-01-01') AND tg.name <> 'Ignore'\n) AS s\nGROUP BY month;",
83
- "queryType": "table",
84
- "rawQueryText": "SELECT\n month AS \"Month\",\n SUM(CASE WHEN s.top_category = 'Revenue' THEN value_usd ELSE 0 END) AS \"Revenue\",\n SUM(CASE WHEN s.top_category = 'Cost of Revenue' THEN value_usd ELSE 0 END) AS \"Cost of Revenue\",\n SUM(CASE WHEN s.top_category = 'Expenses' THEN value_usd ELSE 0 END) AS \"Expenses\",\n SUM(CASE WHEN s.top_category = 'Other Income' THEN value_usd ELSE 0 END) AS \"Other Income\",\n SUM(CASE WHEN s.top_category = 'Other Expenses' THEN value_usd ELSE 0 END) AS \"Other Expense\",\n (\n SUM(CASE WHEN s.top_category = 'Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Cost of Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Expenses' THEN value_usd ELSE 0 END)\n + SUM(CASE WHEN s.top_category = 'Other Income' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Other Expenses' THEN value_usd ELSE 0 END)\n ) AS \"Sorted Net\",\n SUM(CASE WHEN s.top_category = 'Sort Me (Inbound)' THEN value_usd ELSE 0 END) AS \"Unsorted Income\",\n SUM(CASE WHEN s.top_category = 'Sort Me (Outbound)' THEN value_usd ELSE 0 END) AS \"Unsorted Expense\",\n (\n SUM(CASE WHEN s.top_category = 'Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Cost of Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Expenses' THEN value_usd ELSE 0 END)\n + SUM(CASE WHEN s.top_category = 'Other Income' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Other Expenses' THEN value_usd ELSE 0 END)\n + SUM(CASE WHEN s.top_category = 'Sort Me (Inbound)' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Sort Me (Outbound)' THEN value_usd ELSE 0 END)\n ) AS \"Net\"\nFROM (\n SELECT\n strftime('%Y-%m', datetime(t.timestamp, 'unixepoch')) AS month,\n gh.top_category,\n COALESCE(t.value_usd, 0) AS value_usd\n FROM treasury_txs AS t\n JOIN txgroups AS tg ON t.txgroup_id = tg.txgroup_id\n JOIN txgroup_hierarchy AS gh ON tg.txgroup_id = gh.txgroup_id\n WHERE t.timestamp >= strftime('%s', '2025-01-01') AND tg.name <> 'Ignore'\n) AS s\nGROUP BY month;"
341
+ "datasource": "PostgreSQL",
342
+ "format": "table",
343
+ "rawSql": "SELECT\n month AS \"Month\",\n SUM(CASE WHEN s.top_category = 'Revenue' THEN value_usd ELSE 0 END) AS \"Revenue\",\n SUM(CASE WHEN s.top_category = 'Cost of Revenue' THEN value_usd ELSE 0 END) AS \"Cost of Revenue\",\n SUM(CASE WHEN s.top_category = 'Expenses' THEN value_usd ELSE 0 END) AS \"Expenses\",\n (\n SUM(CASE WHEN s.top_category = 'Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Cost of Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Expenses' THEN value_usd ELSE 0 END)\n ) AS \"Operating Net\",\n SUM(CASE WHEN s.top_category = 'Other Income' THEN value_usd ELSE 0 END) AS \"Other Income\",\n SUM(CASE WHEN s.top_category = 'Other Expenses' THEN value_usd ELSE 0 END) AS \"Other Expenses\",\n (\n SUM(CASE WHEN s.top_category = 'Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Cost of Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Expenses' THEN value_usd ELSE 0 END)\n + SUM(CASE WHEN s.top_category = 'Other Income' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Other Expenses' THEN value_usd ELSE 0 END)\n ) AS \"Sorted Net\",\n SUM(CASE WHEN s.top_category = 'Sort Me (Inbound)' THEN value_usd ELSE 0 END) AS \"Unsorted Income\",\n SUM(CASE WHEN s.top_category = 'Sort Me (Outbound)' THEN value_usd ELSE 0 END) AS \"Unsorted Expenses\",\n (\n SUM(CASE WHEN s.top_category = 'Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Cost of Revenue' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Expenses' THEN value_usd ELSE 0 END)\n + SUM(CASE WHEN s.top_category = 'Other Income' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Other Expenses' THEN value_usd ELSE 0 END)\n + SUM(CASE WHEN s.top_category = 'Sort Me (Inbound)' THEN value_usd ELSE 0 END)\n - SUM(CASE WHEN s.top_category = 'Sort Me (Outbound)' THEN value_usd ELSE 0 END)\n ) AS \"Net\",\n -- Month Start as UNIX timestamp (midnight on the first day)\n CAST(EXTRACT(EPOCH FROM (to_date(month || '-01', 'YYYY-MM-DD'))) * 1000 AS TEXT) AS \"month_start\",\n -- Month End as UNIX timestamp (one millisecond before the next month starts)\n CAST(EXTRACT(EPOCH FROM (to_date(month || '-01', 'YYYY-MM-DD') + INTERVAL '1 month' - INTERVAL '1 millisecond')) * 1000 AS TEXT) AS \"month_end\"\nFROM (\n SELECT\n to_char(to_timestamp(t.timestamp), 'YYYY-MM') AS month,\n gh.top_category,\n COALESCE(t.value_usd, 0) AS value_usd\n FROM treasury_txs AS t\n JOIN txgroups AS tg ON t.txgroup_id = tg.txgroup_id\n JOIN txgroup_hierarchy AS gh ON tg.txgroup_id = gh.txgroup_id\n WHERE t.timestamp >= EXTRACT(EPOCH FROM TIMESTAMP '2025-01-01') AND tg.name <> 'Ignore'\n) AS s\nGROUP BY month;",
344
+ "refId": "A",
345
+ "timeColumns": ["time", "ts"]
85
346
  }
86
347
  ],
87
348
  "title": "Monthly Profit & Loss",
88
349
  "type": "table"
89
350
  }
90
351
  ],
352
+ "preload": false,
91
353
  "refresh": "",
92
- "schemaVersion": 38,
354
+ "schemaVersion": 42,
93
355
  "tags": [],
94
356
  "templating": {
95
357
  "list": []
96
358
  },
97
359
  "time": {
98
- "from": "now-6h",
360
+ "from": "now/y",
99
361
  "to": "now"
100
362
  },
101
363
  "timepicker": {},
102
364
  "timezone": "",
103
365
  "title": "Monthly P&L",
104
366
  "uid": "a63fa9a7-d4f3-4092-9bde-194add8bcbeb",
105
- "version": 1,
106
- "weekStart": ""
367
+ "version": 9
107
368
  }