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
|
SENDGRID_API_KEY=CUWRM-eoQfGJNqSU2bbwkg
|
||||||
SMTP_FROM=adrian.wozniak@ita-prog.pl
|
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",
|
"oauth2",
|
||||||
"parking_lot 0.12.0",
|
"parking_lot 0.12.0",
|
||||||
"password-hash",
|
"password-hash",
|
||||||
"pay_u 0.1.3",
|
"pay_u",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"sendgrid",
|
"sendgrid",
|
||||||
@ -2133,20 +2133,6 @@ version = "1.0.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
|
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]]
|
[[package]]
|
||||||
name = "pay_u"
|
name = "pay_u"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
|
@ -65,4 +65,7 @@ jemallocator = { version = "0.3.2", features = [] }
|
|||||||
|
|
||||||
sendgrid = { version = "0.17.4", features = ["async"] }
|
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 {
|
pub struct PaymentManager {
|
||||||
client: pay_u::Client,
|
client: PayUClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PaymentManager {
|
impl PaymentManager {
|
||||||
pub fn new<ClientId, ClientSecret>(
|
pub async fn build<ClientId, ClientSecret>(
|
||||||
client_id: ClientId,
|
client_id: ClientId,
|
||||||
client_secret: ClientSecret,
|
client_secret: ClientSecret,
|
||||||
merchant_pos_id: MerchantPosId,
|
merchant_pos_id: MerchantPosId,
|
||||||
) -> Self
|
) -> Result<Self>
|
||||||
where
|
where
|
||||||
ClientId: Into<String>,
|
ClientId: Into<String>,
|
||||||
ClientSecret: Into<String>,
|
ClientSecret: Into<String>,
|
||||||
{
|
{
|
||||||
let mut client = pay_u::Client::new(client_id, client_secret, merchant_pos_id);
|
let mut client = pay_u::Client::new(client_id, client_secret, merchant_pos_id);
|
||||||
client
|
client.authorize().await?;
|
||||||
Self { client }
|
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 password_hash::SaltString;
|
||||||
use validator::{validate_email, validate_length};
|
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::email_manager::TestMail;
|
||||||
use crate::logic::encrypt_password;
|
use crate::logic::encrypt_password;
|
||||||
use crate::model::{Email, Login, PassHash, Password, Role};
|
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 db = database::Database::build(&opts.db_url()).await?.start();
|
||||||
let token_manager = token_manager::TokenManager::new(db.clone()).start();
|
let token_manager = token_manager::TokenManager::new(db.clone()).start();
|
||||||
let order_manager = order_manager::OrderManager::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 || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
@ -197,6 +210,7 @@ async fn server(opts: ServerOpts) -> Result<()> {
|
|||||||
.app_data(Data::new(db.clone()))
|
.app_data(Data::new(db.clone()))
|
||||||
.app_data(Data::new(token_manager.clone()))
|
.app_data(Data::new(token_manager.clone()))
|
||||||
.app_data(Data::new(order_manager.clone()))
|
.app_data(Data::new(order_manager.clone()))
|
||||||
|
.app_data(Data::new(payment_manager.clone()))
|
||||||
.configure(routes::configure)
|
.configure(routes::configure)
|
||||||
// .default_service(web::to(HttpResponse::Ok))
|
// .default_service(web::to(HttpResponse::Ok))
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user