add: transfer refunds
This commit is contained in:
parent
95cb889080
commit
fdaae8d977
10 changed files with 340 additions and 26 deletions
|
@ -9,5 +9,6 @@ CREATE TABLE IF NOT EXISTS products (
|
|||
price INT NOT NULL,
|
||||
stock INT NOT NULL,
|
||||
single_use INT NOT NULL,
|
||||
data TEXT NOT NULL
|
||||
data TEXT NOT NULL,
|
||||
uploads TEXT NOT NULL
|
||||
)
|
||||
|
|
|
@ -54,10 +54,14 @@ ADD COLUMN IF NOT EXISTS single_use INT DEFAULT 1;
|
|||
ALTER TABLE transfers
|
||||
ADD COLUMN IF NOT EXISTS source TEXT DEFAULT '"General"';
|
||||
|
||||
-- products single_use
|
||||
-- products data
|
||||
ALTER TABLE products
|
||||
ADD COLUMN IF NOT EXISTS data TEXT DEFAULT '';
|
||||
|
||||
-- users applied_configurations
|
||||
ALTER TABLE users
|
||||
ADD COLUMN IF NOT EXISTS applied_configurations TEXT DEFAULT '[]';
|
||||
|
||||
-- products uploads
|
||||
ALTER TABLE products
|
||||
ADD COLUMN IF NOT EXISTS uploads TEXT DEFAULT '{}';
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::model::{
|
|||
auth::User,
|
||||
economy::{
|
||||
CoinTransfer, CoinTransferMethod, CoinTransferSource, Product, ProductFulfillmentMethod,
|
||||
ProductUploads,
|
||||
},
|
||||
mail::Letter,
|
||||
permissions::FinePermission,
|
||||
|
@ -25,6 +26,7 @@ impl DataManager {
|
|||
stock: get!(x->8(i32)),
|
||||
single_use: get!(x->9(i32)) as i8 == 1,
|
||||
data: get!(x->10(String)),
|
||||
uploads: serde_json::from_str(&get!(x->11(String))).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,7 +109,7 @@ impl DataManager {
|
|||
|
||||
let res = execute!(
|
||||
&conn,
|
||||
"INSERT INTO products VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
|
||||
"INSERT INTO products VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
|
||||
params![
|
||||
&(data.id as i64),
|
||||
&(data.created as i64),
|
||||
|
@ -120,6 +122,7 @@ impl DataManager {
|
|||
&(data.stock as i32),
|
||||
&{ if data.single_use { 1 } else { 0 } },
|
||||
&data.data,
|
||||
&serde_json::to_string(&data.uploads).unwrap(),
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -271,6 +274,7 @@ If your product is a purchase of goods or services, please be sure to fulfill th
|
|||
auto_method!(update_product_method(ProductFulfillmentMethod)@get_product_by_id:FinePermission::MANAGE_USERS; -> "UPDATE products SET method = $1 WHERE id = $2" --serde --cache-key-tmpl="atto.product:{}");
|
||||
auto_method!(update_product_single_use(i32)@get_product_by_id:FinePermission::MANAGE_USERS; -> "UPDATE products SET single_use = $1 WHERE id = $2" --cache-key-tmpl="atto.product:{}");
|
||||
auto_method!(update_product_data(&str)@get_product_by_id:FinePermission::MANAGE_USERS; -> "UPDATE products SET data = $1 WHERE id = $2" --cache-key-tmpl="atto.product:{}");
|
||||
auto_method!(update_product_uploads(ProductUploads)@get_product_by_id:FinePermission::MANAGE_USERS; -> "UPDATE products SET uploads = $1 WHERE id = $2" --serde --cache-key-tmpl="atto.product:{}");
|
||||
|
||||
auto_method!(update_product_stock(i32)@get_product_by_id:FinePermission::MANAGE_USERS; -> "UPDATE products SET stock = $1 WHERE id = $2" --cache-key-tmpl="atto.product:{}");
|
||||
auto_method!(incr_product_stock() -> "UPDATE products SET stock = stock + 1 WHERE id = $1" --cache-key-tmpl="atto.product:{}" --incr);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use std::collections::HashMap;
|
||||
use crate::model::{
|
||||
Error, Result,
|
||||
economy::{CoinTransferMethod, Product, CoinTransfer},
|
||||
auth::{Notification, User},
|
||||
economy::{CoinTransfer, CoinTransferMethod, CoinTransferSource, Product},
|
||||
Error, Result,
|
||||
};
|
||||
use crate::{auto_method, DataManager};
|
||||
use oiseau::{cache::Cache, execute, get, params, query_row, query_rows, PostgresRow};
|
||||
|
@ -28,16 +28,13 @@ impl DataManager {
|
|||
pub async fn fill_transfers(
|
||||
&self,
|
||||
list: Vec<CoinTransfer>,
|
||||
) -> Result<Vec<(usize, usize, i32, User, User, Option<Product>, bool)>> {
|
||||
) -> Result<Vec<(User, User, Option<Product>, CoinTransfer)>> {
|
||||
let mut out = Vec::new();
|
||||
let mut seen_users: HashMap<usize, User> = HashMap::new();
|
||||
let mut seen_products: HashMap<usize, Product> = HashMap::new();
|
||||
|
||||
for transfer in list {
|
||||
out.push((
|
||||
transfer.id,
|
||||
transfer.created,
|
||||
transfer.amount,
|
||||
if let Some(user) = seen_users.get(&transfer.sender) {
|
||||
user.to_owned()
|
||||
} else {
|
||||
|
@ -68,7 +65,7 @@ impl DataManager {
|
|||
}
|
||||
}
|
||||
},
|
||||
transfer.is_pending,
|
||||
transfer,
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -163,6 +160,16 @@ impl DataManager {
|
|||
}
|
||||
|
||||
self.update_user_coins(receiver.id, receiver.coins).await?;
|
||||
|
||||
// handle refund notification
|
||||
if data.source == CoinTransferSource::Refund {
|
||||
self.create_notification(Notification::new(
|
||||
"A coin refund has been issued to your account!".to_string(),
|
||||
"You've been issued a refund for a prior purchase. The product will remain in your account, but your coins have been returned.".to_string(),
|
||||
receiver.id,
|
||||
))
|
||||
.await?;
|
||||
}
|
||||
} else {
|
||||
// we haven't applied the transfer, so this must be pending
|
||||
data.is_pending = true;
|
||||
|
|
|
@ -16,6 +16,29 @@ pub enum ProductFulfillmentMethod {
|
|||
ProfileStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct ProductUploads {
|
||||
/// Promotional thumbnails shown on the product page.
|
||||
///
|
||||
/// Maximum of 4 with a maximum upload size of 2 MiB.
|
||||
#[serde(default)]
|
||||
pub thumbnails: Vec<usize>,
|
||||
/// Reward given to users through active configurations after they purchase the product.
|
||||
//
|
||||
// Maximum upload size of 4 MiB.
|
||||
#[serde(default)]
|
||||
pub reward: usize,
|
||||
}
|
||||
|
||||
impl Default for ProductUploads {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
thumbnails: Vec::new(),
|
||||
reward: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct Product {
|
||||
pub id: usize,
|
||||
|
@ -34,9 +57,14 @@ pub struct Product {
|
|||
/// A negative stock means the product has unlimited stock.
|
||||
pub stock: i32,
|
||||
/// If this product is limited to one purchase per person.
|
||||
#[serde(default)]
|
||||
pub single_use: bool,
|
||||
/// Data for this product. Only used by snippets.
|
||||
#[serde(default)]
|
||||
pub data: String,
|
||||
/// Uploads for this product.
|
||||
#[serde(default)]
|
||||
pub uploads: ProductUploads,
|
||||
}
|
||||
|
||||
impl Product {
|
||||
|
@ -54,6 +82,7 @@ impl Product {
|
|||
stock: 0,
|
||||
single_use: true,
|
||||
data: String::new(),
|
||||
uploads: ProductUploads::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +94,7 @@ pub enum CoinTransferMethod {
|
|||
Purchase(usize),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum CoinTransferSource {
|
||||
/// An unknown source, such as a transfer request.
|
||||
General,
|
||||
|
@ -73,6 +102,8 @@ pub enum CoinTransferSource {
|
|||
Sale,
|
||||
/// A purchase of coins through Stripe.
|
||||
Purchase,
|
||||
/// A refund of coins.
|
||||
Refund,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue