mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 21:45:31 +09:00
chore(repo): remove dead code and useless tests (#3375)
This commit is contained in:
1 parent
7e177a1c90
commit
1cd62eb661
1391 files changed
+783
-120415
No files matched your search
@@ -2,21 +2,12 @@
|
||||
|
||||
import {
|
||||
computeStripeUpdatedAt,
|
||||
mapStripeChargeToRow,
|
||||
mapStripeCheckoutSessionToRow,
|
||||
mapStripeCustomerToRow,
|
||||
mapStripeDisputeToRow,
|
||||
mapStripeInvoiceToRow,
|
||||
mapStripePaymentIntentToRow,
|
||||
mapStripePaymentMethodToRow,
|
||||
mapStripePriceToRow,
|
||||
mapStripeProductToRow,
|
||||
mapStripeRefundToRow,
|
||||
mapStripeSubscriptionToRow,
|
||||
normalizeBillingSubscriptionRow,
|
||||
type StripeSubscriptionPayload,
|
||||
safeMetadata,
|
||||
unixToDate,
|
||||
} from '@app/api/billing/mappers/StripeToBillingMapper';
|
||||
import type Stripe from 'stripe';
|
||||
import {describe, expect, it} from 'vitest';
|
||||
@@ -34,35 +25,6 @@ function expectTupleGetValue(value: object, index: number, expected: unknown): v
|
||||
expect(value.get(index)).toBe(expected);
|
||||
}
|
||||
|
||||
describe('unixToDate', () => {
|
||||
it('returns null for null/undefined', () => {
|
||||
expect(unixToDate(null)).toBeNull();
|
||||
expect(unixToDate(undefined)).toBeNull();
|
||||
});
|
||||
it('converts epoch seconds to Date', () => {
|
||||
const d = unixToDate(NOW_UNIX);
|
||||
expect(d).toBeInstanceOf(Date);
|
||||
expect(d!.getTime()).toBe(NOW_UNIX * 1000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('safeMetadata', () => {
|
||||
it('returns null for null/undefined', () => {
|
||||
expect(safeMetadata(null)).toBeNull();
|
||||
expect(safeMetadata(undefined)).toBeNull();
|
||||
});
|
||||
it('returns null for empty metadata', () => {
|
||||
expect(safeMetadata({})).toBeNull();
|
||||
});
|
||||
it('returns Map preserving entries', () => {
|
||||
const m = safeMetadata({foo: 'bar', baz: 'qux'});
|
||||
expect(m).toBeInstanceOf(Map);
|
||||
expect(m!.get('foo')).toBe('bar');
|
||||
expect(m!.get('baz')).toBe('qux');
|
||||
expect(m!.size).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('computeStripeUpdatedAt', () => {
|
||||
it('returns a Date', () => {
|
||||
const d = computeStripeUpdatedAt({created: NOW_UNIX});
|
||||
@@ -154,85 +116,6 @@ describe('mapStripeCustomerToRow', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStripeProductToRow', () => {
|
||||
it('smoke maps minimal product', () => {
|
||||
const p = stripeFixture<Stripe.Product>({
|
||||
id: 'prod_x',
|
||||
name: 'Test',
|
||||
description: null,
|
||||
active: true,
|
||||
livemode: true,
|
||||
metadata: {},
|
||||
images: ['a', 'b'],
|
||||
created: NOW_UNIX,
|
||||
});
|
||||
const row = mapStripeProductToRow(p);
|
||||
expect(row.provider_id).toBe('prod_x');
|
||||
expect(row.name).toBe('Test');
|
||||
expect(row.images).toEqual(['a', 'b']);
|
||||
expect(row.version).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStripePriceToRow', () => {
|
||||
it('smoke maps recurring price', () => {
|
||||
const p = stripeFixture<Stripe.Price>({
|
||||
id: 'price_x',
|
||||
product: 'prod_x',
|
||||
active: true,
|
||||
currency: 'usd',
|
||||
unit_amount: 999,
|
||||
billing_scheme: 'per_unit',
|
||||
type: 'recurring',
|
||||
recurring: {interval: 'month', interval_count: 1, usage_type: 'licensed'},
|
||||
livemode: true,
|
||||
lookup_key: null,
|
||||
metadata: {},
|
||||
tax_behavior: 'inclusive',
|
||||
created: NOW_UNIX,
|
||||
});
|
||||
const row = mapStripePriceToRow(p);
|
||||
expect(row.provider_id).toBe('price_x');
|
||||
expect(row.product_id).toBe('prod_x');
|
||||
expect(row.unit_amount).toBe(999n);
|
||||
expect(row.interval).toBe('month');
|
||||
expect(row.interval_count).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStripePaymentMethodToRow', () => {
|
||||
it('maps card type with apple_pay wallet', () => {
|
||||
const pm = stripeFixture<Stripe.PaymentMethod>({
|
||||
id: 'pm_card',
|
||||
customer: 'cus_x',
|
||||
type: 'card',
|
||||
card: {
|
||||
brand: 'visa',
|
||||
last4: '4242',
|
||||
exp_month: 12,
|
||||
exp_year: 2030,
|
||||
funding: 'credit',
|
||||
country: 'US',
|
||||
fingerprint: 'fp_xx',
|
||||
wallet: {type: 'apple_pay'},
|
||||
},
|
||||
billing_details: {email: '[email protected]', name: 'Bob', address: {country: 'US', postal_code: '94110'}},
|
||||
livemode: true,
|
||||
metadata: {},
|
||||
created: NOW_UNIX,
|
||||
});
|
||||
const {primary, byCustomer} = mapStripePaymentMethodToRow(pm, {isDefault: true});
|
||||
expect(primary.type).toBe('card');
|
||||
expect(primary.card_brand).toBe('visa');
|
||||
expect(primary.card_last4).toBe('4242');
|
||||
expect(primary.card_wallet_type).toBe('apple_pay');
|
||||
expect(primary.is_default).toBe(true);
|
||||
expect(byCustomer).not.toBeNull();
|
||||
expect(byCustomer!.customer_id).toBe('cus_x');
|
||||
expect(byCustomer!.is_default).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStripeSubscriptionToRow', () => {
|
||||
function buildSub(overrides: Partial<StripeSubscriptionPayload> = {}): StripeSubscriptionPayload {
|
||||
return {
|
||||
@@ -396,87 +279,6 @@ describe('mapStripeInvoiceToRow', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStripePaymentIntentToRow', () => {
|
||||
it('maps a succeeded PI with customer', () => {
|
||||
const pi = stripeFixture<Stripe.PaymentIntent>({
|
||||
id: 'pi_x',
|
||||
customer: 'cus_1',
|
||||
invoice: null,
|
||||
status: 'succeeded',
|
||||
amount: 2000,
|
||||
amount_received: 2000,
|
||||
amount_capturable: 0,
|
||||
currency: 'usd',
|
||||
capture_method: 'automatic',
|
||||
confirmation_method: 'automatic',
|
||||
payment_method: 'pm_1',
|
||||
payment_method_types: ['card'],
|
||||
setup_future_usage: null,
|
||||
canceled_at: null,
|
||||
cancellation_reason: null,
|
||||
latest_charge: 'ch_1',
|
||||
last_payment_error: null,
|
||||
livemode: true,
|
||||
metadata: {},
|
||||
created: NOW_UNIX,
|
||||
});
|
||||
const {primary, byCustomer} = mapStripePaymentIntentToRow(pi);
|
||||
expect(primary.provider_id).toBe('pi_x');
|
||||
expect(primary.customer_id).toBe('cus_1');
|
||||
expect(primary.last_charge_id).toBe('ch_1');
|
||||
expect(byCustomer).not.toBeNull();
|
||||
expect(byCustomer!.customer_id).toBe('cus_1');
|
||||
});
|
||||
it('byCustomer is null when customer is null', () => {
|
||||
const pi = stripeFixture<Stripe.PaymentIntent>({
|
||||
id: 'pi_no_cust',
|
||||
customer: null,
|
||||
invoice: null,
|
||||
status: 'requires_payment_method',
|
||||
amount: 100,
|
||||
currency: 'usd',
|
||||
payment_method_types: ['card'],
|
||||
created: NOW_UNIX,
|
||||
metadata: {},
|
||||
});
|
||||
const {byCustomer} = mapStripePaymentIntentToRow(pi);
|
||||
expect(byCustomer).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStripeChargeToRow', () => {
|
||||
it('maps a card charge with brand/last4', () => {
|
||||
const c = stripeFixture<Stripe.Charge>({
|
||||
id: 'ch_1',
|
||||
customer: 'cus_1',
|
||||
payment_intent: 'pi_1',
|
||||
invoice: 'in_1',
|
||||
status: 'succeeded',
|
||||
amount: 1500,
|
||||
amount_captured: 1500,
|
||||
amount_refunded: 0,
|
||||
currency: 'usd',
|
||||
captured: true,
|
||||
paid: true,
|
||||
refunded: false,
|
||||
disputed: false,
|
||||
payment_method: 'pm_1',
|
||||
payment_method_details: {type: 'card', card: {brand: 'mastercard', last4: '5555', country: 'US'}},
|
||||
billing_details: {address: {country: 'US'}},
|
||||
receipt_url: 'https://r',
|
||||
outcome: {type: 'authorized', risk_level: 'normal', seller_message: 'Approved'},
|
||||
livemode: true,
|
||||
metadata: {},
|
||||
created: NOW_UNIX,
|
||||
});
|
||||
const {primary, byCustomer} = mapStripeChargeToRow(c);
|
||||
expect(primary.card_brand).toBe('mastercard');
|
||||
expect(primary.card_last4).toBe('5555');
|
||||
expect(primary.card_country).toBe('US');
|
||||
expect(byCustomer).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStripeRefundToRow', () => {
|
||||
it('payment_intent is a string', () => {
|
||||
const r = stripeFixture<Stripe.Refund>({
|
||||
@@ -523,79 +325,3 @@ describe('mapStripeRefundToRow', () => {
|
||||
expect(result.byCharge).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStripeCheckoutSessionToRow', () => {
|
||||
it('subscription-mode with subscription as string', () => {
|
||||
const cs = stripeFixture<Stripe.Checkout.Session>({
|
||||
id: 'cs_sub',
|
||||
customer: 'cus_1',
|
||||
mode: 'subscription',
|
||||
status: 'complete',
|
||||
payment_status: 'paid',
|
||||
subscription: 'sub_1',
|
||||
payment_intent: null,
|
||||
setup_intent: null,
|
||||
invoice: 'in_1',
|
||||
amount_subtotal: 999,
|
||||
amount_total: 999,
|
||||
currency: 'usd',
|
||||
expires_at: NOW_UNIX + 3600,
|
||||
livemode: true,
|
||||
metadata: {},
|
||||
created: NOW_UNIX,
|
||||
});
|
||||
const {primary, byCustomer} = mapStripeCheckoutSessionToRow(cs);
|
||||
expect(primary.subscription_id).toBe('sub_1');
|
||||
expect(primary.invoice_id).toBe('in_1');
|
||||
expect(primary.payment_intent_id).toBeNull();
|
||||
expect(byCustomer).not.toBeNull();
|
||||
});
|
||||
it('payment-mode with payment_intent as object', () => {
|
||||
const cs = stripeFixture<Stripe.Checkout.Session>({
|
||||
id: 'cs_pay',
|
||||
customer: null,
|
||||
mode: 'payment',
|
||||
status: 'complete',
|
||||
payment_status: 'paid',
|
||||
subscription: null,
|
||||
payment_intent: {id: 'pi_pay'},
|
||||
setup_intent: null,
|
||||
invoice: null,
|
||||
amount_total: 5000,
|
||||
currency: 'usd',
|
||||
created: NOW_UNIX,
|
||||
metadata: {},
|
||||
livemode: true,
|
||||
});
|
||||
const {primary, byCustomer} = mapStripeCheckoutSessionToRow(cs);
|
||||
expect(primary.payment_intent_id).toBe('pi_pay');
|
||||
expect(byCustomer).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('mapStripeDisputeToRow', () => {
|
||||
it('needs_response status', () => {
|
||||
const d = stripeFixture<Stripe.Dispute>({
|
||||
id: 'dp_1',
|
||||
charge: 'ch_1',
|
||||
payment_intent: 'pi_1',
|
||||
status: 'needs_response',
|
||||
reason: 'fraudulent',
|
||||
amount: 1000,
|
||||
currency: 'usd',
|
||||
is_charge_refundable: true,
|
||||
evidence_details: {due_by: NOW_UNIX + 7 * 86400, submission_count: 0},
|
||||
livemode: true,
|
||||
metadata: {},
|
||||
created: NOW_UNIX,
|
||||
});
|
||||
const {primary, byCharge} = mapStripeDisputeToRow(d, {customerId: 'cus_1', userId: 99n});
|
||||
expect(primary.status).toBe('needs_response');
|
||||
expect(primary.charge_id).toBe('ch_1');
|
||||
expect(primary.customer_id).toBe('cus_1');
|
||||
expect(primary.user_id).toBe(99n);
|
||||
expect(primary.evidence_due_by?.getTime()).toBe((NOW_UNIX + 7 * 86400) * 1000);
|
||||
expect(byCharge).not.toBeNull();
|
||||
expect(byCharge!.charge_id).toBe('ch_1');
|
||||
});
|
||||
});
|
||||
@@ -1,52 +0,0 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {fetchOne, upsertOne} from '@app/api/database/CassandraQueryExecution';
|
||||
import type {BillingActionIntentRow, BillingActionType} from '@app/api/database/types/BillingTypes';
|
||||
import type {ISnowflakeService} from '@app/api/infrastructure/ISnowflakeService';
|
||||
import {BillingActionIntents} from '@app/api/Tables';
|
||||
|
||||
const FETCH_BY_ID = BillingActionIntents.selectCql({
|
||||
where: BillingActionIntents.where.eq('intent_id'),
|
||||
limit: 1,
|
||||
});
|
||||
|
||||
export class BillingActionIntentRepository {
|
||||
constructor(private snowflakeService: ISnowflakeService) {}
|
||||
|
||||
async create(params: {
|
||||
userId: bigint;
|
||||
actorAdminId: bigint;
|
||||
actionType: BillingActionType;
|
||||
subscriptionId?: string | null;
|
||||
invoiceId?: string | null;
|
||||
paymentIntentId?: string | null;
|
||||
refundAmount?: bigint | null;
|
||||
refundReason?: string | null;
|
||||
}): Promise<bigint> {
|
||||
const intentId = await this.snowflakeService.generate();
|
||||
const row: BillingActionIntentRow = {
|
||||
intent_id: intentId,
|
||||
user_id: params.userId,
|
||||
actor_admin_id: params.actorAdminId,
|
||||
action_type: params.actionType,
|
||||
subscription_id: params.subscriptionId ?? null,
|
||||
invoice_id: params.invoiceId ?? null,
|
||||
payment_intent_id: params.paymentIntentId ?? null,
|
||||
refund_amount: params.refundAmount ?? null,
|
||||
refund_reason: params.refundReason ?? null,
|
||||
status: 'pending',
|
||||
error_message: null,
|
||||
started_at: new Date(),
|
||||
sub_canceled_at: null,
|
||||
refund_created_at: null,
|
||||
completed_at: null,
|
||||
refund_id: null,
|
||||
};
|
||||
await upsertOne(BillingActionIntents.upsertAll(row));
|
||||
return intentId;
|
||||
}
|
||||
|
||||
async findById(intentId: bigint): Promise<BillingActionIntentRow | null> {
|
||||
return fetchOne<BillingActionIntentRow>(FETCH_BY_ID, {intent_id: intentId});
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,7 @@
|
||||
|
||||
import {mapStripeChargeToRow} from '@app/api/billing/mappers/StripeToBillingMapper';
|
||||
import {isExistingNewer} from '@app/api/billing/repositories/BillingRepoHelpers';
|
||||
import {
|
||||
fetchMany,
|
||||
fetchOne,
|
||||
fetchPage,
|
||||
type PagedQueryResult,
|
||||
upsertOne,
|
||||
} from '@app/api/database/CassandraQueryExecution';
|
||||
import {fetchOne, upsertOne} from '@app/api/database/CassandraQueryExecution';
|
||||
import type {BillingChargeRow} from '@app/api/database/types/BillingTypes';
|
||||
import {BillingCharges, BillingChargesByCustomer} from '@app/api/Tables';
|
||||
import type Stripe from 'stripe';
|
||||
@@ -17,40 +11,12 @@ const FETCH_BY_ID = BillingCharges.selectCql({
|
||||
where: BillingCharges.where.eq('provider_id'),
|
||||
limit: 1,
|
||||
});
|
||||
const FETCH_BY_CUSTOMER = BillingChargesByCustomer.selectCql({
|
||||
where: BillingChargesByCustomer.where.eq('customer_id'),
|
||||
});
|
||||
const FETCH_BY_PROVIDER_IDS = BillingCharges.selectCql({
|
||||
where: BillingCharges.where.in('provider_id', 'provider_ids'),
|
||||
});
|
||||
|
||||
export class BillingChargeRepository {
|
||||
async findById(providerId: string): Promise<BillingChargeRow | null> {
|
||||
return fetchOne<BillingChargeRow>(FETCH_BY_ID, {provider_id: providerId});
|
||||
}
|
||||
|
||||
async listByCustomer(
|
||||
customerId: string,
|
||||
page?: {
|
||||
pageSize: number;
|
||||
pageState?: string | null;
|
||||
},
|
||||
): Promise<PagedQueryResult<BillingChargeRow>> {
|
||||
const refsPage = await fetchPage<{
|
||||
provider_id: string;
|
||||
}>(
|
||||
FETCH_BY_CUSTOMER,
|
||||
{customer_id: customerId},
|
||||
{pageSize: page?.pageSize ?? 50, pageState: page?.pageState ?? null},
|
||||
);
|
||||
if (refsPage.rows.length === 0) {
|
||||
return {rows: [], pageState: refsPage.pageState};
|
||||
}
|
||||
const ids = refsPage.rows.map((r) => r.provider_id);
|
||||
const rows = await fetchMany<BillingChargeRow>(FETCH_BY_PROVIDER_IDS, {provider_ids: ids});
|
||||
return {rows, pageState: refsPage.pageState};
|
||||
}
|
||||
|
||||
async upsertFromStripe(c: Stripe.Charge): Promise<{
|
||||
changed: boolean;
|
||||
row: BillingChargeRow;
|
||||
|
||||
@@ -2,13 +2,7 @@
|
||||
|
||||
import {mapStripeCheckoutSessionToRow} from '@app/api/billing/mappers/StripeToBillingMapper';
|
||||
import {isExistingNewer} from '@app/api/billing/repositories/BillingRepoHelpers';
|
||||
import {
|
||||
fetchMany,
|
||||
fetchOne,
|
||||
fetchPage,
|
||||
type PagedQueryResult,
|
||||
upsertOne,
|
||||
} from '@app/api/database/CassandraQueryExecution';
|
||||
import {fetchOne, upsertOne} from '@app/api/database/CassandraQueryExecution';
|
||||
import type {BillingCheckoutSessionRow} from '@app/api/database/types/BillingTypes';
|
||||
import {BillingCheckoutSessions, BillingCheckoutSessionsByCustomer} from '@app/api/Tables';
|
||||
import type Stripe from 'stripe';
|
||||
@@ -17,40 +11,12 @@ const FETCH_BY_ID = BillingCheckoutSessions.selectCql({
|
||||
where: BillingCheckoutSessions.where.eq('provider_id'),
|
||||
limit: 1,
|
||||
});
|
||||
const FETCH_BY_CUSTOMER = BillingCheckoutSessionsByCustomer.selectCql({
|
||||
where: BillingCheckoutSessionsByCustomer.where.eq('customer_id'),
|
||||
});
|
||||
const FETCH_BY_PROVIDER_IDS = BillingCheckoutSessions.selectCql({
|
||||
where: BillingCheckoutSessions.where.in('provider_id', 'provider_ids'),
|
||||
});
|
||||
|
||||
export class BillingCheckoutSessionRepository {
|
||||
async findById(providerId: string): Promise<BillingCheckoutSessionRow | null> {
|
||||
return fetchOne<BillingCheckoutSessionRow>(FETCH_BY_ID, {provider_id: providerId});
|
||||
}
|
||||
|
||||
async listByCustomer(
|
||||
customerId: string,
|
||||
page?: {
|
||||
pageSize: number;
|
||||
pageState?: string | null;
|
||||
},
|
||||
): Promise<PagedQueryResult<BillingCheckoutSessionRow>> {
|
||||
const refsPage = await fetchPage<{
|
||||
provider_id: string;
|
||||
}>(
|
||||
FETCH_BY_CUSTOMER,
|
||||
{customer_id: customerId},
|
||||
{pageSize: page?.pageSize ?? 50, pageState: page?.pageState ?? null},
|
||||
);
|
||||
if (refsPage.rows.length === 0) {
|
||||
return {rows: [], pageState: refsPage.pageState};
|
||||
}
|
||||
const ids = refsPage.rows.map((r) => r.provider_id);
|
||||
const rows = await fetchMany<BillingCheckoutSessionRow>(FETCH_BY_PROVIDER_IDS, {provider_ids: ids});
|
||||
return {rows, pageState: refsPage.pageState};
|
||||
}
|
||||
|
||||
async upsertFromStripe(
|
||||
cs: Stripe.Checkout.Session,
|
||||
hints?: {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import {mapStripeDisputeToRow} from '@app/api/billing/mappers/StripeToBillingMapper';
|
||||
import {isExistingNewer} from '@app/api/billing/repositories/BillingRepoHelpers';
|
||||
import {fetchMany, fetchOne, upsertOne} from '@app/api/database/CassandraQueryExecution';
|
||||
import {fetchOne, upsertOne} from '@app/api/database/CassandraQueryExecution';
|
||||
import type {BillingDisputeRow} from '@app/api/database/types/BillingTypes';
|
||||
import {BillingDisputes, BillingDisputesByCharge} from '@app/api/Tables';
|
||||
import type Stripe from 'stripe';
|
||||
@@ -11,27 +11,12 @@ const FETCH_BY_ID = BillingDisputes.selectCql({
|
||||
where: BillingDisputes.where.eq('provider_id'),
|
||||
limit: 1,
|
||||
});
|
||||
const FETCH_BY_CHARGE = BillingDisputesByCharge.selectCql({
|
||||
where: BillingDisputesByCharge.where.eq('charge_id'),
|
||||
});
|
||||
const FETCH_BY_PROVIDER_IDS = BillingDisputes.selectCql({
|
||||
where: BillingDisputes.where.in('provider_id', 'provider_ids'),
|
||||
});
|
||||
|
||||
export class BillingDisputeRepository {
|
||||
async findById(providerId: string): Promise<BillingDisputeRow | null> {
|
||||
return fetchOne<BillingDisputeRow>(FETCH_BY_ID, {provider_id: providerId});
|
||||
}
|
||||
|
||||
async listByCharge(chargeId: string): Promise<Array<BillingDisputeRow>> {
|
||||
const refs = await fetchMany<{
|
||||
provider_id: string;
|
||||
}>(FETCH_BY_CHARGE, {charge_id: chargeId});
|
||||
if (refs.length === 0) return [];
|
||||
const ids = refs.map((r) => r.provider_id);
|
||||
return fetchMany<BillingDisputeRow>(FETCH_BY_PROVIDER_IDS, {provider_ids: ids});
|
||||
}
|
||||
|
||||
async upsertFromStripe(
|
||||
d: Stripe.Dispute,
|
||||
hints?: {
|
||||
|
||||
@@ -17,12 +17,7 @@ import {
|
||||
} from '@app/api/database/CassandraQueryExecution';
|
||||
import type {BillingInvoiceRow} from '@app/api/database/types/BillingTypes';
|
||||
import {BILLING_INVOICE_COLUMNS} from '@app/api/database/types/BillingTypes';
|
||||
import {
|
||||
BillingCustomersByUserId,
|
||||
BillingInvoices,
|
||||
BillingInvoicesByCustomer,
|
||||
BillingInvoicesBySubscription,
|
||||
} from '@app/api/Tables';
|
||||
import {BillingInvoices, BillingInvoicesByCustomer, BillingInvoicesBySubscription} from '@app/api/Tables';
|
||||
import type Stripe from 'stripe';
|
||||
|
||||
const FETCH_BY_ID = BillingInvoices.selectCql({
|
||||
@@ -35,9 +30,6 @@ const FETCH_BY_CUSTOMER_PARTITION = BillingInvoicesByCustomer.selectCql({
|
||||
const FETCH_BY_PROVIDER_IDS = BillingInvoices.selectCql({
|
||||
where: BillingInvoices.where.in('provider_id', 'provider_ids'),
|
||||
});
|
||||
const FETCH_CUSTOMERS_BY_USER = BillingCustomersByUserId.selectCql({
|
||||
where: BillingCustomersByUserId.where.eq('user_id'),
|
||||
});
|
||||
|
||||
export class BillingInvoiceRepository {
|
||||
constructor(private paymentsRepo: BillingPaymentRepository) {}
|
||||
@@ -68,29 +60,6 @@ export class BillingInvoiceRepository {
|
||||
return {rows, pageState: refsPage.pageState};
|
||||
}
|
||||
|
||||
async listByUser(
|
||||
userId: bigint,
|
||||
page?: {
|
||||
pageSize: number;
|
||||
pageState?: string | null;
|
||||
},
|
||||
): Promise<PagedQueryResult<BillingInvoiceRow>> {
|
||||
const customerRefs = await fetchMany<{
|
||||
provider_id: string;
|
||||
}>(FETCH_CUSTOMERS_BY_USER, {user_id: userId});
|
||||
if (customerRefs.length === 0) {
|
||||
return {rows: [], pageState: null};
|
||||
}
|
||||
const aggregated: Array<BillingInvoiceRow> = [];
|
||||
let lastPageState: string | null = null;
|
||||
for (const ref of customerRefs) {
|
||||
const result = await this.listByCustomer(ref.provider_id, page);
|
||||
aggregated.push(...result.rows);
|
||||
lastPageState = result.pageState;
|
||||
}
|
||||
return {rows: aggregated, pageState: lastPageState};
|
||||
}
|
||||
|
||||
async upsertFromStripe(
|
||||
inv: Stripe.Invoice,
|
||||
hints?: {
|
||||
|
||||
@@ -2,13 +2,7 @@
|
||||
|
||||
import {mapStripePaymentIntentToRow} from '@app/api/billing/mappers/StripeToBillingMapper';
|
||||
import {isExistingNewer} from '@app/api/billing/repositories/BillingRepoHelpers';
|
||||
import {
|
||||
fetchMany,
|
||||
fetchOne,
|
||||
fetchPage,
|
||||
type PagedQueryResult,
|
||||
upsertOne,
|
||||
} from '@app/api/database/CassandraQueryExecution';
|
||||
import {fetchOne, upsertOne} from '@app/api/database/CassandraQueryExecution';
|
||||
import type {BillingPaymentIntentRow} from '@app/api/database/types/BillingTypes';
|
||||
import {BillingPaymentIntents, BillingPaymentIntentsByCustomer} from '@app/api/Tables';
|
||||
import type Stripe from 'stripe';
|
||||
@@ -17,40 +11,12 @@ const FETCH_BY_ID = BillingPaymentIntents.selectCql({
|
||||
where: BillingPaymentIntents.where.eq('provider_id'),
|
||||
limit: 1,
|
||||
});
|
||||
const FETCH_BY_CUSTOMER = BillingPaymentIntentsByCustomer.selectCql({
|
||||
where: BillingPaymentIntentsByCustomer.where.eq('customer_id'),
|
||||
});
|
||||
const FETCH_BY_PROVIDER_IDS = BillingPaymentIntents.selectCql({
|
||||
where: BillingPaymentIntents.where.in('provider_id', 'provider_ids'),
|
||||
});
|
||||
|
||||
export class BillingPaymentIntentRepository {
|
||||
async findById(providerId: string): Promise<BillingPaymentIntentRow | null> {
|
||||
return fetchOne<BillingPaymentIntentRow>(FETCH_BY_ID, {provider_id: providerId});
|
||||
}
|
||||
|
||||
async listByCustomer(
|
||||
customerId: string,
|
||||
page?: {
|
||||
pageSize: number;
|
||||
pageState?: string | null;
|
||||
},
|
||||
): Promise<PagedQueryResult<BillingPaymentIntentRow>> {
|
||||
const refsPage = await fetchPage<{
|
||||
provider_id: string;
|
||||
}>(
|
||||
FETCH_BY_CUSTOMER,
|
||||
{customer_id: customerId},
|
||||
{pageSize: page?.pageSize ?? 50, pageState: page?.pageState ?? null},
|
||||
);
|
||||
if (refsPage.rows.length === 0) {
|
||||
return {rows: [], pageState: refsPage.pageState};
|
||||
}
|
||||
const ids = refsPage.rows.map((r) => r.provider_id);
|
||||
const rows = await fetchMany<BillingPaymentIntentRow>(FETCH_BY_PROVIDER_IDS, {provider_ids: ids});
|
||||
return {rows, pageState: refsPage.pageState};
|
||||
}
|
||||
|
||||
async upsertFromStripe(pi: Stripe.PaymentIntent): Promise<{
|
||||
changed: boolean;
|
||||
row: BillingPaymentIntentRow;
|
||||
|
||||
@@ -49,24 +49,4 @@ export class BillingPaymentRepository {
|
||||
}
|
||||
return {changed: true, row: mapped.primary};
|
||||
}
|
||||
|
||||
async upsertFromStripe(
|
||||
p: BillingPaymentRow,
|
||||
hints?: {
|
||||
byInvoice?: BillingPaymentByInvoiceRow;
|
||||
},
|
||||
): Promise<{
|
||||
changed: boolean;
|
||||
row: BillingPaymentRow;
|
||||
}> {
|
||||
const existing = await this.findById(p.provider_id);
|
||||
if (isExistingNewer(existing, p)) {
|
||||
return {changed: false, row: existing!};
|
||||
}
|
||||
await upsertOne(BillingPayments.upsertAll(p));
|
||||
if (hints?.byInvoice?.invoice_id) {
|
||||
await upsertOne(BillingPaymentsByInvoice.upsertAll(hints.byInvoice));
|
||||
}
|
||||
return {changed: true, row: p};
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
isExistingNewer,
|
||||
rowsEquivalent,
|
||||
} from '@app/api/billing/repositories/BillingRepoHelpers';
|
||||
import {fetchOne, fetchPage, type PagedQueryResult} from '@app/api/database/CassandraQueryExecution';
|
||||
import {fetchOne} from '@app/api/database/CassandraQueryExecution';
|
||||
import type {BillingPriceRow} from '@app/api/database/types/BillingTypes';
|
||||
import {BILLING_PRICE_COLUMNS} from '@app/api/database/types/BillingTypes';
|
||||
import {BillingPrices} from '@app/api/Tables';
|
||||
@@ -17,28 +17,12 @@ const FETCH_BY_ID = BillingPrices.selectCql({
|
||||
where: BillingPrices.where.eq('provider_id'),
|
||||
limit: 1,
|
||||
});
|
||||
const FETCH_ALL = BillingPrices.selectCql();
|
||||
|
||||
export class BillingPriceRepository {
|
||||
async findById(providerId: string): Promise<BillingPriceRow | null> {
|
||||
return fetchOne<BillingPriceRow>(FETCH_BY_ID, {provider_id: providerId});
|
||||
}
|
||||
|
||||
async listAllActive(page?: {
|
||||
pageSize: number;
|
||||
pageState?: string | null;
|
||||
}): Promise<PagedQueryResult<BillingPriceRow>> {
|
||||
const result = await fetchPage<BillingPriceRow>(
|
||||
FETCH_ALL,
|
||||
{},
|
||||
{pageSize: page?.pageSize ?? 100, pageState: page?.pageState ?? null},
|
||||
);
|
||||
return {
|
||||
rows: result.rows.filter((r) => r.active === true),
|
||||
pageState: result.pageState,
|
||||
};
|
||||
}
|
||||
|
||||
async upsertFromStripe(p: Stripe.Price): Promise<{
|
||||
changed: boolean;
|
||||
row: BillingPriceRow;
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
isExistingNewer,
|
||||
rowsEquivalent,
|
||||
} from '@app/api/billing/repositories/BillingRepoHelpers';
|
||||
import {fetchOne, fetchPage, type PagedQueryResult} from '@app/api/database/CassandraQueryExecution';
|
||||
import {fetchOne} from '@app/api/database/CassandraQueryExecution';
|
||||
import type {BillingProductRow} from '@app/api/database/types/BillingTypes';
|
||||
import {BILLING_PRODUCT_COLUMNS} from '@app/api/database/types/BillingTypes';
|
||||
import {BillingProducts} from '@app/api/Tables';
|
||||
@@ -17,28 +17,12 @@ const FETCH_BY_ID = BillingProducts.selectCql({
|
||||
where: BillingProducts.where.eq('provider_id'),
|
||||
limit: 1,
|
||||
});
|
||||
const FETCH_ALL = BillingProducts.selectCql();
|
||||
|
||||
export class BillingProductRepository {
|
||||
async findById(providerId: string): Promise<BillingProductRow | null> {
|
||||
return fetchOne<BillingProductRow>(FETCH_BY_ID, {provider_id: providerId});
|
||||
}
|
||||
|
||||
async listAllActive(page?: {
|
||||
pageSize: number;
|
||||
pageState?: string | null;
|
||||
}): Promise<PagedQueryResult<BillingProductRow>> {
|
||||
const result = await fetchPage<BillingProductRow>(
|
||||
FETCH_ALL,
|
||||
{},
|
||||
{pageSize: page?.pageSize ?? 100, pageState: page?.pageState ?? null},
|
||||
);
|
||||
return {
|
||||
rows: result.rows.filter((r) => r.active === true),
|
||||
pageState: result.pageState,
|
||||
};
|
||||
}
|
||||
|
||||
async upsertFromStripe(p: Stripe.Product): Promise<{
|
||||
changed: boolean;
|
||||
row: BillingProductRow;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {BillingActionIntentRepository} from '@app/api/billing/repositories/BillingActionIntentRepository';
|
||||
import {BillingChargeRepository} from '@app/api/billing/repositories/BillingChargeRepository';
|
||||
import {BillingCheckoutSessionRepository} from '@app/api/billing/repositories/BillingCheckoutSessionRepository';
|
||||
import {BillingCustomerRepository} from '@app/api/billing/repositories/BillingCustomerRepository';
|
||||
@@ -14,7 +13,6 @@ import {BillingProductRepository} from '@app/api/billing/repositories/BillingPro
|
||||
import {BillingRefundRepository} from '@app/api/billing/repositories/BillingRefundRepository';
|
||||
import {BillingSubscriptionRepository} from '@app/api/billing/repositories/BillingSubscriptionRepository';
|
||||
import {BillingWebhookEventRepository} from '@app/api/billing/repositories/BillingWebhookEventRepository';
|
||||
import type {ISnowflakeService} from '@app/api/infrastructure/ISnowflakeService';
|
||||
import type {IKVProvider} from '@pkgs/kv_client/src/IKVProvider';
|
||||
|
||||
export class BillingRepository {
|
||||
@@ -31,9 +29,8 @@ export class BillingRepository {
|
||||
readonly checkoutSessions: BillingCheckoutSessionRepository;
|
||||
readonly disputes: BillingDisputeRepository;
|
||||
readonly webhookEvents: BillingWebhookEventRepository;
|
||||
readonly actionIntents: BillingActionIntentRepository;
|
||||
|
||||
constructor(snowflakeService: ISnowflakeService, kv: IKVProvider) {
|
||||
constructor(kv: IKVProvider) {
|
||||
this.payments = new BillingPaymentRepository();
|
||||
this.invoices = new BillingInvoiceRepository(this.payments);
|
||||
this.customers = new BillingCustomerRepository();
|
||||
@@ -47,6 +44,5 @@ export class BillingRepository {
|
||||
this.checkoutSessions = new BillingCheckoutSessionRepository();
|
||||
this.disputes = new BillingDisputeRepository();
|
||||
this.webhookEvents = new BillingWebhookEventRepository(kv);
|
||||
this.actionIntents = new BillingActionIntentRepository(snowflakeService);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user