use crate::{
currency::Currency, error::Error, order::Order, payment_method::PaymentMethod, Gateway,
BASE_URL,
};
use rust_decimal::prelude::*;
use serde::Serialize;
impl Gateway {
pub async fn create_order<'a>(
&self,
order_id: &'a str,
accept_url: Option<&'a str>,
cancel_url: Option<&'a str>,
amount: &'a Decimal,
vat: &'a Decimal,
currency: &'a Currency,
callbacks: Option<Vec<&'a str>>,
language: &'a str,
paymentmethods: Vec<&'a PaymentMethod>,
) -> Result<Order, Error> {
#[derive(Serialize)]
struct Request<'a> {
order: OrderRequest<'a>,
#[serde(skip_serializing_if = "Option::is_none")]
url: Option<Url<'a>>,
paymentwindow: PaymentWindow<'a>,
}
#[derive(Serialize)]
struct OrderRequest<'a> {
amount: u64,
id: &'a str,
vatamount: u64,
currency: &'a str,
}
#[derive(Serialize)]
struct Callback<'a> {
url: &'a str,
}
#[derive(Serialize)]
struct Url<'a> {
accept: Option<&'a str>,
cancel: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
callbacks: Option<Vec<Callback<'a>>>,
}
#[derive(Serialize)]
struct PaymentMethodObject<'a> {
id: &'a PaymentMethod,
action: &'a str,
}
#[derive(Serialize)]
struct PaymentWindow<'a> {
language: &'a str,
paymentmethods: Vec<PaymentMethodObject<'a>>,
}
let (currency, decimals) = match currency {
Currency::NOK => ("NOK", 2),
Currency::SEK => ("SEK", 2),
Currency::DKK => ("DKK", 2),
Currency::ISK => ("ISK", 0),
Currency::GBP => ("GBP", 2),
Currency::EUR => ("EUR", 2),
};
let cents_modifier = Decimal::from(10i32.pow(decimals));
let amount = amount * cents_modifier;
let vat = vat * cents_modifier;
let url = if accept_url != None || cancel_url != None || callbacks != None {
Some(Url {
accept: accept_url,
cancel: cancel_url,
callbacks: match callbacks {
Some(c) => Some(
c.iter()
.map(|c| Callback { url: *c })
.collect::<Vec<Callback>>(),
),
None => None,
},
})
} else {
None
};
let body = Request {
order: OrderRequest {
amount: match amount.to_u64() {
Some(a) => a,
None => {
return Err(Error::Unspecified(format!(
"could not convert amount \"{}\" to u64",
amount
)))
}
},
id: order_id,
vatamount: match vat.to_u64() {
Some(a) => a,
None => {
return Err(Error::Unspecified(format!(
"could not convert vat \"{}\" to u64",
amount
)))
}
},
currency,
},
url,
paymentwindow: PaymentWindow {
language,
paymentmethods: paymentmethods
.into_iter()
.map(|p| PaymentMethodObject {
id: p,
action: "include",
})
.collect::<Vec<PaymentMethodObject>>(),
},
};
let url = format!("{}/sessions", BASE_URL);
let res: Order = self.send(&url, &body).await?;
Ok(res)
}
}