Skip to content

Conversation

@aecsocket
Copy link
Contributor

Supercedes #4549

@aecsocket aecsocket marked this pull request as draft October 30, 2025 10:25
@aecsocket aecsocket marked this pull request as ready for review October 31, 2025 11:23
Copy link
Contributor

@fetchfern fetchfern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good direction, would just address the comments and, overall, to strengthen the approach:

  • 1<->1<->1 relationship between charges, users_subscriptions_affiliations_payouts, payouts_values (one charge/payout value per row in usap, maybe UNIQUE (payout_value_id)?)
  • Handle refunded charges:
    • Separate step which goes through refund charges which have a parent charge which have a usap row which have a payout_value that's not yet available and delete the usap row/payout_value
    • In your current query, JOIN the charge with its refund charges and handle the refund amount (don't forget refund charges have a many-to-1 relationship with their parent charge, since multiple refunds can be issued for 1 charge)

continue;
}

let affiliate_cut = net * revenue_split;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

charges.net includes tax amount, you'll probably want to take taxes off the cut (so (charges.net - charges.tax_amount) * revenue_split)

Comment on lines +74 to +81
let now = Utc::now();
let start: DateTime<Utc> = DateTime::from_naive_utc_and_offset(
(now - Duration::days(1))
.date_naive()
.and_hms_nano_opt(0, 0, 0, 0)
.unwrap_or_default(),
Utc,
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The start time (created value of the payouts_values row) should be based on the charge's last attempt time rather than the current time

payout_info.amount += affiliate_cut;
payout_info
.charge_subscription_ids
.push((row.charge_id, row.subscription_id));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would make more sense to have a single payouts_values row for each unique charge? Then it's easier to handle refunds (which aren't handled here—what happens if the charge gets processed here, is added to payouts_values but is later refunded before it is available to withdraw for the affiliate?)

INNER JOIN users_subscriptions_affiliations usa
ON c.subscription_id = usa.subscription_id
AND c.subscription_id IS NOT NULL
AND usa.deactivated_at IS NULL
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be checking if c.last_attempt < usa.deactivated_at

pub struct DBUsersSubscriptionsAffiliations {
pub subscription_id: DBUserSubscriptionId,
pub affiliate_code: DBAffiliateCodeId,
pub deactivated_at: Option<DateTime<Utc>>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be setting deactivated_at when a subscription is cancelled in the subscription cancelled route handler

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants