@powerhousedao/contributor-billing 0.1.37 → 0.1.39
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.
- package/dist/document-models/account-transactions/gen/schema/types.d.ts +3 -3
- package/dist/document-models/account-transactions/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/accounts/gen/schema/types.d.ts +7 -7
- package/dist/document-models/accounts/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/billing-statement/gen/document-schema.d.ts +16 -16
- package/dist/document-models/billing-statement/gen/document-schema.d.ts.map +1 -1
- package/dist/document-models/billing-statement/gen/schema/types.d.ts +5 -5
- package/dist/document-models/billing-statement/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/expense-report/gen/document-model.js +1 -1
- package/dist/document-models/expense-report/gen/document-schema.d.ts +16 -16
- package/dist/document-models/expense-report/gen/ph-factories.d.ts.map +1 -1
- package/dist/document-models/expense-report/gen/ph-factories.js +5 -0
- package/dist/document-models/expense-report/gen/schema/types.d.ts +2 -2
- package/dist/document-models/expense-report/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/expense-report/gen/schema/zod.d.ts.map +1 -1
- package/dist/document-models/expense-report/gen/schema/zod.js +10 -30
- package/dist/document-models/expense-report/gen/utils.d.ts.map +1 -1
- package/dist/document-models/expense-report/gen/utils.js +5 -0
- package/dist/document-models/expense-report/src/reducers/wallet.d.ts.map +1 -1
- package/dist/document-models/expense-report/src/reducers/wallet.js +61 -0
- package/dist/document-models/invoice/gen/document-schema.d.ts +32 -32
- package/dist/document-models/invoice/gen/document-schema.d.ts.map +1 -1
- package/dist/document-models/invoice/gen/schema/types.d.ts +10 -10
- package/dist/document-models/invoice/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/invoice/gen/schema/zod.d.ts.map +1 -1
- package/dist/document-models/service-offering/gen/document-schema.d.ts +16 -16
- package/dist/document-models/service-offering/gen/document-schema.d.ts.map +1 -1
- package/dist/document-models/service-offering/gen/schema/types.d.ts +11 -11
- package/dist/document-models/service-offering/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/service-subscriptions/gen/schema/types.d.ts +6 -6
- package/dist/document-models/service-subscriptions/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/snapshot-report/gen/document-schema.d.ts.map +1 -1
- package/dist/document-models/snapshot-report/gen/schema/types.d.ts +8 -8
- package/dist/document-models/snapshot-report/gen/schema/types.d.ts.map +1 -1
- package/dist/document-models/snapshot-report/src/reducers/configuration.d.ts.map +1 -1
- package/dist/document-models/snapshot-report/src/reducers/configuration.js +1 -1
- package/dist/editors/accounts-editor/components/AccountForm.d.ts.map +1 -1
- package/dist/editors/accounts-editor/components/AccountForm.js +3 -1
- package/dist/editors/builder-team-admin/components/FolderTree.d.ts.map +1 -1
- package/dist/editors/builder-team-admin/components/FolderTree.js +2 -2
- package/dist/editors/contributor-billing/components/AddMonthButton.d.ts +5 -0
- package/dist/editors/contributor-billing/components/AddMonthButton.d.ts.map +1 -0
- package/dist/editors/contributor-billing/components/AddMonthButton.js +56 -0
- package/dist/editors/contributor-billing/components/BillingOverview.d.ts +10 -0
- package/dist/editors/contributor-billing/components/BillingOverview.d.ts.map +1 -0
- package/dist/editors/contributor-billing/components/BillingOverview.js +117 -0
- package/dist/editors/contributor-billing/components/DashboardHome.d.ts +11 -0
- package/dist/editors/contributor-billing/components/DashboardHome.d.ts.map +1 -0
- package/dist/editors/contributor-billing/components/DashboardHome.js +51 -0
- package/dist/editors/contributor-billing/components/DriveContents.d.ts +8 -2
- package/dist/editors/contributor-billing/components/DriveContents.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/DriveContents.js +24 -10
- package/dist/editors/contributor-billing/components/DriveExplorer.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/DriveExplorer.js +18 -3
- package/dist/editors/contributor-billing/components/FolderTree.d.ts +19 -9
- package/dist/editors/contributor-billing/components/FolderTree.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/FolderTree.js +200 -103
- package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.d.ts +8 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/HeaderControls.js +5 -3
- package/dist/editors/contributor-billing/components/InvoiceTable/HeaderStats.d.ts +6 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/HeaderStats.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/HeaderStats.js +14 -6
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTable.d.ts +6 -2
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTable.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTable.js +68 -19
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableContainer.d.ts +10 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableContainer.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableContainer.js +145 -32
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableRow.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableRow.js +6 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableSection.d.ts +1 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableSection.d.ts.map +1 -1
- package/dist/editors/contributor-billing/components/InvoiceTable/InvoiceTableSection.js +33 -7
- package/dist/editors/contributor-billing/components/MonthOverview.d.ts +12 -0
- package/dist/editors/contributor-billing/components/MonthOverview.d.ts.map +1 -0
- package/dist/editors/contributor-billing/components/MonthOverview.js +35 -0
- package/dist/editors/contributor-billing/components/MonthlyReporting.d.ts +13 -0
- package/dist/editors/contributor-billing/components/MonthlyReporting.d.ts.map +1 -0
- package/dist/editors/contributor-billing/components/MonthlyReporting.js +90 -0
- package/dist/editors/contributor-billing/components/ReportingView.d.ts +10 -0
- package/dist/editors/contributor-billing/components/ReportingView.d.ts.map +1 -0
- package/dist/editors/contributor-billing/components/ReportingView.js +112 -0
- package/dist/editors/contributor-billing/config.js +1 -1
- package/dist/editors/contributor-billing/hooks/useBillingFolderStructure.d.ts +54 -0
- package/dist/editors/contributor-billing/hooks/useBillingFolderStructure.d.ts.map +1 -0
- package/dist/editors/contributor-billing/hooks/useBillingFolderStructure.js +145 -0
- package/dist/editors/expense-report/components/AddBillingStatementModal.d.ts +3 -1
- package/dist/editors/expense-report/components/AddBillingStatementModal.d.ts.map +1 -1
- package/dist/editors/expense-report/components/AddBillingStatementModal.js +23 -7
- package/dist/editors/expense-report/components/AggregatedExpensesTable.js +2 -2
- package/dist/editors/expense-report/components/ExpenseReportPDF.js +2 -2
- package/dist/editors/expense-report/editor.d.ts.map +1 -1
- package/dist/editors/expense-report/editor.js +70 -14
- package/dist/editors/expense-report/hooks/useSyncWallet.js +9 -9
- package/dist/editors/invoice/ingestPDF.js +1 -1
- package/dist/editors/invoice/invoiceToGnosis.js +2 -2
- package/dist/editors/invoice/requestFinance.js +2 -2
- package/dist/editors/invoice/uploadPdfChunked.js +2 -2
- package/dist/editors/snapshot-report-editor/editor.d.ts.map +1 -1
- package/dist/editors/snapshot-report-editor/editor.js +26 -5
- package/dist/scripts/invoice/pdfToClaudeAI.d.ts.map +1 -1
- package/dist/scripts/invoice/pdfToClaudeAI.js +3 -1
- package/dist/style.css +85 -0
- package/dist/subgraphs/budget-statements/index.d.ts +11 -0
- package/dist/subgraphs/budget-statements/index.d.ts.map +1 -0
- package/dist/subgraphs/budget-statements/index.js +11 -0
- package/dist/subgraphs/budget-statements/resolvers.d.ts +3 -0
- package/dist/subgraphs/budget-statements/resolvers.d.ts.map +1 -0
- package/dist/subgraphs/budget-statements/resolvers.js +335 -0
- package/dist/subgraphs/budget-statements/schema.d.ts +3 -0
- package/dist/subgraphs/budget-statements/schema.d.ts.map +1 -0
- package/dist/subgraphs/budget-statements/schema.js +131 -0
- package/dist/subgraphs/index.d.ts +1 -0
- package/dist/subgraphs/index.d.ts.map +1 -1
- package/dist/subgraphs/index.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import {} from "@powerhousedao/reactor-api";
|
|
2
|
+
// Helper to create a period key from start and end dates
|
|
3
|
+
const getPeriodKey = (periodStart, periodEnd) => {
|
|
4
|
+
if (!periodStart || !periodEnd)
|
|
5
|
+
return null;
|
|
6
|
+
// Normalize dates to YYYY-MM-DD format for consistent matching
|
|
7
|
+
const startDate = new Date(periodStart);
|
|
8
|
+
const endDate = new Date(periodEnd);
|
|
9
|
+
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime()))
|
|
10
|
+
return null;
|
|
11
|
+
const formatDate = (d) => d.toISOString().split("T")[0];
|
|
12
|
+
return `${formatDate(startDate)}_${formatDate(endDate)}`;
|
|
13
|
+
};
|
|
14
|
+
// Helper to extract month key from date (format: "JAN2026")
|
|
15
|
+
const getMonthKey = (dateStr) => {
|
|
16
|
+
if (!dateStr)
|
|
17
|
+
return null;
|
|
18
|
+
const date = new Date(dateStr);
|
|
19
|
+
if (isNaN(date.getTime()))
|
|
20
|
+
return null;
|
|
21
|
+
const months = [
|
|
22
|
+
"JAN",
|
|
23
|
+
"FEB",
|
|
24
|
+
"MAR",
|
|
25
|
+
"APR",
|
|
26
|
+
"MAY",
|
|
27
|
+
"JUN",
|
|
28
|
+
"JUL",
|
|
29
|
+
"AUG",
|
|
30
|
+
"SEP",
|
|
31
|
+
"OCT",
|
|
32
|
+
"NOV",
|
|
33
|
+
"DEC",
|
|
34
|
+
];
|
|
35
|
+
return `${months[date.getMonth()]}${date.getFullYear()}`;
|
|
36
|
+
};
|
|
37
|
+
// Helper to sort budget statements by month (most recent first)
|
|
38
|
+
const sortByMonth = (a, b) => {
|
|
39
|
+
const parseMonth = (m) => {
|
|
40
|
+
const months = {
|
|
41
|
+
JAN: 0,
|
|
42
|
+
FEB: 1,
|
|
43
|
+
MAR: 2,
|
|
44
|
+
APR: 3,
|
|
45
|
+
MAY: 4,
|
|
46
|
+
JUN: 5,
|
|
47
|
+
JUL: 6,
|
|
48
|
+
AUG: 7,
|
|
49
|
+
SEP: 8,
|
|
50
|
+
OCT: 9,
|
|
51
|
+
NOV: 10,
|
|
52
|
+
DEC: 11,
|
|
53
|
+
};
|
|
54
|
+
const monthStr = m.substring(0, 3);
|
|
55
|
+
const year = parseInt(m.substring(3), 10);
|
|
56
|
+
return new Date(year, months[monthStr] || 0).getTime();
|
|
57
|
+
};
|
|
58
|
+
return parseMonth(b.month) - parseMonth(a.month);
|
|
59
|
+
};
|
|
60
|
+
export const getResolvers = (subgraph) => {
|
|
61
|
+
const reactor = subgraph.reactor;
|
|
62
|
+
return {
|
|
63
|
+
Query: {
|
|
64
|
+
budgetStatements: async (_, args) => {
|
|
65
|
+
const { teamId } = args.filter || {};
|
|
66
|
+
const drives = await reactor.getDrives();
|
|
67
|
+
// Step 1: Collect all documents from all drives
|
|
68
|
+
const snapshotReportDocs = [];
|
|
69
|
+
const expenseReportDocs = [];
|
|
70
|
+
const accountTransactionsDocs = new Map();
|
|
71
|
+
const builderProfileDocs = new Map();
|
|
72
|
+
for (const driveId of drives) {
|
|
73
|
+
const docsIds = await reactor.getDocuments(driveId);
|
|
74
|
+
const docs = await Promise.all(docsIds.map(async (docId) => reactor.getDocument(docId)));
|
|
75
|
+
for (const doc of docs) {
|
|
76
|
+
const docType = doc.header.documentType;
|
|
77
|
+
if (docType === "powerhouse/snapshot-report") {
|
|
78
|
+
const snapshotDoc = doc;
|
|
79
|
+
// If teamId filter is provided, only include matching reports
|
|
80
|
+
if (!teamId || snapshotDoc.state.global.ownerId === teamId) {
|
|
81
|
+
snapshotReportDocs.push(snapshotDoc);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else if (docType === "powerhouse/expense-report") {
|
|
85
|
+
const expenseDoc = doc;
|
|
86
|
+
// If teamId filter is provided, only include matching reports
|
|
87
|
+
if (!teamId || expenseDoc.state.global.ownerId === teamId) {
|
|
88
|
+
expenseReportDocs.push(expenseDoc);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (docType === "powerhouse/account-transactions") {
|
|
92
|
+
const txDoc = doc;
|
|
93
|
+
accountTransactionsDocs.set(doc.header.id, txDoc);
|
|
94
|
+
}
|
|
95
|
+
else if (docType === "powerhouse/builder-profile") {
|
|
96
|
+
builderProfileDocs.set(doc.header.id, doc);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Step 2: Group reports by ownerId AND period
|
|
101
|
+
// Key format: "ownerId_periodStart_periodEnd"
|
|
102
|
+
const budgetStatementsByOwnerAndPeriod = new Map();
|
|
103
|
+
// Group snapshot reports
|
|
104
|
+
for (const snapshotDoc of snapshotReportDocs) {
|
|
105
|
+
const state = snapshotDoc.state.global;
|
|
106
|
+
const ownerId = state.ownerId;
|
|
107
|
+
if (!ownerId)
|
|
108
|
+
continue;
|
|
109
|
+
const periodKey = getPeriodKey(state.reportPeriodStart, state.reportPeriodEnd);
|
|
110
|
+
if (!periodKey)
|
|
111
|
+
continue;
|
|
112
|
+
const key = `${ownerId}_${periodKey}`;
|
|
113
|
+
if (!budgetStatementsByOwnerAndPeriod.has(key)) {
|
|
114
|
+
budgetStatementsByOwnerAndPeriod.set(key, {
|
|
115
|
+
ownerId,
|
|
116
|
+
periodKey,
|
|
117
|
+
snapshotReport: null,
|
|
118
|
+
expenseReport: null,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
budgetStatementsByOwnerAndPeriod.get(key).snapshotReport =
|
|
122
|
+
snapshotDoc;
|
|
123
|
+
}
|
|
124
|
+
// Group expense reports and match with snapshot reports
|
|
125
|
+
for (const expenseDoc of expenseReportDocs) {
|
|
126
|
+
const state = expenseDoc.state.global;
|
|
127
|
+
const ownerId = state.ownerId;
|
|
128
|
+
if (!ownerId)
|
|
129
|
+
continue;
|
|
130
|
+
const periodKey = getPeriodKey(state.periodStart, state.periodEnd);
|
|
131
|
+
if (!periodKey)
|
|
132
|
+
continue;
|
|
133
|
+
const key = `${ownerId}_${periodKey}`;
|
|
134
|
+
if (!budgetStatementsByOwnerAndPeriod.has(key)) {
|
|
135
|
+
budgetStatementsByOwnerAndPeriod.set(key, {
|
|
136
|
+
ownerId,
|
|
137
|
+
periodKey,
|
|
138
|
+
snapshotReport: null,
|
|
139
|
+
expenseReport: null,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
budgetStatementsByOwnerAndPeriod.get(key).expenseReport = expenseDoc;
|
|
143
|
+
}
|
|
144
|
+
// Step 3: Build the budget statements
|
|
145
|
+
const budgetStatements = [];
|
|
146
|
+
for (const [key, { ownerId, periodKey, snapshotReport, expenseReport },] of budgetStatementsByOwnerAndPeriod.entries()) {
|
|
147
|
+
// Get the builder profile for this owner
|
|
148
|
+
let builderProfileDoc = builderProfileDocs.get(ownerId) || null;
|
|
149
|
+
// Try to fetch directly if not found
|
|
150
|
+
if (!builderProfileDoc) {
|
|
151
|
+
try {
|
|
152
|
+
builderProfileDoc =
|
|
153
|
+
await reactor.getDocument(ownerId);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Ignore errors - profile may not exist
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Build owner object
|
|
160
|
+
const ownerState = builderProfileDoc
|
|
161
|
+
? (builderProfileDoc.state?.global ?? null)
|
|
162
|
+
: null;
|
|
163
|
+
const owner = {
|
|
164
|
+
id: ownerId,
|
|
165
|
+
name: ownerState?.name || "Unknown",
|
|
166
|
+
code: ownerState?.code || "",
|
|
167
|
+
logo: ownerState?.icon || "",
|
|
168
|
+
};
|
|
169
|
+
// Derive the month from the period start date
|
|
170
|
+
const periodStartDate = snapshotReport?.state.global.reportPeriodStart ||
|
|
171
|
+
expenseReport?.state.global.periodStart ||
|
|
172
|
+
null;
|
|
173
|
+
const month = getMonthKey(periodStartDate) || periodKey;
|
|
174
|
+
// Build snapshot report data
|
|
175
|
+
const snapshotReportData = snapshotReport
|
|
176
|
+
? buildSnapshotReportData(snapshotReport, accountTransactionsDocs)
|
|
177
|
+
: {
|
|
178
|
+
startDate: "",
|
|
179
|
+
endDate: "",
|
|
180
|
+
accounts: [],
|
|
181
|
+
};
|
|
182
|
+
// Build expense report data
|
|
183
|
+
const expenseReportData = expenseReport
|
|
184
|
+
? buildExpenseReportData(expenseReport)
|
|
185
|
+
: {
|
|
186
|
+
periodStart: "",
|
|
187
|
+
periodEnd: "",
|
|
188
|
+
groups: [],
|
|
189
|
+
wallets: [],
|
|
190
|
+
};
|
|
191
|
+
budgetStatements.push({
|
|
192
|
+
id: key,
|
|
193
|
+
owner,
|
|
194
|
+
month,
|
|
195
|
+
snapshotReport: snapshotReportData,
|
|
196
|
+
expenseReport: expenseReportData,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
// Sort by month (most recent first)
|
|
200
|
+
budgetStatements.sort(sortByMonth);
|
|
201
|
+
return budgetStatements;
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
};
|
|
206
|
+
/**
|
|
207
|
+
* Build snapshot report data from a SnapshotReportDocument
|
|
208
|
+
*/
|
|
209
|
+
function buildSnapshotReportData(doc, accountTransactionsDocs) {
|
|
210
|
+
const state = doc.state.global;
|
|
211
|
+
return {
|
|
212
|
+
startDate: state.reportPeriodStart || state.startDate || "",
|
|
213
|
+
endDate: state.reportPeriodEnd || state.endDate || "",
|
|
214
|
+
accounts: state.snapshotAccounts.map((account) => {
|
|
215
|
+
// Build balances from startingBalances and endingBalances
|
|
216
|
+
const balances = account.startingBalances.map((startBal, index) => {
|
|
217
|
+
const endBal = account.endingBalances[index] || {
|
|
218
|
+
amount: { unit: startBal.token, value: "0" },
|
|
219
|
+
token: startBal.token,
|
|
220
|
+
};
|
|
221
|
+
return {
|
|
222
|
+
startingBalance: startBal.amount,
|
|
223
|
+
endingBalance: endBal.amount,
|
|
224
|
+
token: {
|
|
225
|
+
symbol: startBal.token,
|
|
226
|
+
contractAddress: "", // Not available in the document model
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
});
|
|
230
|
+
// Build transactions from snapshot account transactions
|
|
231
|
+
const transactions = account.transactions.map((tx) => ({
|
|
232
|
+
id: tx.id,
|
|
233
|
+
datetime: tx.datetime,
|
|
234
|
+
txHash: tx.txHash,
|
|
235
|
+
counterParty: tx.counterParty || "",
|
|
236
|
+
counterPartyName: getCounterPartyName(tx.counterPartyAccountId, accountTransactionsDocs),
|
|
237
|
+
amount: {
|
|
238
|
+
value: tx.amount,
|
|
239
|
+
unit: tx.token,
|
|
240
|
+
},
|
|
241
|
+
direction: tx.direction,
|
|
242
|
+
flowType: tx.flowType || "External",
|
|
243
|
+
}));
|
|
244
|
+
return {
|
|
245
|
+
id: account.id,
|
|
246
|
+
name: account.accountName,
|
|
247
|
+
address: account.accountAddress,
|
|
248
|
+
type: account.type,
|
|
249
|
+
balances,
|
|
250
|
+
transactions,
|
|
251
|
+
};
|
|
252
|
+
}),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Build expense report data from an ExpenseReportDocument
|
|
257
|
+
*/
|
|
258
|
+
function buildExpenseReportData(doc) {
|
|
259
|
+
const state = doc.state.global;
|
|
260
|
+
// Build groups
|
|
261
|
+
const groups = state.groups.map((group) => ({
|
|
262
|
+
id: group.id,
|
|
263
|
+
label: group.label || "",
|
|
264
|
+
parentId: group.parentId || "",
|
|
265
|
+
}));
|
|
266
|
+
// Create a map for quick group label lookup
|
|
267
|
+
const groupLabelMap = new Map();
|
|
268
|
+
for (const group of state.groups) {
|
|
269
|
+
groupLabelMap.set(group.id, group.label || "");
|
|
270
|
+
}
|
|
271
|
+
// Build wallets
|
|
272
|
+
const wallets = state.wallets.map((wallet) => {
|
|
273
|
+
// Build totals from wallet totals
|
|
274
|
+
const totals = (wallet.totals || [])
|
|
275
|
+
.filter((t) => t !== null)
|
|
276
|
+
.map((total) => ({
|
|
277
|
+
group: total.group || "",
|
|
278
|
+
groupLabel: groupLabelMap.get(total.group || "") || "",
|
|
279
|
+
totalBudget: { unit: "USDS", value: String(total.totalBudget || 0) },
|
|
280
|
+
totalForecast: {
|
|
281
|
+
unit: "USDS",
|
|
282
|
+
value: String(total.totalForecast || 0),
|
|
283
|
+
},
|
|
284
|
+
totalActuals: { unit: "USDS", value: String(total.totalActuals || 0) },
|
|
285
|
+
totalPayments: {
|
|
286
|
+
unit: "USDS",
|
|
287
|
+
value: String(total.totalPayments || 0),
|
|
288
|
+
},
|
|
289
|
+
}));
|
|
290
|
+
// Build line items
|
|
291
|
+
const lineItems = (wallet.lineItems || [])
|
|
292
|
+
.filter((li) => li !== null)
|
|
293
|
+
.map((item) => ({
|
|
294
|
+
id: item.id || "",
|
|
295
|
+
label: item.label || "",
|
|
296
|
+
groupId: item.group || "",
|
|
297
|
+
groupLabel: groupLabelMap.get(item.group || "") || "",
|
|
298
|
+
budget: { unit: "USDS", value: String(item.budget || 0) },
|
|
299
|
+
forecast: { unit: "USDS", value: String(item.forecast || 0) },
|
|
300
|
+
actuals: { unit: "USDS", value: String(item.actuals || 0) },
|
|
301
|
+
payments: { unit: "USDS", value: String(item.payments || 0) },
|
|
302
|
+
comments: item.comments || null,
|
|
303
|
+
}));
|
|
304
|
+
// Collect billing statement IDs
|
|
305
|
+
const billingStatementIds = (wallet.billingStatements || []).filter((id) => id !== null);
|
|
306
|
+
return {
|
|
307
|
+
name: wallet.name || null,
|
|
308
|
+
address: wallet.wallet || null,
|
|
309
|
+
totals,
|
|
310
|
+
lineItems,
|
|
311
|
+
billingStatementIds,
|
|
312
|
+
};
|
|
313
|
+
});
|
|
314
|
+
return {
|
|
315
|
+
periodStart: state.periodStart || "",
|
|
316
|
+
periodEnd: state.periodEnd || "",
|
|
317
|
+
groups,
|
|
318
|
+
wallets,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Get counter party name from account-transactions document
|
|
323
|
+
*/
|
|
324
|
+
function getCounterPartyName(counterPartyAccountId, accountTransactionsDocs) {
|
|
325
|
+
if (!counterPartyAccountId)
|
|
326
|
+
return "";
|
|
327
|
+
// Search through all account-transactions docs to find the account name
|
|
328
|
+
for (const txDoc of accountTransactionsDocs.values()) {
|
|
329
|
+
const account = txDoc.state.global.account;
|
|
330
|
+
if (account && account.id === counterPartyAccountId) {
|
|
331
|
+
return account.name || "";
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return "";
|
|
335
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../subgraphs/budget-statements/schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,MAAM,EAAE,YAiIpB,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { gql } from "graphql-tag";
|
|
2
|
+
export const schema = gql `
|
|
3
|
+
"""
|
|
4
|
+
Subgraph definition
|
|
5
|
+
"""
|
|
6
|
+
type Query {
|
|
7
|
+
budgetStatements(filter: budgetStatementsFilter): [BudgetStatement!]!
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
input budgetStatementsFilter {
|
|
11
|
+
teamId: PHID!
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
type BudgetStatement {
|
|
15
|
+
id: OID!
|
|
16
|
+
owner: BudgetStatementOwner!
|
|
17
|
+
month: String! ## JAN2026
|
|
18
|
+
snapshotReport: BudgetStatementSnapshotReport!
|
|
19
|
+
expenseReport: BudgetStatementExpenseReport!
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type BudgetStatementOwner {
|
|
23
|
+
id: PHID!
|
|
24
|
+
name: String!
|
|
25
|
+
code: String!
|
|
26
|
+
logo: URL!
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type BudgetStatementSnapshotReport {
|
|
30
|
+
startDate: DateTime!
|
|
31
|
+
endDate: DateTime!
|
|
32
|
+
accounts: [SnapshotAccount!]!
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type SnapshotAccount {
|
|
36
|
+
id: ID!
|
|
37
|
+
name: String!
|
|
38
|
+
address: String!
|
|
39
|
+
type: SnapAccountType!
|
|
40
|
+
balances: [SnapshotAccountBalance!]!
|
|
41
|
+
transactions: [SnapshotAccountTransaction!]!
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type SnapshotAccountBalance {
|
|
45
|
+
startingBalance: Amount_Currency!
|
|
46
|
+
endingBalance: Amount_Currency!
|
|
47
|
+
token: Token!
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type Token {
|
|
51
|
+
symbol: String!
|
|
52
|
+
contractAddress: EthereumAddress!
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
enum SnapAccountType {
|
|
56
|
+
Source
|
|
57
|
+
Internal
|
|
58
|
+
Destination
|
|
59
|
+
External
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type SnapshotAccountTransaction {
|
|
63
|
+
id: ID!
|
|
64
|
+
datetime: DateTime!
|
|
65
|
+
txHash: String!
|
|
66
|
+
counterParty: EthereumAddress!
|
|
67
|
+
counterPartyName: String!
|
|
68
|
+
amount: TxAmount!
|
|
69
|
+
direction: AccountTransactionDirection!
|
|
70
|
+
flowType: AccountTransactionFlowType!
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
type TxAmount {
|
|
74
|
+
value: Amount_Currency!
|
|
75
|
+
unit: String!
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
enum AccountTransactionDirection {
|
|
79
|
+
INFLOW
|
|
80
|
+
OUTFLOW
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
enum AccountTransactionFlowType {
|
|
84
|
+
TopUp
|
|
85
|
+
Return
|
|
86
|
+
Internal
|
|
87
|
+
External
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
type BudgetStatementExpenseReport {
|
|
91
|
+
periodStart: DateTime!
|
|
92
|
+
periodEnd: DateTime!
|
|
93
|
+
groups: [ExpenseReportGroup!]!
|
|
94
|
+
wallets: [ExpenseReportWallet!]!
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
type ExpenseReportGroup {
|
|
98
|
+
id: ID!
|
|
99
|
+
label: String!
|
|
100
|
+
parentId: ID!
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
type ExpenseReportWallet {
|
|
104
|
+
name: String
|
|
105
|
+
address: EthereumAddress
|
|
106
|
+
totals: [ExpenseReportGroupTotals!]!
|
|
107
|
+
lineItems: [ExpenseReportLineItem!]!
|
|
108
|
+
billingStatementIds: [PHID!]!
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
type ExpenseReportGroupTotals {
|
|
112
|
+
group: ID!
|
|
113
|
+
groupLabel: String!
|
|
114
|
+
totalBudget: Amount_Currency!
|
|
115
|
+
totalForecast: Amount_Currency!
|
|
116
|
+
totalActuals: Amount_Currency!
|
|
117
|
+
totalPayments: Amount_Currency!
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
type ExpenseReportLineItem {
|
|
121
|
+
id: ID!
|
|
122
|
+
label: String!
|
|
123
|
+
groupId: ID!
|
|
124
|
+
groupLabel: String! # resolved from groups
|
|
125
|
+
budget: Amount_Currency!
|
|
126
|
+
forecast: Amount_Currency!
|
|
127
|
+
actuals: Amount_Currency!
|
|
128
|
+
payments: Amount_Currency!
|
|
129
|
+
comments: String
|
|
130
|
+
}
|
|
131
|
+
`;
|
|
@@ -8,4 +8,5 @@ export * as SnapshotReportSubgraph from "./snapshot-report/index.js";
|
|
|
8
8
|
export * as AccTxsAddonSubgraph from "./acc-txs-addon/index.js";
|
|
9
9
|
export * as ServiceSubscriptionsSubgraph from "./service-subscriptions/index.js";
|
|
10
10
|
export * as ServiceOfferingSubgraph from "./service-offering/index.js";
|
|
11
|
+
export * as BudgetStatementsSubgraph from "./budget-statements/index.js";
|
|
11
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../subgraphs/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,gBAAgB,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,2BAA2B,MAAM,iCAAiC,CAAC;AAC/E,OAAO,KAAK,eAAe,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,oBAAoB,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,wBAAwB,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,qBAAqB,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,sBAAsB,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,mBAAmB,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,4BAA4B,MAAM,kCAAkC,CAAC;AACjF,OAAO,KAAK,uBAAuB,MAAM,6BAA6B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../subgraphs/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,gBAAgB,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,2BAA2B,MAAM,iCAAiC,CAAC;AAC/E,OAAO,KAAK,eAAe,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,oBAAoB,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,wBAAwB,MAAM,8BAA8B,CAAC;AACzE,OAAO,KAAK,qBAAqB,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,sBAAsB,MAAM,4BAA4B,CAAC;AACrE,OAAO,KAAK,mBAAmB,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,4BAA4B,MAAM,kCAAkC,CAAC;AACjF,OAAO,KAAK,uBAAuB,MAAM,6BAA6B,CAAC;AACvE,OAAO,KAAK,wBAAwB,MAAM,8BAA8B,CAAC"}
|
package/dist/subgraphs/index.js
CHANGED
|
@@ -8,3 +8,4 @@ export * as SnapshotReportSubgraph from "./snapshot-report/index.js";
|
|
|
8
8
|
export * as AccTxsAddonSubgraph from "./acc-txs-addon/index.js";
|
|
9
9
|
export * as ServiceSubscriptionsSubgraph from "./service-subscriptions/index.js";
|
|
10
10
|
export * as ServiceOfferingSubgraph from "./service-offering/index.js";
|
|
11
|
+
export * as BudgetStatementsSubgraph from "./budget-statements/index.js";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powerhousedao/contributor-billing",
|
|
3
3
|
"description": "Document models that help contributors of open organisations get paid anonymously for their work on a monthly basis.",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.39",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|