Add payment
This commit is contained in:
parent
58414f3fe2
commit
cbc2a30e0e
4
.env
4
.env
@ -9,4 +9,6 @@ SENDGRID_SECRET=SG.CUWRM-eoQfGJNqSU2bbwkg.NW5aBy5vZueCSOwIIyWUBqq5USChGiwAFrWzre
|
||||
SENDGRID_API_KEY=CUWRM-eoQfGJNqSU2bbwkg
|
||||
SMTP_FROM=adrian.wozniak@ita-prog.pl
|
||||
|
||||
PAY_U_BEARER=d9a4536e-62ba-4f60-8017-6053211d3f47
|
||||
PAYU_CLIENT_ID="145227"
|
||||
PAYU_CLIENT_SECRET="12f071174cb7eb79d4aac5bc2f07563f"
|
||||
PAYU_CLIENT_MERCHANT_ID=300746
|
||||
|
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -613,7 +613,7 @@ dependencies = [
|
||||
"oauth2",
|
||||
"parking_lot 0.12.0",
|
||||
"password-hash",
|
||||
"pay_u 0.1.3",
|
||||
"pay_u",
|
||||
"pretty_env_logger",
|
||||
"rand_core",
|
||||
"sendgrid",
|
||||
@ -2133,20 +2133,6 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
|
||||
|
||||
[[package]]
|
||||
name = "pay_u"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4eca87ee08eda0742042079ef48c3eb478a3f43dd535b499c88c72e532f6cfb6"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"log",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pay_u"
|
||||
version = "0.1.4"
|
||||
|
@ -65,4 +65,7 @@ jemallocator = { version = "0.3.2", features = [] }
|
||||
|
||||
sendgrid = { version = "0.17.4", features = ["async"] }
|
||||
|
||||
pay_u = { version = '0.1.3', features = ["single-client"] }
|
||||
pay_u = { path = "../pay_u", version = '0.1', features = ["single-client"] }
|
||||
|
||||
[dev-dependencies]
|
||||
pay_u = { path = "../pay_u", version = "0.1", features = ["single-client"] }
|
||||
|
@ -1,21 +1,113 @@
|
||||
use pay_u::MerchantPosId;
|
||||
use std::sync::Arc;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use pay_u::{MerchantPosId, OrderCreateRequest};
|
||||
|
||||
use crate::model;
|
||||
use crate::model::Product;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! pay_async_handler {
|
||||
($msg: ty, $async: ident, $res: ty) => {
|
||||
impl actix::Handler<$msg> for PaymentManager {
|
||||
type Result = actix::ResponseActFuture<Self, Result<$res>>;
|
||||
|
||||
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
||||
use actix::WrapFuture;
|
||||
let db = self.client.clone();
|
||||
Box::pin(async { $async(msg, db).await }.into_actor(self))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub type PayUClient = Arc<Mutex<pay_u::Client>>;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("{0}")]
|
||||
PayU(#[from] pay_u::Error),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PaymentManager {
|
||||
client: pay_u::Client,
|
||||
client: PayUClient,
|
||||
}
|
||||
|
||||
impl PaymentManager {
|
||||
pub fn new<ClientId, ClientSecret>(
|
||||
pub async fn build<ClientId, ClientSecret>(
|
||||
client_id: ClientId,
|
||||
client_secret: ClientSecret,
|
||||
merchant_pos_id: MerchantPosId,
|
||||
) -> Self
|
||||
) -> Result<Self>
|
||||
where
|
||||
ClientId: Into<String>,
|
||||
ClientSecret: Into<String>,
|
||||
{
|
||||
let mut client = pay_u::Client::new(client_id, client_secret, merchant_pos_id);
|
||||
client
|
||||
Self { client }
|
||||
client.authorize().await?;
|
||||
Ok(Self {
|
||||
client: Arc::new(Mutex::new(client)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl actix::Actor for PaymentManager {
|
||||
type Context = actix::Context<Self>;
|
||||
}
|
||||
|
||||
pub struct PaymentResult {
|
||||
pub redirect_uri: String,
|
||||
pub payu_order_id: String,
|
||||
}
|
||||
|
||||
pub struct Buyer {
|
||||
/// Required customer e-mail
|
||||
pub email: String,
|
||||
/// Required customer phone number
|
||||
pub phone: String,
|
||||
/// Required customer first name
|
||||
pub first_name: String,
|
||||
/// Required customer last name
|
||||
pub last_name: String,
|
||||
/// Required customer language
|
||||
pub language: String,
|
||||
}
|
||||
|
||||
impl From<model::Buyer> for pay_u::Buyer {
|
||||
fn from(b: Buyer) -> Self {
|
||||
pay_u::Buyer::new(b.email, b.phone, b.first_name, b.last_name, b.language)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<model::Product> for pay_u::Product {
|
||||
fn from(p: Product) -> Self {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, actix::Message)]
|
||||
#[rtype(result = "Result<PaymentResult>")]
|
||||
pub struct RequestPayment {
|
||||
pub products: Vec<model::Product>,
|
||||
pub redirect_uri: String,
|
||||
pub currency: String,
|
||||
pub description: String,
|
||||
pub buyer: Buyer,
|
||||
pub customer_ip: String,
|
||||
}
|
||||
|
||||
pub(crate) async fn request_payment(
|
||||
msg: RequestPayment,
|
||||
client: PayUClient,
|
||||
) -> Result<PaymentResult> {
|
||||
let mut client = &mut *client.lock();
|
||||
client.create_order(
|
||||
OrderCreateRequest::new(msg.buyer.into(), msg.customer_ip, msg.currency)
|
||||
.with_description(msg.description)
|
||||
.with_notify_url(msg.redirect_uri)
|
||||
.with_products(msg.products.into_iter().map(Into::into)),
|
||||
)
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use jemallocator::Jemalloc;
|
||||
use password_hash::SaltString;
|
||||
use validator::{validate_email, validate_length};
|
||||
|
||||
use crate::actors::{database, email_manager, order_manager, token_manager};
|
||||
use crate::actors::{database, email_manager, order_manager, payment_manager, token_manager};
|
||||
use crate::email_manager::TestMail;
|
||||
use crate::logic::encrypt_password;
|
||||
use crate::model::{Email, Login, PassHash, Password, Role};
|
||||
@ -183,6 +183,19 @@ async fn server(opts: ServerOpts) -> Result<()> {
|
||||
let db = database::Database::build(&opts.db_url()).await?.start();
|
||||
let token_manager = token_manager::TokenManager::new(db.clone()).start();
|
||||
let order_manager = order_manager::OrderManager::new(db.clone()).start();
|
||||
let payment_manager = {
|
||||
let client_id = std::env::var("PAYU_CLIENT_ID").expect("Missing PAYU_CLIENT_ID env");
|
||||
let client_secret =
|
||||
std::env::var("PAYU_CLIENT_SECRET").expect("Missing PAYU_CLIENT_SECRET env");
|
||||
let merchant_id = std::env::var("PAYU_CLIENT_MERCHANT_ID")
|
||||
.expect("Missing PAYU_CLIENT_MERCHANT_ID env")
|
||||
.parse()
|
||||
.expect("Variable PAYU_CLIENT_MERCHANT_ID must be number");
|
||||
payment_manager::PaymentManager::build(client_id, client_secret, merchant_id)
|
||||
.await
|
||||
.expect("Failed to start payment manager")
|
||||
.start()
|
||||
};
|
||||
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
@ -197,6 +210,7 @@ async fn server(opts: ServerOpts) -> Result<()> {
|
||||
.app_data(Data::new(db.clone()))
|
||||
.app_data(Data::new(token_manager.clone()))
|
||||
.app_data(Data::new(order_manager.clone()))
|
||||
.app_data(Data::new(payment_manager.clone()))
|
||||
.configure(routes::configure)
|
||||
// .default_service(web::to(HttpResponse::Ok))
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user