@fairmint/canton-fairmint-sdk 0.0.22 → 0.0.24
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/clients/postgres-db-api/fairmint-db/app-markers.d.ts +26 -0
- package/dist/clients/postgres-db-api/fairmint-db/app-markers.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/app-markers.js +219 -0
- package/dist/clients/postgres-db-api/fairmint-db/app-markers.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/base.d.ts +30 -0
- package/dist/clients/postgres-db-api/fairmint-db/base.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/base.js +208 -0
- package/dist/clients/postgres-db-api/fairmint-db/base.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/index.d.ts +9 -0
- package/dist/clients/postgres-db-api/fairmint-db/index.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/index.js +21 -0
- package/dist/clients/postgres-db-api/fairmint-db/index.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/ocf-deployments.d.ts +95 -0
- package/dist/clients/postgres-db-api/fairmint-db/ocf-deployments.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/ocf-deployments.js +592 -0
- package/dist/clients/postgres-db-api/fairmint-db/ocf-deployments.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/parties.d.ts +26 -0
- package/dist/clients/postgres-db-api/fairmint-db/parties.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/parties.js +190 -0
- package/dist/clients/postgres-db-api/fairmint-db/parties.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/reward-coupons.d.ts +41 -0
- package/dist/clients/postgres-db-api/fairmint-db/reward-coupons.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/reward-coupons.js +467 -0
- package/dist/clients/postgres-db-api/fairmint-db/reward-coupons.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/time-series.d.ts +48 -0
- package/dist/clients/postgres-db-api/fairmint-db/time-series.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/time-series.js +419 -0
- package/dist/clients/postgres-db-api/fairmint-db/time-series.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/transfers.d.ts +25 -0
- package/dist/clients/postgres-db-api/fairmint-db/transfers.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/transfers.js +206 -0
- package/dist/clients/postgres-db-api/fairmint-db/transfers.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/valuation-reports.d.ts +11 -0
- package/dist/clients/postgres-db-api/fairmint-db/valuation-reports.d.ts.map +1 -0
- package/dist/clients/postgres-db-api/fairmint-db/valuation-reports.js +54 -0
- package/dist/clients/postgres-db-api/fairmint-db/valuation-reports.js.map +1 -0
- package/dist/clients/postgres-db-api/fairmintDbClient.d.ts +91 -127
- package/dist/clients/postgres-db-api/fairmintDbClient.d.ts.map +1 -1
- package/dist/clients/postgres-db-api/fairmintDbClient.js +183 -2969
- package/dist/clients/postgres-db-api/fairmintDbClient.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,36 +1,35 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FairmintDbClient = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
4
|
+
const base_1 = require("./fairmint-db/base");
|
|
5
|
+
const transfers_1 = require("./fairmint-db/transfers");
|
|
6
|
+
const reward_coupons_1 = require("./fairmint-db/reward-coupons");
|
|
7
|
+
const app_markers_1 = require("./fairmint-db/app-markers");
|
|
8
|
+
const parties_1 = require("./fairmint-db/parties");
|
|
9
|
+
const ocf_deployments_1 = require("./fairmint-db/ocf-deployments");
|
|
10
|
+
const time_series_1 = require("./fairmint-db/time-series");
|
|
11
|
+
const valuation_reports_1 = require("./fairmint-db/valuation-reports");
|
|
12
|
+
/**
|
|
13
|
+
* FairmintDbClient provides database access for the Fairmint application.
|
|
14
|
+
*
|
|
15
|
+
* This class uses a composition pattern, delegating to domain-specific
|
|
16
|
+
* repositories for better maintainability and code organization.
|
|
17
|
+
*/
|
|
7
18
|
class FairmintDbClient {
|
|
8
19
|
constructor(network) {
|
|
9
|
-
// Initialize the shared config which handles environment loading
|
|
10
|
-
this.config = new config_1.ProviderConfig();
|
|
11
|
-
// Use provided network or get from environment variable, defaulting to devnet
|
|
12
20
|
this.network = network;
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
this.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
});
|
|
26
|
-
// Test the connection
|
|
27
|
-
this.pool.on('error', err => {
|
|
28
|
-
console.error('Unexpected error on idle client', err);
|
|
29
|
-
process.exit(-1);
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
getDatabaseUrl() {
|
|
33
|
-
return this.config.getDatabaseUrl(this.network);
|
|
21
|
+
const { pool, config } = (0, base_1.createFairmintDbPool)(network);
|
|
22
|
+
this.pool = pool;
|
|
23
|
+
this.config = config;
|
|
24
|
+
// Initialize repositories
|
|
25
|
+
this.transfers = new transfers_1.TransfersRepository(pool, config, network);
|
|
26
|
+
this.rewardCoupons = new reward_coupons_1.RewardCouponsRepository(pool, config, network);
|
|
27
|
+
this.appMarkers = new app_markers_1.AppMarkersRepository(pool, config, network);
|
|
28
|
+
this.ocfDeployments = new ocf_deployments_1.OcfDeploymentsRepository(pool, config, network);
|
|
29
|
+
this.timeSeries = new time_series_1.TimeSeriesRepository(pool, config, network);
|
|
30
|
+
this.valuationReports = new valuation_reports_1.ValuationReportsRepository(pool, config, network);
|
|
31
|
+
// Parties needs transfers for payment statistics
|
|
32
|
+
this.parties = new parties_1.PartiesRepository(pool, config, network, this.transfers);
|
|
34
33
|
}
|
|
35
34
|
getNetwork() {
|
|
36
35
|
return this.network;
|
|
@@ -41,3042 +40,313 @@ class FairmintDbClient {
|
|
|
41
40
|
async close() {
|
|
42
41
|
await this.pool.end();
|
|
43
42
|
}
|
|
44
|
-
//
|
|
43
|
+
// ========================================================================
|
|
44
|
+
// Transfer Operations
|
|
45
|
+
// ========================================================================
|
|
45
46
|
async insertCantonTransfer(transfer) {
|
|
46
|
-
|
|
47
|
-
INSERT INTO canton_transfers (
|
|
48
|
-
api_tracking_id, api_expires_at,
|
|
49
|
-
transfer_sender_party_id, transfer_receiver_party_id, transfer_amount,
|
|
50
|
-
transfer_description, transfer_burned_amount, receiver_holding_cids,
|
|
51
|
-
sender_change_cids, tx_update_id, tx_record_time,
|
|
52
|
-
status, app_reward_coupon_id
|
|
53
|
-
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
|
|
54
|
-
RETURNING *
|
|
55
|
-
`;
|
|
56
|
-
const values = [
|
|
57
|
-
transfer.api_tracking_id,
|
|
58
|
-
transfer.api_expires_at,
|
|
59
|
-
transfer.transfer_sender_party_id,
|
|
60
|
-
transfer.transfer_receiver_party_id,
|
|
61
|
-
transfer.transfer_amount,
|
|
62
|
-
transfer.transfer_description,
|
|
63
|
-
transfer.transfer_burned_amount,
|
|
64
|
-
transfer.receiver_holding_cids,
|
|
65
|
-
transfer.sender_change_cids,
|
|
66
|
-
transfer.tx_update_id,
|
|
67
|
-
transfer.tx_record_time,
|
|
68
|
-
transfer.status,
|
|
69
|
-
transfer.app_reward_coupon_id,
|
|
70
|
-
];
|
|
71
|
-
const result = await this.pool.query(query, values);
|
|
72
|
-
return this.mapTransferFromDb(result.rows[0]);
|
|
47
|
+
return this.transfers.insertCantonTransfer(transfer);
|
|
73
48
|
}
|
|
74
49
|
async getCantonTransfer(id) {
|
|
75
|
-
|
|
76
|
-
const result = await this.pool.query(query, [id]);
|
|
77
|
-
return result.rows.length > 0
|
|
78
|
-
? this.mapTransferFromDb(result.rows[0])
|
|
79
|
-
: null;
|
|
50
|
+
return this.transfers.getCantonTransfer(id);
|
|
80
51
|
}
|
|
81
52
|
async getCantonTransferByTrackingId(apiTrackingId) {
|
|
82
|
-
|
|
83
|
-
const result = await this.pool.query(query, [apiTrackingId]);
|
|
84
|
-
return result.rows.length > 0
|
|
85
|
-
? this.mapTransferFromDb(result.rows[0])
|
|
86
|
-
: null;
|
|
53
|
+
return this.transfers.getCantonTransferByTrackingId(apiTrackingId);
|
|
87
54
|
}
|
|
88
55
|
async getSubmittedTransfers() {
|
|
89
|
-
|
|
90
|
-
SELECT * FROM canton_transfers
|
|
91
|
-
WHERE status = $1
|
|
92
|
-
ORDER BY created_at ASC
|
|
93
|
-
`;
|
|
94
|
-
const result = await this.pool.query(query, [types_1.TransferStatus.SUBMITTED]);
|
|
95
|
-
return result.rows.map(row => this.mapTransferFromDb(row));
|
|
56
|
+
return this.transfers.getSubmittedTransfers();
|
|
96
57
|
}
|
|
97
58
|
async updateCantonTransfer(id, updates) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
SET ${setClauses.join(', ')}, updated_at = NOW()
|
|
116
|
-
WHERE id = $${paramIndex}
|
|
117
|
-
RETURNING *
|
|
118
|
-
`;
|
|
119
|
-
const result = await this.pool.query(query, values);
|
|
120
|
-
return result.rows.length > 0
|
|
121
|
-
? this.mapTransferFromDb(result.rows[0])
|
|
122
|
-
: null;
|
|
123
|
-
}
|
|
124
|
-
// Canton App Reward Coupons CRUD operations
|
|
59
|
+
return this.transfers.updateCantonTransfer(id, updates);
|
|
60
|
+
}
|
|
61
|
+
async getMonthlyPaymentTotalForParty(partyId, roundDurationMinutes = 10) {
|
|
62
|
+
return this.transfers.getMonthlyPaymentTotalForParty(partyId, roundDurationMinutes);
|
|
63
|
+
}
|
|
64
|
+
getRemainingRoundsInMonth(roundDurationMinutes = 10) {
|
|
65
|
+
return this.transfers.getRemainingRoundsInMonth(roundDurationMinutes);
|
|
66
|
+
}
|
|
67
|
+
async getMonthlyPaymentTotalsForParties(partyIds) {
|
|
68
|
+
return this.transfers.getMonthlyPaymentTotalsForParties(partyIds);
|
|
69
|
+
}
|
|
70
|
+
async getLifetimePaymentStatisticsForParties(partyIds) {
|
|
71
|
+
return this.transfers.getLifetimePaymentStatisticsForParties(partyIds);
|
|
72
|
+
}
|
|
73
|
+
// ========================================================================
|
|
74
|
+
// Reward Coupon Operations
|
|
75
|
+
// ========================================================================
|
|
125
76
|
async insertCantonAppRewardCoupon(coupon) {
|
|
126
|
-
|
|
127
|
-
INSERT INTO canton_app_reward_coupons (
|
|
128
|
-
status, tx_update_id, tx_record_time, contract_id, template_id, package_name,
|
|
129
|
-
dso_party_id, provider_party_id, featured, round_number, beneficiary_party_id, coupon_amount
|
|
130
|
-
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
|
131
|
-
RETURNING *
|
|
132
|
-
`;
|
|
133
|
-
const values = [
|
|
134
|
-
coupon.status,
|
|
135
|
-
coupon.tx_update_id,
|
|
136
|
-
coupon.tx_record_time,
|
|
137
|
-
coupon.contract_id,
|
|
138
|
-
coupon.template_id,
|
|
139
|
-
coupon.package_name,
|
|
140
|
-
coupon.dso_party_id,
|
|
141
|
-
coupon.provider_party_id,
|
|
142
|
-
coupon.featured,
|
|
143
|
-
coupon.round_number,
|
|
144
|
-
coupon.beneficiary_party_id,
|
|
145
|
-
coupon.coupon_amount,
|
|
146
|
-
];
|
|
147
|
-
const result = await this.pool.query(query, values);
|
|
148
|
-
return this.mapRewardCouponFromDb(result.rows[0]);
|
|
77
|
+
return this.rewardCoupons.insertCantonAppRewardCoupon(coupon);
|
|
149
78
|
}
|
|
150
79
|
async batchInsertCantonAppRewardCoupons(coupons) {
|
|
151
|
-
|
|
152
|
-
return { insertedCount: 0, skippedCount: 0 };
|
|
153
|
-
}
|
|
154
|
-
// Build the VALUES clause with placeholders
|
|
155
|
-
const valuesPlaceholders = coupons
|
|
156
|
-
.map((_, idx) => `($${idx * 12 + 1}, $${idx * 12 + 2}, $${idx * 12 + 3}, $${idx * 12 + 4}, $${idx * 12 + 5}, $${idx * 12 + 6}, $${idx * 12 + 7}, $${idx * 12 + 8}, $${idx * 12 + 9}, $${idx * 12 + 10}, $${idx * 12 + 11}, $${idx * 12 + 12})`)
|
|
157
|
-
.join(', ');
|
|
158
|
-
const query = `
|
|
159
|
-
INSERT INTO canton_app_reward_coupons (
|
|
160
|
-
status, tx_update_id, tx_record_time, contract_id, template_id, package_name,
|
|
161
|
-
dso_party_id, provider_party_id, featured, round_number, beneficiary_party_id, coupon_amount
|
|
162
|
-
) VALUES ${valuesPlaceholders}
|
|
163
|
-
ON CONFLICT (contract_id) DO NOTHING
|
|
164
|
-
RETURNING *
|
|
165
|
-
`;
|
|
166
|
-
// Flatten all coupon values into a single array
|
|
167
|
-
const values = coupons.flatMap(coupon => [
|
|
168
|
-
coupon.status,
|
|
169
|
-
coupon.tx_update_id,
|
|
170
|
-
coupon.tx_record_time,
|
|
171
|
-
coupon.contract_id,
|
|
172
|
-
coupon.template_id,
|
|
173
|
-
coupon.package_name,
|
|
174
|
-
coupon.dso_party_id,
|
|
175
|
-
coupon.provider_party_id,
|
|
176
|
-
coupon.featured,
|
|
177
|
-
coupon.round_number,
|
|
178
|
-
coupon.beneficiary_party_id,
|
|
179
|
-
coupon.coupon_amount,
|
|
180
|
-
]);
|
|
181
|
-
const result = await this.pool.query(query, values);
|
|
182
|
-
const insertedCount = result.rowCount ?? 0;
|
|
183
|
-
const skippedCount = coupons.length - insertedCount;
|
|
184
|
-
return { insertedCount, skippedCount };
|
|
80
|
+
return this.rewardCoupons.batchInsertCantonAppRewardCoupons(coupons);
|
|
185
81
|
}
|
|
186
82
|
async upsertCantonAppRewardCouponWithStatus(coupon) {
|
|
187
|
-
|
|
188
|
-
INSERT INTO canton_app_reward_coupons (
|
|
189
|
-
status, tx_update_id, tx_record_time, contract_id, template_id, package_name,
|
|
190
|
-
dso_party_id, provider_party_id, featured, round_number, beneficiary_party_id, coupon_amount
|
|
191
|
-
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
|
|
192
|
-
ON CONFLICT (contract_id) DO UPDATE
|
|
193
|
-
SET status = EXCLUDED.status, updated_at = NOW()
|
|
194
|
-
RETURNING *
|
|
195
|
-
`;
|
|
196
|
-
const values = [
|
|
197
|
-
coupon.status,
|
|
198
|
-
coupon.tx_update_id,
|
|
199
|
-
coupon.tx_record_time,
|
|
200
|
-
coupon.contract_id,
|
|
201
|
-
coupon.template_id,
|
|
202
|
-
coupon.package_name,
|
|
203
|
-
coupon.dso_party_id,
|
|
204
|
-
coupon.provider_party_id,
|
|
205
|
-
coupon.featured,
|
|
206
|
-
coupon.round_number,
|
|
207
|
-
coupon.beneficiary_party_id,
|
|
208
|
-
coupon.coupon_amount,
|
|
209
|
-
];
|
|
210
|
-
const result = await this.pool.query(query, values);
|
|
211
|
-
return this.mapRewardCouponFromDb(result.rows[0]);
|
|
83
|
+
return this.rewardCoupons.upsertCantonAppRewardCouponWithStatus(coupon);
|
|
212
84
|
}
|
|
213
85
|
async getCantonAppRewardCoupon(id) {
|
|
214
|
-
|
|
215
|
-
const result = await this.pool.query(query, [id]);
|
|
216
|
-
return result.rows.length > 0
|
|
217
|
-
? this.mapRewardCouponFromDb(result.rows[0])
|
|
218
|
-
: null;
|
|
86
|
+
return this.rewardCoupons.getCantonAppRewardCoupon(id);
|
|
219
87
|
}
|
|
220
88
|
async getCantonAppRewardCouponByContractId(contractId) {
|
|
221
|
-
|
|
222
|
-
const result = await this.pool.query(query, [contractId]);
|
|
223
|
-
return result.rows.length > 0
|
|
224
|
-
? this.mapRewardCouponFromDb(result.rows[0])
|
|
225
|
-
: null;
|
|
89
|
+
return this.rewardCoupons.getCantonAppRewardCouponByContractId(contractId);
|
|
226
90
|
}
|
|
227
91
|
async getCantonAppRewardCouponsByContractIds(contractIds) {
|
|
228
|
-
|
|
229
|
-
return [];
|
|
230
|
-
}
|
|
231
|
-
const placeholders = contractIds
|
|
232
|
-
.map((_, index) => `$${index + 1}`)
|
|
233
|
-
.join(', ');
|
|
234
|
-
const query = `
|
|
235
|
-
SELECT * FROM canton_app_reward_coupons
|
|
236
|
-
WHERE contract_id IN (${placeholders})
|
|
237
|
-
`;
|
|
238
|
-
const result = await this.pool.query(query, contractIds);
|
|
239
|
-
return result.rows.map(row => this.mapRewardCouponFromDb(row));
|
|
92
|
+
return this.rewardCoupons.getCantonAppRewardCouponsByContractIds(contractIds);
|
|
240
93
|
}
|
|
241
94
|
async getCantonAppRewardCouponsByStatus(status, limit = 100, sortOrder = 'ASC', beneficiaryPartyId) {
|
|
242
|
-
|
|
243
|
-
SELECT * FROM canton_app_reward_coupons
|
|
244
|
-
WHERE status = $1
|
|
245
|
-
`;
|
|
246
|
-
const params = [status];
|
|
247
|
-
if (beneficiaryPartyId) {
|
|
248
|
-
query += ` AND beneficiary_party_id = $${params.length + 1}`;
|
|
249
|
-
params.push(beneficiaryPartyId);
|
|
250
|
-
}
|
|
251
|
-
query += ` ORDER BY tx_record_time ${sortOrder} LIMIT $${params.length + 1}`;
|
|
252
|
-
params.push(limit);
|
|
253
|
-
const result = await this.pool.query(query, params);
|
|
254
|
-
return result.rows.map(row => this.mapRewardCouponFromDb(row));
|
|
95
|
+
return this.rewardCoupons.getCantonAppRewardCouponsByStatus(status, limit, sortOrder, beneficiaryPartyId);
|
|
255
96
|
}
|
|
256
97
|
async countCantonAppRewardCouponsByStatus(status) {
|
|
257
|
-
|
|
258
|
-
SELECT COUNT(*) FROM canton_app_reward_coupons
|
|
259
|
-
WHERE status = $1
|
|
260
|
-
`;
|
|
261
|
-
const result = await this.pool.query(query, [status]);
|
|
262
|
-
return result.rows[0].count;
|
|
98
|
+
return this.rewardCoupons.countCantonAppRewardCouponsByStatus(status);
|
|
263
99
|
}
|
|
264
100
|
async getOldestCreatedCantonAppRewardCoupons(limit = 100) {
|
|
265
|
-
|
|
266
|
-
SELECT * FROM canton_app_reward_coupons
|
|
267
|
-
WHERE status = 'created'
|
|
268
|
-
ORDER BY tx_record_time ASC
|
|
269
|
-
LIMIT $1
|
|
270
|
-
`;
|
|
271
|
-
const result = await this.pool.query(query, [limit]);
|
|
272
|
-
return result.rows.map(row => this.mapRewardCouponFromDb(row));
|
|
101
|
+
return this.rewardCoupons.getOldestCreatedCantonAppRewardCoupons(limit);
|
|
273
102
|
}
|
|
274
103
|
async getCantonAppRewardCouponsByDateRange(startDate, endDate, status, limit = 1000, sortOrder = 'ASC') {
|
|
275
|
-
|
|
276
|
-
SELECT * FROM canton_app_reward_coupons
|
|
277
|
-
WHERE tx_archive_record_time >= $1 AND tx_archive_record_time <= $2
|
|
278
|
-
`;
|
|
279
|
-
const values = [startDate, endDate];
|
|
280
|
-
let paramIndex = 3;
|
|
281
|
-
if (status) {
|
|
282
|
-
query += ` AND status = $${paramIndex}`;
|
|
283
|
-
values.push(status);
|
|
284
|
-
paramIndex++;
|
|
285
|
-
}
|
|
286
|
-
query += ` ORDER BY tx_archive_record_time ${sortOrder} LIMIT $${paramIndex}`;
|
|
287
|
-
values.push(limit);
|
|
288
|
-
const result = await this.pool.query(query, values);
|
|
289
|
-
return result.rows.map(row => this.mapRewardCouponFromDb(row));
|
|
104
|
+
return this.rewardCoupons.getCantonAppRewardCouponsByDateRange(startDate, endDate, status, limit, sortOrder);
|
|
290
105
|
}
|
|
291
106
|
async updateCantonAppRewardCoupon(id, updates) {
|
|
292
|
-
|
|
293
|
-
const values = [];
|
|
294
|
-
let paramIndex = 1;
|
|
295
|
-
// Build dynamic update query
|
|
296
|
-
Object.entries(updates).forEach(([key, value]) => {
|
|
297
|
-
if (key !== 'id' && key !== 'created_at') {
|
|
298
|
-
setClauses.push(`${this.toSnakeCase(key)} = $${paramIndex}`);
|
|
299
|
-
values.push(value);
|
|
300
|
-
paramIndex++;
|
|
301
|
-
}
|
|
302
|
-
});
|
|
303
|
-
if (setClauses.length === 0) {
|
|
304
|
-
throw new Error('No valid fields to update');
|
|
305
|
-
}
|
|
306
|
-
values.push(id);
|
|
307
|
-
const query = `
|
|
308
|
-
UPDATE canton_app_reward_coupons
|
|
309
|
-
SET ${setClauses.join(', ')}, updated_at = NOW()
|
|
310
|
-
WHERE id = $${paramIndex}
|
|
311
|
-
RETURNING *
|
|
312
|
-
`;
|
|
313
|
-
const result = await this.pool.query(query, values);
|
|
314
|
-
return result.rows.length > 0
|
|
315
|
-
? this.mapRewardCouponFromDb(result.rows[0])
|
|
316
|
-
: null;
|
|
107
|
+
return this.rewardCoupons.updateCantonAppRewardCoupon(id, updates);
|
|
317
108
|
}
|
|
318
109
|
async batchUpdateCantonAppRewardCouponsByContractIds(contractIds, updates) {
|
|
319
|
-
|
|
320
|
-
return [];
|
|
321
|
-
}
|
|
322
|
-
const setClauses = [];
|
|
323
|
-
const values = [];
|
|
324
|
-
let paramIndex = 1;
|
|
325
|
-
// Build dynamic update query
|
|
326
|
-
Object.entries(updates).forEach(([key, value]) => {
|
|
327
|
-
if (key !== 'id' && key !== 'created_at') {
|
|
328
|
-
setClauses.push(`${this.toSnakeCase(key)} = $${paramIndex}`);
|
|
329
|
-
values.push(value);
|
|
330
|
-
paramIndex++;
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
if (setClauses.length === 0) {
|
|
334
|
-
throw new Error('No valid fields to update');
|
|
335
|
-
}
|
|
336
|
-
// Build the WHERE clause for contract IDs
|
|
337
|
-
const contractIdPlaceholders = contractIds
|
|
338
|
-
.map((_, index) => `$${paramIndex + index}`)
|
|
339
|
-
.join(', ');
|
|
340
|
-
values.push(...contractIds);
|
|
341
|
-
const query = `
|
|
342
|
-
UPDATE canton_app_reward_coupons
|
|
343
|
-
SET ${setClauses.join(', ')}, updated_at = NOW()
|
|
344
|
-
WHERE contract_id IN (${contractIdPlaceholders})
|
|
345
|
-
RETURNING *
|
|
346
|
-
`;
|
|
347
|
-
const result = await this.pool.query(query, values);
|
|
348
|
-
return result.rows.map(row => this.mapRewardCouponFromDb(row));
|
|
110
|
+
return this.rewardCoupons.batchUpdateCantonAppRewardCouponsByContractIds(contractIds, updates);
|
|
349
111
|
}
|
|
350
112
|
async getRewardCoupons(options = {}) {
|
|
351
|
-
|
|
352
|
-
let query = `
|
|
353
|
-
SELECT
|
|
354
|
-
c.id as coupon_id,
|
|
355
|
-
c.status as coupon_status,
|
|
356
|
-
c.tx_update_id as coupon_tx_update_id,
|
|
357
|
-
c.tx_record_time as coupon_tx_record_time,
|
|
358
|
-
c.contract_id as coupon_contract_id,
|
|
359
|
-
c.template_id as coupon_template_id,
|
|
360
|
-
c.package_name as coupon_package_name,
|
|
361
|
-
c.dso_party_id as coupon_dso_party_id,
|
|
362
|
-
c.provider_party_id as coupon_provider_party_id,
|
|
363
|
-
c.featured as coupon_featured,
|
|
364
|
-
c.round_number as coupon_round_number,
|
|
365
|
-
c.beneficiary_party_id as coupon_beneficiary_party_id,
|
|
366
|
-
c.coupon_amount as coupon_coupon_amount,
|
|
367
|
-
c.tx_archive_update_id as coupon_tx_archive_update_id,
|
|
368
|
-
c.tx_archive_record_time as coupon_tx_archive_record_time,
|
|
369
|
-
c.app_reward_amount as coupon_app_reward_amount,
|
|
370
|
-
c.created_at as coupon_created_at,
|
|
371
|
-
c.updated_at as coupon_updated_at,
|
|
372
|
-
t.id as transfer_id,
|
|
373
|
-
t.status as transfer_status,
|
|
374
|
-
t.api_tracking_id as transfer_api_tracking_id,
|
|
375
|
-
t.api_expires_at as transfer_api_expires_at,
|
|
376
|
-
t.transfer_sender_party_id as transfer_transfer_sender_party_id,
|
|
377
|
-
t.transfer_receiver_party_id as transfer_transfer_receiver_party_id,
|
|
378
|
-
t.transfer_amount as transfer_transfer_amount,
|
|
379
|
-
t.transfer_description as transfer_transfer_description,
|
|
380
|
-
t.transfer_burned_amount as transfer_transfer_burned_amount,
|
|
381
|
-
t.receiver_holding_cids as transfer_receiver_holding_cids,
|
|
382
|
-
t.sender_change_cids as transfer_sender_change_cids,
|
|
383
|
-
t.tx_update_id as transfer_tx_update_id,
|
|
384
|
-
t.tx_record_time as transfer_tx_record_time,
|
|
385
|
-
t.app_reward_coupon_id as transfer_app_reward_coupon_id,
|
|
386
|
-
t.created_at as transfer_created_at,
|
|
387
|
-
t.updated_at as transfer_updated_at,
|
|
388
|
-
r.id as redemption_id,
|
|
389
|
-
r.tx_update_id as redemption_tx_update_id,
|
|
390
|
-
r.tx_record_time as redemption_tx_record_time,
|
|
391
|
-
r.tx_synchronizer_id as redemption_tx_synchronizer_id,
|
|
392
|
-
r.tx_effective_at as redemption_tx_effective_at,
|
|
393
|
-
r.total_app_rewards,
|
|
394
|
-
r.created_at as redemption_created_at,
|
|
395
|
-
r.updated_at as redemption_updated_at
|
|
396
|
-
FROM canton_app_reward_coupons c
|
|
397
|
-
LEFT JOIN canton_transfers t ON t.app_reward_coupon_id = c.id
|
|
398
|
-
`;
|
|
399
|
-
const conditions = [];
|
|
400
|
-
const values = [];
|
|
401
|
-
const paramIndex = 1;
|
|
402
|
-
// Filter by redemption status
|
|
403
|
-
if (redeemed === 'Unredeemed') {
|
|
404
|
-
conditions.push('r.id IS NULL');
|
|
405
|
-
}
|
|
406
|
-
else if (redeemed === 'Redeemed') {
|
|
407
|
-
conditions.push('r.id IS NOT NULL');
|
|
408
|
-
}
|
|
409
|
-
if (conditions.length > 0) {
|
|
410
|
-
query += ` WHERE ${conditions.join(' AND ')}`;
|
|
411
|
-
}
|
|
412
|
-
// Order by
|
|
413
|
-
query += ` ORDER BY c.tx_record_time ${order === 'oldest' ? 'ASC' : 'DESC'}`;
|
|
414
|
-
// Limit
|
|
415
|
-
query += ` LIMIT $${paramIndex}`;
|
|
416
|
-
values.push(limit);
|
|
417
|
-
const result = await this.pool.query(query, values);
|
|
418
|
-
return result.rows.map(row => this.mapRewardCouponWithTransferFromDb(row));
|
|
113
|
+
return this.rewardCoupons.getRewardCoupons(options);
|
|
419
114
|
}
|
|
420
115
|
async getRewardCoupon(options) {
|
|
421
|
-
|
|
422
|
-
const query = `
|
|
423
|
-
SELECT
|
|
424
|
-
c.id as coupon_id,
|
|
425
|
-
c.status as coupon_status,
|
|
426
|
-
c.tx_update_id as coupon_tx_update_id,
|
|
427
|
-
c.tx_record_time as coupon_tx_record_time,
|
|
428
|
-
c.contract_id as coupon_contract_id,
|
|
429
|
-
c.template_id as coupon_template_id,
|
|
430
|
-
c.package_name as coupon_package_name,
|
|
431
|
-
c.dso_party_id as coupon_dso_party_id,
|
|
432
|
-
c.provider_party_id as coupon_provider_party_id,
|
|
433
|
-
c.featured as coupon_featured,
|
|
434
|
-
c.round_number as coupon_round_number,
|
|
435
|
-
c.beneficiary_party_id as coupon_beneficiary_party_id,
|
|
436
|
-
c.coupon_amount as coupon_coupon_amount,
|
|
437
|
-
c.tx_archive_update_id as coupon_tx_archive_update_id,
|
|
438
|
-
c.tx_archive_record_time as coupon_tx_archive_record_time,
|
|
439
|
-
c.app_reward_amount as coupon_app_reward_amount,
|
|
440
|
-
c.created_at as coupon_created_at,
|
|
441
|
-
c.updated_at as coupon_updated_at,
|
|
442
|
-
t.id as transfer_id,
|
|
443
|
-
t.status as transfer_status,
|
|
444
|
-
t.api_tracking_id as transfer_api_tracking_id,
|
|
445
|
-
t.api_expires_at as transfer_api_expires_at,
|
|
446
|
-
t.transfer_sender_party_id as transfer_transfer_sender_party_id,
|
|
447
|
-
t.transfer_receiver_party_id as transfer_transfer_receiver_party_id,
|
|
448
|
-
t.transfer_amount as transfer_transfer_amount,
|
|
449
|
-
t.transfer_description as transfer_transfer_description,
|
|
450
|
-
t.transfer_burned_amount as transfer_transfer_burned_amount,
|
|
451
|
-
t.receiver_holding_cids as transfer_receiver_holding_cids,
|
|
452
|
-
t.sender_change_cids as transfer_sender_change_cids,
|
|
453
|
-
t.tx_update_id as transfer_tx_update_id,
|
|
454
|
-
t.tx_record_time as transfer_tx_record_time,
|
|
455
|
-
t.app_reward_coupon_id as transfer_app_reward_coupon_id,
|
|
456
|
-
t.created_at as transfer_created_at,
|
|
457
|
-
t.updated_at as transfer_updated_at,
|
|
458
|
-
r.id as redemption_id,
|
|
459
|
-
r.tx_update_id as redemption_tx_update_id,
|
|
460
|
-
r.tx_record_time as redemption_tx_record_time,
|
|
461
|
-
r.tx_synchronizer_id as redemption_tx_synchronizer_id,
|
|
462
|
-
r.tx_effective_at as redemption_tx_effective_at,
|
|
463
|
-
r.total_app_rewards,
|
|
464
|
-
r.created_at as redemption_created_at,
|
|
465
|
-
r.updated_at as redemption_updated_at
|
|
466
|
-
FROM canton_app_reward_coupons c
|
|
467
|
-
LEFT JOIN canton_transfers t ON t.app_reward_coupon_id = c.id
|
|
468
|
-
WHERE c.contract_id = $1
|
|
469
|
-
`;
|
|
470
|
-
const result = await this.pool.query(query, [contract_id]);
|
|
471
|
-
return result.rows.length > 0
|
|
472
|
-
? this.mapRewardCouponWithTransferFromDb(result.rows[0])
|
|
473
|
-
: null;
|
|
474
|
-
}
|
|
475
|
-
async getMonthlyTransferTotal(monthStart, monthEnd) {
|
|
476
|
-
const query = `
|
|
477
|
-
SELECT COALESCE(SUM(transfer_amount), 0) as total_amount
|
|
478
|
-
FROM canton_transfers
|
|
479
|
-
WHERE tx_record_time >= $1
|
|
480
|
-
AND tx_record_time <= $2
|
|
481
|
-
AND status IN ($3, $4)
|
|
482
|
-
`;
|
|
483
|
-
const result = await this.pool.query(query, [
|
|
484
|
-
monthStart,
|
|
485
|
-
monthEnd,
|
|
486
|
-
types_1.TransferStatus.CONFIRMED,
|
|
487
|
-
types_1.TransferStatus.PENDING,
|
|
488
|
-
]);
|
|
489
|
-
const totalAmount = parseFloat(result.rows[0].total_amount);
|
|
490
|
-
return totalAmount;
|
|
116
|
+
return this.rewardCoupons.getRewardCoupon(options);
|
|
491
117
|
}
|
|
492
118
|
async getMonthlyAppRewardAmountTotal(monthStart, monthEnd) {
|
|
493
|
-
|
|
494
|
-
SELECT COALESCE(SUM(app_reward_amount), 0) as total_amount
|
|
495
|
-
FROM canton_app_reward_coupons
|
|
496
|
-
WHERE created_at >= $1
|
|
497
|
-
AND created_at <= $2
|
|
498
|
-
AND app_reward_amount IS NOT NULL
|
|
499
|
-
`;
|
|
500
|
-
const result = await this.pool.query(query, [monthStart, monthEnd]);
|
|
501
|
-
const totalAmount = parseFloat(result.rows[0].total_amount);
|
|
502
|
-
return totalAmount;
|
|
503
|
-
}
|
|
504
|
-
async getTransferTimeSeriesData(timeRange, _metric = 'count', timePeriod, customStartDate) {
|
|
505
|
-
let interval;
|
|
506
|
-
let timeFilter;
|
|
507
|
-
let timeSeriesStart;
|
|
508
|
-
let timeSeriesEnd = 'NOW()';
|
|
509
|
-
let timeRangeInterval;
|
|
510
|
-
switch (timeRange) {
|
|
511
|
-
case '15m':
|
|
512
|
-
interval = 'minute';
|
|
513
|
-
timeFilter = "created_at >= NOW() - INTERVAL '15 minutes'";
|
|
514
|
-
timeRangeInterval = '15 minutes';
|
|
515
|
-
timeSeriesStart = "NOW() - INTERVAL '15 minutes'";
|
|
516
|
-
break;
|
|
517
|
-
case '1h':
|
|
518
|
-
interval = 'minute';
|
|
519
|
-
timeFilter = "created_at >= NOW() - INTERVAL '1 hour'";
|
|
520
|
-
timeRangeInterval = '1 hour';
|
|
521
|
-
timeSeriesStart = "NOW() - INTERVAL '1 hour'";
|
|
522
|
-
break;
|
|
523
|
-
case '6h':
|
|
524
|
-
interval = 'minute';
|
|
525
|
-
timeFilter = "created_at >= NOW() - INTERVAL '6 hours'";
|
|
526
|
-
timeRangeInterval = '6 hours';
|
|
527
|
-
timeSeriesStart = "NOW() - INTERVAL '6 hours'";
|
|
528
|
-
break;
|
|
529
|
-
case '1d':
|
|
530
|
-
interval = 'hour';
|
|
531
|
-
timeFilter = "created_at >= NOW() - INTERVAL '1 day'";
|
|
532
|
-
timeRangeInterval = '1 day';
|
|
533
|
-
timeSeriesStart = "NOW() - INTERVAL '1 day'";
|
|
534
|
-
break;
|
|
535
|
-
case '7d':
|
|
536
|
-
interval = 'hour';
|
|
537
|
-
timeFilter = "created_at >= NOW() - INTERVAL '7 days'";
|
|
538
|
-
timeRangeInterval = '7 days';
|
|
539
|
-
timeSeriesStart = "NOW() - INTERVAL '7 days'";
|
|
540
|
-
break;
|
|
541
|
-
case '30d':
|
|
542
|
-
interval = 'day';
|
|
543
|
-
timeFilter = "created_at >= NOW() - INTERVAL '30 days'";
|
|
544
|
-
timeRangeInterval = '30 days';
|
|
545
|
-
timeSeriesStart = "NOW() - INTERVAL '30 days'";
|
|
546
|
-
break;
|
|
547
|
-
case 'last-month':
|
|
548
|
-
interval = 'day';
|
|
549
|
-
timeFilter =
|
|
550
|
-
"created_at >= date_trunc('month', current_date - interval '1 month') AND created_at < date_trunc('month', current_date)";
|
|
551
|
-
timeRangeInterval = '1 month';
|
|
552
|
-
timeSeriesStart =
|
|
553
|
-
"date_trunc('month', current_date - interval '1 month')";
|
|
554
|
-
timeSeriesEnd = "date_trunc('month', current_date)";
|
|
555
|
-
break;
|
|
556
|
-
case 'all':
|
|
557
|
-
interval = 'day';
|
|
558
|
-
timeFilter = '1=1';
|
|
559
|
-
timeRangeInterval = '100 years';
|
|
560
|
-
timeSeriesStart = "'2023-01-01'::timestamp";
|
|
561
|
-
break;
|
|
562
|
-
default:
|
|
563
|
-
interval = 'hour';
|
|
564
|
-
timeFilter = "created_at >= NOW() - INTERVAL '1 day'";
|
|
565
|
-
timeRangeInterval = '1 day';
|
|
566
|
-
timeSeriesStart = "NOW() - INTERVAL '1 day'";
|
|
567
|
-
}
|
|
568
|
-
// If custom start date is provided, override the timeFilter and time series start/end
|
|
569
|
-
if (timePeriod === 'custom-start' && customStartDate) {
|
|
570
|
-
timeFilter = `created_at >= '${customStartDate}:00' AND created_at < ('${customStartDate}:00'::timestamp + INTERVAL '${timeRangeInterval}')`;
|
|
571
|
-
timeSeriesStart = `'${customStartDate}:00'::timestamp`;
|
|
572
|
-
timeSeriesEnd = `('${customStartDate}:00'::timestamp + INTERVAL '${timeRangeInterval}')`;
|
|
573
|
-
}
|
|
574
|
-
const query = `
|
|
575
|
-
WITH time_series AS (
|
|
576
|
-
SELECT generate_series(
|
|
577
|
-
date_trunc('${interval}', ${timeSeriesStart}),
|
|
578
|
-
date_trunc('${interval}', ${timeSeriesEnd}),
|
|
579
|
-
INTERVAL '1 ${interval}'
|
|
580
|
-
) AS timestamp
|
|
581
|
-
),
|
|
582
|
-
transfer_data AS (
|
|
583
|
-
SELECT
|
|
584
|
-
date_trunc('${interval}', created_at) AS timestamp,
|
|
585
|
-
COUNT(*) as count,
|
|
586
|
-
COALESCE(SUM(transfer_amount), 0) as amount
|
|
587
|
-
FROM canton_transfers
|
|
588
|
-
WHERE ${timeFilter}
|
|
589
|
-
AND status IN ('pending', 'submitted', 'confirmed')
|
|
590
|
-
GROUP BY date_trunc('${interval}', created_at)
|
|
591
|
-
)
|
|
592
|
-
SELECT
|
|
593
|
-
ts.timestamp::text,
|
|
594
|
-
COALESCE(td.count, 0) as count,
|
|
595
|
-
COALESCE(td.amount, 0) as amount
|
|
596
|
-
FROM time_series ts
|
|
597
|
-
LEFT JOIN transfer_data td ON ts.timestamp = td.timestamp
|
|
598
|
-
ORDER BY ts.timestamp ASC
|
|
599
|
-
`;
|
|
600
|
-
const result = await this.pool.query(query);
|
|
601
|
-
return result.rows.map(row => ({
|
|
602
|
-
timestamp: row.timestamp,
|
|
603
|
-
count: parseInt(row.count, 10),
|
|
604
|
-
amount: parseFloat(row.amount),
|
|
605
|
-
}));
|
|
606
|
-
}
|
|
607
|
-
async getRewardCouponTimeSeriesData(timeRange, _metric = 'count', timePeriod, customStartDate, partyFilter, couponStatus = 'all') {
|
|
608
|
-
let interval;
|
|
609
|
-
let timeFilter;
|
|
610
|
-
let timeSeriesStart;
|
|
611
|
-
let timeSeriesEnd = 'NOW()';
|
|
612
|
-
let timeRangeInterval;
|
|
613
|
-
switch (timeRange) {
|
|
614
|
-
case '15m':
|
|
615
|
-
interval = 'minute';
|
|
616
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '15 minutes'";
|
|
617
|
-
timeRangeInterval = '15 minutes';
|
|
618
|
-
timeSeriesStart = "NOW() - INTERVAL '15 minutes'";
|
|
619
|
-
break;
|
|
620
|
-
case '1h':
|
|
621
|
-
interval = 'minute';
|
|
622
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '1 hour'";
|
|
623
|
-
timeRangeInterval = '1 hour';
|
|
624
|
-
timeSeriesStart = "NOW() - INTERVAL '1 hour'";
|
|
625
|
-
break;
|
|
626
|
-
case '6h':
|
|
627
|
-
interval = 'minute';
|
|
628
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '6 hours'";
|
|
629
|
-
timeRangeInterval = '6 hours';
|
|
630
|
-
timeSeriesStart = "NOW() - INTERVAL '6 hours'";
|
|
631
|
-
break;
|
|
632
|
-
case '1d':
|
|
633
|
-
interval = 'hour';
|
|
634
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '1 day'";
|
|
635
|
-
timeRangeInterval = '1 day';
|
|
636
|
-
timeSeriesStart = "NOW() - INTERVAL '1 day'";
|
|
637
|
-
break;
|
|
638
|
-
case '7d':
|
|
639
|
-
interval = 'hour';
|
|
640
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '7 days'";
|
|
641
|
-
timeRangeInterval = '7 days';
|
|
642
|
-
timeSeriesStart = "NOW() - INTERVAL '7 days'";
|
|
643
|
-
break;
|
|
644
|
-
case '30d':
|
|
645
|
-
interval = 'day';
|
|
646
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '30 days'";
|
|
647
|
-
timeRangeInterval = '30 days';
|
|
648
|
-
timeSeriesStart = "NOW() - INTERVAL '30 days'";
|
|
649
|
-
break;
|
|
650
|
-
case 'last-month':
|
|
651
|
-
interval = 'day';
|
|
652
|
-
timeFilter =
|
|
653
|
-
"tx_record_time >= date_trunc('month', current_date - interval '1 month') AND tx_record_time < date_trunc('month', current_date)";
|
|
654
|
-
timeRangeInterval = '1 month';
|
|
655
|
-
timeSeriesStart =
|
|
656
|
-
"date_trunc('month', current_date - interval '1 month')";
|
|
657
|
-
timeSeriesEnd = "date_trunc('month', current_date)";
|
|
658
|
-
break;
|
|
659
|
-
case 'all':
|
|
660
|
-
interval = 'day'; // Default to daily for 'all' to avoid too many points
|
|
661
|
-
timeFilter = '1=1';
|
|
662
|
-
timeRangeInterval = '100 years'; // Just for custom start calc
|
|
663
|
-
timeSeriesStart = "'2023-01-01'::timestamp"; // Reasonable start date
|
|
664
|
-
break;
|
|
665
|
-
default:
|
|
666
|
-
interval = 'hour';
|
|
667
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '1 day'";
|
|
668
|
-
timeRangeInterval = '1 day';
|
|
669
|
-
timeSeriesStart = "NOW() - INTERVAL '1 day'";
|
|
670
|
-
}
|
|
671
|
-
// If custom start date is provided, override the timeFilter and time series start/end
|
|
672
|
-
if (timePeriod === 'custom-start' && customStartDate) {
|
|
673
|
-
timeFilter = `tx_record_time >= '${customStartDate}:00' AND tx_record_time < ('${customStartDate}:00'::timestamp + INTERVAL '${timeRangeInterval}')`;
|
|
674
|
-
timeSeriesStart = `'${customStartDate}:00'::timestamp`;
|
|
675
|
-
timeSeriesEnd = `('${customStartDate}:00'::timestamp + INTERVAL '${timeRangeInterval}')`;
|
|
676
|
-
}
|
|
677
|
-
// Add party filter if provided
|
|
678
|
-
const partyCondition = partyFilter
|
|
679
|
-
? ` AND beneficiary_party_id = '${partyFilter}'`
|
|
680
|
-
: '';
|
|
681
|
-
// Add status filter based on couponStatus
|
|
682
|
-
// 'created' = not yet archived, 'archived' = has been collected
|
|
683
|
-
// 'all' = all coupons regardless of archive status
|
|
684
|
-
let statusCondition = '';
|
|
685
|
-
if (couponStatus === 'created') {
|
|
686
|
-
statusCondition = ` AND status = 'created'`;
|
|
687
|
-
}
|
|
688
|
-
else if (couponStatus === 'archived') {
|
|
689
|
-
statusCondition = ` AND status = 'archived'`;
|
|
690
|
-
}
|
|
691
|
-
// When couponStatus === 'all', no filter is applied (statusCondition remains '')
|
|
692
|
-
const query = `
|
|
693
|
-
WITH time_series AS (
|
|
694
|
-
SELECT generate_series(
|
|
695
|
-
date_trunc('${interval}', ${timeSeriesStart}),
|
|
696
|
-
date_trunc('${interval}', ${timeSeriesEnd}),
|
|
697
|
-
INTERVAL '1 ${interval}'
|
|
698
|
-
) AS timestamp
|
|
699
|
-
),
|
|
700
|
-
coupon_data AS (
|
|
701
|
-
SELECT
|
|
702
|
-
date_trunc('${interval}', tx_record_time) AS timestamp,
|
|
703
|
-
COUNT(*) as count,
|
|
704
|
-
COALESCE(SUM(app_reward_amount), 0) as amount,
|
|
705
|
-
COALESCE(SUM(coupon_amount), 0) as coupon_amount
|
|
706
|
-
FROM canton_app_reward_coupons
|
|
707
|
-
WHERE ${timeFilter}${partyCondition}${statusCondition}
|
|
708
|
-
GROUP BY date_trunc('${interval}', tx_record_time)
|
|
709
|
-
)
|
|
710
|
-
SELECT
|
|
711
|
-
ts.timestamp::text,
|
|
712
|
-
COALESCE(cd.count, 0) as count,
|
|
713
|
-
COALESCE(cd.amount, 0) as amount,
|
|
714
|
-
COALESCE(cd.coupon_amount, 0) as coupon_amount
|
|
715
|
-
FROM time_series ts
|
|
716
|
-
LEFT JOIN coupon_data cd ON ts.timestamp = cd.timestamp
|
|
717
|
-
ORDER BY ts.timestamp ASC
|
|
718
|
-
`;
|
|
719
|
-
const result = await this.pool.query(query);
|
|
720
|
-
return result.rows.map(row => ({
|
|
721
|
-
timestamp: row.timestamp,
|
|
722
|
-
count: parseInt(row.count, 10),
|
|
723
|
-
amount: parseFloat(row.amount),
|
|
724
|
-
couponAmount: parseFloat(row.coupon_amount),
|
|
725
|
-
}));
|
|
726
|
-
}
|
|
727
|
-
async getRewardCouponRoundSeriesData(timeRange, _metric = 'count', timePeriod, customStartDate, partyFilter, couponStatus = 'all') {
|
|
728
|
-
let timeRangeInterval;
|
|
729
|
-
let timeFilter;
|
|
730
|
-
switch (timeRange) {
|
|
731
|
-
case '15m':
|
|
732
|
-
timeRangeInterval = '15 minutes';
|
|
733
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '15 minutes'";
|
|
734
|
-
break;
|
|
735
|
-
case '1h':
|
|
736
|
-
timeRangeInterval = '1 hour';
|
|
737
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '1 hour'";
|
|
738
|
-
break;
|
|
739
|
-
case '6h':
|
|
740
|
-
timeRangeInterval = '6 hours';
|
|
741
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '6 hours'";
|
|
742
|
-
break;
|
|
743
|
-
case '1d':
|
|
744
|
-
timeRangeInterval = '1 day';
|
|
745
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '1 day'";
|
|
746
|
-
break;
|
|
747
|
-
case '7d':
|
|
748
|
-
timeRangeInterval = '7 days';
|
|
749
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '7 days'";
|
|
750
|
-
break;
|
|
751
|
-
case '30d':
|
|
752
|
-
timeRangeInterval = '30 days';
|
|
753
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '30 days'";
|
|
754
|
-
break;
|
|
755
|
-
case 'last-month':
|
|
756
|
-
timeRangeInterval = '1 month';
|
|
757
|
-
timeFilter =
|
|
758
|
-
"tx_record_time >= date_trunc('month', current_date - interval '1 month') AND tx_record_time < date_trunc('month', current_date)";
|
|
759
|
-
break;
|
|
760
|
-
case 'all':
|
|
761
|
-
default:
|
|
762
|
-
timeRangeInterval = '1 day';
|
|
763
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '1 day'";
|
|
764
|
-
}
|
|
765
|
-
if (timePeriod === 'custom-start' && customStartDate) {
|
|
766
|
-
timeFilter = `tx_record_time >= '${customStartDate}:00' AND tx_record_time < ('${customStartDate}:00'::timestamp + INTERVAL '${timeRangeInterval}')`;
|
|
767
|
-
}
|
|
768
|
-
// Add party filter if provided
|
|
769
|
-
const partyCondition = partyFilter
|
|
770
|
-
? ` AND beneficiary_party_id = '${partyFilter}'`
|
|
771
|
-
: '';
|
|
772
|
-
// Add status filter based on couponStatus
|
|
773
|
-
// 'created' = not yet archived, 'archived' = has been collected
|
|
774
|
-
// 'all' = all coupons regardless of archive status
|
|
775
|
-
let statusCondition = '';
|
|
776
|
-
if (couponStatus === 'created') {
|
|
777
|
-
statusCondition = ` AND status = 'created'`;
|
|
778
|
-
}
|
|
779
|
-
else if (couponStatus === 'archived') {
|
|
780
|
-
statusCondition = ` AND status = 'archived'`;
|
|
781
|
-
}
|
|
782
|
-
// When couponStatus === 'all', no filter is applied (statusCondition remains '')
|
|
783
|
-
const query = `
|
|
784
|
-
WITH time_filtered AS (
|
|
785
|
-
SELECT round_number
|
|
786
|
-
FROM canton_app_reward_coupons
|
|
787
|
-
WHERE ${timeFilter}${partyCondition}${statusCondition}
|
|
788
|
-
),
|
|
789
|
-
round_bounds AS (
|
|
790
|
-
SELECT
|
|
791
|
-
COALESCE(MIN(round_number), 0) AS min_round,
|
|
792
|
-
COALESCE(MAX(round_number), 0) AS max_round
|
|
793
|
-
FROM time_filtered
|
|
794
|
-
),
|
|
795
|
-
rounds AS (
|
|
796
|
-
SELECT generate_series(
|
|
797
|
-
GREATEST((SELECT min_round FROM round_bounds), 0),
|
|
798
|
-
GREATEST((SELECT max_round FROM round_bounds), 0)
|
|
799
|
-
) AS round
|
|
800
|
-
WHERE (SELECT max_round FROM round_bounds) > 0
|
|
801
|
-
),
|
|
802
|
-
coupon_data AS (
|
|
803
|
-
SELECT
|
|
804
|
-
round_number AS round,
|
|
805
|
-
MIN(tx_record_time) AS timestamp,
|
|
806
|
-
COUNT(*) AS count,
|
|
807
|
-
COALESCE(SUM(app_reward_amount), 0) AS amount,
|
|
808
|
-
COALESCE(SUM(coupon_amount), 0) AS coupon_amount
|
|
809
|
-
FROM canton_app_reward_coupons
|
|
810
|
-
WHERE round_number IN (SELECT round FROM rounds)${partyCondition}${statusCondition}
|
|
811
|
-
GROUP BY round_number
|
|
812
|
-
)
|
|
813
|
-
SELECT
|
|
814
|
-
r.round,
|
|
815
|
-
cd.timestamp,
|
|
816
|
-
COALESCE(cd.count, 0) AS count,
|
|
817
|
-
COALESCE(cd.amount, 0) AS amount,
|
|
818
|
-
COALESCE(cd.coupon_amount, 0) AS coupon_amount
|
|
819
|
-
FROM rounds r
|
|
820
|
-
LEFT JOIN coupon_data cd ON cd.round = r.round
|
|
821
|
-
ORDER BY r.round ASC
|
|
822
|
-
`;
|
|
823
|
-
const result = await this.pool.query(query);
|
|
824
|
-
return result.rows.map(row => ({
|
|
825
|
-
timestamp: row.timestamp
|
|
826
|
-
? new Date(row.timestamp).toISOString()
|
|
827
|
-
: new Date().toISOString(),
|
|
828
|
-
count: parseInt(row.count, 10),
|
|
829
|
-
amount: parseFloat(row.amount),
|
|
830
|
-
couponAmount: parseFloat(row.coupon_amount),
|
|
831
|
-
round: typeof row.round === 'number' ? row.round : parseInt(row.round, 10),
|
|
832
|
-
}));
|
|
119
|
+
return this.rewardCoupons.getMonthlyAppRewardAmountTotal(monthStart, monthEnd);
|
|
833
120
|
}
|
|
834
121
|
async getLatestCouponAmounts() {
|
|
835
|
-
|
|
836
|
-
WITH latest AS (
|
|
837
|
-
SELECT DISTINCT ON (featured)
|
|
838
|
-
featured,
|
|
839
|
-
coupon_amount
|
|
840
|
-
FROM canton_app_reward_coupons
|
|
841
|
-
WHERE coupon_amount IS NOT NULL
|
|
842
|
-
ORDER BY featured, tx_record_time DESC
|
|
843
|
-
)
|
|
844
|
-
SELECT
|
|
845
|
-
MAX(coupon_amount) FILTER (WHERE featured) AS featured_amount,
|
|
846
|
-
MAX(coupon_amount) FILTER (WHERE NOT featured) AS unfeatured_amount
|
|
847
|
-
FROM latest
|
|
848
|
-
`;
|
|
849
|
-
const result = await this.pool.query(query);
|
|
850
|
-
const row = result.rows[0] ?? {};
|
|
851
|
-
return {
|
|
852
|
-
featured: row.featured_amount !== null && row.featured_amount !== undefined
|
|
853
|
-
? parseFloat(row.featured_amount)
|
|
854
|
-
: null,
|
|
855
|
-
unfeatured: row.unfeatured_amount !== null && row.unfeatured_amount !== undefined
|
|
856
|
-
? parseFloat(row.unfeatured_amount)
|
|
857
|
-
: null,
|
|
858
|
-
};
|
|
122
|
+
return this.rewardCoupons.getLatestCouponAmounts();
|
|
859
123
|
}
|
|
860
124
|
async getLastAppRewardCouponTimestamp(partyFilter) {
|
|
861
|
-
|
|
862
|
-
? ` AND beneficiary_party_id = '${partyFilter}'`
|
|
863
|
-
: '';
|
|
864
|
-
const query = `
|
|
865
|
-
SELECT MAX(tx_record_time) AS last_timestamp
|
|
866
|
-
FROM canton_app_reward_coupons
|
|
867
|
-
WHERE status IN ('created', 'archived')
|
|
868
|
-
AND app_reward_amount IS NOT NULL${partyCondition}
|
|
869
|
-
`;
|
|
870
|
-
const result = await this.pool.query(query);
|
|
871
|
-
const timestamp = result.rows[0]?.last_timestamp;
|
|
872
|
-
return timestamp ? new Date(timestamp).toISOString() : null;
|
|
125
|
+
return this.rewardCoupons.getLastAppRewardCouponTimestamp(partyFilter);
|
|
873
126
|
}
|
|
874
127
|
async getLifetimeAppRewards() {
|
|
875
|
-
|
|
876
|
-
SELECT COALESCE(SUM(app_reward_amount), 0) AS total
|
|
877
|
-
FROM canton_app_reward_coupons
|
|
878
|
-
WHERE status = 'archived'
|
|
879
|
-
`;
|
|
880
|
-
const result = await this.pool.query(query);
|
|
881
|
-
return Number(result.rows[0]?.total ?? 0);
|
|
128
|
+
return this.rewardCoupons.getLifetimeAppRewards();
|
|
882
129
|
}
|
|
883
130
|
async getUniqueCouponBeneficiaryParties() {
|
|
884
|
-
|
|
885
|
-
SELECT DISTINCT
|
|
886
|
-
beneficiary_party_id as party_id,
|
|
887
|
-
beneficiary_party_id as display_name
|
|
888
|
-
FROM canton_app_reward_coupons
|
|
889
|
-
WHERE beneficiary_party_id IS NOT NULL
|
|
890
|
-
ORDER BY beneficiary_party_id ASC
|
|
891
|
-
`;
|
|
892
|
-
const result = await this.pool.query(query);
|
|
893
|
-
return result.rows;
|
|
894
|
-
}
|
|
895
|
-
async getAppMarkerTimeSeriesData(timeRange, _metric = 'count', timePeriod, customStartDate, partyFilter, _statusFilter) {
|
|
896
|
-
let interval;
|
|
897
|
-
let timeFilter;
|
|
898
|
-
let timeSeriesStart;
|
|
899
|
-
let timeSeriesEnd = 'NOW()';
|
|
900
|
-
let timeRangeInterval;
|
|
901
|
-
switch (timeRange) {
|
|
902
|
-
case '15m':
|
|
903
|
-
interval = 'minute';
|
|
904
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '15 minutes'";
|
|
905
|
-
timeRangeInterval = '15 minutes';
|
|
906
|
-
timeSeriesStart = "NOW() - INTERVAL '15 minutes'";
|
|
907
|
-
break;
|
|
908
|
-
case '1h':
|
|
909
|
-
interval = 'minute';
|
|
910
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '1 hour'";
|
|
911
|
-
timeRangeInterval = '1 hour';
|
|
912
|
-
timeSeriesStart = "NOW() - INTERVAL '1 hour'";
|
|
913
|
-
break;
|
|
914
|
-
case '6h':
|
|
915
|
-
interval = 'minute';
|
|
916
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '6 hours'";
|
|
917
|
-
timeRangeInterval = '6 hours';
|
|
918
|
-
timeSeriesStart = "NOW() - INTERVAL '6 hours'";
|
|
919
|
-
break;
|
|
920
|
-
case '1d':
|
|
921
|
-
interval = 'hour';
|
|
922
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '1 day'";
|
|
923
|
-
timeRangeInterval = '1 day';
|
|
924
|
-
timeSeriesStart = "NOW() - INTERVAL '1 day'";
|
|
925
|
-
break;
|
|
926
|
-
case '7d':
|
|
927
|
-
interval = 'hour';
|
|
928
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '7 days'";
|
|
929
|
-
timeRangeInterval = '7 days';
|
|
930
|
-
timeSeriesStart = "NOW() - INTERVAL '7 days'";
|
|
931
|
-
break;
|
|
932
|
-
case '30d':
|
|
933
|
-
interval = 'day';
|
|
934
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '30 days'";
|
|
935
|
-
timeRangeInterval = '30 days';
|
|
936
|
-
timeSeriesStart = "NOW() - INTERVAL '30 days'";
|
|
937
|
-
break;
|
|
938
|
-
case 'last-month':
|
|
939
|
-
interval = 'day';
|
|
940
|
-
timeFilter =
|
|
941
|
-
"tx_record_time >= date_trunc('month', current_date - interval '1 month') AND tx_record_time < date_trunc('month', current_date)";
|
|
942
|
-
timeRangeInterval = '1 month';
|
|
943
|
-
timeSeriesStart =
|
|
944
|
-
"date_trunc('month', current_date - interval '1 month')";
|
|
945
|
-
timeSeriesEnd = "date_trunc('month', current_date)";
|
|
946
|
-
break;
|
|
947
|
-
case 'all':
|
|
948
|
-
interval = 'day';
|
|
949
|
-
timeFilter = '1=1';
|
|
950
|
-
timeRangeInterval = '100 years';
|
|
951
|
-
timeSeriesStart = "'2023-01-01'::timestamp";
|
|
952
|
-
break;
|
|
953
|
-
default:
|
|
954
|
-
interval = 'hour';
|
|
955
|
-
timeFilter = "tx_record_time >= NOW() - INTERVAL '1 day'";
|
|
956
|
-
timeRangeInterval = '1 day';
|
|
957
|
-
timeSeriesStart = "NOW() - INTERVAL '1 day'";
|
|
958
|
-
}
|
|
959
|
-
// If custom start date is provided, override the timeFilter and time series start/end
|
|
960
|
-
if (timePeriod === 'custom-start' && customStartDate) {
|
|
961
|
-
timeFilter = `tx_record_time >= '${customStartDate}:00' AND tx_record_time < ('${customStartDate}:00'::timestamp + INTERVAL '${timeRangeInterval}')`;
|
|
962
|
-
timeSeriesStart = `'${customStartDate}:00'::timestamp`;
|
|
963
|
-
timeSeriesEnd = `('${customStartDate}:00'::timestamp + INTERVAL '${timeRangeInterval}')`;
|
|
964
|
-
}
|
|
965
|
-
// Add party filter if provided
|
|
966
|
-
const partyCondition = partyFilter
|
|
967
|
-
? ` AND beneficiary_party_id = '${partyFilter}'`
|
|
968
|
-
: '';
|
|
969
|
-
const query = `
|
|
970
|
-
WITH time_series AS (
|
|
971
|
-
SELECT generate_series(
|
|
972
|
-
date_trunc('${interval}', ${timeSeriesStart}),
|
|
973
|
-
date_trunc('${interval}', ${timeSeriesEnd}),
|
|
974
|
-
INTERVAL '1 ${interval}'
|
|
975
|
-
) AS timestamp
|
|
976
|
-
),
|
|
977
|
-
marker_data AS (
|
|
978
|
-
SELECT
|
|
979
|
-
date_trunc('${interval}', tx_record_time) AS timestamp,
|
|
980
|
-
COUNT(*) FILTER (WHERE status = 'archived') as archived_count,
|
|
981
|
-
COUNT(*) FILTER (WHERE status = 'created') as created_count,
|
|
982
|
-
COUNT(*) FILTER (WHERE status = 'archived') as archived_weight,
|
|
983
|
-
COUNT(*) FILTER (WHERE status = 'created') as created_weight
|
|
984
|
-
FROM canton_app_markers
|
|
985
|
-
WHERE ${timeFilter}${partyCondition}
|
|
986
|
-
GROUP BY date_trunc('${interval}', tx_record_time)
|
|
987
|
-
)
|
|
988
|
-
SELECT
|
|
989
|
-
ts.timestamp::text,
|
|
990
|
-
COALESCE(md.archived_count, 0) as archived_count,
|
|
991
|
-
COALESCE(md.created_count, 0) as created_count,
|
|
992
|
-
COALESCE(md.archived_count, 0) + COALESCE(md.created_count, 0) as count,
|
|
993
|
-
COALESCE(md.archived_weight, 0) as archived_weight,
|
|
994
|
-
COALESCE(md.created_weight, 0) as created_weight,
|
|
995
|
-
0 as amount,
|
|
996
|
-
0 as coupon_amount
|
|
997
|
-
FROM time_series ts
|
|
998
|
-
LEFT JOIN marker_data md ON ts.timestamp = md.timestamp
|
|
999
|
-
ORDER BY ts.timestamp ASC
|
|
1000
|
-
`;
|
|
1001
|
-
const result = await this.pool.query(query);
|
|
1002
|
-
return result.rows.map(row => ({
|
|
1003
|
-
timestamp: row.timestamp,
|
|
1004
|
-
count: parseInt(row.count, 10),
|
|
1005
|
-
archivedCount: parseInt(row.archived_count, 10),
|
|
1006
|
-
createdCount: parseInt(row.created_count, 10),
|
|
1007
|
-
archivedWeight: parseFloat(row.archived_weight),
|
|
1008
|
-
createdWeight: parseFloat(row.created_weight),
|
|
1009
|
-
amount: 0,
|
|
1010
|
-
couponAmount: 0,
|
|
1011
|
-
}));
|
|
1012
|
-
}
|
|
1013
|
-
async getAppMarkerRoundSeriesData(timeRange, _metric = 'count', timePeriod, customStartDate, partyFilter, _statusFilter) {
|
|
1014
|
-
let timeRangeInterval;
|
|
1015
|
-
switch (timeRange) {
|
|
1016
|
-
case '15m':
|
|
1017
|
-
timeRangeInterval = '15 minutes';
|
|
1018
|
-
break;
|
|
1019
|
-
case '1h':
|
|
1020
|
-
timeRangeInterval = '1 hour';
|
|
1021
|
-
break;
|
|
1022
|
-
case '6h':
|
|
1023
|
-
timeRangeInterval = '6 hours';
|
|
1024
|
-
break;
|
|
1025
|
-
case '1d':
|
|
1026
|
-
timeRangeInterval = '1 day';
|
|
1027
|
-
break;
|
|
1028
|
-
case '7d':
|
|
1029
|
-
timeRangeInterval = '7 days';
|
|
1030
|
-
break;
|
|
1031
|
-
case '30d':
|
|
1032
|
-
timeRangeInterval = '30 days';
|
|
1033
|
-
break;
|
|
1034
|
-
default:
|
|
1035
|
-
timeRangeInterval = '1 day';
|
|
1036
|
-
}
|
|
1037
|
-
if (timePeriod === 'custom-start' && customStartDate) {
|
|
1038
|
-
const _timeFilter = `tx_record_time >= '${customStartDate}:00' AND tx_record_time < ('${customStartDate}:00'::timestamp + INTERVAL '${timeRangeInterval}')`;
|
|
1039
|
-
void _timeFilter;
|
|
1040
|
-
}
|
|
1041
|
-
// Add party filter if provided
|
|
1042
|
-
const _partyCondition = partyFilter
|
|
1043
|
-
? ` AND beneficiary_party_id = '${partyFilter}'`
|
|
1044
|
-
: '';
|
|
1045
|
-
void _partyCondition;
|
|
1046
|
-
// Note: Markers don't have round numbers, so we just return time-based groupings
|
|
1047
|
-
// This method shouldn't be used for markers - use getAppMarkerTimeSeriesData instead
|
|
1048
|
-
// Returning empty result set as markers don't have rounds
|
|
1049
|
-
const query = `
|
|
1050
|
-
SELECT
|
|
1051
|
-
0::bigint as round,
|
|
1052
|
-
NOW()::text as timestamp,
|
|
1053
|
-
0::bigint as archived_count,
|
|
1054
|
-
0::bigint as created_count,
|
|
1055
|
-
0::bigint as count,
|
|
1056
|
-
0::numeric as archived_weight,
|
|
1057
|
-
0::numeric as created_weight,
|
|
1058
|
-
0::numeric as amount,
|
|
1059
|
-
0::numeric as coupon_amount
|
|
1060
|
-
WHERE false
|
|
1061
|
-
`;
|
|
1062
|
-
const result = await this.pool.query(query);
|
|
1063
|
-
return result.rows.map(row => ({
|
|
1064
|
-
timestamp: row.timestamp
|
|
1065
|
-
? new Date(row.timestamp).toISOString()
|
|
1066
|
-
: new Date().toISOString(),
|
|
1067
|
-
count: parseInt(row.count, 10),
|
|
1068
|
-
archivedCount: parseInt(row.archived_count, 10),
|
|
1069
|
-
createdCount: parseInt(row.created_count, 10),
|
|
1070
|
-
archivedWeight: parseFloat(row.archived_weight),
|
|
1071
|
-
createdWeight: parseFloat(row.created_weight),
|
|
1072
|
-
amount: 0,
|
|
1073
|
-
couponAmount: 0,
|
|
1074
|
-
round: typeof row.round === 'number' ? row.round : parseInt(row.round, 10),
|
|
1075
|
-
}));
|
|
1076
|
-
}
|
|
1077
|
-
async getUniqueMarkerBeneficiaryParties() {
|
|
1078
|
-
const query = `
|
|
1079
|
-
SELECT DISTINCT
|
|
1080
|
-
beneficiary_party_id as party_id,
|
|
1081
|
-
beneficiary_party_id as display_name
|
|
1082
|
-
FROM canton_app_markers
|
|
1083
|
-
WHERE beneficiary_party_id IS NOT NULL
|
|
1084
|
-
ORDER BY beneficiary_party_id ASC
|
|
1085
|
-
`;
|
|
1086
|
-
const result = await this.pool.query(query);
|
|
1087
|
-
return result.rows;
|
|
1088
|
-
}
|
|
1089
|
-
async getMonthlyPaymentTotalForParty(partyId, monthStart, monthEnd) {
|
|
1090
|
-
// Check for transfers using created_at since tx_record_time might be null
|
|
1091
|
-
const query = `
|
|
1092
|
-
SELECT COALESCE(SUM(transfer_amount), 0) as total_amount
|
|
1093
|
-
FROM canton_transfers
|
|
1094
|
-
WHERE transfer_sender_party_id = $1
|
|
1095
|
-
AND created_at >= $2
|
|
1096
|
-
AND created_at <= $3
|
|
1097
|
-
AND status = $4
|
|
1098
|
-
`;
|
|
1099
|
-
const result = await this.pool.query(query, [
|
|
1100
|
-
partyId,
|
|
1101
|
-
monthStart,
|
|
1102
|
-
monthEnd,
|
|
1103
|
-
types_1.TransferStatus.CONFIRMED,
|
|
1104
|
-
]);
|
|
1105
|
-
return parseFloat(result.rows[0].total_amount);
|
|
1106
|
-
}
|
|
1107
|
-
getRemainingRoundsInMonth(roundDurationMinutes = 10) {
|
|
1108
|
-
if (roundDurationMinutes <= 0) {
|
|
1109
|
-
throw new Error('roundDurationMinutes must be greater than 0');
|
|
1110
|
-
}
|
|
1111
|
-
const now = new Date();
|
|
1112
|
-
const nextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);
|
|
1113
|
-
const monthEnd = new Date(nextMonth.getTime() - 1); // Last moment of current month
|
|
1114
|
-
// Calculate how many intervals are remaining in the current month
|
|
1115
|
-
const roundDurationInMs = roundDurationMinutes * 60 * 1000;
|
|
1116
|
-
const remainingTimeInMs = monthEnd.getTime() - now.getTime();
|
|
1117
|
-
const remainingRounds = Math.max(0, Math.floor(remainingTimeInMs / roundDurationInMs));
|
|
1118
|
-
return remainingRounds;
|
|
1119
|
-
}
|
|
1120
|
-
async getMonthlyPaymentTotalsForParties(partyIds, monthStart, monthEnd) {
|
|
1121
|
-
if (partyIds.length === 0) {
|
|
1122
|
-
return new Map();
|
|
1123
|
-
}
|
|
1124
|
-
// Create placeholders for the IN clause
|
|
1125
|
-
const placeholders = partyIds.map((_, index) => `$${index + 4}`).join(',');
|
|
1126
|
-
const query = `
|
|
1127
|
-
SELECT transfer_sender_party_id, COALESCE(SUM(transfer_amount), 0) as total_amount
|
|
1128
|
-
FROM canton_transfers
|
|
1129
|
-
WHERE transfer_sender_party_id IN (${placeholders})
|
|
1130
|
-
AND created_at >= $1
|
|
1131
|
-
AND created_at <= $2
|
|
1132
|
-
AND status = $3
|
|
1133
|
-
GROUP BY transfer_sender_party_id
|
|
1134
|
-
`;
|
|
1135
|
-
const params = [
|
|
1136
|
-
monthStart,
|
|
1137
|
-
monthEnd,
|
|
1138
|
-
types_1.TransferStatus.CONFIRMED,
|
|
1139
|
-
...partyIds,
|
|
1140
|
-
];
|
|
1141
|
-
const result = await this.pool.query(query, params);
|
|
1142
|
-
const totals = new Map();
|
|
1143
|
-
result.rows.forEach(row => {
|
|
1144
|
-
totals.set(row.transfer_sender_party_id, parseFloat(row.total_amount));
|
|
1145
|
-
});
|
|
1146
|
-
// Ensure all party IDs are in the map (with 0 if no transfers found)
|
|
1147
|
-
partyIds.forEach(partyId => {
|
|
1148
|
-
if (!totals.has(partyId)) {
|
|
1149
|
-
totals.set(partyId, 0);
|
|
1150
|
-
}
|
|
1151
|
-
});
|
|
1152
|
-
return totals;
|
|
1153
|
-
}
|
|
1154
|
-
async getLifetimePaymentStatisticsForParties(partyIds) {
|
|
1155
|
-
if (partyIds.length === 0) {
|
|
1156
|
-
return new Map();
|
|
1157
|
-
}
|
|
1158
|
-
// Create placeholders for the IN clause
|
|
1159
|
-
const placeholders = partyIds.map((_, index) => `$${index + 1}`).join(',');
|
|
1160
|
-
const query = `
|
|
1161
|
-
SELECT
|
|
1162
|
-
transfer_sender_party_id,
|
|
1163
|
-
COUNT(*) as payment_count,
|
|
1164
|
-
COALESCE(SUM(transfer_amount), 0) as total_value_sent
|
|
1165
|
-
FROM canton_transfers
|
|
1166
|
-
WHERE transfer_sender_party_id IN (${placeholders})
|
|
1167
|
-
AND status = $${partyIds.length + 1}
|
|
1168
|
-
GROUP BY transfer_sender_party_id
|
|
1169
|
-
`;
|
|
1170
|
-
const params = [...partyIds, types_1.TransferStatus.CONFIRMED];
|
|
1171
|
-
const result = await this.pool.query(query, params);
|
|
1172
|
-
const statistics = new Map();
|
|
1173
|
-
result.rows.forEach(row => {
|
|
1174
|
-
const paymentCount = parseInt(row.payment_count, 10);
|
|
1175
|
-
const totalValueSent = parseFloat(row.total_value_sent);
|
|
1176
|
-
const totalFeesPaid = paymentCount * 0.6; // 0.6 * count as specified
|
|
1177
|
-
statistics.set(row.transfer_sender_party_id, {
|
|
1178
|
-
paymentCount,
|
|
1179
|
-
totalValueSent,
|
|
1180
|
-
totalFeesPaid,
|
|
1181
|
-
});
|
|
1182
|
-
});
|
|
1183
|
-
// Ensure all party IDs are in the map (with 0 if no transfers found)
|
|
1184
|
-
partyIds.forEach(partyId => {
|
|
1185
|
-
if (!statistics.has(partyId)) {
|
|
1186
|
-
statistics.set(partyId, {
|
|
1187
|
-
paymentCount: 0,
|
|
1188
|
-
totalValueSent: 0,
|
|
1189
|
-
totalFeesPaid: 0,
|
|
1190
|
-
});
|
|
1191
|
-
}
|
|
1192
|
-
});
|
|
1193
|
-
return statistics;
|
|
131
|
+
return this.rewardCoupons.getUniqueCouponBeneficiaryParties();
|
|
1194
132
|
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
*
|
|
1198
|
-
* @returns Array of portal info that need canton parties created
|
|
1199
|
-
*/
|
|
1200
|
-
async getPortalsNeedingCantonParties() {
|
|
1201
|
-
const query = `
|
|
1202
|
-
SELECT p.id, p.company->>'name' as company_name
|
|
1203
|
-
FROM portal p
|
|
1204
|
-
WHERE p.enable_canton_rewards = true
|
|
1205
|
-
AND NOT EXISTS (
|
|
1206
|
-
SELECT 1 FROM canton_parties cp
|
|
1207
|
-
WHERE cp.portal_id = p.id
|
|
1208
|
-
)
|
|
1209
|
-
ORDER BY p.created_at ASC
|
|
1210
|
-
`;
|
|
1211
|
-
const result = await this.pool.query(query);
|
|
1212
|
-
return result.rows.map(row => ({
|
|
1213
|
-
id: row.id,
|
|
1214
|
-
companyName: row.company_name ?? undefined,
|
|
1215
|
-
}));
|
|
1216
|
-
}
|
|
1217
|
-
// Transaction helper - runs a callback within a database transaction
|
|
1218
|
-
async runInTransaction(callback) {
|
|
1219
|
-
const client = await this.pool.connect();
|
|
1220
|
-
try {
|
|
1221
|
-
await client.query('BEGIN');
|
|
1222
|
-
const result = await callback(client);
|
|
1223
|
-
await client.query('COMMIT');
|
|
1224
|
-
return result;
|
|
1225
|
-
}
|
|
1226
|
-
catch (error) {
|
|
1227
|
-
await client.query('ROLLBACK');
|
|
1228
|
-
throw error;
|
|
1229
|
-
}
|
|
1230
|
-
finally {
|
|
1231
|
-
client.release();
|
|
1232
|
-
}
|
|
133
|
+
async getHistoricalIssuanceRates(roundNumbers) {
|
|
134
|
+
return this.rewardCoupons.getHistoricalIssuanceRates(roundNumbers);
|
|
1233
135
|
}
|
|
1234
|
-
//
|
|
136
|
+
// ========================================================================
|
|
137
|
+
// App Marker Operations
|
|
138
|
+
// ========================================================================
|
|
1235
139
|
async insertCantonAppMarker(marker) {
|
|
1236
|
-
|
|
1237
|
-
INSERT INTO canton_app_markers (
|
|
1238
|
-
status, contract_id, provider_party_id, beneficiary_party_id, tx_record_time, weight
|
|
1239
|
-
) VALUES ($1, $2, $3, $4, $5, $6)
|
|
1240
|
-
RETURNING *
|
|
1241
|
-
`;
|
|
1242
|
-
const values = [
|
|
1243
|
-
marker.status,
|
|
1244
|
-
marker.contract_id,
|
|
1245
|
-
marker.provider_party_id,
|
|
1246
|
-
marker.beneficiary_party_id,
|
|
1247
|
-
marker.tx_record_time,
|
|
1248
|
-
marker.weight,
|
|
1249
|
-
];
|
|
1250
|
-
const result = await this.pool.query(query, values);
|
|
1251
|
-
return this.mapAppMarkerFromDb(result.rows[0]);
|
|
140
|
+
return this.appMarkers.insertCantonAppMarker(marker);
|
|
1252
141
|
}
|
|
1253
142
|
async batchInsertCantonAppMarkers(markers) {
|
|
1254
|
-
|
|
1255
|
-
return { insertedCount: 0, skippedCount: 0 };
|
|
1256
|
-
}
|
|
1257
|
-
// Build the VALUES clause with placeholders
|
|
1258
|
-
const valuesPlaceholders = markers
|
|
1259
|
-
.map((_, idx) => `($${idx * 6 + 1}, $${idx * 6 + 2}, $${idx * 6 + 3}, $${idx * 6 + 4}, $${idx * 6 + 5}, $${idx * 6 + 6})`)
|
|
1260
|
-
.join(', ');
|
|
1261
|
-
const query = `
|
|
1262
|
-
INSERT INTO canton_app_markers (
|
|
1263
|
-
status, contract_id, provider_party_id, beneficiary_party_id, tx_record_time, weight
|
|
1264
|
-
) VALUES ${valuesPlaceholders}
|
|
1265
|
-
ON CONFLICT (contract_id) DO NOTHING
|
|
1266
|
-
RETURNING *
|
|
1267
|
-
`;
|
|
1268
|
-
// Flatten all marker values into a single array
|
|
1269
|
-
const values = markers.flatMap(marker => [
|
|
1270
|
-
marker.status,
|
|
1271
|
-
marker.contract_id,
|
|
1272
|
-
marker.provider_party_id,
|
|
1273
|
-
marker.beneficiary_party_id,
|
|
1274
|
-
marker.tx_record_time,
|
|
1275
|
-
marker.weight,
|
|
1276
|
-
]);
|
|
1277
|
-
const result = await this.pool.query(query, values);
|
|
1278
|
-
const insertedCount = result.rowCount ?? 0;
|
|
1279
|
-
const skippedCount = markers.length - insertedCount;
|
|
1280
|
-
return { insertedCount, skippedCount };
|
|
143
|
+
return this.appMarkers.batchInsertCantonAppMarkers(markers);
|
|
1281
144
|
}
|
|
1282
145
|
async upsertCantonAppMarkerAsArchived(marker) {
|
|
1283
|
-
|
|
1284
|
-
INSERT INTO canton_app_markers (
|
|
1285
|
-
status, contract_id, provider_party_id, beneficiary_party_id, tx_record_time, weight
|
|
1286
|
-
) VALUES ($1, $2, $3, $4, $5, $6)
|
|
1287
|
-
ON CONFLICT (contract_id) DO UPDATE
|
|
1288
|
-
SET status = EXCLUDED.status, updated_at = NOW()
|
|
1289
|
-
RETURNING *
|
|
1290
|
-
`;
|
|
1291
|
-
const values = [
|
|
1292
|
-
marker.status,
|
|
1293
|
-
marker.contract_id,
|
|
1294
|
-
marker.provider_party_id,
|
|
1295
|
-
marker.beneficiary_party_id,
|
|
1296
|
-
marker.tx_record_time,
|
|
1297
|
-
marker.weight,
|
|
1298
|
-
];
|
|
1299
|
-
const result = await this.pool.query(query, values);
|
|
1300
|
-
return this.mapAppMarkerFromDb(result.rows[0]);
|
|
146
|
+
return this.appMarkers.upsertCantonAppMarkerAsArchived(marker);
|
|
1301
147
|
}
|
|
1302
148
|
async getCantonAppMarker(id) {
|
|
1303
|
-
|
|
1304
|
-
const result = await this.pool.query(query, [id]);
|
|
1305
|
-
return result.rows.length > 0
|
|
1306
|
-
? this.mapAppMarkerFromDb(result.rows[0])
|
|
1307
|
-
: null;
|
|
149
|
+
return this.appMarkers.getCantonAppMarker(id);
|
|
1308
150
|
}
|
|
1309
151
|
async getCantonAppMarkerByContractId(contractId) {
|
|
1310
|
-
|
|
1311
|
-
const result = await this.pool.query(query, [contractId]);
|
|
1312
|
-
return result.rows.length > 0
|
|
1313
|
-
? this.mapAppMarkerFromDb(result.rows[0])
|
|
1314
|
-
: null;
|
|
152
|
+
return this.appMarkers.getCantonAppMarkerByContractId(contractId);
|
|
1315
153
|
}
|
|
1316
154
|
async getCantonAppMarkersByContractIds(contractIds) {
|
|
1317
|
-
|
|
1318
|
-
return [];
|
|
1319
|
-
}
|
|
1320
|
-
const placeholders = contractIds
|
|
1321
|
-
.map((_, index) => `$${index + 1}`)
|
|
1322
|
-
.join(', ');
|
|
1323
|
-
const query = `
|
|
1324
|
-
SELECT * FROM canton_app_markers
|
|
1325
|
-
WHERE contract_id IN (${placeholders})
|
|
1326
|
-
`;
|
|
1327
|
-
const result = await this.pool.query(query, contractIds);
|
|
1328
|
-
return result.rows.map(row => this.mapAppMarkerFromDb(row));
|
|
155
|
+
return this.appMarkers.getCantonAppMarkersByContractIds(contractIds);
|
|
1329
156
|
}
|
|
1330
157
|
async batchUpdateCantonAppMarkersByContractIds(contractIds, updates) {
|
|
1331
|
-
|
|
1332
|
-
return [];
|
|
1333
|
-
}
|
|
1334
|
-
const setClauses = [];
|
|
1335
|
-
const values = [];
|
|
1336
|
-
let paramIndex = 1;
|
|
1337
|
-
// Build dynamic update query
|
|
1338
|
-
Object.entries(updates).forEach(([key, value]) => {
|
|
1339
|
-
if (key !== 'id' && key !== 'created_at') {
|
|
1340
|
-
setClauses.push(`${this.toSnakeCase(key)} = $${paramIndex}`);
|
|
1341
|
-
values.push(value);
|
|
1342
|
-
paramIndex++;
|
|
1343
|
-
}
|
|
1344
|
-
});
|
|
1345
|
-
if (setClauses.length === 0) {
|
|
1346
|
-
throw new Error('No valid fields to update');
|
|
1347
|
-
}
|
|
1348
|
-
// Build the WHERE clause for contract IDs
|
|
1349
|
-
const contractIdPlaceholders = contractIds
|
|
1350
|
-
.map((_, index) => `$${paramIndex + index}`)
|
|
1351
|
-
.join(', ');
|
|
1352
|
-
values.push(...contractIds);
|
|
1353
|
-
const query = `
|
|
1354
|
-
UPDATE canton_app_markers
|
|
1355
|
-
SET ${setClauses.join(', ')}, updated_at = NOW()
|
|
1356
|
-
WHERE contract_id IN (${contractIdPlaceholders})
|
|
1357
|
-
RETURNING *
|
|
1358
|
-
`;
|
|
1359
|
-
const result = await this.pool.query(query, values);
|
|
1360
|
-
return result.rows.map(row => this.mapAppMarkerFromDb(row));
|
|
158
|
+
return this.appMarkers.batchUpdateCantonAppMarkersByContractIds(contractIds, updates);
|
|
1361
159
|
}
|
|
1362
160
|
async getCantonAppMarkersByStatus(status, limit = 100, sortOrder = 'ASC') {
|
|
1363
|
-
|
|
1364
|
-
SELECT * FROM canton_app_markers
|
|
1365
|
-
WHERE status = $1
|
|
1366
|
-
ORDER BY tx_record_time ${sortOrder}
|
|
1367
|
-
LIMIT $2
|
|
1368
|
-
`;
|
|
1369
|
-
const result = await this.pool.query(query, [status, limit]);
|
|
1370
|
-
return result.rows.map(row => this.mapAppMarkerFromDb(row));
|
|
161
|
+
return this.appMarkers.getCantonAppMarkersByStatus(status, limit, sortOrder);
|
|
1371
162
|
}
|
|
1372
163
|
async getLatestCantonAppMarkers(limit = 3, beneficiaryPartyId) {
|
|
1373
|
-
|
|
1374
|
-
SELECT * FROM canton_app_markers
|
|
1375
|
-
`;
|
|
1376
|
-
const params = [];
|
|
1377
|
-
if (beneficiaryPartyId) {
|
|
1378
|
-
query += ` WHERE beneficiary_party_id = $1`;
|
|
1379
|
-
params.push(beneficiaryPartyId);
|
|
1380
|
-
}
|
|
1381
|
-
query += ` ORDER BY tx_record_time DESC LIMIT $${params.length + 1}`;
|
|
1382
|
-
params.push(limit);
|
|
1383
|
-
const result = await this.pool.query(query, params);
|
|
1384
|
-
return result.rows.map(row => this.mapAppMarkerFromDb(row));
|
|
164
|
+
return this.appMarkers.getLatestCantonAppMarkers(limit, beneficiaryPartyId);
|
|
1385
165
|
}
|
|
1386
166
|
async getOldestUnarchivedCantonAppMarkers(limit = 3, beneficiaryPartyId) {
|
|
1387
|
-
|
|
1388
|
-
SELECT * FROM canton_app_markers
|
|
1389
|
-
WHERE status = 'created'
|
|
1390
|
-
`;
|
|
1391
|
-
const params = [];
|
|
1392
|
-
if (beneficiaryPartyId) {
|
|
1393
|
-
query += ` AND beneficiary_party_id = $${params.length + 1}`;
|
|
1394
|
-
params.push(beneficiaryPartyId);
|
|
1395
|
-
}
|
|
1396
|
-
query += ` ORDER BY tx_record_time ASC LIMIT $${params.length + 1}`;
|
|
1397
|
-
params.push(limit);
|
|
1398
|
-
const result = await this.pool.query(query, params);
|
|
1399
|
-
return result.rows.map(row => this.mapAppMarkerFromDb(row));
|
|
167
|
+
return this.appMarkers.getOldestUnarchivedCantonAppMarkers(limit, beneficiaryPartyId);
|
|
1400
168
|
}
|
|
1401
169
|
async updateCantonAppMarker(id, updates) {
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
paramIndex++;
|
|
1411
|
-
}
|
|
1412
|
-
});
|
|
1413
|
-
if (setClauses.length === 0) {
|
|
1414
|
-
throw new Error('No valid fields to update');
|
|
1415
|
-
}
|
|
1416
|
-
values.push(id);
|
|
1417
|
-
const query = `
|
|
1418
|
-
UPDATE canton_app_markers
|
|
1419
|
-
SET ${setClauses.join(', ')}, updated_at = NOW()
|
|
1420
|
-
WHERE id = $${paramIndex}
|
|
1421
|
-
RETURNING *
|
|
1422
|
-
`;
|
|
1423
|
-
const result = await this.pool.query(query, values);
|
|
1424
|
-
return result.rows.length > 0
|
|
1425
|
-
? this.mapAppMarkerFromDb(result.rows[0])
|
|
1426
|
-
: null;
|
|
1427
|
-
}
|
|
1428
|
-
// Canton Parties CRUD operations
|
|
170
|
+
return this.appMarkers.updateCantonAppMarker(id, updates);
|
|
171
|
+
}
|
|
172
|
+
async getUniqueMarkerBeneficiaryParties() {
|
|
173
|
+
return this.appMarkers.getUniqueMarkerBeneficiaryParties();
|
|
174
|
+
}
|
|
175
|
+
// ========================================================================
|
|
176
|
+
// Party Operations
|
|
177
|
+
// ========================================================================
|
|
1429
178
|
async insertCantonParty(party) {
|
|
1430
|
-
|
|
1431
|
-
INSERT INTO canton_parties (
|
|
1432
|
-
party_id, portal_id, provider, last_payment_until, is_active_customer_since
|
|
1433
|
-
) VALUES ($1, $2, $3, $4, $5)
|
|
1434
|
-
RETURNING *
|
|
1435
|
-
`;
|
|
1436
|
-
const values = [
|
|
1437
|
-
party.party_id,
|
|
1438
|
-
party.portal_id,
|
|
1439
|
-
party.provider,
|
|
1440
|
-
party.last_payment_until,
|
|
1441
|
-
party.is_active_customer_since,
|
|
1442
|
-
];
|
|
1443
|
-
const result = await this.pool.query(query, values);
|
|
1444
|
-
return this.mapPartyFromDb(result.rows[0]);
|
|
179
|
+
return this.parties.insertCantonParty(party);
|
|
1445
180
|
}
|
|
1446
181
|
async getCantonParty(id) {
|
|
1447
|
-
|
|
1448
|
-
SELECT
|
|
1449
|
-
cp.*,
|
|
1450
|
-
p.company
|
|
1451
|
-
FROM canton_parties cp
|
|
1452
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
1453
|
-
WHERE cp.id = $1
|
|
1454
|
-
`;
|
|
1455
|
-
const result = await this.pool.query(query, [id]);
|
|
1456
|
-
return result.rows.length > 0 ? this.mapPartyFromDb(result.rows[0]) : null;
|
|
182
|
+
return this.parties.getCantonParty(id);
|
|
1457
183
|
}
|
|
1458
184
|
async getCantonPartyByPartyId(partyId) {
|
|
1459
|
-
|
|
1460
|
-
SELECT
|
|
1461
|
-
cp.*,
|
|
1462
|
-
p.company
|
|
1463
|
-
FROM canton_parties cp
|
|
1464
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
1465
|
-
WHERE cp.party_id = $1
|
|
1466
|
-
`;
|
|
1467
|
-
const result = await this.pool.query(query, [partyId]);
|
|
1468
|
-
return result.rows.length > 0 ? this.mapPartyFromDb(result.rows[0]) : null;
|
|
185
|
+
return this.parties.getCantonPartyByPartyId(partyId);
|
|
1469
186
|
}
|
|
1470
187
|
async updateCantonParty(id, updates) {
|
|
1471
|
-
|
|
1472
|
-
const values = [];
|
|
1473
|
-
let paramIndex = 1;
|
|
1474
|
-
// Build dynamic update query - exclude amulets field
|
|
1475
|
-
Object.entries(updates).forEach(([key, value]) => {
|
|
1476
|
-
if (key !== 'id' && key !== 'created_at' && key !== 'amulets') {
|
|
1477
|
-
setClauses.push(`${this.toSnakeCase(key)} = $${paramIndex}`);
|
|
1478
|
-
values.push(value);
|
|
1479
|
-
paramIndex++;
|
|
1480
|
-
}
|
|
1481
|
-
});
|
|
1482
|
-
if (setClauses.length === 0) {
|
|
1483
|
-
throw new Error('No valid fields to update');
|
|
1484
|
-
}
|
|
1485
|
-
values.push(id);
|
|
1486
|
-
const query = `
|
|
1487
|
-
UPDATE canton_parties
|
|
1488
|
-
SET ${setClauses.join(', ')}, updated_at = NOW()
|
|
1489
|
-
WHERE id = $${paramIndex}
|
|
1490
|
-
RETURNING id
|
|
1491
|
-
`;
|
|
1492
|
-
const result = await this.pool.query(query, values);
|
|
1493
|
-
if (result.rows.length > 0) {
|
|
1494
|
-
return this.getCantonParty(id);
|
|
1495
|
-
}
|
|
1496
|
-
return null;
|
|
188
|
+
return this.parties.updateCantonParty(id, updates);
|
|
1497
189
|
}
|
|
1498
190
|
async updateCantonPartyByPartyId(partyId, updates) {
|
|
1499
|
-
|
|
1500
|
-
const values = [];
|
|
1501
|
-
let paramIndex = 1;
|
|
1502
|
-
// Build dynamic update query - exclude amulets field
|
|
1503
|
-
Object.entries(updates).forEach(([key, value]) => {
|
|
1504
|
-
if (key !== 'id' && key !== 'created_at' && key !== 'amulets') {
|
|
1505
|
-
setClauses.push(`${this.toSnakeCase(key)} = $${paramIndex}`);
|
|
1506
|
-
values.push(value);
|
|
1507
|
-
paramIndex++;
|
|
1508
|
-
}
|
|
1509
|
-
});
|
|
1510
|
-
if (setClauses.length === 0) {
|
|
1511
|
-
throw new Error('No valid fields to update');
|
|
1512
|
-
}
|
|
1513
|
-
values.push(partyId);
|
|
1514
|
-
const query = `
|
|
1515
|
-
UPDATE canton_parties
|
|
1516
|
-
SET ${setClauses.join(', ')}, updated_at = NOW()
|
|
1517
|
-
WHERE party_id = $${paramIndex}
|
|
1518
|
-
RETURNING party_id
|
|
1519
|
-
`;
|
|
1520
|
-
const result = await this.pool.query(query, values);
|
|
1521
|
-
if (result.rows.length > 0) {
|
|
1522
|
-
return this.getCantonPartyByPartyId(partyId);
|
|
1523
|
-
}
|
|
1524
|
-
return null;
|
|
191
|
+
return this.parties.updateCantonPartyByPartyId(partyId, updates);
|
|
1525
192
|
}
|
|
1526
|
-
// Amulet operations removed - use getActiveContracts instead
|
|
1527
|
-
// async addAmuletToParty() - REMOVED
|
|
1528
|
-
// async removeAmuletFromParty() - REMOVED
|
|
1529
|
-
// async replaceAmuletsForParty() - REMOVED
|
|
1530
193
|
async getActiveCustomersWithExpiredPayment() {
|
|
1531
|
-
|
|
1532
|
-
SELECT
|
|
1533
|
-
cp.*,
|
|
1534
|
-
p.company
|
|
1535
|
-
FROM canton_parties cp
|
|
1536
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
1537
|
-
WHERE cp.is_active_customer_since IS NOT NULL
|
|
1538
|
-
AND (cp.last_payment_until IS NULL OR cp.last_payment_until < NOW())
|
|
1539
|
-
ORDER BY cp.last_payment_until ASC NULLS FIRST
|
|
1540
|
-
`;
|
|
1541
|
-
const result = await this.pool.query(query);
|
|
1542
|
-
return result.rows.map(row => this.mapPartyFromDb(row));
|
|
194
|
+
return this.parties.getActiveCustomersWithExpiredPayment();
|
|
1543
195
|
}
|
|
1544
196
|
async getAllParties(provider) {
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
const partyIds = parties.map(party => party.party_id);
|
|
1575
|
-
const paymentStats = await this.getLifetimePaymentStatisticsForParties(partyIds);
|
|
1576
|
-
// Merge payment statistics with party data
|
|
1577
|
-
return parties.map(party => {
|
|
1578
|
-
const stats = paymentStats.get(party.party_id);
|
|
1579
|
-
return {
|
|
1580
|
-
...party,
|
|
1581
|
-
payment_count: stats?.paymentCount ?? 0,
|
|
1582
|
-
total_value_sent: stats?.totalValueSent ?? 0,
|
|
1583
|
-
total_fees_paid: stats?.totalFeesPaid ?? 0,
|
|
1584
|
-
};
|
|
1585
|
-
});
|
|
1586
|
-
}
|
|
1587
|
-
// OCF Deployments CRUD operations
|
|
197
|
+
return this.parties.getAllParties(provider);
|
|
198
|
+
}
|
|
199
|
+
async getPortalsNeedingCantonParties() {
|
|
200
|
+
return this.parties.getPortalsNeedingCantonParties();
|
|
201
|
+
}
|
|
202
|
+
// ========================================================================
|
|
203
|
+
// Time Series Operations
|
|
204
|
+
// ========================================================================
|
|
205
|
+
async getTransferTimeSeriesData(timeRange, metric = 'count', timePeriod, customStartDate) {
|
|
206
|
+
return this.timeSeries.getTransferTimeSeriesData(timeRange, metric, timePeriod, customStartDate);
|
|
207
|
+
}
|
|
208
|
+
async getRewardCouponTimeSeriesData(timeRange, metric = 'count', timePeriod, customStartDate, partyFilter, couponStatus = 'all') {
|
|
209
|
+
return this.timeSeries.getRewardCouponTimeSeriesData(timeRange, metric, timePeriod, customStartDate, partyFilter, couponStatus);
|
|
210
|
+
}
|
|
211
|
+
async getRewardCouponRoundSeriesData(timeRange, metric = 'count', timePeriod, customStartDate, partyFilter, couponStatus = 'all') {
|
|
212
|
+
return this.timeSeries.getRewardCouponRoundSeriesData(timeRange, metric, timePeriod, customStartDate, partyFilter, couponStatus);
|
|
213
|
+
}
|
|
214
|
+
async getAppMarkerTimeSeriesData(timeRange, metric = 'count', timePeriod, customStartDate, partyFilter, statusFilter) {
|
|
215
|
+
return this.timeSeries.getAppMarkerTimeSeriesData(timeRange, metric, timePeriod, customStartDate, partyFilter, statusFilter);
|
|
216
|
+
}
|
|
217
|
+
async getAppMarkerRoundSeriesData(timeRange, metric = 'count', timePeriod, customStartDate, partyFilter, statusFilter) {
|
|
218
|
+
return this.timeSeries.getAppMarkerRoundSeriesData(timeRange, metric, timePeriod, customStartDate, partyFilter, statusFilter);
|
|
219
|
+
}
|
|
220
|
+
async getMonthlyTransferTotal(monthStart, monthEnd) {
|
|
221
|
+
return this.timeSeries.getMonthlyTransferTotal(monthStart, monthEnd);
|
|
222
|
+
}
|
|
223
|
+
// ========================================================================
|
|
224
|
+
// OCF Deployment Operations
|
|
225
|
+
// ========================================================================
|
|
1588
226
|
async insertOcfDeployment(deployment) {
|
|
1589
|
-
|
|
1590
|
-
INSERT INTO ocf_deployments (
|
|
1591
|
-
ocf_object_id, version, chain_id, status, tx_hash, contract_id, party_id, wallet_address
|
|
1592
|
-
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
1593
|
-
RETURNING id, ocf_object_id, version, chain_id, status, tx_hash, contract_id, party_id, wallet_address, created_at, updated_at
|
|
1594
|
-
`;
|
|
1595
|
-
const values = [
|
|
1596
|
-
deployment.ocf_object_id,
|
|
1597
|
-
deployment.version,
|
|
1598
|
-
deployment.chain_id,
|
|
1599
|
-
deployment.status,
|
|
1600
|
-
deployment.tx_hash,
|
|
1601
|
-
deployment.contract_id,
|
|
1602
|
-
deployment.party_id,
|
|
1603
|
-
deployment.wallet_address,
|
|
1604
|
-
];
|
|
1605
|
-
const result = await this.pool.query(query, values);
|
|
1606
|
-
const row = result.rows[0];
|
|
1607
|
-
return {
|
|
1608
|
-
id: row.id,
|
|
1609
|
-
ocf_object_id: row.ocf_object_id,
|
|
1610
|
-
version: row.version,
|
|
1611
|
-
chain_id: row.chain_id,
|
|
1612
|
-
status: row.status,
|
|
1613
|
-
tx_hash: row.tx_hash,
|
|
1614
|
-
contract_id: row.contract_id,
|
|
1615
|
-
party_id: row.party_id,
|
|
1616
|
-
wallet_address: row.wallet_address,
|
|
1617
|
-
created_at: row.created_at,
|
|
1618
|
-
updated_at: row.updated_at,
|
|
1619
|
-
};
|
|
227
|
+
return this.ocfDeployments.insertOcfDeployment(deployment);
|
|
1620
228
|
}
|
|
1621
229
|
async getLatestOcfDeploymentByPartyId(partyId) {
|
|
1622
|
-
|
|
1623
|
-
SELECT id, ocf_object_id, version, chain_id, status, tx_hash, contract_id, party_id, wallet_address, created_at, updated_at
|
|
1624
|
-
FROM ocf_deployments
|
|
1625
|
-
WHERE party_id = $1
|
|
1626
|
-
ORDER BY version DESC
|
|
1627
|
-
LIMIT 1
|
|
1628
|
-
`;
|
|
1629
|
-
const result = await this.pool.query(query, [partyId]);
|
|
1630
|
-
if (result.rows.length === 0) {
|
|
1631
|
-
return null;
|
|
1632
|
-
}
|
|
1633
|
-
const row = result.rows[0];
|
|
1634
|
-
return {
|
|
1635
|
-
id: row.id,
|
|
1636
|
-
ocf_object_id: row.ocf_object_id,
|
|
1637
|
-
version: row.version,
|
|
1638
|
-
chain_id: row.chain_id,
|
|
1639
|
-
status: row.status,
|
|
1640
|
-
tx_hash: row.tx_hash,
|
|
1641
|
-
contract_id: row.contract_id,
|
|
1642
|
-
party_id: row.party_id,
|
|
1643
|
-
wallet_address: row.wallet_address,
|
|
1644
|
-
created_at: row.created_at,
|
|
1645
|
-
updated_at: row.updated_at,
|
|
1646
|
-
};
|
|
230
|
+
return this.ocfDeployments.getLatestOcfDeploymentByPartyId(partyId);
|
|
1647
231
|
}
|
|
1648
232
|
async getLatestOcfObjectByPortalId(portalId) {
|
|
1649
|
-
|
|
1650
|
-
SELECT o.id as ocf_object_id, o.version
|
|
1651
|
-
FROM latest_ocf_objects o
|
|
1652
|
-
WHERE o.portal_id = $1
|
|
1653
|
-
AND o.type = 'ISSUER'
|
|
1654
|
-
ORDER BY o.version DESC
|
|
1655
|
-
LIMIT 1
|
|
1656
|
-
`;
|
|
1657
|
-
const result = await this.pool.query(query, [portalId]);
|
|
1658
|
-
if (result.rows.length === 0) {
|
|
1659
|
-
return null;
|
|
1660
|
-
}
|
|
1661
|
-
const row = result.rows[0];
|
|
1662
|
-
return {
|
|
1663
|
-
ocf_object_id: row.ocf_object_id,
|
|
1664
|
-
version: row.version,
|
|
1665
|
-
};
|
|
233
|
+
return this.ocfDeployments.getLatestOcfObjectByPortalId(portalId);
|
|
1666
234
|
}
|
|
1667
|
-
/** Retrieve a specific OCF object row by id and version */
|
|
1668
235
|
async getOcfObjectDataByIdAndVersion(ocfObjectId, version) {
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
FROM ocf_objects
|
|
1672
|
-
WHERE id = $1 AND version = $2
|
|
1673
|
-
LIMIT 1
|
|
1674
|
-
`;
|
|
1675
|
-
const result = await this.pool.query(query, [ocfObjectId, version]);
|
|
1676
|
-
if (result.rows.length === 0)
|
|
1677
|
-
return null;
|
|
1678
|
-
const row = result.rows[0];
|
|
1679
|
-
return {
|
|
1680
|
-
type: row.type,
|
|
1681
|
-
subtype: row.subtype ?? null,
|
|
1682
|
-
ocf_data: row.ocf_data,
|
|
1683
|
-
};
|
|
1684
|
-
}
|
|
1685
|
-
/** List OCF deployments, optionally filtered */
|
|
236
|
+
return this.ocfDeployments.getOcfObjectDataByIdAndVersion(ocfObjectId, version);
|
|
237
|
+
}
|
|
1686
238
|
async listOcfDeployments(params) {
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
let idx = 1;
|
|
1690
|
-
if (params?.chainId) {
|
|
1691
|
-
conditions.push(`chain_id = $${idx++}`);
|
|
1692
|
-
values.push(params.chainId);
|
|
1693
|
-
}
|
|
1694
|
-
if (params?.status) {
|
|
1695
|
-
conditions.push(`status = $${idx++}`);
|
|
1696
|
-
values.push(params.status);
|
|
1697
|
-
}
|
|
1698
|
-
if (params?.partyId) {
|
|
1699
|
-
conditions.push(`party_id = $${idx++}`);
|
|
1700
|
-
values.push(params.partyId);
|
|
1701
|
-
}
|
|
1702
|
-
const whereClause = conditions.length
|
|
1703
|
-
? `WHERE ${conditions.join(' AND ')}`
|
|
1704
|
-
: '';
|
|
1705
|
-
const limitClause = typeof params?.limit === 'number' ? `LIMIT ${params.limit}` : '';
|
|
1706
|
-
const offsetClause = typeof params?.offset === 'number' ? `OFFSET ${params.offset}` : '';
|
|
1707
|
-
const query = `
|
|
1708
|
-
SELECT id, ocf_object_id, version, chain_id, status, tx_hash, contract_id, party_id, wallet_address, created_at, updated_at
|
|
1709
|
-
FROM ocf_deployments
|
|
1710
|
-
${whereClause}
|
|
1711
|
-
ORDER BY created_at DESC
|
|
1712
|
-
${limitClause}
|
|
1713
|
-
${offsetClause}
|
|
1714
|
-
`;
|
|
1715
|
-
const result = await this.pool.query(query, values);
|
|
1716
|
-
return result.rows.map(row => ({
|
|
1717
|
-
id: row.id,
|
|
1718
|
-
ocf_object_id: row.ocf_object_id,
|
|
1719
|
-
version: row.version,
|
|
1720
|
-
chain_id: row.chain_id,
|
|
1721
|
-
status: row.status,
|
|
1722
|
-
tx_hash: row.tx_hash,
|
|
1723
|
-
contract_id: row.contract_id,
|
|
1724
|
-
party_id: row.party_id,
|
|
1725
|
-
wallet_address: row.wallet_address,
|
|
1726
|
-
created_at: row.created_at,
|
|
1727
|
-
updated_at: row.updated_at,
|
|
1728
|
-
}));
|
|
1729
|
-
}
|
|
1730
|
-
/** Count total rows in latest_ocf_objects for progress stats */
|
|
239
|
+
return this.ocfDeployments.listOcfDeployments(params);
|
|
240
|
+
}
|
|
1731
241
|
async countLatestOcfObjects() {
|
|
1732
|
-
|
|
1733
|
-
const result = await this.pool.query(query);
|
|
1734
|
-
return Number(result.rows[0]?.cnt ?? 0);
|
|
242
|
+
return this.ocfDeployments.countLatestOcfObjects();
|
|
1735
243
|
}
|
|
1736
|
-
/**
|
|
1737
|
-
* Count rows in latest_ocf_objects that belong to portals with sync_captable_onchain=true Used for actionable
|
|
1738
|
-
* progress stats (objects that should be synced onchain)
|
|
1739
|
-
*/
|
|
1740
244
|
async countLatestOcfObjectsForOnchainSync() {
|
|
1741
|
-
|
|
1742
|
-
SELECT COUNT(*) AS cnt
|
|
1743
|
-
FROM latest_ocf_objects o
|
|
1744
|
-
JOIN portal p ON p.id = o.portal_id
|
|
1745
|
-
WHERE p.enable_canton_rewards = true
|
|
1746
|
-
`;
|
|
1747
|
-
const result = await this.pool.query(query);
|
|
1748
|
-
return Number(result.rows[0]?.cnt ?? 0);
|
|
245
|
+
return this.ocfDeployments.countLatestOcfObjectsForOnchainSync();
|
|
1749
246
|
}
|
|
1750
247
|
async getLatestOcfObjectDataByPortalId(portalId) {
|
|
1751
|
-
|
|
1752
|
-
SELECT o.id as ocf_object_id, o.version, o.ocf_data, o.type
|
|
1753
|
-
FROM latest_ocf_objects o
|
|
1754
|
-
WHERE o.portal_id = $1
|
|
1755
|
-
AND o.type = 'ISSUER'
|
|
1756
|
-
ORDER BY o.version DESC
|
|
1757
|
-
LIMIT 1
|
|
1758
|
-
`;
|
|
1759
|
-
const result = await this.pool.query(query, [portalId]);
|
|
1760
|
-
if (result.rows.length === 0) {
|
|
1761
|
-
return null;
|
|
1762
|
-
}
|
|
1763
|
-
const row = result.rows[0];
|
|
1764
|
-
return {
|
|
1765
|
-
ocf_object_id: row.ocf_object_id,
|
|
1766
|
-
version: row.version,
|
|
1767
|
-
ocf_data: row.ocf_data,
|
|
1768
|
-
type: row.type,
|
|
1769
|
-
};
|
|
248
|
+
return this.ocfDeployments.getLatestOcfObjectDataByPortalId(portalId);
|
|
1770
249
|
}
|
|
1771
250
|
async getPartiesWithoutOcfObjects() {
|
|
1772
|
-
|
|
1773
|
-
SELECT
|
|
1774
|
-
cp.party_id,
|
|
1775
|
-
cp.portal_id,
|
|
1776
|
-
cp.provider,
|
|
1777
|
-
p.company
|
|
1778
|
-
FROM canton_parties cp
|
|
1779
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
1780
|
-
WHERE NOT EXISTS (
|
|
1781
|
-
SELECT 1 FROM latest_ocf_objects o
|
|
1782
|
-
WHERE o.portal_id = cp.portal_id
|
|
1783
|
-
AND o.type = 'ISSUER'
|
|
1784
|
-
)
|
|
1785
|
-
ORDER BY cp.created_at ASC
|
|
1786
|
-
`;
|
|
1787
|
-
const result = await this.pool.query(query);
|
|
1788
|
-
return result.rows;
|
|
251
|
+
return this.ocfDeployments.getPartiesWithoutOcfObjects();
|
|
1789
252
|
}
|
|
1790
253
|
async getPartiesWithOcfObjectsButNoIssuerDeployments() {
|
|
1791
|
-
|
|
1792
|
-
SELECT
|
|
1793
|
-
cp.party_id,
|
|
1794
|
-
cp.portal_id,
|
|
1795
|
-
cp.provider,
|
|
1796
|
-
p.company,
|
|
1797
|
-
o.id as ocf_object_id,
|
|
1798
|
-
o.version as ocf_version,
|
|
1799
|
-
o.ocf_data,
|
|
1800
|
-
o.type as ocf_type
|
|
1801
|
-
FROM canton_parties cp
|
|
1802
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
1803
|
-
INNER JOIN latest_ocf_objects o ON o.portal_id = cp.portal_id AND o.type = 'ISSUER'
|
|
1804
|
-
WHERE NOT EXISTS (
|
|
1805
|
-
SELECT 1 FROM ocf_deployments od
|
|
1806
|
-
WHERE od.party_id = cp.party_id
|
|
1807
|
-
AND od.ocf_object_id = o.id
|
|
1808
|
-
)
|
|
1809
|
-
ORDER BY cp.created_at ASC
|
|
1810
|
-
`;
|
|
1811
|
-
const result = await this.pool.query(query);
|
|
1812
|
-
return result.rows;
|
|
254
|
+
return this.ocfDeployments.getPartiesWithOcfObjectsButNoIssuerDeployments();
|
|
1813
255
|
}
|
|
1814
256
|
async getPartiesWithOutdatedIssuerDeployments() {
|
|
1815
|
-
|
|
1816
|
-
SELECT
|
|
1817
|
-
cp.party_id,
|
|
1818
|
-
cp.portal_id,
|
|
1819
|
-
cp.provider,
|
|
1820
|
-
p.company,
|
|
1821
|
-
latest_ocf.version as latest_ocf_version,
|
|
1822
|
-
latest_deployment.version as deployed_version,
|
|
1823
|
-
latest_ocf.id as latest_ocf_object_id,
|
|
1824
|
-
latest_deployment.contract_id as current_contract_id,
|
|
1825
|
-
latest_ocf.ocf_data,
|
|
1826
|
-
latest_ocf.type as ocf_type
|
|
1827
|
-
FROM canton_parties cp
|
|
1828
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
1829
|
-
INNER JOIN (
|
|
1830
|
-
SELECT o.portal_id, o.id, o.version, o.ocf_data, o.type
|
|
1831
|
-
FROM latest_ocf_objects o
|
|
1832
|
-
WHERE o.type = 'ISSUER'
|
|
1833
|
-
) latest_ocf ON latest_ocf.portal_id = cp.portal_id
|
|
1834
|
-
INNER JOIN (
|
|
1835
|
-
SELECT od.party_id, od.ocf_object_id, od.version, od.contract_id,
|
|
1836
|
-
ROW_NUMBER() OVER (PARTITION BY od.party_id ORDER BY od.version DESC) as rn
|
|
1837
|
-
FROM ocf_deployments od
|
|
1838
|
-
WHERE od.status = 'deployed'
|
|
1839
|
-
) latest_deployment ON latest_deployment.party_id = cp.party_id
|
|
1840
|
-
AND latest_deployment.rn = 1
|
|
1841
|
-
WHERE latest_ocf.version > latest_deployment.version
|
|
1842
|
-
ORDER BY cp.created_at ASC
|
|
1843
|
-
`;
|
|
1844
|
-
const result = await this.pool.query(query);
|
|
1845
|
-
return result.rows;
|
|
257
|
+
return this.ocfDeployments.getPartiesWithOutdatedIssuerDeployments();
|
|
1846
258
|
}
|
|
1847
259
|
async getOnchainEquityValuations() {
|
|
1848
|
-
|
|
1849
|
-
SELECT p.id AS portal_id,
|
|
1850
|
-
p.id AS company_id,
|
|
1851
|
-
p.company->>'name' AS company_name,
|
|
1852
|
-
CASE
|
|
1853
|
-
WHEN COALESCE((pp.company_data ->> 'company_custom_valuation')::numeric, 0) > COALESCE((pp.company_data ->> 'company_computed_valuation')::numeric, 0)
|
|
1854
|
-
THEN COALESCE((pp.company_data ->> 'company_custom_valuation')::numeric, 0)
|
|
1855
|
-
ELSE COALESCE((pp.company_data ->> 'company_computed_valuation')::numeric, 0)
|
|
1856
|
-
END AS company_valuation
|
|
1857
|
-
FROM portal p
|
|
1858
|
-
JOIN portal_private pp ON pp.portal_id = p.id
|
|
1859
|
-
WHERE (p.company ->> 'name') !~* 'Fairbnb'
|
|
1860
|
-
AND (
|
|
1861
|
-
p.captable_minted
|
|
1862
|
-
OR (
|
|
1863
|
-
p.domain !~* 'staging'
|
|
1864
|
-
AND p.domain !~* 'websitecf'
|
|
1865
|
-
AND p.domain !~* '.cafe'
|
|
1866
|
-
)
|
|
1867
|
-
)
|
|
1868
|
-
ORDER BY p.captable_minted,
|
|
1869
|
-
CASE
|
|
1870
|
-
WHEN COALESCE((pp.company_data ->> 'company_custom_valuation')::numeric, 0) > COALESCE((pp.company_data ->> 'company_computed_valuation')::numeric, 0)
|
|
1871
|
-
THEN COALESCE((pp.company_data ->> 'company_custom_valuation')::numeric, 0)
|
|
1872
|
-
ELSE COALESCE((pp.company_data ->> 'company_computed_valuation')::numeric, 0)
|
|
1873
|
-
END DESC
|
|
1874
|
-
`;
|
|
1875
|
-
const result = await this.pool.query(query);
|
|
1876
|
-
return result.rows.map(row => ({
|
|
1877
|
-
portal_id: row.portal_id,
|
|
1878
|
-
company_id: row.company_id,
|
|
1879
|
-
company_name: row.company_name ?? null,
|
|
1880
|
-
company_valuation: Number(row.company_valuation ?? 0),
|
|
1881
|
-
}));
|
|
260
|
+
return this.ocfDeployments.getOnchainEquityValuations();
|
|
1882
261
|
}
|
|
1883
262
|
async getPortalsNeedingStockClassDeployments() {
|
|
1884
|
-
|
|
1885
|
-
SELECT DISTINCT
|
|
1886
|
-
cp.portal_id,
|
|
1887
|
-
cp.party_id,
|
|
1888
|
-
cp.provider,
|
|
1889
|
-
cp.created_at,
|
|
1890
|
-
p.company,
|
|
1891
|
-
loo.ocf_data,
|
|
1892
|
-
loo.id AS ocf_object_id,
|
|
1893
|
-
loo.version AS ocf_version,
|
|
1894
|
-
(
|
|
1895
|
-
SELECT od_issuer.contract_id
|
|
1896
|
-
FROM ocf_deployments od_issuer
|
|
1897
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
1898
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
1899
|
-
AND od_issuer.status = 'deployed'
|
|
1900
|
-
AND loo_issuer.type = 'ISSUER'
|
|
1901
|
-
ORDER BY od_issuer.created_at DESC
|
|
1902
|
-
LIMIT 1
|
|
1903
|
-
) as issuer_contract_id
|
|
1904
|
-
FROM canton_parties cp
|
|
1905
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
1906
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
1907
|
-
WHERE
|
|
1908
|
-
loo.type = 'STOCK_CLASS'
|
|
1909
|
-
AND EXISTS (
|
|
1910
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
1911
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
1912
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
1913
|
-
AND od_issuer.status = 'deployed'
|
|
1914
|
-
AND loo_issuer.type = 'ISSUER'
|
|
1915
|
-
)
|
|
1916
|
-
AND NOT EXISTS (
|
|
1917
|
-
SELECT 1 FROM ocf_deployments od_sc
|
|
1918
|
-
WHERE od_sc.ocf_object_id = loo.id
|
|
1919
|
-
AND od_sc.party_id = cp.party_id
|
|
1920
|
-
AND od_sc.status = 'deployed'
|
|
1921
|
-
)
|
|
1922
|
-
ORDER BY cp.created_at ASC
|
|
1923
|
-
`;
|
|
1924
|
-
const result = await this.pool.query(query);
|
|
1925
|
-
return result.rows;
|
|
263
|
+
return this.ocfDeployments.getPortalsNeedingStockClassDeployments();
|
|
1926
264
|
}
|
|
1927
265
|
async getPortalsNeedingStockClassUpdates() {
|
|
1928
|
-
|
|
1929
|
-
SELECT DISTINCT
|
|
1930
|
-
cp.portal_id,
|
|
1931
|
-
cp.party_id,
|
|
1932
|
-
cp.provider,
|
|
1933
|
-
cp.created_at,
|
|
1934
|
-
p.company,
|
|
1935
|
-
loo.ocf_data,
|
|
1936
|
-
loo.id AS ocf_object_id,
|
|
1937
|
-
loo.version as latest_ocf_version,
|
|
1938
|
-
od.version as deployed_version,
|
|
1939
|
-
od.contract_id as current_contract_id,
|
|
1940
|
-
(loo.version - od.version) AS version_diff,
|
|
1941
|
-
(
|
|
1942
|
-
SELECT od_issuer.contract_id
|
|
1943
|
-
FROM ocf_deployments od_issuer
|
|
1944
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
1945
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
1946
|
-
AND od_issuer.status = 'deployed'
|
|
1947
|
-
AND loo_issuer.type = 'ISSUER'
|
|
1948
|
-
ORDER BY od_issuer.created_at DESC
|
|
1949
|
-
LIMIT 1
|
|
1950
|
-
) as issuer_contract_id
|
|
1951
|
-
FROM canton_parties cp
|
|
1952
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
1953
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
1954
|
-
JOIN ocf_deployments od ON loo.id = od.ocf_object_id AND cp.party_id = od.party_id
|
|
1955
|
-
WHERE
|
|
1956
|
-
loo.type = 'STOCK_CLASS'
|
|
1957
|
-
AND EXISTS (
|
|
1958
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
1959
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
1960
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
1961
|
-
AND od_issuer.status = 'deployed'
|
|
1962
|
-
AND loo_issuer.type = 'ISSUER'
|
|
1963
|
-
)
|
|
1964
|
-
AND od.version < loo.version
|
|
1965
|
-
AND od.status = 'deployed'
|
|
1966
|
-
ORDER BY version_diff DESC, cp.created_at ASC
|
|
1967
|
-
`;
|
|
1968
|
-
const result = await this.pool.query(query);
|
|
1969
|
-
return result.rows;
|
|
266
|
+
return this.ocfDeployments.getPortalsNeedingStockClassUpdates();
|
|
1970
267
|
}
|
|
1971
268
|
async getPortalsNeedingStakeholderDeployments() {
|
|
1972
|
-
|
|
1973
|
-
SELECT DISTINCT
|
|
1974
|
-
cp.portal_id,
|
|
1975
|
-
cp.party_id,
|
|
1976
|
-
cp.provider,
|
|
1977
|
-
cp.created_at,
|
|
1978
|
-
p.company,
|
|
1979
|
-
loo.ocf_data,
|
|
1980
|
-
loo.id AS ocf_object_id,
|
|
1981
|
-
loo.version AS ocf_version,
|
|
1982
|
-
(
|
|
1983
|
-
SELECT od_issuer.contract_id
|
|
1984
|
-
FROM ocf_deployments od_issuer
|
|
1985
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
1986
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
1987
|
-
AND od_issuer.status = 'deployed'
|
|
1988
|
-
AND loo_issuer.type = 'ISSUER'
|
|
1989
|
-
ORDER BY od_issuer.created_at DESC
|
|
1990
|
-
LIMIT 1
|
|
1991
|
-
) as issuer_contract_id
|
|
1992
|
-
FROM canton_parties cp
|
|
1993
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
1994
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
1995
|
-
WHERE
|
|
1996
|
-
loo.type = 'STAKEHOLDER'
|
|
1997
|
-
AND EXISTS (
|
|
1998
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
1999
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2000
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2001
|
-
AND od_issuer.status = 'deployed'
|
|
2002
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2003
|
-
)
|
|
2004
|
-
AND NOT EXISTS (
|
|
2005
|
-
SELECT 1 FROM ocf_deployments od_sh
|
|
2006
|
-
WHERE od_sh.ocf_object_id = loo.id
|
|
2007
|
-
AND od_sh.party_id = cp.party_id
|
|
2008
|
-
AND od_sh.status = 'deployed'
|
|
2009
|
-
)
|
|
2010
|
-
ORDER BY cp.created_at ASC
|
|
2011
|
-
`;
|
|
2012
|
-
const result = await this.pool.query(query);
|
|
2013
|
-
return result.rows;
|
|
269
|
+
return this.ocfDeployments.getPortalsNeedingStakeholderDeployments();
|
|
2014
270
|
}
|
|
2015
271
|
async getPortalsNeedingStakeholderReDeployments() {
|
|
2016
|
-
|
|
2017
|
-
SELECT DISTINCT
|
|
2018
|
-
cp.portal_id,
|
|
2019
|
-
cp.party_id,
|
|
2020
|
-
cp.provider,
|
|
2021
|
-
cp.created_at,
|
|
2022
|
-
p.company,
|
|
2023
|
-
loo.ocf_data,
|
|
2024
|
-
loo.id AS ocf_object_id,
|
|
2025
|
-
loo.version as latest_ocf_version,
|
|
2026
|
-
od.version as deployed_version,
|
|
2027
|
-
od.contract_id as current_contract_id,
|
|
2028
|
-
(loo.version - od.version) AS version_diff,
|
|
2029
|
-
(
|
|
2030
|
-
SELECT od_issuer.contract_id
|
|
2031
|
-
FROM ocf_deployments od_issuer
|
|
2032
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2033
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2034
|
-
AND od_issuer.status = 'deployed'
|
|
2035
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2036
|
-
ORDER BY od_issuer.created_at DESC
|
|
2037
|
-
LIMIT 1
|
|
2038
|
-
) as issuer_contract_id
|
|
2039
|
-
FROM canton_parties cp
|
|
2040
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2041
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2042
|
-
JOIN ocf_deployments od ON loo.id = od.ocf_object_id AND cp.party_id = od.party_id
|
|
2043
|
-
WHERE
|
|
2044
|
-
loo.type = 'STAKEHOLDER'
|
|
2045
|
-
AND EXISTS (
|
|
2046
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2047
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2048
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2049
|
-
AND od_issuer.status = 'deployed'
|
|
2050
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2051
|
-
)
|
|
2052
|
-
AND od.version < loo.version
|
|
2053
|
-
AND od.status = 'deployed'
|
|
2054
|
-
ORDER BY version_diff DESC, cp.created_at ASC
|
|
2055
|
-
`;
|
|
2056
|
-
const result = await this.pool.query(query);
|
|
2057
|
-
return result.rows;
|
|
272
|
+
return this.ocfDeployments.getPortalsNeedingStakeholderReDeployments();
|
|
2058
273
|
}
|
|
2059
274
|
async getPortalsNeedingStockPlanDeployments() {
|
|
2060
|
-
|
|
2061
|
-
SELECT DISTINCT
|
|
2062
|
-
cp.portal_id,
|
|
2063
|
-
cp.party_id,
|
|
2064
|
-
cp.provider,
|
|
2065
|
-
cp.created_at,
|
|
2066
|
-
p.company,
|
|
2067
|
-
loo.ocf_data,
|
|
2068
|
-
loo.id AS ocf_object_id,
|
|
2069
|
-
loo.version AS ocf_version,
|
|
2070
|
-
(
|
|
2071
|
-
SELECT od_issuer.contract_id
|
|
2072
|
-
FROM ocf_deployments od_issuer
|
|
2073
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2074
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2075
|
-
AND od_issuer.status = 'deployed'
|
|
2076
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2077
|
-
ORDER BY od_issuer.created_at DESC
|
|
2078
|
-
LIMIT 1
|
|
2079
|
-
) as issuer_contract_id
|
|
2080
|
-
FROM canton_parties cp
|
|
2081
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2082
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2083
|
-
WHERE
|
|
2084
|
-
loo.type = 'STOCK_PLAN'
|
|
2085
|
-
AND EXISTS (
|
|
2086
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2087
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2088
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2089
|
-
AND od_issuer.status = 'deployed'
|
|
2090
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2091
|
-
)
|
|
2092
|
-
AND NOT EXISTS (
|
|
2093
|
-
SELECT 1 FROM ocf_deployments od_sp
|
|
2094
|
-
WHERE od_sp.ocf_object_id = loo.id
|
|
2095
|
-
AND od_sp.party_id = cp.party_id
|
|
2096
|
-
AND od_sp.status = 'deployed'
|
|
2097
|
-
)
|
|
2098
|
-
ORDER BY cp.created_at ASC
|
|
2099
|
-
`;
|
|
2100
|
-
const result = await this.pool.query(query);
|
|
2101
|
-
return result.rows;
|
|
275
|
+
return this.ocfDeployments.getPortalsNeedingStockPlanDeployments();
|
|
2102
276
|
}
|
|
2103
277
|
async getPortalsNeedingStockPlanReDeployments() {
|
|
2104
|
-
|
|
2105
|
-
SELECT DISTINCT
|
|
2106
|
-
cp.portal_id,
|
|
2107
|
-
cp.party_id,
|
|
2108
|
-
cp.provider,
|
|
2109
|
-
cp.created_at,
|
|
2110
|
-
p.company,
|
|
2111
|
-
loo.ocf_data,
|
|
2112
|
-
loo.id AS ocf_object_id,
|
|
2113
|
-
loo.version as latest_ocf_version,
|
|
2114
|
-
od.version as deployed_version,
|
|
2115
|
-
od.contract_id as current_contract_id,
|
|
2116
|
-
(loo.version - od.version) AS version_diff,
|
|
2117
|
-
(
|
|
2118
|
-
SELECT od_issuer.contract_id
|
|
2119
|
-
FROM ocf_deployments od_issuer
|
|
2120
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2121
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2122
|
-
AND od_issuer.status = 'deployed'
|
|
2123
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2124
|
-
ORDER BY od_issuer.created_at DESC
|
|
2125
|
-
LIMIT 1
|
|
2126
|
-
) as issuer_contract_id
|
|
2127
|
-
FROM canton_parties cp
|
|
2128
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2129
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2130
|
-
JOIN ocf_deployments od ON loo.id = od.ocf_object_id AND cp.party_id = od.party_id
|
|
2131
|
-
WHERE
|
|
2132
|
-
loo.type = 'STOCK_PLAN'
|
|
2133
|
-
AND EXISTS (
|
|
2134
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2135
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2136
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2137
|
-
AND od_issuer.status = 'deployed'
|
|
2138
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2139
|
-
)
|
|
2140
|
-
AND od.version < loo.version
|
|
2141
|
-
AND od.status = 'deployed'
|
|
2142
|
-
ORDER BY version_diff DESC, cp.created_at ASC
|
|
2143
|
-
`;
|
|
2144
|
-
const result = await this.pool.query(query);
|
|
2145
|
-
return result.rows;
|
|
278
|
+
return this.ocfDeployments.getPortalsNeedingStockPlanReDeployments();
|
|
2146
279
|
}
|
|
2147
280
|
async getPortalsNeedingStockLegendTemplateDeployments() {
|
|
2148
|
-
|
|
2149
|
-
SELECT DISTINCT
|
|
2150
|
-
cp.portal_id,
|
|
2151
|
-
cp.party_id,
|
|
2152
|
-
cp.provider,
|
|
2153
|
-
cp.created_at,
|
|
2154
|
-
p.company,
|
|
2155
|
-
loo.ocf_data,
|
|
2156
|
-
loo.id AS ocf_object_id,
|
|
2157
|
-
loo.version AS ocf_version,
|
|
2158
|
-
(
|
|
2159
|
-
SELECT od_issuer.contract_id
|
|
2160
|
-
FROM ocf_deployments od_issuer
|
|
2161
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2162
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2163
|
-
AND od_issuer.status = 'deployed'
|
|
2164
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2165
|
-
ORDER BY od_issuer.created_at DESC
|
|
2166
|
-
LIMIT 1
|
|
2167
|
-
) as issuer_contract_id
|
|
2168
|
-
FROM canton_parties cp
|
|
2169
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2170
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2171
|
-
WHERE
|
|
2172
|
-
(loo.type = 'OBJECT' AND loo.subtype = 'STOCK_LEGEND_TEMPLATE')
|
|
2173
|
-
AND EXISTS (
|
|
2174
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2175
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2176
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2177
|
-
AND od_issuer.status = 'deployed'
|
|
2178
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2179
|
-
)
|
|
2180
|
-
AND NOT EXISTS (
|
|
2181
|
-
SELECT 1 FROM ocf_deployments od
|
|
2182
|
-
WHERE od.ocf_object_id = loo.id
|
|
2183
|
-
AND od.party_id = cp.party_id
|
|
2184
|
-
AND od.status = 'deployed'
|
|
2185
|
-
)
|
|
2186
|
-
ORDER BY cp.created_at ASC
|
|
2187
|
-
`;
|
|
2188
|
-
const result = await this.pool.query(query);
|
|
2189
|
-
return result.rows;
|
|
281
|
+
return this.ocfDeployments.getPortalsNeedingStockLegendTemplateDeployments();
|
|
2190
282
|
}
|
|
2191
283
|
async getPortalsNeedingDocumentDeployments() {
|
|
2192
|
-
|
|
2193
|
-
SELECT DISTINCT
|
|
2194
|
-
cp.portal_id,
|
|
2195
|
-
cp.party_id,
|
|
2196
|
-
cp.provider,
|
|
2197
|
-
cp.created_at,
|
|
2198
|
-
p.company,
|
|
2199
|
-
loo.ocf_data,
|
|
2200
|
-
loo.id AS ocf_object_id,
|
|
2201
|
-
loo.version AS ocf_version,
|
|
2202
|
-
(
|
|
2203
|
-
SELECT od_issuer.contract_id
|
|
2204
|
-
FROM ocf_deployments od_issuer
|
|
2205
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2206
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2207
|
-
AND od_issuer.status = 'deployed'
|
|
2208
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2209
|
-
ORDER BY od_issuer.created_at DESC
|
|
2210
|
-
LIMIT 1
|
|
2211
|
-
) as issuer_contract_id
|
|
2212
|
-
FROM canton_parties cp
|
|
2213
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2214
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2215
|
-
WHERE
|
|
2216
|
-
(loo.type = 'OBJECT' AND loo.subtype = 'DOCUMENT')
|
|
2217
|
-
AND EXISTS (
|
|
2218
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2219
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2220
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2221
|
-
AND od_issuer.status = 'deployed'
|
|
2222
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2223
|
-
)
|
|
2224
|
-
AND NOT EXISTS (
|
|
2225
|
-
SELECT 1 FROM ocf_deployments od
|
|
2226
|
-
WHERE od.ocf_object_id = loo.id
|
|
2227
|
-
AND od.party_id = cp.party_id
|
|
2228
|
-
AND od.status = 'deployed'
|
|
2229
|
-
)
|
|
2230
|
-
ORDER BY cp.created_at ASC
|
|
2231
|
-
`;
|
|
2232
|
-
const result = await this.pool.query(query);
|
|
2233
|
-
return result.rows;
|
|
284
|
+
return this.ocfDeployments.getPortalsNeedingDocumentDeployments();
|
|
2234
285
|
}
|
|
2235
286
|
async getPortalsNeedingVestingTermsDeployments() {
|
|
2236
|
-
|
|
2237
|
-
SELECT DISTINCT
|
|
2238
|
-
cp.portal_id,
|
|
2239
|
-
cp.party_id,
|
|
2240
|
-
cp.provider,
|
|
2241
|
-
cp.created_at,
|
|
2242
|
-
p.company,
|
|
2243
|
-
loo.ocf_data,
|
|
2244
|
-
loo.id AS ocf_object_id,
|
|
2245
|
-
loo.version AS ocf_version,
|
|
2246
|
-
(
|
|
2247
|
-
SELECT od_issuer.contract_id
|
|
2248
|
-
FROM ocf_deployments od_issuer
|
|
2249
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2250
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2251
|
-
AND od_issuer.status = 'deployed'
|
|
2252
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2253
|
-
ORDER BY od_issuer.created_at DESC
|
|
2254
|
-
LIMIT 1
|
|
2255
|
-
) as issuer_contract_id
|
|
2256
|
-
FROM canton_parties cp
|
|
2257
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2258
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2259
|
-
WHERE
|
|
2260
|
-
(loo.type = 'OBJECT' AND loo.subtype = 'VESTING_TERMS')
|
|
2261
|
-
AND EXISTS (
|
|
2262
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2263
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2264
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2265
|
-
AND od_issuer.status = 'deployed'
|
|
2266
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2267
|
-
)
|
|
2268
|
-
AND NOT EXISTS (
|
|
2269
|
-
SELECT 1 FROM ocf_deployments od
|
|
2270
|
-
WHERE od.ocf_object_id = loo.id
|
|
2271
|
-
AND od.party_id = cp.party_id
|
|
2272
|
-
AND od.status = 'deployed'
|
|
2273
|
-
)
|
|
2274
|
-
ORDER BY cp.created_at ASC
|
|
2275
|
-
`;
|
|
2276
|
-
const result = await this.pool.query(query);
|
|
2277
|
-
return result.rows;
|
|
287
|
+
return this.ocfDeployments.getPortalsNeedingVestingTermsDeployments();
|
|
2278
288
|
}
|
|
2279
289
|
async getPortalsNeedingStockIssuanceDeployments() {
|
|
2280
|
-
|
|
2281
|
-
SELECT DISTINCT
|
|
2282
|
-
cp.portal_id,
|
|
2283
|
-
cp.party_id,
|
|
2284
|
-
cp.provider,
|
|
2285
|
-
cp.created_at,
|
|
2286
|
-
p.company,
|
|
2287
|
-
loo.ocf_data,
|
|
2288
|
-
loo.id AS ocf_object_id,
|
|
2289
|
-
loo.version AS ocf_version,
|
|
2290
|
-
(
|
|
2291
|
-
SELECT od_issuer.contract_id
|
|
2292
|
-
FROM ocf_deployments od_issuer
|
|
2293
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2294
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2295
|
-
AND od_issuer.status = 'deployed'
|
|
2296
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2297
|
-
ORDER BY od_issuer.created_at DESC
|
|
2298
|
-
LIMIT 1
|
|
2299
|
-
) as issuer_contract_id
|
|
2300
|
-
FROM canton_parties cp
|
|
2301
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2302
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2303
|
-
WHERE
|
|
2304
|
-
(loo.type = 'TRANSACTION' AND loo.subtype = 'TX_STOCK_ISSUANCE')
|
|
2305
|
-
AND EXISTS (
|
|
2306
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2307
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2308
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2309
|
-
AND od_issuer.status = 'deployed'
|
|
2310
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2311
|
-
)
|
|
2312
|
-
AND NOT EXISTS (
|
|
2313
|
-
SELECT 1 FROM ocf_deployments od
|
|
2314
|
-
WHERE od.ocf_object_id = loo.id
|
|
2315
|
-
AND od.party_id = cp.party_id
|
|
2316
|
-
AND od.status = 'deployed'
|
|
2317
|
-
)
|
|
2318
|
-
ORDER BY cp.created_at ASC
|
|
2319
|
-
`;
|
|
2320
|
-
const result = await this.pool.query(query);
|
|
2321
|
-
return result.rows;
|
|
290
|
+
return this.ocfDeployments.getPortalsNeedingStockIssuanceDeployments();
|
|
2322
291
|
}
|
|
2323
292
|
async getPortalsNeedingWarrantIssuanceDeployments() {
|
|
2324
|
-
|
|
2325
|
-
SELECT DISTINCT
|
|
2326
|
-
cp.portal_id,
|
|
2327
|
-
cp.party_id,
|
|
2328
|
-
cp.provider,
|
|
2329
|
-
cp.created_at,
|
|
2330
|
-
p.company,
|
|
2331
|
-
loo.ocf_data,
|
|
2332
|
-
loo.id AS ocf_object_id,
|
|
2333
|
-
loo.version AS ocf_version,
|
|
2334
|
-
(
|
|
2335
|
-
SELECT od_issuer.contract_id
|
|
2336
|
-
FROM ocf_deployments od_issuer
|
|
2337
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2338
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2339
|
-
AND od_issuer.status = 'deployed'
|
|
2340
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2341
|
-
ORDER BY od_issuer.created_at DESC
|
|
2342
|
-
LIMIT 1
|
|
2343
|
-
) as issuer_contract_id
|
|
2344
|
-
FROM canton_parties cp
|
|
2345
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2346
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2347
|
-
WHERE
|
|
2348
|
-
(loo.type = 'TRANSACTION' AND loo.subtype = 'TX_WARRANT_ISSUANCE')
|
|
2349
|
-
AND EXISTS (
|
|
2350
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2351
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2352
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2353
|
-
AND od_issuer.status = 'deployed'
|
|
2354
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2355
|
-
)
|
|
2356
|
-
AND NOT EXISTS (
|
|
2357
|
-
SELECT 1 FROM ocf_deployments od
|
|
2358
|
-
WHERE od.ocf_object_id = loo.id
|
|
2359
|
-
AND od.party_id = cp.party_id
|
|
2360
|
-
AND od.status = 'deployed'
|
|
2361
|
-
)
|
|
2362
|
-
ORDER BY cp.created_at ASC
|
|
2363
|
-
`;
|
|
2364
|
-
const result = await this.pool.query(query);
|
|
2365
|
-
return result.rows;
|
|
293
|
+
return this.ocfDeployments.getPortalsNeedingWarrantIssuanceDeployments();
|
|
2366
294
|
}
|
|
2367
295
|
async getPortalsNeedingStockPlanPoolAdjustmentDeployments() {
|
|
2368
|
-
|
|
2369
|
-
SELECT DISTINCT
|
|
2370
|
-
cp.portal_id,
|
|
2371
|
-
cp.party_id,
|
|
2372
|
-
cp.provider,
|
|
2373
|
-
cp.created_at,
|
|
2374
|
-
p.company,
|
|
2375
|
-
loo.ocf_data,
|
|
2376
|
-
loo.id AS ocf_object_id,
|
|
2377
|
-
loo.version AS ocf_version,
|
|
2378
|
-
(
|
|
2379
|
-
SELECT od_issuer.contract_id
|
|
2380
|
-
FROM ocf_deployments od_issuer
|
|
2381
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2382
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2383
|
-
AND od_issuer.status = 'deployed'
|
|
2384
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2385
|
-
ORDER BY od_issuer.created_at DESC
|
|
2386
|
-
LIMIT 1
|
|
2387
|
-
) as issuer_contract_id
|
|
2388
|
-
FROM canton_parties cp
|
|
2389
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2390
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2391
|
-
WHERE
|
|
2392
|
-
(loo.type = 'TRANSACTION' AND loo.subtype = 'TX_STOCK_PLAN_POOL_ADJUSTMENT')
|
|
2393
|
-
AND EXISTS (
|
|
2394
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2395
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2396
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2397
|
-
AND od_issuer.status = 'deployed'
|
|
2398
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2399
|
-
)
|
|
2400
|
-
AND NOT EXISTS (
|
|
2401
|
-
SELECT 1 FROM ocf_deployments od
|
|
2402
|
-
WHERE od.ocf_object_id = loo.id
|
|
2403
|
-
AND od.party_id = cp.party_id
|
|
2404
|
-
AND od.status = 'deployed'
|
|
2405
|
-
)
|
|
2406
|
-
ORDER BY cp.created_at ASC
|
|
2407
|
-
`;
|
|
2408
|
-
const result = await this.pool.query(query);
|
|
2409
|
-
return result.rows;
|
|
296
|
+
return this.ocfDeployments.getPortalsNeedingStockPlanPoolAdjustmentDeployments();
|
|
2410
297
|
}
|
|
2411
298
|
async getPortalsNeedingStockClassAuthorizedSharesAdjustmentDeployments() {
|
|
2412
|
-
|
|
2413
|
-
SELECT DISTINCT
|
|
2414
|
-
cp.portal_id,
|
|
2415
|
-
cp.party_id,
|
|
2416
|
-
cp.provider,
|
|
2417
|
-
cp.created_at,
|
|
2418
|
-
p.company,
|
|
2419
|
-
loo.ocf_data,
|
|
2420
|
-
loo.id AS ocf_object_id,
|
|
2421
|
-
loo.version AS ocf_version,
|
|
2422
|
-
(
|
|
2423
|
-
SELECT od_issuer.contract_id
|
|
2424
|
-
FROM ocf_deployments od_issuer
|
|
2425
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2426
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2427
|
-
AND od_issuer.status = 'deployed'
|
|
2428
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2429
|
-
ORDER BY od_issuer.created_at DESC
|
|
2430
|
-
LIMIT 1
|
|
2431
|
-
) as issuer_contract_id
|
|
2432
|
-
FROM canton_parties cp
|
|
2433
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2434
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2435
|
-
WHERE
|
|
2436
|
-
(loo.type = 'TRANSACTION' AND loo.subtype = 'TX_STOCK_CLASS_AUTHORIZED_SHARES_ADJUSTMENT')
|
|
2437
|
-
AND EXISTS (
|
|
2438
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2439
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2440
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2441
|
-
AND od_issuer.status = 'deployed'
|
|
2442
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2443
|
-
)
|
|
2444
|
-
AND NOT EXISTS (
|
|
2445
|
-
SELECT 1 FROM ocf_deployments od
|
|
2446
|
-
WHERE od.ocf_object_id = loo.id
|
|
2447
|
-
AND od.party_id = cp.party_id
|
|
2448
|
-
AND od.status = 'deployed'
|
|
2449
|
-
)
|
|
2450
|
-
ORDER BY cp.created_at ASC
|
|
2451
|
-
`;
|
|
2452
|
-
const result = await this.pool.query(query);
|
|
2453
|
-
return result.rows;
|
|
299
|
+
return this.ocfDeployments.getPortalsNeedingStockClassAuthorizedSharesAdjustmentDeployments();
|
|
2454
300
|
}
|
|
2455
301
|
async getPortalsNeedingStockCancellationDeployments() {
|
|
2456
|
-
|
|
2457
|
-
SELECT DISTINCT
|
|
2458
|
-
cp.portal_id,
|
|
2459
|
-
cp.party_id,
|
|
2460
|
-
cp.provider,
|
|
2461
|
-
cp.created_at,
|
|
2462
|
-
p.company,
|
|
2463
|
-
loo.ocf_data,
|
|
2464
|
-
loo.id AS ocf_object_id,
|
|
2465
|
-
loo.version AS ocf_version,
|
|
2466
|
-
(
|
|
2467
|
-
SELECT od_issuer.contract_id
|
|
2468
|
-
FROM ocf_deployments od_issuer
|
|
2469
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2470
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2471
|
-
AND od_issuer.status = 'deployed'
|
|
2472
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2473
|
-
ORDER BY od_issuer.created_at DESC
|
|
2474
|
-
LIMIT 1
|
|
2475
|
-
) as issuer_contract_id
|
|
2476
|
-
FROM canton_parties cp
|
|
2477
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2478
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2479
|
-
WHERE
|
|
2480
|
-
(loo.type = 'TRANSACTION' AND loo.subtype = 'TX_STOCK_CANCELLATION')
|
|
2481
|
-
AND EXISTS (
|
|
2482
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2483
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2484
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2485
|
-
AND od_issuer.status = 'deployed'
|
|
2486
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2487
|
-
)
|
|
2488
|
-
AND NOT EXISTS (
|
|
2489
|
-
SELECT 1 FROM ocf_deployments od
|
|
2490
|
-
WHERE od.ocf_object_id = loo.id
|
|
2491
|
-
AND od.party_id = cp.party_id
|
|
2492
|
-
AND od.status = 'deployed'
|
|
2493
|
-
)
|
|
2494
|
-
ORDER BY cp.created_at ASC
|
|
2495
|
-
`;
|
|
2496
|
-
const result = await this.pool.query(query);
|
|
2497
|
-
return result.rows;
|
|
302
|
+
return this.ocfDeployments.getPortalsNeedingStockCancellationDeployments();
|
|
2498
303
|
}
|
|
2499
304
|
async getPortalsNeedingIssuerAuthorizedSharesAdjustmentDeployments() {
|
|
2500
|
-
|
|
2501
|
-
SELECT DISTINCT
|
|
2502
|
-
cp.portal_id,
|
|
2503
|
-
cp.party_id,
|
|
2504
|
-
cp.provider,
|
|
2505
|
-
cp.created_at,
|
|
2506
|
-
p.company,
|
|
2507
|
-
loo.ocf_data,
|
|
2508
|
-
loo.id AS ocf_object_id,
|
|
2509
|
-
loo.version AS ocf_version,
|
|
2510
|
-
(
|
|
2511
|
-
SELECT od_issuer.contract_id
|
|
2512
|
-
FROM ocf_deployments od_issuer
|
|
2513
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2514
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2515
|
-
AND od_issuer.status = 'deployed'
|
|
2516
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2517
|
-
ORDER BY od_issuer.created_at DESC
|
|
2518
|
-
LIMIT 1
|
|
2519
|
-
) as issuer_contract_id
|
|
2520
|
-
FROM canton_parties cp
|
|
2521
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2522
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2523
|
-
WHERE
|
|
2524
|
-
(loo.type = 'TRANSACTION' AND loo.subtype = 'TX_ISSUER_AUTHORIZED_SHARES_ADJUSTMENT')
|
|
2525
|
-
AND EXISTS (
|
|
2526
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2527
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2528
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2529
|
-
AND od_issuer.status = 'deployed'
|
|
2530
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2531
|
-
)
|
|
2532
|
-
AND NOT EXISTS (
|
|
2533
|
-
SELECT 1 FROM ocf_deployments od
|
|
2534
|
-
WHERE od.ocf_object_id = loo.id
|
|
2535
|
-
AND od.party_id = cp.party_id
|
|
2536
|
-
AND od.status = 'deployed'
|
|
2537
|
-
)
|
|
2538
|
-
ORDER BY cp.created_at ASC
|
|
2539
|
-
`;
|
|
2540
|
-
const result = await this.pool.query(query);
|
|
2541
|
-
return result.rows;
|
|
305
|
+
return this.ocfDeployments.getPortalsNeedingIssuerAuthorizedSharesAdjustmentDeployments();
|
|
2542
306
|
}
|
|
2543
307
|
async getPortalsNeedingEquityCompensationIssuanceDeployments() {
|
|
2544
|
-
|
|
2545
|
-
SELECT DISTINCT
|
|
2546
|
-
cp.portal_id,
|
|
2547
|
-
cp.party_id,
|
|
2548
|
-
cp.provider,
|
|
2549
|
-
cp.created_at,
|
|
2550
|
-
p.company,
|
|
2551
|
-
loo.ocf_data,
|
|
2552
|
-
loo.id AS ocf_object_id,
|
|
2553
|
-
loo.version AS ocf_version,
|
|
2554
|
-
(
|
|
2555
|
-
SELECT od_issuer.contract_id
|
|
2556
|
-
FROM ocf_deployments od_issuer
|
|
2557
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2558
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2559
|
-
AND od_issuer.status = 'deployed'
|
|
2560
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2561
|
-
ORDER BY od_issuer.created_at DESC
|
|
2562
|
-
LIMIT 1
|
|
2563
|
-
) as issuer_contract_id
|
|
2564
|
-
FROM canton_parties cp
|
|
2565
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2566
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2567
|
-
WHERE
|
|
2568
|
-
(loo.type = 'TRANSACTION' AND loo.subtype = 'TX_EQUITY_COMPENSATION_ISSUANCE')
|
|
2569
|
-
AND EXISTS (
|
|
2570
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2571
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2572
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2573
|
-
AND od_issuer.status = 'deployed'
|
|
2574
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2575
|
-
)
|
|
2576
|
-
AND NOT EXISTS (
|
|
2577
|
-
SELECT 1 FROM ocf_deployments od
|
|
2578
|
-
WHERE od.ocf_object_id = loo.id
|
|
2579
|
-
AND od.party_id = cp.party_id
|
|
2580
|
-
AND od.status = 'deployed'
|
|
2581
|
-
)
|
|
2582
|
-
ORDER BY cp.created_at ASC
|
|
2583
|
-
`;
|
|
2584
|
-
const result = await this.pool.query(query);
|
|
2585
|
-
return result.rows;
|
|
308
|
+
return this.ocfDeployments.getPortalsNeedingEquityCompensationIssuanceDeployments();
|
|
2586
309
|
}
|
|
2587
310
|
async getPortalsNeedingEquityCompensationExerciseDeployments() {
|
|
2588
|
-
|
|
2589
|
-
SELECT DISTINCT
|
|
2590
|
-
cp.portal_id,
|
|
2591
|
-
cp.party_id,
|
|
2592
|
-
cp.provider,
|
|
2593
|
-
cp.created_at,
|
|
2594
|
-
p.company,
|
|
2595
|
-
loo.ocf_data,
|
|
2596
|
-
loo.id AS ocf_object_id,
|
|
2597
|
-
loo.version AS ocf_version,
|
|
2598
|
-
(
|
|
2599
|
-
SELECT od_issuer.contract_id
|
|
2600
|
-
FROM ocf_deployments od_issuer
|
|
2601
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2602
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2603
|
-
AND od_issuer.status = 'deployed'
|
|
2604
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2605
|
-
ORDER BY od_issuer.created_at DESC
|
|
2606
|
-
LIMIT 1
|
|
2607
|
-
) as issuer_contract_id
|
|
2608
|
-
FROM canton_parties cp
|
|
2609
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2610
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2611
|
-
WHERE
|
|
2612
|
-
(loo.type = 'TRANSACTION' AND loo.subtype = 'TX_EQUITY_COMPENSATION_EXERCISE')
|
|
2613
|
-
AND EXISTS (
|
|
2614
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2615
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2616
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2617
|
-
AND od_issuer.status = 'deployed'
|
|
2618
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2619
|
-
)
|
|
2620
|
-
AND NOT EXISTS (
|
|
2621
|
-
SELECT 1 FROM ocf_deployments od
|
|
2622
|
-
WHERE od.ocf_object_id = loo.id
|
|
2623
|
-
AND od.party_id = cp.party_id
|
|
2624
|
-
AND od.status = 'deployed'
|
|
2625
|
-
)
|
|
2626
|
-
ORDER BY cp.created_at ASC
|
|
2627
|
-
`;
|
|
2628
|
-
const result = await this.pool.query(query);
|
|
2629
|
-
return result.rows;
|
|
311
|
+
return this.ocfDeployments.getPortalsNeedingEquityCompensationExerciseDeployments();
|
|
2630
312
|
}
|
|
2631
313
|
async getPortalsNeedingConvertibleIssuanceDeployments() {
|
|
2632
|
-
|
|
2633
|
-
SELECT DISTINCT
|
|
2634
|
-
cp.portal_id,
|
|
2635
|
-
cp.party_id,
|
|
2636
|
-
cp.provider,
|
|
2637
|
-
cp.created_at,
|
|
2638
|
-
p.company,
|
|
2639
|
-
loo.ocf_data,
|
|
2640
|
-
loo.id AS ocf_object_id,
|
|
2641
|
-
loo.version AS ocf_version,
|
|
2642
|
-
(
|
|
2643
|
-
SELECT od_issuer.contract_id
|
|
2644
|
-
FROM ocf_deployments od_issuer
|
|
2645
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2646
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2647
|
-
AND od_issuer.status = 'deployed'
|
|
2648
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2649
|
-
ORDER BY od_issuer.created_at DESC
|
|
2650
|
-
LIMIT 1
|
|
2651
|
-
) as issuer_contract_id
|
|
2652
|
-
FROM canton_parties cp
|
|
2653
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2654
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2655
|
-
WHERE
|
|
2656
|
-
(loo.type = 'TRANSACTION' AND loo.subtype = 'TX_CONVERTIBLE_ISSUANCE')
|
|
2657
|
-
AND EXISTS (
|
|
2658
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2659
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2660
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2661
|
-
AND od_issuer.status = 'deployed'
|
|
2662
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2663
|
-
)
|
|
2664
|
-
AND NOT EXISTS (
|
|
2665
|
-
SELECT 1 FROM ocf_deployments od
|
|
2666
|
-
WHERE od.ocf_object_id = loo.id
|
|
2667
|
-
AND od.party_id = cp.party_id
|
|
2668
|
-
AND od.status = 'deployed'
|
|
2669
|
-
)
|
|
2670
|
-
ORDER BY cp.created_at ASC
|
|
2671
|
-
`;
|
|
2672
|
-
const result = await this.pool.query(query);
|
|
2673
|
-
return result.rows;
|
|
314
|
+
return this.ocfDeployments.getPortalsNeedingConvertibleIssuanceDeployments();
|
|
2674
315
|
}
|
|
2675
|
-
/**
|
|
2676
|
-
* Returns the next party_id that has any pending OCF work (missing deployments or updates), ordered by the associated
|
|
2677
|
-
* party creation time.
|
|
2678
|
-
*/
|
|
2679
316
|
async getNextPartyIdWithPendingOcfWork() {
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2689
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2690
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2691
|
-
AND od_issuer.status = 'deployed'
|
|
2692
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2693
|
-
)
|
|
2694
|
-
AND (
|
|
2695
|
-
-- Missing for any object/transaction/record type (excluding ISSUER)
|
|
2696
|
-
(loo.type <> 'ISSUER' AND NOT EXISTS (
|
|
2697
|
-
SELECT 1 FROM ocf_deployments od
|
|
2698
|
-
WHERE od.ocf_object_id = loo.id
|
|
2699
|
-
AND od.party_id = cp.party_id
|
|
2700
|
-
AND od.status = 'deployed'
|
|
2701
|
-
))
|
|
2702
|
-
OR
|
|
2703
|
-
-- Updates for any type/subtype except ISSUER
|
|
2704
|
-
(
|
|
2705
|
-
loo.type <> 'ISSUER'
|
|
2706
|
-
AND EXISTS (
|
|
2707
|
-
SELECT 1 FROM ocf_deployments od2
|
|
2708
|
-
WHERE od2.ocf_object_id = loo.id
|
|
2709
|
-
AND od2.party_id = cp.party_id
|
|
2710
|
-
AND od2.status = 'deployed'
|
|
2711
|
-
AND od2.version < loo.version
|
|
2712
|
-
)
|
|
2713
|
-
)
|
|
2714
|
-
)
|
|
2715
|
-
)
|
|
2716
|
-
SELECT party_id
|
|
2717
|
-
FROM eligible_party
|
|
2718
|
-
ORDER BY created_at ASC
|
|
2719
|
-
LIMIT 1
|
|
2720
|
-
`;
|
|
2721
|
-
const result = await this.pool.query(query);
|
|
2722
|
-
if (result.rows.length === 0)
|
|
2723
|
-
return null;
|
|
2724
|
-
return result.rows[0].party_id;
|
|
317
|
+
return this.ocfDeployments.getNextPartyIdWithPendingOcfWork();
|
|
318
|
+
}
|
|
319
|
+
async getPendingOcfItemsForParty(partyId) {
|
|
320
|
+
return this.ocfDeployments.getPendingOcfItemsForParty(partyId);
|
|
321
|
+
}
|
|
322
|
+
// Cap Table Replication
|
|
323
|
+
async getAllIssuersToReplicate() {
|
|
324
|
+
return this.ocfDeployments.getAllIssuersToReplicate();
|
|
2725
325
|
}
|
|
2726
326
|
/**
|
|
2727
|
-
*
|
|
2728
|
-
* objects/transactions and core records, and includes metadata needed by the script.
|
|
327
|
+
* @deprecated Use `getAllIssuersToReplicate` instead.
|
|
2729
328
|
*/
|
|
2730
|
-
async
|
|
2731
|
-
|
|
2732
|
-
(
|
|
2733
|
-
-- Missing deployments across all OCF types/subtypes
|
|
2734
|
-
SELECT DISTINCT
|
|
2735
|
-
cp.portal_id,
|
|
2736
|
-
cp.party_id,
|
|
2737
|
-
cp.provider,
|
|
2738
|
-
p.company,
|
|
2739
|
-
loo.id AS ocf_object_id,
|
|
2740
|
-
loo.ocf_data,
|
|
2741
|
-
loo.version AS ocf_version,
|
|
2742
|
-
NULL::int AS latest_ocf_version,
|
|
2743
|
-
NULL::int AS deployed_version,
|
|
2744
|
-
NULL::text AS current_contract_id,
|
|
2745
|
-
loo.type AS ocf_type,
|
|
2746
|
-
loo.subtype AS ocf_subtype,
|
|
2747
|
-
(
|
|
2748
|
-
SELECT od_issuer.contract_id
|
|
2749
|
-
FROM ocf_deployments od_issuer
|
|
2750
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2751
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2752
|
-
AND od_issuer.status = 'deployed'
|
|
2753
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2754
|
-
ORDER BY od_issuer.created_at DESC
|
|
2755
|
-
LIMIT 1
|
|
2756
|
-
) AS issuer_contract_id,
|
|
2757
|
-
cp.created_at
|
|
2758
|
-
FROM canton_parties cp
|
|
2759
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2760
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2761
|
-
WHERE cp.party_id = $1
|
|
2762
|
-
AND EXISTS (
|
|
2763
|
-
SELECT 1 FROM ocf_deployments od_issuer
|
|
2764
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2765
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2766
|
-
AND od_issuer.status = 'deployed'
|
|
2767
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2768
|
-
)
|
|
2769
|
-
AND NOT EXISTS (
|
|
2770
|
-
SELECT 1 FROM ocf_deployments od
|
|
2771
|
-
WHERE od.ocf_object_id = loo.id
|
|
2772
|
-
AND od.party_id = cp.party_id
|
|
2773
|
-
AND od.status = 'deployed'
|
|
2774
|
-
)
|
|
2775
|
-
)
|
|
2776
|
-
UNION ALL
|
|
2777
|
-
(
|
|
2778
|
-
-- Updates for core record types
|
|
2779
|
-
SELECT DISTINCT
|
|
2780
|
-
cp.portal_id,
|
|
2781
|
-
cp.party_id,
|
|
2782
|
-
cp.provider,
|
|
2783
|
-
p.company,
|
|
2784
|
-
loo.id AS ocf_object_id,
|
|
2785
|
-
loo.ocf_data,
|
|
2786
|
-
NULL::int AS ocf_version,
|
|
2787
|
-
loo.version AS latest_ocf_version,
|
|
2788
|
-
od.version AS deployed_version,
|
|
2789
|
-
od.contract_id AS current_contract_id,
|
|
2790
|
-
loo.type AS ocf_type,
|
|
2791
|
-
loo.subtype AS ocf_subtype,
|
|
2792
|
-
(
|
|
2793
|
-
SELECT od_issuer.contract_id
|
|
2794
|
-
FROM ocf_deployments od_issuer
|
|
2795
|
-
JOIN latest_ocf_objects loo_issuer ON od_issuer.ocf_object_id = loo_issuer.id
|
|
2796
|
-
WHERE od_issuer.party_id = cp.party_id
|
|
2797
|
-
AND od_issuer.status = 'deployed'
|
|
2798
|
-
AND loo_issuer.type = 'ISSUER'
|
|
2799
|
-
ORDER BY od_issuer.created_at DESC
|
|
2800
|
-
LIMIT 1
|
|
2801
|
-
) AS issuer_contract_id,
|
|
2802
|
-
cp.created_at
|
|
2803
|
-
FROM canton_parties cp
|
|
2804
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
2805
|
-
JOIN latest_ocf_objects loo ON cp.portal_id = loo.portal_id
|
|
2806
|
-
JOIN ocf_deployments od ON loo.id = od.ocf_object_id AND cp.party_id = od.party_id
|
|
2807
|
-
WHERE cp.party_id = $1
|
|
2808
|
-
AND loo.type <> 'ISSUER'
|
|
2809
|
-
AND od.status = 'deployed'
|
|
2810
|
-
AND od.version < loo.version
|
|
2811
|
-
)
|
|
2812
|
-
ORDER BY created_at ASC
|
|
2813
|
-
`;
|
|
2814
|
-
const result = await this.pool.query(query, [partyId]);
|
|
2815
|
-
return result.rows;
|
|
329
|
+
async getNextIssuerToReplicate() {
|
|
330
|
+
return this.ocfDeployments.getNextIssuerToReplicate();
|
|
2816
331
|
}
|
|
332
|
+
async getAllOcfObjectsForIssuer(portalId) {
|
|
333
|
+
return this.ocfDeployments.getAllOcfObjectsForIssuer(portalId);
|
|
334
|
+
}
|
|
335
|
+
// ========================================================================
|
|
336
|
+
// Valuation Report Operations
|
|
337
|
+
// ========================================================================
|
|
2817
338
|
async getLatestValuationReportByPortalId(portalId) {
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
FROM canton_valuation_reports
|
|
2821
|
-
WHERE portal_id = $1
|
|
2822
|
-
ORDER BY version DESC
|
|
2823
|
-
LIMIT 1
|
|
2824
|
-
`;
|
|
2825
|
-
const result = await this.pool.query(query, [portalId]);
|
|
2826
|
-
if (result.rows.length === 0)
|
|
2827
|
-
return null;
|
|
2828
|
-
return this.mapValuationReportFromDb(result.rows[0]);
|
|
2829
|
-
}
|
|
2830
|
-
/** Get the latest valuation report row for each distinct company_id */
|
|
339
|
+
return this.valuationReports.getLatestValuationReportByPortalId(portalId);
|
|
340
|
+
}
|
|
2831
341
|
async getLatestValuationReportsGroupedByCompany() {
|
|
2832
|
-
|
|
2833
|
-
SELECT DISTINCT ON (company_id)
|
|
2834
|
-
id, portal_id, company_id, version, contract_id, company_valuation,
|
|
2835
|
-
tx_update_id, last_valuation_until, created_at, updated_at
|
|
2836
|
-
FROM canton_valuation_reports
|
|
2837
|
-
ORDER BY company_id, version DESC
|
|
2838
|
-
`;
|
|
2839
|
-
const result = await this.pool.query(query);
|
|
2840
|
-
return result.rows.map(row => this.mapValuationReportFromDb(row));
|
|
342
|
+
return this.valuationReports.getLatestValuationReportsGroupedByCompany();
|
|
2841
343
|
}
|
|
2842
344
|
async insertValuationReport(report) {
|
|
2843
|
-
|
|
2844
|
-
INSERT INTO canton_valuation_reports (
|
|
2845
|
-
portal_id, company_id, version, contract_id, company_valuation, tx_update_id, last_valuation_until
|
|
2846
|
-
) VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
2847
|
-
RETURNING *
|
|
2848
|
-
`;
|
|
2849
|
-
const values = [
|
|
2850
|
-
report.portal_id,
|
|
2851
|
-
report.company_id,
|
|
2852
|
-
report.version,
|
|
2853
|
-
report.contract_id,
|
|
2854
|
-
report.company_valuation,
|
|
2855
|
-
report.tx_update_id,
|
|
2856
|
-
report.last_valuation_until,
|
|
2857
|
-
];
|
|
2858
|
-
const result = await this.pool.query(query, values);
|
|
2859
|
-
return this.mapValuationReportFromDb(result.rows[0]);
|
|
2860
|
-
}
|
|
2861
|
-
// Helper methods for mapping database results
|
|
2862
|
-
mapTransferFromDb(row) {
|
|
2863
|
-
return {
|
|
2864
|
-
id: row.id,
|
|
2865
|
-
api_tracking_id: row.api_tracking_id,
|
|
2866
|
-
api_expires_at: row.api_expires_at,
|
|
2867
|
-
transfer_sender_party_id: row.transfer_sender_party_id,
|
|
2868
|
-
transfer_receiver_party_id: row.transfer_receiver_party_id,
|
|
2869
|
-
transfer_amount: parseFloat(row.transfer_amount),
|
|
2870
|
-
transfer_description: row.transfer_description,
|
|
2871
|
-
transfer_burned_amount: parseFloat(row.transfer_burned_amount),
|
|
2872
|
-
receiver_holding_cids: row.receiver_holding_cids,
|
|
2873
|
-
sender_change_cids: row.sender_change_cids,
|
|
2874
|
-
tx_update_id: row.tx_update_id,
|
|
2875
|
-
tx_record_time: row.tx_record_time,
|
|
2876
|
-
status: row.status,
|
|
2877
|
-
app_reward_coupon_id: row.app_reward_coupon_id,
|
|
2878
|
-
created_at: row.created_at,
|
|
2879
|
-
updated_at: row.updated_at,
|
|
2880
|
-
};
|
|
2881
|
-
}
|
|
2882
|
-
mapRewardCouponFromDb(row) {
|
|
2883
|
-
return {
|
|
2884
|
-
id: row.id,
|
|
2885
|
-
status: row.status,
|
|
2886
|
-
tx_update_id: row.tx_update_id,
|
|
2887
|
-
tx_record_time: row.tx_record_time,
|
|
2888
|
-
contract_id: row.contract_id,
|
|
2889
|
-
template_id: row.template_id,
|
|
2890
|
-
package_name: row.package_name,
|
|
2891
|
-
dso_party_id: row.dso_party_id,
|
|
2892
|
-
provider_party_id: row.provider_party_id,
|
|
2893
|
-
featured: row.featured,
|
|
2894
|
-
round_number: row.round_number,
|
|
2895
|
-
beneficiary_party_id: row.beneficiary_party_id,
|
|
2896
|
-
coupon_amount: parseFloat(row.coupon_amount),
|
|
2897
|
-
tx_archive_update_id: row.tx_archive_update_id,
|
|
2898
|
-
tx_archive_record_time: row.tx_archive_record_time,
|
|
2899
|
-
app_reward_amount: row.app_reward_amount
|
|
2900
|
-
? parseFloat(row.app_reward_amount)
|
|
2901
|
-
: null,
|
|
2902
|
-
created_at: row.created_at,
|
|
2903
|
-
updated_at: row.updated_at,
|
|
2904
|
-
};
|
|
2905
|
-
}
|
|
2906
|
-
mapAppMarkerFromDb(row) {
|
|
2907
|
-
return {
|
|
2908
|
-
id: row.id,
|
|
2909
|
-
status: row.status,
|
|
2910
|
-
contract_id: row.contract_id,
|
|
2911
|
-
provider_party_id: row.provider_party_id,
|
|
2912
|
-
beneficiary_party_id: row.beneficiary_party_id,
|
|
2913
|
-
tx_record_time: row.tx_record_time,
|
|
2914
|
-
weight: parseFloat(row.weight),
|
|
2915
|
-
created_at: row.created_at,
|
|
2916
|
-
updated_at: row.updated_at,
|
|
2917
|
-
};
|
|
2918
|
-
}
|
|
2919
|
-
mapRedemptionFromDb(row) {
|
|
2920
|
-
return {
|
|
2921
|
-
id: row.id,
|
|
2922
|
-
transfer_id: row.transfer_id,
|
|
2923
|
-
app_reward_coupon_ids: row.app_reward_coupon_ids,
|
|
2924
|
-
tx_update_id: row.tx_update_id,
|
|
2925
|
-
tx_record_time: row.tx_record_time,
|
|
2926
|
-
tx_synchronizer_id: row.tx_synchronizer_id,
|
|
2927
|
-
tx_effective_at: row.tx_effective_at,
|
|
2928
|
-
total_app_rewards: parseFloat(row.total_app_rewards),
|
|
2929
|
-
created_at: row.created_at,
|
|
2930
|
-
updated_at: row.updated_at,
|
|
2931
|
-
};
|
|
2932
|
-
}
|
|
2933
|
-
mapRewardCouponWithTransferFromDb(row) {
|
|
2934
|
-
const coupon = {
|
|
2935
|
-
id: row.coupon_id,
|
|
2936
|
-
status: row.coupon_status,
|
|
2937
|
-
tx_update_id: row.coupon_tx_update_id,
|
|
2938
|
-
tx_record_time: row.coupon_tx_record_time,
|
|
2939
|
-
contract_id: row.coupon_contract_id,
|
|
2940
|
-
template_id: row.coupon_template_id,
|
|
2941
|
-
package_name: row.coupon_package_name,
|
|
2942
|
-
dso_party_id: row.coupon_dso_party_id,
|
|
2943
|
-
provider_party_id: row.coupon_provider_party_id,
|
|
2944
|
-
featured: row.coupon_featured,
|
|
2945
|
-
round_number: row.coupon_round_number,
|
|
2946
|
-
beneficiary_party_id: row.coupon_beneficiary_party_id,
|
|
2947
|
-
coupon_amount: parseFloat(row.coupon_coupon_amount),
|
|
2948
|
-
tx_archive_update_id: row.coupon_tx_archive_update_id,
|
|
2949
|
-
tx_archive_record_time: row.coupon_tx_archive_record_time,
|
|
2950
|
-
app_reward_amount: row.coupon_app_reward_amount
|
|
2951
|
-
? parseFloat(row.coupon_app_reward_amount)
|
|
2952
|
-
: null,
|
|
2953
|
-
created_at: row.coupon_created_at,
|
|
2954
|
-
updated_at: row.coupon_updated_at,
|
|
2955
|
-
};
|
|
2956
|
-
const transfer = {
|
|
2957
|
-
id: row.transfer_id,
|
|
2958
|
-
api_tracking_id: row.transfer_api_tracking_id,
|
|
2959
|
-
api_expires_at: row.transfer_api_expires_at,
|
|
2960
|
-
transfer_sender_party_id: row.transfer_transfer_sender_party_id,
|
|
2961
|
-
transfer_receiver_party_id: row.transfer_transfer_receiver_party_id,
|
|
2962
|
-
transfer_amount: parseFloat(row.transfer_transfer_amount),
|
|
2963
|
-
transfer_description: row.transfer_transfer_description,
|
|
2964
|
-
transfer_burned_amount: parseFloat(row.transfer_transfer_burned_amount),
|
|
2965
|
-
receiver_holding_cids: row.transfer_receiver_holding_cids,
|
|
2966
|
-
sender_change_cids: row.transfer_sender_change_cids,
|
|
2967
|
-
tx_update_id: row.transfer_tx_update_id,
|
|
2968
|
-
tx_record_time: row.transfer_tx_record_time,
|
|
2969
|
-
status: row.transfer_status,
|
|
2970
|
-
app_reward_coupon_id: row.transfer_app_reward_coupon_id,
|
|
2971
|
-
created_at: row.transfer_created_at,
|
|
2972
|
-
updated_at: row.transfer_updated_at,
|
|
2973
|
-
};
|
|
2974
|
-
const redemption = row.redemption_id
|
|
2975
|
-
? {
|
|
2976
|
-
id: row.redemption_id,
|
|
2977
|
-
transfer_id: row.transfer_id,
|
|
2978
|
-
app_reward_coupon_ids: [], // This would need to be fetched separately if needed
|
|
2979
|
-
tx_update_id: row.redemption_tx_update_id,
|
|
2980
|
-
tx_record_time: row.redemption_tx_record_time,
|
|
2981
|
-
tx_synchronizer_id: row.redemption_tx_synchronizer_id,
|
|
2982
|
-
tx_effective_at: row.redemption_tx_effective_at,
|
|
2983
|
-
total_app_rewards: parseFloat(row.total_app_rewards),
|
|
2984
|
-
created_at: row.redemption_created_at,
|
|
2985
|
-
updated_at: row.redemption_updated_at,
|
|
2986
|
-
}
|
|
2987
|
-
: null;
|
|
2988
|
-
return {
|
|
2989
|
-
...coupon,
|
|
2990
|
-
transfer,
|
|
2991
|
-
redemption,
|
|
2992
|
-
};
|
|
2993
|
-
}
|
|
2994
|
-
mapPartyFromDb(row) {
|
|
2995
|
-
return {
|
|
2996
|
-
id: row.id,
|
|
2997
|
-
party_id: row.party_id,
|
|
2998
|
-
portal_id: row.portal_id,
|
|
2999
|
-
provider: row.provider,
|
|
3000
|
-
last_payment_until: row.last_payment_until,
|
|
3001
|
-
is_active_customer_since: row.is_active_customer_since,
|
|
3002
|
-
created_at: row.created_at,
|
|
3003
|
-
updated_at: row.updated_at,
|
|
3004
|
-
portal: row.company
|
|
3005
|
-
? {
|
|
3006
|
-
id: row.portal_id,
|
|
3007
|
-
company: row.company,
|
|
3008
|
-
}
|
|
3009
|
-
: null,
|
|
3010
|
-
};
|
|
3011
|
-
}
|
|
3012
|
-
toSnakeCase(str) {
|
|
3013
|
-
return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
|
|
3014
|
-
}
|
|
3015
|
-
/**
|
|
3016
|
-
* Get historical issuance rates for specific rounds from the scan_acs_store table This queries ClosedMiningRound
|
|
3017
|
-
* contracts to get issuance rates for old rounds
|
|
3018
|
-
*
|
|
3019
|
-
* @param roundNumbers - Array of round numbers to get issuance rates for
|
|
3020
|
-
* @returns Array of issuance rates for the specified rounds
|
|
3021
|
-
*/
|
|
3022
|
-
async getHistoricalIssuanceRates(roundNumbers) {
|
|
3023
|
-
if (roundNumbers.length === 0) {
|
|
3024
|
-
return [];
|
|
3025
|
-
}
|
|
3026
|
-
// Query the scan_acs_store table for ClosedMiningRound contracts
|
|
3027
|
-
// The template_id_qualified_name should match the ClosedMiningRound template
|
|
3028
|
-
const query = `
|
|
3029
|
-
SELECT
|
|
3030
|
-
round,
|
|
3031
|
-
create_arguments
|
|
3032
|
-
FROM scan_acs_store
|
|
3033
|
-
WHERE template_id_qualified_name LIKE '%:Splice.Round:ClosedMiningRound'
|
|
3034
|
-
AND round = ANY($1)
|
|
3035
|
-
AND create_arguments IS NOT NULL
|
|
3036
|
-
ORDER BY round ASC
|
|
3037
|
-
`;
|
|
3038
|
-
try {
|
|
3039
|
-
const result = await this.pool.query(query, [roundNumbers]);
|
|
3040
|
-
return result.rows.map(row => {
|
|
3041
|
-
const payload = row.create_arguments;
|
|
3042
|
-
const roundNumber = parseInt(row.round, 10);
|
|
3043
|
-
// Extract issuance rates from the contract payload
|
|
3044
|
-
// The payload is stored as JSON and contains the issuance rate fields
|
|
3045
|
-
const issuancePerFeaturedAppRewardCoupon = parseFloat(payload.issuancePerFeaturedAppRewardCoupon ?? '0');
|
|
3046
|
-
const issuancePerUnfeaturedAppRewardCoupon = parseFloat(payload.issuancePerUnfeaturedAppRewardCoupon ?? '0');
|
|
3047
|
-
return {
|
|
3048
|
-
roundNumber,
|
|
3049
|
-
issuancePerFeaturedAppRewardCoupon,
|
|
3050
|
-
issuancePerUnfeaturedAppRewardCoupon,
|
|
3051
|
-
};
|
|
3052
|
-
});
|
|
3053
|
-
}
|
|
3054
|
-
catch (error) {
|
|
3055
|
-
console.error('Error querying historical issuance rates:', error);
|
|
3056
|
-
throw new Error(`Failed to get historical issuance rates: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
3057
|
-
}
|
|
3058
|
-
}
|
|
3059
|
-
mapValuationReportFromDb(row) {
|
|
3060
|
-
return {
|
|
3061
|
-
id: row.id,
|
|
3062
|
-
portal_id: row.portal_id,
|
|
3063
|
-
company_id: row.company_id,
|
|
3064
|
-
version: row.version,
|
|
3065
|
-
contract_id: row.contract_id,
|
|
3066
|
-
company_valuation: Number(row.company_valuation),
|
|
3067
|
-
tx_update_id: row.tx_update_id,
|
|
3068
|
-
last_valuation_until: row.last_valuation_until,
|
|
3069
|
-
created_at: row.created_at,
|
|
3070
|
-
updated_at: row.updated_at,
|
|
3071
|
-
};
|
|
345
|
+
return this.valuationReports.insertValuationReport(report);
|
|
3072
346
|
}
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
* @param query - SQL query to execute
|
|
3077
|
-
* @param params - Query parameters
|
|
3078
|
-
* @returns Query result
|
|
3079
|
-
*/
|
|
347
|
+
// ========================================================================
|
|
348
|
+
// Debug Operations
|
|
349
|
+
// ========================================================================
|
|
3080
350
|
async debugQuery(query, params = []) {
|
|
3081
351
|
try {
|
|
3082
352
|
const result = await this.pool.query(query, params);
|
|
@@ -3087,62 +357,6 @@ class FairmintDbClient {
|
|
|
3087
357
|
throw new Error(`Failed to execute debug query: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
3088
358
|
}
|
|
3089
359
|
}
|
|
3090
|
-
// ========================================================================
|
|
3091
|
-
// Cap Table Replication Methods
|
|
3092
|
-
// ========================================================================
|
|
3093
|
-
/**
|
|
3094
|
-
* Get the next issuer that needs cap table replication.
|
|
3095
|
-
*
|
|
3096
|
-
* Returns issuers that have OCF objects and a canton party configured.
|
|
3097
|
-
* Ordered by portal_id for deterministic processing order.
|
|
3098
|
-
*
|
|
3099
|
-
* @returns Issuer info with party_id and portal_id, or null if none need sync
|
|
3100
|
-
*/
|
|
3101
|
-
async getNextIssuerToReplicate() {
|
|
3102
|
-
const query = `
|
|
3103
|
-
SELECT DISTINCT
|
|
3104
|
-
cp.party_id,
|
|
3105
|
-
cp.portal_id,
|
|
3106
|
-
p.company
|
|
3107
|
-
FROM canton_parties cp
|
|
3108
|
-
LEFT JOIN portal p ON cp.portal_id = p.id
|
|
3109
|
-
WHERE EXISTS (
|
|
3110
|
-
SELECT 1 FROM latest_ocf_objects loo
|
|
3111
|
-
WHERE loo.portal_id = cp.portal_id
|
|
3112
|
-
AND loo.type = 'ISSUER'
|
|
3113
|
-
)
|
|
3114
|
-
ORDER BY cp.portal_id
|
|
3115
|
-
LIMIT 1
|
|
3116
|
-
`;
|
|
3117
|
-
const result = await this.pool.query(query);
|
|
3118
|
-
if (result.rows.length === 0) {
|
|
3119
|
-
return null;
|
|
3120
|
-
}
|
|
3121
|
-
return result.rows[0];
|
|
3122
|
-
}
|
|
3123
|
-
/**
|
|
3124
|
-
* Get all OCF objects for an issuer.
|
|
3125
|
-
*
|
|
3126
|
-
* Returns all OCF objects from the latest_ocf_objects view for a given portal.
|
|
3127
|
-
* Used by the replication script to determine desired state.
|
|
3128
|
-
*
|
|
3129
|
-
* @param portalId - Portal ID of the issuer
|
|
3130
|
-
* @returns Array of OCF objects with type, subtype, and data
|
|
3131
|
-
*/
|
|
3132
|
-
async getAllOcfObjectsForIssuer(portalId) {
|
|
3133
|
-
const query = `
|
|
3134
|
-
SELECT
|
|
3135
|
-
loo.id as ocf_id,
|
|
3136
|
-
loo.type,
|
|
3137
|
-
loo.subtype,
|
|
3138
|
-
loo.ocf_data as data
|
|
3139
|
-
FROM latest_ocf_objects loo
|
|
3140
|
-
WHERE loo.portal_id = $1
|
|
3141
|
-
ORDER BY loo.type, loo.subtype, loo.id
|
|
3142
|
-
`;
|
|
3143
|
-
const result = await this.pool.query(query, [portalId]);
|
|
3144
|
-
return result.rows;
|
|
3145
|
-
}
|
|
3146
360
|
}
|
|
3147
361
|
exports.FairmintDbClient = FairmintDbClient;
|
|
3148
362
|
//# sourceMappingURL=fairmintDbClient.js.map
|