@@ -678,6 +678,38 @@ pub struct SubscriptionEditQuery {
678678 pub dry : Option < bool > ,
679679}
680680
681+ /// Returned by a dry run of resubscribing to a subscription (`cancelled: false`).
682+ #[ derive( Serialize ) ]
683+ struct ResubscribePreview {
684+ pub subtotal : i64 ,
685+ pub tax : i64 ,
686+ pub total : i64 ,
687+ pub currency_code : String ,
688+ pub interval : Option < PriceDuration > ,
689+ pub due : chrono:: DateTime < Utc > ,
690+ pub payment_method : stripe:: PaymentMethod ,
691+ }
692+
693+ /// Recalculates the tax amount of a charge being resubscribed to, as the tax amount
694+ /// isn't kept up to date while the charge is cancelled or failed.
695+ async fn refresh_charge_tax (
696+ pool : & PgPool ,
697+ redis : & RedisPool ,
698+ stripe_client : & stripe:: Client ,
699+ anrok_client : & anrok:: Client ,
700+ charge : & mut charge_item:: DBCharge ,
701+ ) -> Result < ChargeTaxQuote , ApiError > {
702+ let quote =
703+ quote_charge_tax ( pool, redis, stripe_client, anrok_client, charge)
704+ . await
705+ . wrap_api_err ( "calculating tax amount for resubscription" ) ?;
706+
707+ charge. tax_amount = quote. tax_amount ;
708+ charge. tax_last_updated = Some ( Utc :: now ( ) ) ;
709+
710+ Ok ( quote)
711+ }
712+
681713/// Update a subscription.
682714#[ utoipa:: path(
683715 context_path = "/billing" ,
@@ -871,6 +903,8 @@ pub async fn edit_subscription(
871903 "could not find current product price" . to_string ( )
872904 } ) ?;
873905
906+ let mut resubscribe_quote = None ;
907+
874908 let maybe_intent_metadata = match edit_subscription. into_inner ( ) {
875909 // Case of toggling cancellation when the next charge is a failed charge
876910 SubscriptionEdit {
@@ -880,6 +914,16 @@ pub async fn edit_subscription(
880914 if cancelled {
881915 open_charge. status = ChargeStatus :: Cancelled ;
882916 } else {
917+ resubscribe_quote = Some (
918+ refresh_charge_tax (
919+ & pool,
920+ & redis,
921+ & stripe_client,
922+ & anrok_client,
923+ & mut open_charge,
924+ )
925+ . await ?,
926+ ) ;
883927 // Forces another resubscription attempt
884928 open_charge. last_attempt = Some ( Utc :: now ( ) - Duration :: days ( 2 ) ) ;
885929 }
@@ -899,6 +943,16 @@ pub async fn edit_subscription(
899943 open_charge. status = if cancelled {
900944 ChargeStatus :: Cancelled
901945 } else {
946+ resubscribe_quote = Some (
947+ refresh_charge_tax (
948+ & pool,
949+ & redis,
950+ & stripe_client,
951+ & anrok_client,
952+ & mut open_charge,
953+ )
954+ . await ?,
955+ ) ;
902956 ChargeStatus :: Open
903957 } ;
904958
@@ -1134,6 +1188,18 @@ pub async fn edit_subscription(
11341188 }
11351189 } ;
11361190
1191+ if dry && let Some ( quote) = resubscribe_quote {
1192+ return Ok ( HttpResponse :: Ok ( ) . json ( ResubscribePreview {
1193+ subtotal : open_charge. amount ,
1194+ tax : quote. tax_amount ,
1195+ total : open_charge. amount + quote. tax_amount ,
1196+ currency_code : open_charge. currency_code ,
1197+ interval : open_charge. subscription_interval ,
1198+ due : open_charge. due ,
1199+ payment_method : quote. payment_method ,
1200+ } ) ) ;
1201+ }
1202+
11371203 if !dry {
11381204 // If `?dry=true`, don't actually commit the changes.
11391205 //
0 commit comments