Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
cb0e721dc0
@ -33,6 +33,31 @@ macro_rules! db_async_handler {
|
||||
}
|
||||
}
|
||||
};
|
||||
($msg: ty, $async: ident, $res: ty, $inner_async: ident) => {
|
||||
async fn $inner_async(msg: $msg, pool: sqlx::PgPool) -> Result<$res> {
|
||||
let mut t = pool.begin().await?;
|
||||
match $async(msg, &mut t).await {
|
||||
Ok(res) => {
|
||||
t.commit().await?;
|
||||
Ok(res)
|
||||
}
|
||||
Err(e) => {
|
||||
let _ = t.rollback().await;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl actix::Handler<$msg> for Database {
|
||||
type Result = actix::ResponseActFuture<Self, Result<$res>>;
|
||||
|
||||
fn handle(&mut self, msg: $msg, _ctx: &mut Self::Context) -> Self::Result {
|
||||
use actix::WrapFuture;
|
||||
let pool = self.pool.clone();
|
||||
Box::pin(async { $inner_async(msg, pool).await }.into_actor(self))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
@ -31,7 +31,7 @@ pub(crate) async fn all_account_orders(
|
||||
) -> Result<Vec<AccountOrder>> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, buyer_id, status, order_ext_id
|
||||
SELECT id, buyer_id, status, order_ext_id, service_order_id
|
||||
FROM account_orders
|
||||
ORDER BY id DESC
|
||||
"#,
|
||||
@ -62,30 +62,32 @@ pub struct CreateAccountOrder {
|
||||
pub shopping_cart_id: ShoppingCartId,
|
||||
}
|
||||
|
||||
db_async_handler!(CreateAccountOrder, create_account_order, AccountOrder);
|
||||
db_async_handler!(
|
||||
CreateAccountOrder,
|
||||
create_account_order,
|
||||
AccountOrder,
|
||||
inner_create_account_order
|
||||
);
|
||||
|
||||
pub(crate) async fn create_account_order(
|
||||
msg: CreateAccountOrder,
|
||||
db: PgPool,
|
||||
t: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<AccountOrder> {
|
||||
let mut t = db.begin().await?;
|
||||
|
||||
let order: AccountOrder = match sqlx::query_as(
|
||||
r#"
|
||||
INSERT INTO account_orders (buyer_id, status)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING id, buyer_id, status, order_ext_id
|
||||
RETURNING id, buyer_id, status, order_ext_id, service_order_id
|
||||
"#,
|
||||
)
|
||||
.bind(msg.buyer_id)
|
||||
.bind(OrderStatus::Confirmed)
|
||||
.fetch_one(&mut t)
|
||||
.fetch_one(&mut *t)
|
||||
.await
|
||||
{
|
||||
Ok(order) => order,
|
||||
Err(e) => {
|
||||
log::error!("{e:?}");
|
||||
t.rollback().await.ok();
|
||||
return Err(super::Error::AccountOrder(Error::CantCreate));
|
||||
}
|
||||
};
|
||||
@ -97,13 +99,12 @@ RETURNING id, buyer_id, status, order_ext_id
|
||||
quantity: item.quantity,
|
||||
quantity_unit: item.quantity_unit,
|
||||
},
|
||||
&mut t,
|
||||
&mut *t,
|
||||
)
|
||||
.await
|
||||
{
|
||||
log::error!("{e:?}");
|
||||
|
||||
t.rollback().await.ok();
|
||||
return Err(super::Error::AccountOrder(Error::CantCreate));
|
||||
}
|
||||
}
|
||||
@ -113,18 +114,15 @@ RETURNING id, buyer_id, status, order_ext_id
|
||||
id: msg.shopping_cart_id,
|
||||
state: ShoppingCartState::Closed,
|
||||
},
|
||||
&mut t,
|
||||
t,
|
||||
)
|
||||
.await
|
||||
{
|
||||
log::error!("{e:?}");
|
||||
|
||||
t.rollback().await.ok();
|
||||
return Err(super::Error::AccountOrder(Error::CantCreate));
|
||||
};
|
||||
|
||||
t.commit().await.ok();
|
||||
|
||||
Ok(order)
|
||||
}
|
||||
|
||||
@ -148,7 +146,7 @@ pub(crate) async fn update_account_order(
|
||||
UPDATE account_orders
|
||||
SET buyer_id = $2 AND status = $3 AND order_id = $4
|
||||
WHERE id = $1
|
||||
RETURNING id, buyer_id, status, order_ext_id
|
||||
RETURNING id, buyer_id, status, order_ext_id, service_order_id
|
||||
"#,
|
||||
)
|
||||
.bind(msg.id)
|
||||
@ -185,7 +183,7 @@ pub(crate) async fn update_account_order_by_ext(
|
||||
UPDATE account_orders
|
||||
SET status = $2
|
||||
WHERE order_ext_id = $1
|
||||
RETURNING id, buyer_id, status, order_ext_id
|
||||
RETURNING id, buyer_id, status, order_ext_id, service_order_id
|
||||
"#,
|
||||
)
|
||||
.bind(msg.order_ext_id)
|
||||
@ -209,7 +207,7 @@ db_async_handler!(FindAccountOrder, find_account_order, AccountOrder);
|
||||
pub(crate) async fn find_account_order(msg: FindAccountOrder, db: PgPool) -> Result<AccountOrder> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id, buyer_id, status, order_ext_id
|
||||
SELECT id, buyer_id, status, order_ext_id, service_order_id
|
||||
FROM account_orders
|
||||
WHERE id = $1
|
||||
"#,
|
||||
@ -222,3 +220,34 @@ WHERE id = $1
|
||||
super::Error::AccountOrder(Error::NotExists)
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<AccountOrder>")]
|
||||
pub struct SetOrderServiceId {
|
||||
pub id: AccountOrderId,
|
||||
pub service_order_id: String,
|
||||
}
|
||||
|
||||
db_async_handler!(SetOrderServiceId, set_order_service_id, AccountOrder);
|
||||
|
||||
pub(crate) async fn set_order_service_id(
|
||||
msg: SetOrderServiceId,
|
||||
db: PgPool,
|
||||
) -> Result<AccountOrder> {
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
UPDATE account_orders
|
||||
SET service_order_id = $2
|
||||
WHERE id = $1
|
||||
RETURNING id, buyer_id, status, order_ext_id, service_order_id
|
||||
"#,
|
||||
)
|
||||
.bind(msg.id)
|
||||
.bind(msg.service_order_id)
|
||||
.fetch_one(&db)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
super::Error::AccountOrder(Error::NotExists)
|
||||
})
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
use actix::Message;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use super::Result;
|
||||
use crate::database::Database;
|
||||
@ -27,9 +26,12 @@ pub enum Error {
|
||||
#[rtype(result = "Result<Vec<model::Product>>")]
|
||||
pub struct AllProducts;
|
||||
|
||||
crate::db_async_handler!(AllProducts, all, Vec<Product>);
|
||||
crate::db_async_handler!(AllProducts, all, Vec<Product>, inner_all);
|
||||
|
||||
pub(crate) async fn all(_msg: AllProducts, pool: PgPool) -> Result<Vec<model::Product>> {
|
||||
pub(crate) async fn all<'e, E>(_msg: AllProducts, pool: E) -> Result<Vec<model::Product>>
|
||||
where
|
||||
E: sqlx::Executor<'e, Database = sqlx::Postgres>,
|
||||
{
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT id,
|
||||
@ -42,7 +44,7 @@ SELECT id,
|
||||
FROM products
|
||||
"#,
|
||||
)
|
||||
.fetch_all(&pool)
|
||||
.fetch_all(pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
@ -61,9 +63,12 @@ pub struct CreateProduct {
|
||||
pub deliver_days_flag: Days,
|
||||
}
|
||||
|
||||
crate::db_async_handler!(CreateProduct, create_product, Product);
|
||||
crate::db_async_handler!(CreateProduct, create_product, Product, inner_create_product);
|
||||
|
||||
pub(crate) async fn create_product(msg: CreateProduct, pool: PgPool) -> Result<model::Product> {
|
||||
pub(crate) async fn create_product<'e, E>(msg: CreateProduct, pool: E) -> Result<model::Product>
|
||||
where
|
||||
E: sqlx::Executor<'e, Database = sqlx::Postgres>,
|
||||
{
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
INSERT INTO products (name, short_description, long_description, category, price, deliver_days_flag)
|
||||
@ -83,7 +88,7 @@ RETURNING id,
|
||||
.bind(msg.category)
|
||||
.bind(msg.price)
|
||||
.bind(msg.deliver_days_flag)
|
||||
.fetch_one(&pool)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
@ -103,9 +108,12 @@ pub struct UpdateProduct {
|
||||
pub deliver_days_flag: Days,
|
||||
}
|
||||
|
||||
crate::db_async_handler!(UpdateProduct, update_product, Product);
|
||||
crate::db_async_handler!(UpdateProduct, update_product, Product, inner_update_product);
|
||||
|
||||
pub(crate) async fn update_product(msg: UpdateProduct, pool: PgPool) -> Result<model::Product> {
|
||||
pub(crate) async fn update_product<'e, E>(msg: UpdateProduct, pool: E) -> Result<model::Product>
|
||||
where
|
||||
E: sqlx::Executor<'e, Database = sqlx::Postgres>,
|
||||
{
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
UPDATE products
|
||||
@ -132,7 +140,7 @@ RETURNING id,
|
||||
.bind(msg.category)
|
||||
.bind(msg.price)
|
||||
.bind(msg.deliver_days_flag)
|
||||
.fetch_one(&pool)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
@ -146,9 +154,17 @@ pub struct DeleteProduct {
|
||||
pub product_id: ProductId,
|
||||
}
|
||||
|
||||
crate::db_async_handler!(DeleteProduct, delete_product, Option<model::Product>);
|
||||
crate::db_async_handler!(
|
||||
DeleteProduct,
|
||||
delete_product,
|
||||
Option<model::Product>,
|
||||
inner_delete_product
|
||||
);
|
||||
|
||||
pub(crate) async fn delete_product(msg: DeleteProduct, pool: PgPool) -> Result<Option<Product>> {
|
||||
pub(crate) async fn delete_product<'e, E>(msg: DeleteProduct, pool: E) -> Result<Option<Product>>
|
||||
where
|
||||
E: sqlx::Executor<'e, Database = sqlx::Postgres>,
|
||||
{
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
DELETE FROM products
|
||||
@ -163,7 +179,7 @@ RETURNING id,
|
||||
"#,
|
||||
)
|
||||
.bind(msg.product_id)
|
||||
.fetch_optional(&pool)
|
||||
.fetch_optional(pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
@ -180,13 +196,17 @@ pub struct ShoppingCartProducts {
|
||||
crate::db_async_handler!(
|
||||
ShoppingCartProducts,
|
||||
shopping_cart_products,
|
||||
Vec<model::Product>
|
||||
Vec<model::Product>,
|
||||
inner_shopping_cart_products
|
||||
);
|
||||
|
||||
pub(crate) async fn shopping_cart_products(
|
||||
pub(crate) async fn shopping_cart_products<'e, E>(
|
||||
msg: ShoppingCartProducts,
|
||||
pool: PgPool,
|
||||
) -> Result<Vec<Product>> {
|
||||
pool: E,
|
||||
) -> Result<Vec<Product>>
|
||||
where
|
||||
E: sqlx::Executor<'e, Database = sqlx::Postgres>,
|
||||
{
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
SELECT products.id,
|
||||
@ -202,7 +222,7 @@ WHERE shopping_cart_id = $1
|
||||
"#,
|
||||
)
|
||||
.bind(msg.shopping_cart_id)
|
||||
.fetch_all(&pool)
|
||||
.fetch_all(pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
|
@ -229,9 +229,17 @@ pub struct CartItems {
|
||||
pub shopping_cart_id: ShoppingCartId,
|
||||
}
|
||||
|
||||
db_async_handler!(CartItems, cart_items, Vec<ShoppingCartItem>);
|
||||
db_async_handler!(
|
||||
CartItems,
|
||||
cart_items,
|
||||
Vec<ShoppingCartItem>,
|
||||
inner_cart_items
|
||||
);
|
||||
|
||||
pub(crate) async fn cart_items(msg: CartItems, pool: PgPool) -> Result<Vec<ShoppingCartItem>> {
|
||||
pub(crate) async fn cart_items<'e, E>(msg: CartItems, pool: E) -> Result<Vec<ShoppingCartItem>>
|
||||
where
|
||||
E: sqlx::Executor<'e, Database = sqlx::Postgres>,
|
||||
{
|
||||
let shopping_cart_id = msg.shopping_cart_id;
|
||||
sqlx::query_as(
|
||||
r#"
|
||||
@ -241,7 +249,7 @@ WHERE shopping_cart_id = $1
|
||||
"#,
|
||||
)
|
||||
.bind(msg.shopping_cart_id)
|
||||
.fetch_all(&pool)
|
||||
.fetch_all(pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
|
@ -232,12 +232,13 @@ pub struct EnsureActiveShoppingCart {
|
||||
db_async_handler!(
|
||||
EnsureActiveShoppingCart,
|
||||
ensure_active_shopping_cart,
|
||||
ShoppingCart
|
||||
ShoppingCart,
|
||||
inner_ensure_active_shopping_cart
|
||||
);
|
||||
|
||||
pub(crate) async fn ensure_active_shopping_cart(
|
||||
msg: EnsureActiveShoppingCart,
|
||||
pool: PgPool,
|
||||
pool: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<ShoppingCart> {
|
||||
if let Ok(Some(cart)) = sqlx::query_as(
|
||||
r#"
|
||||
@ -249,7 +250,7 @@ RETURNING id, buyer_id, payment_method, state;
|
||||
"#,
|
||||
)
|
||||
.bind(msg.buyer_id)
|
||||
.fetch_optional(&pool)
|
||||
.fetch_optional(&mut *pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
@ -265,7 +266,7 @@ WHERE buyer_id = $1 AND state = 'active'
|
||||
"#,
|
||||
)
|
||||
.bind(msg.buyer_id)
|
||||
.fetch_one(&pool)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
log::error!("{e:?}");
|
||||
|
@ -159,6 +159,9 @@ pub struct RequestPayment {
|
||||
pub buyer: Buyer,
|
||||
pub customer_ip: String,
|
||||
pub buyer_id: AccountId,
|
||||
/// False if customer is allowed to be charged on site.
|
||||
/// Otherwise it should be true to use payment service for charging
|
||||
pub charge_client: bool,
|
||||
}
|
||||
|
||||
pay_async_handler!(RequestPayment, request_payment, CreatePaymentResult);
|
||||
@ -177,6 +180,7 @@ pub(crate) async fn request_payment(
|
||||
format!("{}/payment/success", w.host()),
|
||||
)
|
||||
};
|
||||
|
||||
let cart: model::ShoppingCart = query_db!(
|
||||
db,
|
||||
database::EnsureActiveShoppingCart {
|
||||
@ -233,36 +237,54 @@ pub(crate) async fn request_payment(
|
||||
Error::CreateOrder
|
||||
);
|
||||
|
||||
let pay_u::res::CreateOrder {
|
||||
status: _,
|
||||
redirect_uri,
|
||||
order_id: _,
|
||||
ext_order_id: _,
|
||||
} = {
|
||||
client
|
||||
.lock()
|
||||
.create_order(
|
||||
pay_u::req::OrderCreate::build(
|
||||
msg.buyer.into(),
|
||||
msg.customer_ip,
|
||||
msg.currency,
|
||||
format!("Order #{}", db_order.id),
|
||||
)?
|
||||
.with_products(cart_products.into_iter().map(|p| {
|
||||
pay_u::Product::new(
|
||||
p.name.to_string(),
|
||||
**p.price,
|
||||
items
|
||||
.remove(&p.id)
|
||||
.map(|(quantity, _)| **quantity as u32)
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
}))
|
||||
.with_ext_order_id(db_order.order_ext_id.to_string())
|
||||
.with_notify_url(notify_uri)
|
||||
.with_continue_url(continue_uri),
|
||||
)
|
||||
.await?
|
||||
let payment_required = {
|
||||
let l = config.lock();
|
||||
l.payment().optional_payment() != false
|
||||
};
|
||||
let redirect_uri = if msg.charge_client || payment_required {
|
||||
let pay_u::res::CreateOrder {
|
||||
status: _,
|
||||
redirect_uri,
|
||||
order_id,
|
||||
ext_order_id: _,
|
||||
} = {
|
||||
client
|
||||
.lock()
|
||||
.create_order(
|
||||
pay_u::req::OrderCreate::build(
|
||||
msg.buyer.into(),
|
||||
msg.customer_ip,
|
||||
msg.currency,
|
||||
format!("Order #{}", db_order.id),
|
||||
)?
|
||||
.with_products(cart_products.into_iter().map(|p| {
|
||||
pay_u::Product::new(
|
||||
p.name.to_string(),
|
||||
**p.price,
|
||||
items
|
||||
.remove(&p.id)
|
||||
.map(|(quantity, _)| **quantity as u32)
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
}))
|
||||
.with_ext_order_id(db_order.order_ext_id.to_string())
|
||||
.with_notify_url(notify_uri)
|
||||
.with_continue_url(continue_uri),
|
||||
)
|
||||
.await?
|
||||
};
|
||||
|
||||
query_db!(
|
||||
db,
|
||||
database::SetOrderServiceId {
|
||||
service_order_id: order_id.0,
|
||||
id: db_order.id,
|
||||
},
|
||||
Error::CreateOrder
|
||||
);
|
||||
redirect_uri
|
||||
} else {
|
||||
String::from("/pay-on-site")
|
||||
};
|
||||
|
||||
let order_items = query_db!(
|
||||
|
@ -37,7 +37,10 @@ impl std::ops::DerefMut for SharedAppConfig {
|
||||
pub struct PaymentConfig {
|
||||
payu_client_id: Option<pay_u::ClientId>,
|
||||
payu_client_secret: Option<pay_u::ClientSecret>,
|
||||
/// Create payu account and copy here merchant id
|
||||
payu_client_merchant_id: Option<pay_u::MerchantPosId>,
|
||||
/// Allow customers to pay on site
|
||||
optional_payment: bool,
|
||||
}
|
||||
|
||||
impl Example for PaymentConfig {
|
||||
@ -49,13 +52,19 @@ impl Example for PaymentConfig {
|
||||
payu_client_secret: Some(pay_u::ClientSecret::new(
|
||||
"Create payu account and copy here client_secret",
|
||||
)),
|
||||
/// "Create payu account and copy here merchant id"
|
||||
/// Create payu account and copy here merchant id
|
||||
payu_client_merchant_id: Some(pay_u::MerchantPosId::from(0)),
|
||||
/// Allow customers to pay on site
|
||||
optional_payment: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PaymentConfig {
|
||||
pub fn optional_payment(&self) -> bool {
|
||||
self.optional_payment
|
||||
}
|
||||
|
||||
pub fn payu_client_id(&self) -> pay_u::ClientId {
|
||||
self.payu_client_id
|
||||
.as_ref()
|
||||
@ -342,7 +351,10 @@ fn load(config_path: &str, opts: &impl UpdateConfig) -> SharedAppConfig {
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||
let config = AppConfig::example();
|
||||
std::fs::write(config_path, toml::to_string_pretty(&config).unwrap()).unwrap();
|
||||
SharedAppConfig::new(config)
|
||||
eprintln!("Config was automatically generated");
|
||||
eprintln!("Please review ./bazzar.toml, fill all fields or provide all environment variables in .env");
|
||||
eprintln!("And restart service.");
|
||||
std::process::exit(1);
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("{e:?}");
|
||||
@ -351,6 +363,28 @@ fn load(config_path: &str, opts: &impl UpdateConfig) -> SharedAppConfig {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn config_info() -> crate::Result<()> {
|
||||
println!(
|
||||
r#"Environment variables:
|
||||
PAYU_CLIENT_ID - PayU client id, you can obtain it by creating account (account requires one-time payment)
|
||||
PAYU_CLIENT_SECRET - PayU client secret
|
||||
PAYU_CLIENT_MERCHANT_ID - PayU client merchant id, you can obtain it by creating account (account requires one-time payment)
|
||||
WEB_HOST - your domain name, it's required for PayU notifications, service emails and redirections
|
||||
PASS_SALT - password encryption secret string, you can generate it with this CLI
|
||||
SESSION_SECRET - 100 characters admin session encryption
|
||||
JWT_SECRET - 100 characters user session encryption
|
||||
BAZZAR_BIND - address to which server should be bind, typically 0.0.0.0
|
||||
BAZZAR_PORT - port which server should use, typically 80
|
||||
SENDGRID_SECRET - e-mail sending service secret
|
||||
SENDGRID_API_KEY - e-mail sending service api key
|
||||
SMTP_FROM - e-mail sending service authorized e-mail address used as sender e-mail address
|
||||
DATABASE_URL - postgresql address (ex. postgres://postgres@localhost/bazzar)
|
||||
"#
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn save(config_path: &str, config: &mut AppConfig) {
|
||||
config.config_path = String::from(config_path);
|
||||
std::fs::write(config_path, toml::to_string_pretty(&config).unwrap()).unwrap();
|
||||
|
@ -100,7 +100,7 @@ async fn migrate(opts: MigrateOpts) -> Result<()> {
|
||||
let config = config::default_load(&opts);
|
||||
let db = database::Database::build(config).await?;
|
||||
let res: std::result::Result<(), MigrateError> =
|
||||
sqlx::migrate!("../db/migrate").run(db.pool()).await;
|
||||
sqlx::migrate!("../migrations").run(db.pool()).await;
|
||||
match res {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => {
|
||||
@ -204,5 +204,6 @@ async fn main() -> Result<()> {
|
||||
Command::GenerateHash(opts) => generate_hash(opts).await,
|
||||
Command::CreateAccount(opts) => create_account(opts).await,
|
||||
Command::TestMailer(opts) => test_mailer(opts).await,
|
||||
Command::ConfigInfo(_) => config::config_info().await,
|
||||
}
|
||||
}
|
||||
|
@ -535,6 +535,7 @@ pub struct AccountOrder {
|
||||
pub status: OrderStatus,
|
||||
pub order_id: Option<OrderId>,
|
||||
pub order_ext_id: uuid::Uuid,
|
||||
pub service_order_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(sqlx::FromRow, Serialize, Deserialize)]
|
||||
@ -553,6 +554,7 @@ impl From<AccountOrder> for PublicAccountOrder {
|
||||
status,
|
||||
order_id,
|
||||
order_ext_id: _,
|
||||
service_order_id: _,
|
||||
}: AccountOrder,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -19,6 +19,7 @@ impl From<(Vec<model::AccountOrder>, Vec<model::OrderItem>)> for AccountOrders {
|
||||
status,
|
||||
order_id,
|
||||
order_ext_id: _,
|
||||
service_order_id: _,
|
||||
}| {
|
||||
AccountOrder {
|
||||
id,
|
||||
@ -43,6 +44,7 @@ impl From<(model::AccountOrder, Vec<model::OrderItem>)> for AccountOrder {
|
||||
status,
|
||||
order_id,
|
||||
order_ext_id: _,
|
||||
service_order_id: _,
|
||||
},
|
||||
mut items,
|
||||
): (model::AccountOrder, Vec<model::OrderItem>),
|
||||
|
@ -47,6 +47,8 @@ pub enum Command {
|
||||
CreateAccount(CreateAccountOpts),
|
||||
#[options(help = "Check mailer config")]
|
||||
TestMailer(TestMailerOpts),
|
||||
#[options(help = "Print config information")]
|
||||
ConfigInfo(ConfigInfo),
|
||||
}
|
||||
|
||||
impl UpdateConfig for Command {
|
||||
@ -67,6 +69,7 @@ impl UpdateConfig for Command {
|
||||
Command::TestMailer(opts) => {
|
||||
opts.update_config(config);
|
||||
}
|
||||
Command::ConfigInfo(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -77,6 +80,8 @@ impl Default for Command {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConfigInfo {}
|
||||
|
||||
#[derive(Options, Debug)]
|
||||
pub struct GenerateHashOpts {
|
||||
pub help: bool,
|
||||
|
@ -40,10 +40,14 @@ pub enum Error {
|
||||
|
||||
#[get("/")]
|
||||
async fn landing() -> HttpResponse {
|
||||
HttpResponse::SeeOther().append_header((actix_web::http::header::LOCATION, ""));
|
||||
HttpResponse::NotImplemented().body("")
|
||||
}
|
||||
|
||||
#[get("/pay-on-site")]
|
||||
async fn pay_on_site() -> HttpResponse {
|
||||
HttpResponse::Ok().body("<h1>Pay on Site</h1>")
|
||||
}
|
||||
|
||||
pub fn configure(config: &mut ServiceConfig) {
|
||||
config.service(landing).configure(api_v1::configure);
|
||||
}
|
||||
|
@ -200,6 +200,9 @@ pub struct CreateOrderInput {
|
||||
pub last_name: String,
|
||||
/// Required customer language
|
||||
pub language: String,
|
||||
/// False if customer is allowed to be charged on site.
|
||||
/// Otherwise it should be true to use payment service for charging
|
||||
pub charge_client: bool,
|
||||
}
|
||||
|
||||
#[post("/order")]
|
||||
@ -233,6 +236,7 @@ pub(crate) async fn create_order(
|
||||
first_name,
|
||||
last_name,
|
||||
language,
|
||||
charge_client,
|
||||
} = payload;
|
||||
let ip = match req.peer_addr() {
|
||||
Some(ip) => ip,
|
||||
@ -252,6 +256,7 @@ pub(crate) async fn create_order(
|
||||
},
|
||||
customer_ip: ip.to_string(),
|
||||
buyer_id,
|
||||
charge_client
|
||||
},
|
||||
routes::Error::Public(PublicError::DatabaseConnection)
|
||||
);
|
||||
|
5
build.rs
Normal file
5
build.rs
Normal file
@ -0,0 +1,5 @@
|
||||
// generated by `sqlx migrate build-script`
|
||||
fn main() {
|
||||
// trigger recompilation when a new migration is added
|
||||
println!("cargo:rerun-if-changed=migrations");
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
alter table account_orders
|
||||
ADD COLUMN service_order_id TEXT UNIQUE;
|
Loading…
Reference in New Issue
Block a user