@@ -27,6 +27,7 @@ use crate::{
2727 } ,
2828} ;
2929use actix_web:: { web, HttpRequest , HttpResponse } ;
30+ use dateparser:: DateTimeUtc ;
3031use serde:: { Deserialize , Serialize } ;
3132use stripe:: { EventObject , EventType , Object , Webhook } ;
3233use utoipa:: ToSchema ;
@@ -205,6 +206,7 @@ pub async fn webhook(
205206 subscription_stripe_id,
206207 plan_id,
207208 organization_id,
209+ None ,
208210 pool. clone ( ) ,
209211 )
210212 . await ?;
@@ -480,6 +482,7 @@ pub async fn update_subscription_plan(
480482 current_trieve_subscription. stripe_subscription_id ( ) ,
481483 flat_plan. id ,
482484 current_trieve_subscription. organization_id ( ) ,
485+ current_trieve_subscription. current_period_end ( ) ,
483486 pool. clone ( ) ,
484487 )
485488 . await ?;
@@ -722,20 +725,15 @@ pub async fn estimate_bill_from_range(
722725#[ derive( Debug , Serialize , Deserialize , ToSchema ) ]
723726pub struct ShopifyPlanChangePayload {
724727 pub organization_id : uuid:: Uuid ,
725- pub session_token : String ,
728+ pub idempotency_key : String ,
726729 pub shopify_plan : ShopifyPlan ,
727730}
728731
729732#[ derive( Debug , Serialize , Deserialize , ToSchema ) ]
730733pub struct ShopifyPlan {
731- pub name : String ,
732734 pub handle : String ,
733735 pub status : String ,
734- }
735-
736- #[ derive( Debug , Serialize , Deserialize , ToSchema ) ]
737- pub struct ShopifyClaims {
738- pub dest : String ,
736+ pub current_period_end : Option < String > ,
739737}
740738
741739#[ utoipa:: path(
@@ -749,10 +747,22 @@ pub struct ShopifyClaims {
749747 ) ,
750748) ]
751749pub async fn handle_shopify_plan_change (
750+ req : HttpRequest ,
752751 payload : web:: Json < ShopifyPlanChangePayload > ,
753752 pool : web:: Data < Pool > ,
754753) -> Result < HttpResponse , actix_web:: Error > {
755- if payload. session_token != get_env ! ( "SHOPIFY_SECRET_KEY" , "SHOPIFY_SECRET_KEY must be set" ) {
754+ let access_key = req
755+ . headers ( )
756+ . get ( "X-Shopify-Authorization" )
757+ . ok_or ( ServiceError :: BadRequest (
758+ "X-Shopify-Authorization header is required" . to_string ( ) ,
759+ ) ) ?
760+ . to_str ( )
761+ . map_err ( |_| {
762+ ServiceError :: BadRequest ( "Failed to parse X-Shopify-Authorization header" . to_string ( ) )
763+ } ) ?;
764+
765+ if access_key != get_env ! ( "SHOPIFY_SECRET_KEY" , "SHOPIFY_SECRET_KEY must be set" ) {
756766 return Err ( ServiceError :: BadRequest ( "Invalid session token" . to_string ( ) ) . into ( ) ) ;
757767 }
758768
@@ -766,6 +776,11 @@ pub async fn handle_shopify_plan_change(
766776 . map_err ( |e| ServiceError :: BadRequest ( e. to_string ( ) ) ) ?;
767777
768778 if let Some ( organization_plan) = organization_plan {
779+ if organization_plan. stripe_id == payload. idempotency_key {
780+ // No changes
781+ return Ok ( HttpResponse :: NoContent ( ) . finish ( ) ) ;
782+ }
783+
769784 if organization_plan. plan_id == plan. id
770785 && payload. shopify_plan . status . to_lowercase ( ) == "active"
771786 {
@@ -786,19 +801,33 @@ pub async fn handle_shopify_plan_change(
786801 {
787802 // Create a new plan
788803 create_stripe_subscription_query (
789- plan . stripe_id ,
804+ payload . idempotency_key . clone ( ) ,
790805 plan. id ,
791806 payload. organization_id ,
807+ payload. shopify_plan . current_period_end . clone ( ) . map ( |s| {
808+ s. parse :: < DateTimeUtc > ( )
809+ . unwrap ( )
810+ . 0
811+ . with_timezone ( & chrono:: Utc )
812+ . naive_utc ( )
813+ } ) ,
792814 pool. clone ( ) ,
793815 )
794816 . await ?;
795817 }
796818 } else if payload. shopify_plan . status . to_lowercase ( ) == "active" {
797819 // Create a new plan
798820 create_stripe_subscription_query (
799- plan . stripe_id ,
821+ payload . idempotency_key . clone ( ) ,
800822 plan. id ,
801823 payload. organization_id ,
824+ payload. shopify_plan . current_period_end . clone ( ) . map ( |s| {
825+ s. parse :: < DateTimeUtc > ( )
826+ . unwrap ( )
827+ . 0
828+ . with_timezone ( & chrono:: Utc )
829+ . naive_utc ( )
830+ } ) ,
802831 pool. clone ( ) ,
803832 )
804833 . await ?;
0 commit comments