Selaa lähdekoodia

Create Purchase after retrieving payment intent

Lee Morgan 1 kuukausi sitten
vanhempi
sitoutus
4b2a51267d
3 muutettua tiedostoa jossa 39 lisäystä ja 11 poistoa
  1. 33 8
      src/controllers/user/payment_intent.rs
  2. 3 1
      src/main.rs
  3. 3 2
      src/models/purchase.rs

+ 33 - 8
src/controllers/user/payment_intent.rs

@@ -7,12 +7,13 @@ use uuid::Uuid;
 use crate::{
     http_error::HttpError,
     auth::user_auth,
-    STRIPE_KEY, TOKEN_PACK_PRICE
+    models::purchase::{Purchase},
+    STRIPE_KEY, TOKEN_PACK_PRICE, TOKENS_PER_PACK
 };
 
 #[derive(Deserialize)]
 struct Body {
-    token_packs: u32
+    token_packs: i32
 }
 
 #[post("/user/payment-intent")]
@@ -25,11 +26,13 @@ pub async fn route(
         return Err(HttpError::InvalidInput("Must buy minimum 5 token packs".into()));
     }
     let user = user_auth(&db, &req).await?;
-    let client_secret = request_payment_intent(body.token_packs, user.id).await?;
+    let (pi_id, client_secret) = request_payment_intent(body.token_packs, user.id).await?;
+    let purchase = create_purchase(user.id, pi_id, body.token_packs)?;
+    purchase.insert_one(&db).await?;
     Ok(HttpResponse::Ok().json(json!({"client_secret": client_secret})))
 }
 
-async fn request_payment_intent(token_packs: u32, user_id: Uuid) -> Result<String, HttpError> {
+async fn request_payment_intent(token_packs: i32, user_id: Uuid) -> Result<(String, String), HttpError> {
     let client = Client::new();
     let amount = (token_packs * TOKEN_PACK_PRICE.get().unwrap()).to_string();
 
@@ -48,8 +51,30 @@ async fn request_payment_intent(token_packs: u32, user_id: Uuid) -> Result<Strin
 
     let body = res.json::<Value>().await
         .map_err(|_| HttpError::InternalError("Failed to convert stripe response to json".into()))?;
-    Ok(body["client_secret"]
-        .as_str()
-        .ok_or(HttpError::InternalError("Bad client secret".into()))?
-        .to_string())
+
+    Ok((
+        body["id"]
+            .as_str()
+            .ok_or(HttpError::InternalError("Bad Payment Intent ID".into()))?
+            .to_string(),
+        body["client_secret"]
+            .as_str()
+            .ok_or(HttpError::InternalError("Bad client secret".into()))?
+            .to_string()
+    ))
+}
+
+fn create_purchase(user_id: Uuid, pi_id: String, pack_count: i32) -> Result<Purchase, HttpError> {
+    Purchase::new(
+        user_id,
+        pi_id,
+        "Pending".to_string(),
+        pack_count,
+        *TOKEN_PACK_PRICE
+            .get()
+            .unwrap(),
+        *TOKENS_PER_PACK
+            .get()
+            .unwrap()
+    )
 }

+ 3 - 1
src/main.rs

@@ -13,7 +13,8 @@ mod auth;
 
 static JWT_SECRET: OnceLock<String> = OnceLock::new();
 static STRIPE_KEY: OnceLock<String> = OnceLock::new();
-static TOKEN_PACK_PRICE: OnceLock<u32> = OnceLock::new();
+static TOKEN_PACK_PRICE: OnceLock<i32> = OnceLock::new();
+static TOKENS_PER_PACK: OnceLock<i32> = OnceLock::new();
 
 #[actix_web::main]
 async fn main() -> std::io::Result<()> {
@@ -26,6 +27,7 @@ async fn main() -> std::io::Result<()> {
     JWT_SECRET.set(env_var("JWT_SECRET")).expect("Failed to set JWT");
     STRIPE_KEY.set(env_var("STRIPE_KEY")).expect("Failed to set Stripe key");
     TOKEN_PACK_PRICE.set(env_var("TOKEN_PACK_PRICE")).expect("Failed to set token pack price");
+    TOKENS_PER_PACK.set(env_var("TOKENS_PER_PACK")).expect("Failed to set tokens per pack");
 
     //Database
     let pool = PgPool::connect(&database_url)

+ 3 - 2
src/models/purchase.rs

@@ -17,7 +17,7 @@ pub struct Purchase {
     pub created_at: DateTime<Utc>
 }
 
-enum Status {
+pub enum Status {
     Pending,
     Succeeded,
     Failed,
@@ -82,10 +82,11 @@ impl Purchase {
                 tokens_per_pack,
                 created_at
             )
-            VALUES($1, $2, $3, $4, $5, $6, $7)"
+            VALUES($1, $2, $3, $4, $5, $6, $7, $8)"
         )
             .bind(&self.id)
             .bind(&self.user_id)
+            .bind(&self.stripe_id)
             .bind(&self.status.to_string())
             .bind(&self.pack_count)
             .bind(&self.cost_per_pack)