Merge pull request #1612 from useautumn/fix/dashboard-customer-cache
fix: dashboard customer cache
This commit is contained in:
2
ai
2
ai
Submodule ai updated: a6d3ad0403...b1efb8d303
@@ -14,7 +14,10 @@ import {
|
||||
} from "@autumn/shared";
|
||||
import * as Sentry from "@sentry/bun";
|
||||
import type { AutumnContext, RequestContext } from "@/honoUtils/HonoEnv.js";
|
||||
import { getOrgCusProductLimit } from "../misc/edgeConfig/orgLimitsStore.js";
|
||||
import {
|
||||
getOrgCusProductLimit,
|
||||
getOrgEntitiesLimit,
|
||||
} from "../misc/edgeConfig/orgLimitsStore.js";
|
||||
import { triggerBatchResetCustomerEntitlements } from "./actions/resetCustomerEntitlements/triggerBatchResetCustomerEntitlements.js";
|
||||
import { CusSearchService } from "./CusSearchService.js";
|
||||
import { getCursorPaginatedFullCusQuery } from "./cursorPaginatedFullCusQuery.js";
|
||||
@@ -324,6 +327,10 @@ export class CusBatchService {
|
||||
orgId: ctx.org.id,
|
||||
orgSlug: ctx.org.slug,
|
||||
});
|
||||
const entitiesLimit = getOrgEntitiesLimit({
|
||||
orgId: ctx.org.id,
|
||||
orgSlug: ctx.org.slug,
|
||||
});
|
||||
|
||||
const statusFilters = (filters?.status ?? []).filter(
|
||||
(s): s is DashboardStatusFilter =>
|
||||
@@ -373,6 +380,9 @@ export class CusBatchService {
|
||||
env: ctx.env,
|
||||
inStatuses: RELEVANT_STATUSES,
|
||||
withSubs: true,
|
||||
withEntities: true,
|
||||
includeInvoices: true,
|
||||
entitiesLimit,
|
||||
limit: internalIds ? internalIds.length : limit,
|
||||
cursor:
|
||||
!requiresResolveStep && cursor
|
||||
@@ -403,6 +413,8 @@ export class CusBatchService {
|
||||
replaceables: [],
|
||||
free_trials: [],
|
||||
subscriptions: [],
|
||||
entities: [],
|
||||
invoices: [],
|
||||
}) as unknown as FlattenedCustomerRow;
|
||||
|
||||
const allCustomers = reassembleFlattenedCustomer(flat);
|
||||
|
||||
@@ -16,6 +16,10 @@ export type CursorPaginatedFullCusQueryArgs = {
|
||||
env: AppEnv;
|
||||
inStatuses?: CusProductStatus[];
|
||||
withSubs?: boolean;
|
||||
withEntities?: boolean;
|
||||
includeInvoices?: boolean;
|
||||
entitiesLimit?: number;
|
||||
invoicesLimit?: number;
|
||||
limit: number;
|
||||
cursor?: StandardCursorFields;
|
||||
internalCustomerIds?: string[];
|
||||
@@ -38,6 +42,10 @@ export const getCursorPaginatedFullCusQuery = ({
|
||||
env,
|
||||
inStatuses,
|
||||
withSubs = true,
|
||||
withEntities = false,
|
||||
includeInvoices = false,
|
||||
entitiesLimit = 300,
|
||||
invoicesLimit = 10,
|
||||
limit,
|
||||
cursor,
|
||||
internalCustomerIds,
|
||||
@@ -86,6 +94,42 @@ export const getCursorPaginatedFullCusQuery = ({
|
||||
) AS subscriptions`
|
||||
: sql`'[]'::json AS subscriptions`;
|
||||
|
||||
const entitiesCte = withEntities
|
||||
? sql`, entities_all AS MATERIALIZED (
|
||||
SELECT e.internal_customer_id, row_to_json(e) AS row_json
|
||||
FROM cr
|
||||
JOIN LATERAL (
|
||||
SELECT e.*
|
||||
FROM entities e
|
||||
WHERE e.internal_customer_id = cr.internal_id
|
||||
ORDER BY e.internal_id DESC
|
||||
LIMIT ${entitiesLimit}
|
||||
) e ON true
|
||||
)`
|
||||
: sql``;
|
||||
|
||||
const invoicesCte = includeInvoices
|
||||
? sql`, invoices_all AS MATERIALIZED (
|
||||
SELECT i.internal_customer_id, row_to_json(i) AS row_json
|
||||
FROM cr
|
||||
JOIN LATERAL (
|
||||
SELECT i.*
|
||||
FROM invoices i
|
||||
WHERE i.internal_customer_id = cr.internal_id
|
||||
ORDER BY i.created_at DESC, i.id DESC
|
||||
LIMIT ${invoicesLimit}
|
||||
) i ON true
|
||||
)`
|
||||
: sql``;
|
||||
|
||||
const entitiesSelect = withEntities
|
||||
? sql`, (SELECT COALESCE(json_agg(row_json), '[]'::json) FROM entities_all) AS entities`
|
||||
: sql``;
|
||||
|
||||
const invoicesSelect = includeInvoices
|
||||
? sql`, (SELECT COALESCE(json_agg(row_json), '[]'::json) FROM invoices_all) AS invoices`
|
||||
: sql``;
|
||||
|
||||
return sql`
|
||||
WITH cr AS MATERIALIZED (
|
||||
SELECT
|
||||
@@ -155,6 +199,8 @@ export const getCursorPaginatedFullCusQuery = ({
|
||||
UNION ALL
|
||||
SELECT id, entitlement_id FROM ces_loose
|
||||
)
|
||||
${entitiesCte}
|
||||
${invoicesCte}
|
||||
SELECT
|
||||
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM cr) AS customers,
|
||||
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM cps_ranked) AS customer_products,
|
||||
@@ -184,5 +230,7 @@ export const getCursorPaginatedFullCusQuery = ({
|
||||
JOIN free_trials ft ON ft.id = cps.free_trial_id
|
||||
) AS free_trials,
|
||||
${subscriptionsSelect}
|
||||
${entitiesSelect}
|
||||
${invoicesSelect}
|
||||
`;
|
||||
};
|
||||
|
||||
@@ -49,16 +49,41 @@ export const reassembleFlattenedCustomer = (
|
||||
subscriptionByStripeId: maps.subscriptionByStripeId,
|
||||
});
|
||||
|
||||
const entitiesByCusId = groupByInternalCustomerId(flat.entities);
|
||||
const invoicesByCusId = groupByInternalCustomerId(flat.invoices);
|
||||
|
||||
const out: FullCustomer[] = [];
|
||||
for (const c of flat.customers) {
|
||||
const internalId = c.internal_id as string;
|
||||
out.push({
|
||||
const hydrated: Record<string, unknown> = {
|
||||
...c,
|
||||
created_at: toTimestamp(c.created_at),
|
||||
customer_products: cpsByCusId.get(internalId) ?? [],
|
||||
extra_customer_entitlements: looseCesByCusId.get(internalId) ?? [],
|
||||
subscriptions: subsByCusId.get(internalId) ?? [],
|
||||
} as unknown as FullCustomer);
|
||||
};
|
||||
if (flat.entities !== undefined) {
|
||||
hydrated.entities = entitiesByCusId.get(internalId) ?? [];
|
||||
}
|
||||
if (flat.invoices !== undefined) {
|
||||
hydrated.invoices = invoicesByCusId.get(internalId) ?? [];
|
||||
}
|
||||
out.push(hydrated as unknown as FullCustomer);
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
const groupByInternalCustomerId = (
|
||||
rows: { internal_customer_id?: string; [k: string]: unknown }[] | undefined,
|
||||
): Map<string, unknown[]> => {
|
||||
const out = new Map<string, unknown[]>();
|
||||
if (!rows) return out;
|
||||
for (const row of rows) {
|
||||
const cusId = row.internal_customer_id;
|
||||
if (!cusId) continue;
|
||||
const list = out.get(cusId);
|
||||
if (list) list.push(row);
|
||||
else out.set(cusId, [row]);
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
@@ -9,6 +9,8 @@ export type FlattenedCustomerRow = {
|
||||
replaceables: any[];
|
||||
free_trials: any[];
|
||||
subscriptions: any[];
|
||||
entities?: any[];
|
||||
invoices?: any[];
|
||||
};
|
||||
|
||||
export type FlatCustomerEntitlement = {
|
||||
|
||||
Reference in New Issue
Block a user