mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-09 15:35:22 +02:00
rollback more stuff
This commit is contained in:
parent
18562477bf
commit
187b84e1c5
4 changed files with 271 additions and 262 deletions
|
@ -99,21 +99,7 @@ export async function createTestInvestmentAccount(
|
||||||
(s) => s.date === it.date && s.ticker === it.ticker
|
(s) => s.date === it.date && s.ticker === it.ticker
|
||||||
)?.price
|
)?.price
|
||||||
|
|
||||||
function getTransactionCategory(type: string) {
|
const isCashFlow = it.type === 'DEPOSIT' || it.type === 'WITHDRAW'
|
||||||
switch (type) {
|
|
||||||
case 'BUY':
|
|
||||||
return 'buy'
|
|
||||||
case 'SELL':
|
|
||||||
return 'sell'
|
|
||||||
case 'DIVIDEND':
|
|
||||||
return 'dividend'
|
|
||||||
case 'DEPOSIT':
|
|
||||||
case 'WITHDRAW':
|
|
||||||
return 'transfer'
|
|
||||||
default:
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
securityId: securities.find((s) => it.ticker === s.symbol)?.id,
|
securityId: securities.find((s) => it.ticker === s.symbol)?.id,
|
||||||
|
@ -122,7 +108,26 @@ export async function createTestInvestmentAccount(
|
||||||
amount: price ? new Prisma.Decimal(price).times(it.qty) : it.qty,
|
amount: price ? new Prisma.Decimal(price).times(it.qty) : it.qty,
|
||||||
quantity: price ? it.qty : 0,
|
quantity: price ? it.qty : 0,
|
||||||
price: price ?? 0,
|
price: price ?? 0,
|
||||||
category: getTransactionCategory(it.type),
|
plaidType:
|
||||||
|
isCashFlow || it.type === 'DIVIDEND'
|
||||||
|
? 'cash'
|
||||||
|
: it.type === 'BUY'
|
||||||
|
? 'buy'
|
||||||
|
: it.type === 'SELL'
|
||||||
|
? 'sell'
|
||||||
|
: undefined,
|
||||||
|
plaidSubtype:
|
||||||
|
it.type === 'DEPOSIT'
|
||||||
|
? 'deposit'
|
||||||
|
: it.type === 'WITHDRAW'
|
||||||
|
? 'withdrawal'
|
||||||
|
: it.type === 'DIVIDEND'
|
||||||
|
? 'dividend'
|
||||||
|
: it.type === 'BUY'
|
||||||
|
? 'buy'
|
||||||
|
: it.type === 'SELL'
|
||||||
|
? 'sell'
|
||||||
|
: undefined,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|
|
@ -70,7 +70,8 @@ export class InvestmentTransactionBalanceSyncStrategy extends BalanceSyncStrateg
|
||||||
it.account_id = ${pAccountId}
|
it.account_id = ${pAccountId}
|
||||||
AND it.date BETWEEN ${pStart} AND now()
|
AND it.date BETWEEN ${pStart} AND now()
|
||||||
AND ( -- filter for transactions that modify a position
|
AND ( -- filter for transactions that modify a position
|
||||||
it.category IN ('buy', 'sell', 'transfer')
|
it.plaid_type IN ('buy', 'sell', 'transfer')
|
||||||
|
OR it.finicity_transaction_id IS NOT NULL
|
||||||
)
|
)
|
||||||
GROUP BY
|
GROUP BY
|
||||||
1, 2
|
1, 2
|
||||||
|
|
|
@ -117,33 +117,33 @@ export class AccountQueryService implements IAccountQueryService {
|
||||||
}
|
}
|
||||||
>(
|
>(
|
||||||
sql`
|
sql`
|
||||||
SELECT
|
SELECT
|
||||||
h.id,
|
h.id,
|
||||||
h.security_id,
|
h.security_id,
|
||||||
s.name,
|
s.name,
|
||||||
s.symbol,
|
s.symbol,
|
||||||
s.shares_per_contract,
|
s.shares_per_contract,
|
||||||
he.quantity,
|
he.quantity,
|
||||||
he.value,
|
he.value,
|
||||||
he.cost_basis,
|
he.cost_basis,
|
||||||
h.cost_basis_user,
|
h.cost_basis_user,
|
||||||
h.cost_basis_provider,
|
h.cost_basis_provider,
|
||||||
he.cost_basis_per_share,
|
he.cost_basis_per_share,
|
||||||
he.price,
|
he.price,
|
||||||
he.price_prev,
|
he.price_prev,
|
||||||
he.excluded
|
he.excluded
|
||||||
FROM
|
FROM
|
||||||
holdings_enriched he
|
holdings_enriched he
|
||||||
INNER JOIN security s ON s.id = he.security_id
|
INNER JOIN security s ON s.id = he.security_id
|
||||||
INNER JOIN holding h ON h.id = he.id
|
INNER JOIN holding h ON h.id = he.id
|
||||||
WHERE
|
WHERE
|
||||||
he.account_id = ${accountId}
|
he.account_id = ${accountId}
|
||||||
ORDER BY
|
ORDER BY
|
||||||
he.excluded ASC,
|
he.excluded ASC,
|
||||||
he.value DESC
|
he.value DESC
|
||||||
OFFSET ${page * pageSize}
|
OFFSET ${page * pageSize}
|
||||||
LIMIT ${pageSize};
|
LIMIT ${pageSize};
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
return rows
|
return rows
|
||||||
|
@ -158,53 +158,53 @@ export class AccountQueryService implements IAccountQueryService {
|
||||||
|
|
||||||
const { rows } = await this.pg.pool.query<ValuationTrend>(
|
const { rows } = await this.pg.pool.query<ValuationTrend>(
|
||||||
sql`
|
sql`
|
||||||
WITH valuation_trends AS (
|
WITH valuation_trends AS (
|
||||||
SELECT
|
|
||||||
date,
|
|
||||||
COALESCE(interpolated::numeric, filled) AS amount
|
|
||||||
FROM (
|
|
||||||
SELECT
|
|
||||||
time_bucket_gapfill('1d', v.date) AS date,
|
|
||||||
interpolate(avg(v.amount)) AS interpolated,
|
|
||||||
locf(avg(v.amount)) AS filled
|
|
||||||
FROM
|
|
||||||
valuation v
|
|
||||||
WHERE
|
|
||||||
v.account_id = ${accountId}
|
|
||||||
AND v.date BETWEEN ${pStart} AND ${pEnd}
|
|
||||||
GROUP BY
|
|
||||||
1
|
|
||||||
) valuations_gapfilled
|
|
||||||
WHERE
|
|
||||||
to_char(date, 'MM-DD') = '01-01'
|
|
||||||
), valuations_combined AS (
|
|
||||||
SELECT
|
|
||||||
COALESCE(v.date, vt.date) AS date,
|
|
||||||
COALESCE(v.amount, vt.amount) AS amount,
|
|
||||||
v.id AS valuation_id
|
|
||||||
FROM
|
|
||||||
(SELECT * FROM valuation WHERE account_id = ${accountId}) v
|
|
||||||
FULL OUTER JOIN valuation_trends vt ON vt.date = v.date
|
|
||||||
)
|
|
||||||
SELECT
|
SELECT
|
||||||
v.date,
|
date,
|
||||||
v.amount,
|
COALESCE(interpolated::numeric, filled) AS amount
|
||||||
v.valuation_id,
|
|
||||||
v.amount - v.prev_amount AS period_change,
|
|
||||||
ROUND((v.amount - v.prev_amount)::numeric / NULLIF(v.prev_amount, 0), 4) AS period_change_pct,
|
|
||||||
v.amount - v.first_amount AS total_change,
|
|
||||||
ROUND((v.amount - v.first_amount)::numeric / NULLIF(v.first_amount, 0), 4) AS total_change_pct
|
|
||||||
FROM (
|
FROM (
|
||||||
SELECT
|
SELECT
|
||||||
*,
|
time_bucket_gapfill('1d', v.date) AS date,
|
||||||
LAG(amount, 1) OVER (ORDER BY date ASC) AS prev_amount,
|
interpolate(avg(v.amount)) AS interpolated,
|
||||||
(SELECT amount FROM valuations_combined ORDER BY date ASC LIMIT 1) AS first_amount
|
locf(avg(v.amount)) AS filled
|
||||||
FROM
|
FROM
|
||||||
valuations_combined
|
valuation v
|
||||||
) v
|
WHERE
|
||||||
ORDER BY
|
v.account_id = ${accountId}
|
||||||
v.date ASC
|
AND v.date BETWEEN ${pStart} AND ${pEnd}
|
||||||
`
|
GROUP BY
|
||||||
|
1
|
||||||
|
) valuations_gapfilled
|
||||||
|
WHERE
|
||||||
|
to_char(date, 'MM-DD') = '01-01'
|
||||||
|
), valuations_combined AS (
|
||||||
|
SELECT
|
||||||
|
COALESCE(v.date, vt.date) AS date,
|
||||||
|
COALESCE(v.amount, vt.amount) AS amount,
|
||||||
|
v.id AS valuation_id
|
||||||
|
FROM
|
||||||
|
(SELECT * FROM valuation WHERE account_id = ${accountId}) v
|
||||||
|
FULL OUTER JOIN valuation_trends vt ON vt.date = v.date
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
v.date,
|
||||||
|
v.amount,
|
||||||
|
v.valuation_id,
|
||||||
|
v.amount - v.prev_amount AS period_change,
|
||||||
|
ROUND((v.amount - v.prev_amount)::numeric / NULLIF(v.prev_amount, 0), 4) AS period_change_pct,
|
||||||
|
v.amount - v.first_amount AS total_change,
|
||||||
|
ROUND((v.amount - v.first_amount)::numeric / NULLIF(v.first_amount, 0), 4) AS total_change_pct
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
*,
|
||||||
|
LAG(amount, 1) OVER (ORDER BY date ASC) AS prev_amount,
|
||||||
|
(SELECT amount FROM valuations_combined ORDER BY date ASC LIMIT 1) AS first_amount
|
||||||
|
FROM
|
||||||
|
valuations_combined
|
||||||
|
) v
|
||||||
|
ORDER BY
|
||||||
|
v.date ASC
|
||||||
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
return rows
|
return rows
|
||||||
|
@ -220,77 +220,80 @@ export class AccountQueryService implements IAccountQueryService {
|
||||||
|
|
||||||
const { rows } = await this.pg.pool.query<ReturnSeries>(
|
const { rows } = await this.pg.pool.query<ReturnSeries>(
|
||||||
sql`
|
sql`
|
||||||
WITH start_date AS (
|
WITH start_date AS (
|
||||||
SELECT
|
|
||||||
a.id AS "account_id",
|
|
||||||
GREATEST(account_value_start_date(a.id), a.start_date) AS "start_date"
|
|
||||||
FROM
|
|
||||||
account a
|
|
||||||
WHERE
|
|
||||||
a.id = ANY(${pAccountIds})
|
|
||||||
GROUP BY
|
|
||||||
1
|
|
||||||
), external_flows AS (
|
|
||||||
SELECT
|
|
||||||
it.account_id,
|
|
||||||
it.date,
|
|
||||||
SUM(it.amount) AS "amount"
|
|
||||||
FROM
|
|
||||||
investment_transaction it
|
|
||||||
LEFT JOIN start_date sd ON sd.account_id = it.account_id
|
|
||||||
WHERE
|
|
||||||
it.account_id = ANY(${pAccountIds})
|
|
||||||
AND it.date BETWEEN sd.start_date AND ${pEnd}
|
|
||||||
-- filter for investment_transactions that represent external flows
|
|
||||||
AND (
|
|
||||||
it.category = 'transfer'
|
|
||||||
)
|
|
||||||
GROUP BY
|
|
||||||
1, 2
|
|
||||||
), external_flow_totals AS (
|
|
||||||
SELECT
|
|
||||||
account_id,
|
|
||||||
SUM(amount) as "amount"
|
|
||||||
FROM
|
|
||||||
external_flows
|
|
||||||
GROUP BY
|
|
||||||
1
|
|
||||||
), balances AS (
|
|
||||||
SELECT
|
|
||||||
abg.account_id,
|
|
||||||
abg.date,
|
|
||||||
abg.balance,
|
|
||||||
0 - SUM(COALESCE(ef.amount, 0)) OVER (PARTITION BY abg.account_id ORDER BY abg.date ASC) AS "contributions_period",
|
|
||||||
COALESCE(-1 * (eft.amount - coalesce(SUM(ef.amount) OVER (PARTITION BY abg.account_id ORDER BY abg.date DESC ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0)), 0) AS "contributions"
|
|
||||||
FROM
|
|
||||||
account_balances_gapfilled(
|
|
||||||
${pStart},
|
|
||||||
${pEnd},
|
|
||||||
'1d',
|
|
||||||
${pAccountIds}
|
|
||||||
) abg
|
|
||||||
LEFT JOIN external_flows ef ON ef.account_id = abg.account_id AND ef.date = abg.date
|
|
||||||
LEFT JOIN external_flow_totals eft ON eft.account_id = abg.account_id
|
|
||||||
)
|
|
||||||
SELECT
|
SELECT
|
||||||
b.account_id,
|
a.id AS "account_id",
|
||||||
b.date,
|
GREATEST(account_value_start_date(a.id), a.start_date) AS "start_date"
|
||||||
b.balance,
|
|
||||||
b.contributions,
|
|
||||||
b.contributions_period,
|
|
||||||
COALESCE(ROUND((b.balance - b0.balance - b.contributions_period) / COALESCE(NULLIF(b0.balance, 0), NULLIF(b.contributions_period, 0)), 4), 0) AS "rate_of_return"
|
|
||||||
FROM
|
FROM
|
||||||
balances b
|
account a
|
||||||
LEFT JOIN (
|
WHERE
|
||||||
SELECT DISTINCT ON (account_id)
|
a.id = ANY(${pAccountIds})
|
||||||
account_id,
|
GROUP BY
|
||||||
balance
|
1
|
||||||
FROM
|
), external_flows AS (
|
||||||
balances
|
SELECT
|
||||||
ORDER BY
|
it.account_id,
|
||||||
account_id, date ASC
|
it.date,
|
||||||
) b0 ON b0.account_id = b.account_id
|
SUM(it.amount) AS "amount"
|
||||||
`
|
FROM
|
||||||
|
investment_transaction it
|
||||||
|
LEFT JOIN start_date sd ON sd.account_id = it.account_id
|
||||||
|
WHERE
|
||||||
|
it.account_id = ANY(${pAccountIds})
|
||||||
|
AND it.date BETWEEN sd.start_date AND ${pEnd}
|
||||||
|
-- filter for investment_transactions that represent external flows
|
||||||
|
AND (
|
||||||
|
(it.plaid_type = 'cash' AND it.plaid_subtype IN ('contribution', 'deposit', 'withdrawal'))
|
||||||
|
OR (it.plaid_type = 'transfer' AND it.plaid_subtype IN ('transfer'))
|
||||||
|
OR (it.plaid_type = 'buy' AND it.plaid_subtype IN ('contribution'))
|
||||||
|
OR (it.finicity_transaction_id IS NOT NULL AND it.finicity_investment_transaction_type IN ('contribution', 'deposit', 'transfer'))
|
||||||
|
)
|
||||||
|
GROUP BY
|
||||||
|
1, 2
|
||||||
|
), external_flow_totals AS (
|
||||||
|
SELECT
|
||||||
|
account_id,
|
||||||
|
SUM(amount) as "amount"
|
||||||
|
FROM
|
||||||
|
external_flows
|
||||||
|
GROUP BY
|
||||||
|
1
|
||||||
|
), balances AS (
|
||||||
|
SELECT
|
||||||
|
abg.account_id,
|
||||||
|
abg.date,
|
||||||
|
abg.balance,
|
||||||
|
0 - SUM(COALESCE(ef.amount, 0)) OVER (PARTITION BY abg.account_id ORDER BY abg.date ASC) AS "contributions_period",
|
||||||
|
COALESCE(-1 * (eft.amount - coalesce(SUM(ef.amount) OVER (PARTITION BY abg.account_id ORDER BY abg.date DESC ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0)), 0) AS "contributions"
|
||||||
|
FROM
|
||||||
|
account_balances_gapfilled(
|
||||||
|
${pStart},
|
||||||
|
${pEnd},
|
||||||
|
'1d',
|
||||||
|
${pAccountIds}
|
||||||
|
) abg
|
||||||
|
LEFT JOIN external_flows ef ON ef.account_id = abg.account_id AND ef.date = abg.date
|
||||||
|
LEFT JOIN external_flow_totals eft ON eft.account_id = abg.account_id
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
b.account_id,
|
||||||
|
b.date,
|
||||||
|
b.balance,
|
||||||
|
b.contributions,
|
||||||
|
b.contributions_period,
|
||||||
|
COALESCE(ROUND((b.balance - b0.balance - b.contributions_period) / COALESCE(NULLIF(b0.balance, 0), NULLIF(b.contributions_period, 0)), 4), 0) AS "rate_of_return"
|
||||||
|
FROM
|
||||||
|
balances b
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT DISTINCT ON (account_id)
|
||||||
|
account_id,
|
||||||
|
balance
|
||||||
|
FROM
|
||||||
|
balances
|
||||||
|
ORDER BY
|
||||||
|
account_id, date ASC
|
||||||
|
) b0 ON b0.account_id = b.account_id
|
||||||
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
return rows
|
return rows
|
||||||
|
@ -310,18 +313,18 @@ export class AccountQueryService implements IAccountQueryService {
|
||||||
|
|
||||||
const { rows } = await this.pg.pool.query<BalanceSeries>(
|
const { rows } = await this.pg.pool.query<BalanceSeries>(
|
||||||
sql`
|
sql`
|
||||||
SELECT
|
SELECT
|
||||||
abg.account_id,
|
abg.account_id,
|
||||||
abg.date,
|
abg.date,
|
||||||
abg.balance
|
abg.balance
|
||||||
FROM
|
FROM
|
||||||
account_balances_gapfilled(
|
account_balances_gapfilled(
|
||||||
${pStart},
|
${pStart},
|
||||||
${pEnd},
|
${pEnd},
|
||||||
${pInterval},
|
${pInterval},
|
||||||
${pAccountIds}
|
${pAccountIds}
|
||||||
) abg
|
) abg
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
return rows
|
return rows
|
||||||
|
@ -341,15 +344,15 @@ export class AccountQueryService implements IAccountQueryService {
|
||||||
'accountIds' in id
|
'accountIds' in id
|
||||||
? id.accountIds
|
? id.accountIds
|
||||||
: sql`(
|
: sql`(
|
||||||
SELECT
|
SELECT
|
||||||
array_agg(a.id)
|
array_agg(a.id)
|
||||||
FROM
|
FROM
|
||||||
account a
|
account a
|
||||||
LEFT JOIN account_connection ac ON ac.id = a.account_connection_id
|
LEFT JOIN account_connection ac ON ac.id = a.account_connection_id
|
||||||
WHERE
|
WHERE
|
||||||
(a.user_id = ${id.userId} OR ac.user_id = ${id.userId})
|
(a.user_id = ${id.userId} OR ac.user_id = ${id.userId})
|
||||||
AND a.is_active
|
AND a.is_active
|
||||||
)`
|
)`
|
||||||
|
|
||||||
const pStart = raw(`'${start}'`)
|
const pStart = raw(`'${start}'`)
|
||||||
const pEnd = raw(`'${end}'`)
|
const pEnd = raw(`'${end}'`)
|
||||||
|
@ -376,27 +379,27 @@ export class AccountQueryService implements IAccountQueryService {
|
||||||
}
|
}
|
||||||
>(
|
>(
|
||||||
sql`
|
sql`
|
||||||
SELECT
|
SELECT
|
||||||
abg.date,
|
abg.date,
|
||||||
a.category,
|
a.category,
|
||||||
a.classification,
|
a.classification,
|
||||||
SUM(CASE WHEN a.classification = 'asset' THEN abg.balance ELSE -abg.balance END) AS balance
|
SUM(CASE WHEN a.classification = 'asset' THEN abg.balance ELSE -abg.balance END) AS balance
|
||||||
FROM
|
FROM
|
||||||
account_balances_gapfilled(
|
account_balances_gapfilled(
|
||||||
${pStart},
|
${pStart},
|
||||||
${pEnd},
|
${pEnd},
|
||||||
${pInterval},
|
${pInterval},
|
||||||
${pAccountIds}
|
${pAccountIds}
|
||||||
) abg
|
) abg
|
||||||
INNER JOIN account a ON a.id = abg.account_id
|
INNER JOIN account a ON a.id = abg.account_id
|
||||||
GROUP BY
|
GROUP BY
|
||||||
GROUPING SETS (
|
GROUPING SETS (
|
||||||
(abg.date, a.classification, a.category),
|
(abg.date, a.classification, a.category),
|
||||||
(abg.date, a.classification),
|
(abg.date, a.classification),
|
||||||
(abg.date)
|
(abg.date)
|
||||||
)
|
)
|
||||||
ORDER BY date ASC;
|
ORDER BY date ASC;
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
// Group independent rows into NetWorthSeries objects
|
// Group independent rows into NetWorthSeries objects
|
||||||
|
@ -450,15 +453,15 @@ export class AccountQueryService implements IAccountQueryService {
|
||||||
'accountId' in id
|
'accountId' in id
|
||||||
? [id.accountId]
|
? [id.accountId]
|
||||||
: sql`(
|
: sql`(
|
||||||
SELECT
|
SELECT
|
||||||
array_agg(a.id)
|
array_agg(a.id)
|
||||||
FROM
|
FROM
|
||||||
account a
|
account a
|
||||||
LEFT JOIN account_connection ac ON ac.id = a.account_connection_id
|
LEFT JOIN account_connection ac ON ac.id = a.account_connection_id
|
||||||
WHERE
|
WHERE
|
||||||
(a.user_id = ${id.userId} OR ac.user_id = ${id.userId})
|
(a.user_id = ${id.userId} OR ac.user_id = ${id.userId})
|
||||||
AND a.is_active
|
AND a.is_active
|
||||||
)`
|
)`
|
||||||
|
|
||||||
const pStart = raw(`'${start}'`)
|
const pStart = raw(`'${start}'`)
|
||||||
const pEnd = raw(`'${end}'`)
|
const pEnd = raw(`'${end}'`)
|
||||||
|
@ -466,59 +469,59 @@ export class AccountQueryService implements IAccountQueryService {
|
||||||
|
|
||||||
const { rows } = await this.pg.pool.query<AccountRollup>(
|
const { rows } = await this.pg.pool.query<AccountRollup>(
|
||||||
sql`
|
sql`
|
||||||
WITH account_rollup AS (
|
WITH account_rollup AS (
|
||||||
SELECT
|
|
||||||
abg.date,
|
|
||||||
a.classification,
|
|
||||||
a.category,
|
|
||||||
a.id,
|
|
||||||
SUM(abg.balance) AS balance,
|
|
||||||
CASE GROUPING(abg.date, a.classification, a.category, a.id)
|
|
||||||
WHEN 3 THEN 'classification'
|
|
||||||
WHEN 1 THEN 'category'
|
|
||||||
WHEN 0 THEN 'account'
|
|
||||||
ELSE NULL
|
|
||||||
END AS grouping
|
|
||||||
FROM
|
|
||||||
account_balances_gapfilled(
|
|
||||||
${pStart},
|
|
||||||
${pEnd},
|
|
||||||
${pInterval},
|
|
||||||
${pAccountIds}
|
|
||||||
) abg
|
|
||||||
INNER JOIN account a ON a.id = abg.account_id
|
|
||||||
GROUP BY
|
|
||||||
GROUPING SETS (
|
|
||||||
(abg.date, a.classification, a.category, a.id),
|
|
||||||
(abg.date, a.classification, a.category),
|
|
||||||
(abg.date, a.classification)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
SELECT
|
SELECT
|
||||||
ar.date,
|
abg.date,
|
||||||
ar.classification,
|
a.classification,
|
||||||
ar.category,
|
a.category,
|
||||||
ar.id,
|
a.id,
|
||||||
ar.balance,
|
SUM(abg.balance) AS balance,
|
||||||
ar.grouping,
|
CASE GROUPING(abg.date, a.classification, a.category, a.id)
|
||||||
CASE
|
WHEN 3 THEN 'classification'
|
||||||
WHEN a.id IS NULL THEN NULL
|
WHEN 1 THEN 'category'
|
||||||
ELSE json_build_object('id', a.id, 'name', a.name, 'mask', a.mask, 'syncStatus', a.sync_status, 'connection', CASE WHEN ac.id IS NULL THEN NULL ELSE json_build_object('name', ac.name, 'syncStatus', ac.sync_status) END)
|
WHEN 0 THEN 'account'
|
||||||
END AS account,
|
ELSE NULL
|
||||||
ROUND(
|
END AS grouping
|
||||||
CASE ar.grouping
|
|
||||||
WHEN 'account' THEN COALESCE(ar.balance / SUM(NULLIF(ar.balance, 0)) OVER (PARTITION BY ar.grouping, ar.date, ar.classification, ar.category), 0)
|
|
||||||
WHEN 'category' THEN COALESCE(ar.balance / SUM(NULLIF(ar.balance, 0)) OVER (PARTITION BY ar.grouping, ar.date, ar.classification), 0)
|
|
||||||
WHEN 'classification' THEN COALESCE(ar.balance / SUM(NULLIF(ar.balance, 0)) OVER (PARTITION BY ar.grouping, ar.date), 0)
|
|
||||||
END, 4) AS rollup_pct,
|
|
||||||
ROUND(ar.balance / SUM(NULLIF(ar.balance, 0)) OVER (PARTITION BY ar.grouping, ar.date), 4) AS total_pct
|
|
||||||
FROM
|
FROM
|
||||||
account_rollup ar
|
account_balances_gapfilled(
|
||||||
LEFT JOIN account a ON a.id = ar.id
|
${pStart},
|
||||||
LEFT JOIN account_connection ac ON ac.id = a.account_connection_id
|
${pEnd},
|
||||||
ORDER BY
|
${pInterval},
|
||||||
ar.classification, ar.category, ar.id, ar.date;
|
${pAccountIds}
|
||||||
`
|
) abg
|
||||||
|
INNER JOIN account a ON a.id = abg.account_id
|
||||||
|
GROUP BY
|
||||||
|
GROUPING SETS (
|
||||||
|
(abg.date, a.classification, a.category, a.id),
|
||||||
|
(abg.date, a.classification, a.category),
|
||||||
|
(abg.date, a.classification)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
ar.date,
|
||||||
|
ar.classification,
|
||||||
|
ar.category,
|
||||||
|
ar.id,
|
||||||
|
ar.balance,
|
||||||
|
ar.grouping,
|
||||||
|
CASE
|
||||||
|
WHEN a.id IS NULL THEN NULL
|
||||||
|
ELSE json_build_object('id', a.id, 'name', a.name, 'mask', a.mask, 'syncStatus', a.sync_status, 'connection', CASE WHEN ac.id IS NULL THEN NULL ELSE json_build_object('name', ac.name, 'syncStatus', ac.sync_status) END)
|
||||||
|
END AS account,
|
||||||
|
ROUND(
|
||||||
|
CASE ar.grouping
|
||||||
|
WHEN 'account' THEN COALESCE(ar.balance / SUM(NULLIF(ar.balance, 0)) OVER (PARTITION BY ar.grouping, ar.date, ar.classification, ar.category), 0)
|
||||||
|
WHEN 'category' THEN COALESCE(ar.balance / SUM(NULLIF(ar.balance, 0)) OVER (PARTITION BY ar.grouping, ar.date, ar.classification), 0)
|
||||||
|
WHEN 'classification' THEN COALESCE(ar.balance / SUM(NULLIF(ar.balance, 0)) OVER (PARTITION BY ar.grouping, ar.date), 0)
|
||||||
|
END, 4) AS rollup_pct,
|
||||||
|
ROUND(ar.balance / SUM(NULLIF(ar.balance, 0)) OVER (PARTITION BY ar.grouping, ar.date), 4) AS total_pct
|
||||||
|
FROM
|
||||||
|
account_rollup ar
|
||||||
|
LEFT JOIN account a ON a.id = ar.id
|
||||||
|
LEFT JOIN account_connection ac ON ac.id = a.account_connection_id
|
||||||
|
ORDER BY
|
||||||
|
ar.classification, ar.category, ar.id, ar.date;
|
||||||
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
return rows
|
return rows
|
||||||
|
|
|
@ -315,9 +315,6 @@ export class InsightService implements IInsightService {
|
||||||
{
|
{
|
||||||
finicityInvestmentTransactionType: 'dividend',
|
finicityInvestmentTransactionType: 'dividend',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
category: 'dividend',
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
@ -750,7 +747,10 @@ export class InsightService implements IInsightService {
|
||||||
WHERE
|
WHERE
|
||||||
it.account_id = ${accountId}
|
it.account_id = ${accountId}
|
||||||
AND (
|
AND (
|
||||||
it.category = 'transfer'
|
(it.plaid_type = 'cash' AND it.plaid_subtype IN ('contribution', 'deposit', 'withdrawal'))
|
||||||
|
OR (it.plaid_type = 'transfer' AND it.plaid_subtype IN ('transfer', 'send', 'request'))
|
||||||
|
OR (it.plaid_type = 'buy' AND it.plaid_subtype IN ('contribution'))
|
||||||
|
OR (it.finicity_transaction_id IS NOT NULL AND it.finicity_investment_transaction_type IN ('contribution', 'deposit', 'transfer'))
|
||||||
)
|
)
|
||||||
-- Exclude any contributions made prior to the start date since balances will be 0
|
-- Exclude any contributions made prior to the start date since balances will be 0
|
||||||
AND (a.start_date is NULL OR it.date >= a.start_date)
|
AND (a.start_date is NULL OR it.date >= a.start_date)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue