mirror of
https://github.com/creating2morrow/neveko.git
synced 2024-12-22 19:49:24 +00:00
start vendor shipping update and draft txset
This commit is contained in:
parent
79f526d211
commit
86c77feac6
9 changed files with 308 additions and 63 deletions
|
@ -38,6 +38,7 @@ pub const MEDIATOR_DB_KEY: &str = "med8";
|
||||||
pub const MSIG_MESSAGE_DB_KEY: &str = "msig";
|
pub const MSIG_MESSAGE_DB_KEY: &str = "msig";
|
||||||
pub const MSIG_MESSAGE_LIST_DB_KEY: &str = "msigl";
|
pub const MSIG_MESSAGE_LIST_DB_KEY: &str = "msigl";
|
||||||
pub const FTS_JWP_DB_KEY: &str = "fts-jwp";
|
pub const FTS_JWP_DB_KEY: &str = "fts-jwp";
|
||||||
|
pub const DELIVERY_INFO_DB_KEY: &str = "delivery";
|
||||||
// End LMDB Keys
|
// End LMDB Keys
|
||||||
|
|
||||||
/// Environment variable for injecting wallet password
|
/// Environment variable for injecting wallet password
|
||||||
|
|
|
@ -396,6 +396,37 @@ pub async fn check_rpc_connection() -> () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs the xmr rpc 'sign' method
|
||||||
|
pub async fn sign(data: String) -> reqres::XmrRpcSignResponse {
|
||||||
|
info!("executing {}", RpcFields::Sign.value());
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
let host = get_rpc_host();
|
||||||
|
let params = reqres::XmrRpcSignParams { data };
|
||||||
|
let req = reqres::XmrRpcSignRequest {
|
||||||
|
jsonrpc: RpcFields::JsonRpcVersion.value(),
|
||||||
|
id: RpcFields::Id.value(),
|
||||||
|
method: RpcFields::Sign.value(),
|
||||||
|
params,
|
||||||
|
};
|
||||||
|
let login: RpcLogin = get_rpc_creds();
|
||||||
|
match client
|
||||||
|
.post(host)
|
||||||
|
.json(&req)
|
||||||
|
.send_with_digest_auth(&login.username, &login.credential)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => {
|
||||||
|
let res = response.json::<reqres::XmrRpcSignResponse>().await;
|
||||||
|
debug!("{} response: {:?}", RpcFields::Sign.value(), res);
|
||||||
|
match res {
|
||||||
|
Ok(res) => res,
|
||||||
|
_ => Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_e) => Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Performs the xmr rpc 'verify' method
|
/// Performs the xmr rpc 'verify' method
|
||||||
pub async fn verify(address: String, data: String, signature: String) -> bool {
|
pub async fn verify(address: String, data: String, signature: String) -> bool {
|
||||||
info!("executing {}", RpcFields::Verify.value());
|
info!("executing {}", RpcFields::Verify.value());
|
||||||
|
@ -423,13 +454,7 @@ pub async fn verify(address: String, data: String, signature: String) -> bool {
|
||||||
let res = response.json::<reqres::XmrRpcVerifyResponse>().await;
|
let res = response.json::<reqres::XmrRpcVerifyResponse>().await;
|
||||||
debug!("{} response: {:?}", RpcFields::Verify.value(), res);
|
debug!("{} response: {:?}", RpcFields::Verify.value(), res);
|
||||||
match res {
|
match res {
|
||||||
Ok(res) => {
|
Ok(res) => res.result.good,
|
||||||
if res.result.good {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,15 @@ use crate::{
|
||||||
contact,
|
contact,
|
||||||
db,
|
db,
|
||||||
gpg,
|
gpg,
|
||||||
i2p,
|
|
||||||
message,
|
message,
|
||||||
models::*,
|
models::*,
|
||||||
monero,
|
monero,
|
||||||
order,
|
order,
|
||||||
product,
|
product,
|
||||||
reqres,
|
reqres::{
|
||||||
|
self,
|
||||||
|
FinalizeOrderResponse,
|
||||||
|
},
|
||||||
utils,
|
utils,
|
||||||
};
|
};
|
||||||
use log::{
|
use log::{
|
||||||
|
@ -98,6 +100,7 @@ pub fn backup(order: &Order) {
|
||||||
info!("creating backup of order: {}", order.orid);
|
info!("creating backup of order: {}", order.orid);
|
||||||
let s = db::Interface::open();
|
let s = db::Interface::open();
|
||||||
let k = &order.orid;
|
let k = &order.orid;
|
||||||
|
db::Interface::delete(&s.env, &s.handle, k);
|
||||||
db::Interface::write(&s.env, &s.handle, k, &Order::to_db(&order));
|
db::Interface::write(&s.env, &s.handle, k, &Order::to_db(&order));
|
||||||
// in order to retrieve all orders, write keys to with col
|
// in order to retrieve all orders, write keys to with col
|
||||||
let list_key = crate::CUSTOMER_ORDER_LIST_DB_KEY;
|
let list_key = crate::CUSTOMER_ORDER_LIST_DB_KEY;
|
||||||
|
@ -222,6 +225,7 @@ pub async fn sign_and_submit_multisig(
|
||||||
///
|
///
|
||||||
/// the details of said order.
|
/// the details of said order.
|
||||||
pub async fn secure_retrieval(orid: &String, signature: &String) -> Order {
|
pub async fn secure_retrieval(orid: &String, signature: &String) -> Order {
|
||||||
|
info!("secure order retrieval for {}", orid);
|
||||||
// get customer address for NEVEKO NOT order wallet
|
// get customer address for NEVEKO NOT order wallet
|
||||||
let m_order: Order = find(&orid);
|
let m_order: Order = find(&orid);
|
||||||
let mut xmr_address: String = String::new();
|
let mut xmr_address: String = String::new();
|
||||||
|
@ -248,12 +252,14 @@ pub async fn secure_retrieval(orid: &String, signature: &String) -> Order {
|
||||||
/// Check for import multisig info, validate block time and that the
|
/// Check for import multisig info, validate block time and that the
|
||||||
///
|
///
|
||||||
/// order wallet has been funded properly. Update the order to multisig complete
|
/// order wallet has been funded properly. Update the order to multisig complete
|
||||||
pub async fn validate_order_for_ship(orid: &String) -> bool {
|
pub async fn validate_order_for_ship(orid: &String) -> reqres::FinalizeOrderResponse {
|
||||||
info!("validating order for shipment");
|
info!("validating order for shipment");
|
||||||
let mut m_order: Order = find(orid);
|
let m_order: Order = find(orid);
|
||||||
|
let delivery_info: Vec<u8> = hex::decode(&m_order.ship_address).unwrap();
|
||||||
|
let mut j_order: Order = find(orid);
|
||||||
let m_product: Product = product::find(&m_order.pid);
|
let m_product: Product = product::find(&m_order.pid);
|
||||||
let price = m_product.price;
|
let price = m_product.price;
|
||||||
let total = price * m_order.quantity;
|
let total = price * &m_order.quantity;
|
||||||
let wallet_password = utils::empty_string();
|
let wallet_password = utils::empty_string();
|
||||||
monero::open_wallet(&orid, &wallet_password).await;
|
monero::open_wallet(&orid, &wallet_password).await;
|
||||||
// check balance and unlock_time
|
// check balance and unlock_time
|
||||||
|
@ -263,10 +269,13 @@ pub async fn validate_order_for_ship(orid: &String) -> bool {
|
||||||
let ready_to_ship: bool = r_balance.result.balance >= total as u128
|
let ready_to_ship: bool = r_balance.result.balance >= total as u128
|
||||||
&& r_balance.result.blocks_to_unlock < monero::LockTimeLimit::Blocks.value();
|
&& r_balance.result.blocks_to_unlock < monero::LockTimeLimit::Blocks.value();
|
||||||
if ready_to_ship {
|
if ready_to_ship {
|
||||||
m_order.status = StatusType::Shipped.value();
|
j_order.status = StatusType::Shipped.value();
|
||||||
order::modify(Json(m_order));
|
order::modify(Json(j_order));
|
||||||
|
}
|
||||||
|
reqres::FinalizeOrderResponse {
|
||||||
|
orid: String::from(orid),
|
||||||
|
delivery_info,
|
||||||
}
|
}
|
||||||
ready_to_ship
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write encrypted delivery info to lmdb. Once the customer releases the signed
|
/// Write encrypted delivery info to lmdb. Once the customer releases the signed
|
||||||
|
@ -274,23 +283,30 @@ pub async fn validate_order_for_ship(orid: &String) -> bool {
|
||||||
///
|
///
|
||||||
/// they will have access to this information (tracking number, locker code,
|
/// they will have access to this information (tracking number, locker code,
|
||||||
/// etc.)
|
/// etc.)
|
||||||
pub async fn upload_delivery_info(orid: &String, delivery_info: &Vec<u8>) {
|
pub async fn upload_delivery_info(
|
||||||
|
orid: &String,
|
||||||
|
delivery_info: &Vec<u8>,
|
||||||
|
) -> reqres::FinalizeOrderResponse {
|
||||||
info!("uploading delivery info");
|
info!("uploading delivery info");
|
||||||
let name = i2p::get_destination(None);
|
let lookup: Order = order::find(orid);
|
||||||
let e_delivery_info: Vec<u8> = gpg::encrypt(name, &delivery_info).unwrap_or(Vec::new());
|
let e_delivery_info: Vec<u8> = gpg::encrypt(lookup.cid, &delivery_info).unwrap_or(Vec::new());
|
||||||
if e_delivery_info.is_empty() {
|
if e_delivery_info.is_empty() {
|
||||||
error!("unable to encrypt delivery info");
|
error!("unable to encrypt delivery info");
|
||||||
}
|
}
|
||||||
// write delivery info {delivery}-{order id}
|
// get draft payment txset
|
||||||
let s = db::Interface::async_open().await;
|
let sweep: reqres::XmrRpcSweepAllResponse =
|
||||||
let k = format!("delivery-{}", orid);
|
monero::sweep_all(String::from(&lookup.subaddress)).await;
|
||||||
let data = hex::encode(e_delivery_info);
|
|
||||||
db::Interface::async_write(&s.env, &s.handle, &k, &data).await;
|
|
||||||
// update the order
|
// update the order
|
||||||
let mut m_order: Order = find(orid);
|
let mut m_order: Order = find(orid);
|
||||||
m_order.status = StatusType::Shipped.value();
|
m_order.status = StatusType::Shipped.value();
|
||||||
db::Interface::async_delete(&s.env, &s.handle, &m_order.orid).await;
|
m_order.deliver_date = chrono::offset::Utc::now().timestamp();
|
||||||
db::Interface::async_write(&s.env, &s.handle, &m_order.orid, &Order::to_db(&m_order)).await;
|
m_order.ship_address = delivery_info.to_vec();
|
||||||
|
m_order.vend_msig_txset = sweep.result.multisig_txset;
|
||||||
|
modify(Json(m_order));
|
||||||
|
FinalizeOrderResponse {
|
||||||
|
delivery_info: delivery_info.to_vec(),
|
||||||
|
orid: String::from(orid),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The vendor will first search for an encrypted multisig message in the form
|
/// The vendor will first search for an encrypted multisig message in the form
|
||||||
|
@ -341,6 +357,7 @@ pub async fn transmit_order_request(
|
||||||
jwp: String,
|
jwp: String,
|
||||||
request: reqres::OrderRequest,
|
request: reqres::OrderRequest,
|
||||||
) -> Result<Order, Box<dyn Error>> {
|
) -> Result<Order, Box<dyn Error>> {
|
||||||
|
info!("executing trasmit_order_request");
|
||||||
let host = utils::get_i2p_http_proxy();
|
let host = utils::get_i2p_http_proxy();
|
||||||
let proxy = reqwest::Proxy::http(&host)?;
|
let proxy = reqwest::Proxy::http(&host)?;
|
||||||
let client = reqwest::Client::builder().proxy(proxy).build();
|
let client = reqwest::Client::builder().proxy(proxy).build();
|
||||||
|
@ -366,6 +383,122 @@ pub async fn transmit_order_request(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send the ship request to the vendor.
|
||||||
|
pub async fn transmit_ship_request(
|
||||||
|
contact: &String,
|
||||||
|
jwp: &String,
|
||||||
|
orid: &String,
|
||||||
|
) -> Result<Order, Box<dyn Error>> {
|
||||||
|
info!("executing transmit_ship_request");
|
||||||
|
let host = utils::get_i2p_http_proxy();
|
||||||
|
let proxy = reqwest::Proxy::http(&host)?;
|
||||||
|
let client = reqwest::Client::builder().proxy(proxy).build();
|
||||||
|
match client?
|
||||||
|
.post(format!("http://{}/market/ship/{}", contact, orid))
|
||||||
|
.header("proof", jwp)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => {
|
||||||
|
let res = response.json::<Order>().await;
|
||||||
|
debug!("ship request response: {:?}", res);
|
||||||
|
match res {
|
||||||
|
Ok(r) => Ok(r),
|
||||||
|
_ => Ok(Default::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("failed to generate ship request due to: {:?}", e);
|
||||||
|
Ok(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Executes GET /order/retrieve/orid/signature returning the order information
|
||||||
|
///
|
||||||
|
/// from the vendor.
|
||||||
|
///
|
||||||
|
/// see `fn secure_order_retrieval()`
|
||||||
|
pub async fn transmit_sor_request(
|
||||||
|
contact: &String,
|
||||||
|
jwp: &String,
|
||||||
|
orid: &String,
|
||||||
|
signature: &String,
|
||||||
|
) -> Result<Order, Box<dyn Error>> {
|
||||||
|
info!("executing transmit_sor_request");
|
||||||
|
let host = utils::get_i2p_http_proxy();
|
||||||
|
let proxy = reqwest::Proxy::http(&host)?;
|
||||||
|
let client = reqwest::Client::builder().proxy(proxy).build();
|
||||||
|
match client?
|
||||||
|
.get(format!(
|
||||||
|
"http://{}/order/retrieve/{}/{}",
|
||||||
|
contact, orid, signature
|
||||||
|
))
|
||||||
|
.header("proof", jwp)
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(response) => {
|
||||||
|
let res = response.json::<Order>().await;
|
||||||
|
debug!("order retrieve response: {:?}", res);
|
||||||
|
match res {
|
||||||
|
Ok(r) => Ok(r),
|
||||||
|
_ => Ok(Default::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("failed to retrieve order due to: {:?}", e);
|
||||||
|
Ok(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A decomposition trigger for the shipping request so that the logic
|
||||||
|
///
|
||||||
|
/// can be executed from the gui.
|
||||||
|
pub async fn trigger_ship_request(
|
||||||
|
contact: &String,
|
||||||
|
db_key: &String,
|
||||||
|
jwp: &String,
|
||||||
|
orid: &String,
|
||||||
|
) -> Order {
|
||||||
|
info!("executing trigger_ship_request");
|
||||||
|
let data = String::from(orid);
|
||||||
|
let pre_sign = monero::sign(data).await;
|
||||||
|
let order = transmit_sor_request(contact, jwp, orid, &pre_sign.result.signature).await;
|
||||||
|
// cache order request to db
|
||||||
|
if order.is_err() {
|
||||||
|
log::error!("failed to trigger shipping request");
|
||||||
|
return Default::default();
|
||||||
|
}
|
||||||
|
let unwrap_order: Order = order.unwrap();
|
||||||
|
backup(&unwrap_order);
|
||||||
|
let prefix = String::from(db_key);
|
||||||
|
utils::clear_gui_db(String::from(&prefix), String::from(orid));
|
||||||
|
utils::write_gui_db(prefix, String::from(orid), String::from(orid));
|
||||||
|
unwrap_order
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decomposition trigger for the shipping request
|
||||||
|
pub async fn d_trigger_ship_request(
|
||||||
|
contact: &String,
|
||||||
|
jwp: &String,
|
||||||
|
orid: &String,
|
||||||
|
status: &String,
|
||||||
|
) -> Order {
|
||||||
|
info!("executing d_trigger_ship_request");
|
||||||
|
// request shipment if the order status is MultisigComplete
|
||||||
|
let trigger = trigger_ship_request(contact, jwp, orid, status).await;
|
||||||
|
if trigger.status == order::StatusType::MulitsigComplete.value() {
|
||||||
|
let ship_res = transmit_ship_request(contact, jwp, orid).await;
|
||||||
|
if ship_res.is_err() {
|
||||||
|
error!("failure to decompose trigger_ship_request");
|
||||||
|
return Default::default();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trigger
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn init_mediator_wallet(orid: &String) {
|
pub async fn init_mediator_wallet(orid: &String) {
|
||||||
let password = utils::empty_string();
|
let password = utils::empty_string();
|
||||||
let m_wallet = monero::create_wallet(orid, &password).await;
|
let m_wallet = monero::create_wallet(orid, &password).await;
|
||||||
|
|
|
@ -18,6 +18,11 @@ pub struct XmrRpcValidateAddressParams {
|
||||||
pub allow_openalias: bool,
|
pub allow_openalias: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
pub struct XmrRpcSignParams {
|
||||||
|
pub data: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
pub struct XmrRpcVerifyParams {
|
pub struct XmrRpcVerifyParams {
|
||||||
pub address: String,
|
pub address: String,
|
||||||
|
@ -246,6 +251,14 @@ pub struct XmrRpcExchangeMultisigKeysRequest {
|
||||||
pub params: XmrRpcExchangeMultisigKeysParams,
|
pub params: XmrRpcExchangeMultisigKeysParams,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
pub struct XmrRpcSignRequest {
|
||||||
|
pub jsonrpc: String,
|
||||||
|
pub id: String,
|
||||||
|
pub method: String,
|
||||||
|
pub params: XmrRpcSignParams,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
pub struct XmrRpcVerifyRequest {
|
pub struct XmrRpcVerifyRequest {
|
||||||
pub jsonrpc: String,
|
pub jsonrpc: String,
|
||||||
|
@ -328,6 +341,11 @@ pub struct XmrRpcValidateAddressResult {
|
||||||
pub valid: bool,
|
pub valid: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct XmrRpcSignResult {
|
||||||
|
pub signature: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct XmrRpcVerifyResult {
|
pub struct XmrRpcVerifyResult {
|
||||||
pub good: bool,
|
pub good: bool,
|
||||||
|
@ -770,6 +788,21 @@ impl Default for XmrDaemonGetTransactionsResponse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
pub struct XmrRpcSignResponse {
|
||||||
|
pub result: XmrRpcSignResult,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for XmrRpcSignResponse {
|
||||||
|
fn default() -> Self {
|
||||||
|
XmrRpcSignResponse {
|
||||||
|
result: XmrRpcSignResult {
|
||||||
|
signature: utils::empty_string(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct XmrRpcVerifyResponse {
|
pub struct XmrRpcVerifyResponse {
|
||||||
pub result: XmrRpcVerifyResult,
|
pub result: XmrRpcVerifyResult,
|
||||||
|
|
|
@ -12,6 +12,7 @@ pub struct MultisigManagement {
|
||||||
pub completed_kex_final: bool,
|
pub completed_kex_final: bool,
|
||||||
pub completed_export: bool,
|
pub completed_export: bool,
|
||||||
pub completed_funding: bool,
|
pub completed_funding: bool,
|
||||||
|
pub completed_payment_release: bool,
|
||||||
pub completed_prepare: bool,
|
pub completed_prepare: bool,
|
||||||
pub completed_shipping_request: bool,
|
pub completed_shipping_request: bool,
|
||||||
pub completed_make: bool,
|
pub completed_make: bool,
|
||||||
|
@ -33,6 +34,7 @@ impl Default for MultisigManagement {
|
||||||
completed_kex_final: false,
|
completed_kex_final: false,
|
||||||
completed_export: false,
|
completed_export: false,
|
||||||
completed_funding: false,
|
completed_funding: false,
|
||||||
|
completed_payment_release: false,
|
||||||
completed_prepare: false,
|
completed_prepare: false,
|
||||||
completed_shipping_request: false,
|
completed_shipping_request: false,
|
||||||
completed_make: false,
|
completed_make: false,
|
||||||
|
@ -107,6 +109,8 @@ pub struct MarketApp {
|
||||||
_refresh_on_delete_product_rx: Receiver<bool>,
|
_refresh_on_delete_product_rx: Receiver<bool>,
|
||||||
submit_order_tx: Sender<models::Order>,
|
submit_order_tx: Sender<models::Order>,
|
||||||
submit_order_rx: Receiver<models::Order>,
|
submit_order_rx: Receiver<models::Order>,
|
||||||
|
ship_request_tx: Sender<models::Order>,
|
||||||
|
ship_request_rx: Receiver<models::Order>,
|
||||||
s_contact: models::Contact,
|
s_contact: models::Contact,
|
||||||
s_order: models::Order,
|
s_order: models::Order,
|
||||||
vendor_status: utils::ContactStatus,
|
vendor_status: utils::ContactStatus,
|
||||||
|
@ -128,6 +132,7 @@ impl Default for MarketApp {
|
||||||
let (get_vendor_products_tx, get_vendor_products_rx) = std::sync::mpsc::channel();
|
let (get_vendor_products_tx, get_vendor_products_rx) = std::sync::mpsc::channel();
|
||||||
let (get_vendor_product_tx, get_vendor_product_rx) = std::sync::mpsc::channel();
|
let (get_vendor_product_tx, get_vendor_product_rx) = std::sync::mpsc::channel();
|
||||||
let (submit_order_tx, submit_order_rx) = std::sync::mpsc::channel();
|
let (submit_order_tx, submit_order_rx) = std::sync::mpsc::channel();
|
||||||
|
let (ship_request_tx, ship_request_rx) = std::sync::mpsc::channel();
|
||||||
let (our_prepare_info_tx, our_prepare_info_rx) = std::sync::mpsc::channel();
|
let (our_prepare_info_tx, our_prepare_info_rx) = std::sync::mpsc::channel();
|
||||||
let (our_make_info_tx, our_make_info_rx) = std::sync::mpsc::channel();
|
let (our_make_info_tx, our_make_info_rx) = std::sync::mpsc::channel();
|
||||||
let (order_xmr_address_tx, order_xmr_address_rx) = std::sync::mpsc::channel();
|
let (order_xmr_address_tx, order_xmr_address_rx) = std::sync::mpsc::channel();
|
||||||
|
@ -196,6 +201,8 @@ impl Default for MarketApp {
|
||||||
_refresh_on_delete_product_rx,
|
_refresh_on_delete_product_rx,
|
||||||
s_contact: Default::default(),
|
s_contact: Default::default(),
|
||||||
s_order: Default::default(),
|
s_order: Default::default(),
|
||||||
|
ship_request_rx,
|
||||||
|
ship_request_tx,
|
||||||
submit_order_rx,
|
submit_order_rx,
|
||||||
submit_order_tx,
|
submit_order_tx,
|
||||||
vendor_status: Default::default(),
|
vendor_status: Default::default(),
|
||||||
|
@ -294,6 +301,13 @@ impl eframe::App for MarketApp {
|
||||||
self.is_loading = false;
|
self.is_loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Ok(shipped) = self.ship_request_rx.try_recv() {
|
||||||
|
if shipped.status != order::StatusType::Shipped.value() {
|
||||||
|
log::error!("failure to obtain shipment please contact vendor")
|
||||||
|
}
|
||||||
|
self.is_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Vendor status window
|
// Vendor status window
|
||||||
//-----------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------
|
||||||
let mut is_showing_vendor_status = self.is_showing_vendor_status;
|
let mut is_showing_vendor_status = self.is_showing_vendor_status;
|
||||||
|
@ -348,7 +362,7 @@ impl eframe::App for MarketApp {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Customer Multisig Management window
|
// Multisig Management window
|
||||||
//-----------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------
|
||||||
let mut is_managing_multisig = self.is_managing_multisig;
|
let mut is_managing_multisig = self.is_managing_multisig;
|
||||||
egui::Window::new("msig")
|
egui::Window::new("msig")
|
||||||
|
@ -610,22 +624,39 @@ impl eframe::App for MarketApp {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement SOR (secure order retrieval) validate order is MultisigComplete
|
|
||||||
// cache the new order and then implement the async shipping request
|
|
||||||
// use SOR to cache the order and validate order is status Shipped
|
|
||||||
// also the sign api is missing hahaha
|
|
||||||
|
|
||||||
if self.msig.completed_export && !self.msig.completed_shipping_request {
|
if self.msig.completed_export && !self.msig.completed_shipping_request {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
let vendor_prefix = String::from(crate::GUI_OVL_DB_KEY);
|
||||||
|
let vendor = utils::search_gui_db(vendor_prefix, self.m_order.orid.clone());
|
||||||
ui.label("Request Shipping: \t");
|
ui.label("Request Shipping: \t");
|
||||||
if ui.button("Send").clicked() {}
|
if ui.button("Send").clicked() {
|
||||||
if ui.button("Check").clicked() {}
|
self.is_loading = true;
|
||||||
|
let jwp = utils::search_gui_db(
|
||||||
|
String::from(crate::GUI_JWP_DB_KEY),
|
||||||
|
String::from(&vendor),
|
||||||
|
);
|
||||||
|
shipping_req(
|
||||||
|
self.ship_request_tx.clone(),
|
||||||
|
ctx.clone(),
|
||||||
|
&self.m_order.orid,
|
||||||
|
&vendor,
|
||||||
|
&jwp,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ui.button("Check").clicked() {
|
||||||
|
let order = order::find(&self.m_order.orid);
|
||||||
|
if order.status == order::StatusType::Shipped.value() {
|
||||||
|
self.msig.completed_shipping_request = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if self.msig.completed_shipping_request && !self.msig.completed_payment_release {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Release Payment: \t");
|
||||||
|
if ui.button("Submit Txset").clicked() {}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// ui.horizontal(|ui| {
|
|
||||||
// ui.label("Release Payment: \t");
|
|
||||||
// if ui.button("Sign Txset").clicked() {}
|
|
||||||
// });
|
|
||||||
// ui.horizontal(|ui| {
|
// ui.horizontal(|ui| {
|
||||||
// ui.label("Create Dispute: \t\t");
|
// ui.label("Create Dispute: \t\t");
|
||||||
// if ui.button("Dispute").clicked() {}
|
// if ui.button("Dispute").clicked() {}
|
||||||
|
@ -2107,6 +2138,25 @@ fn send_import_info_req(tx: Sender<String>, ctx: egui::Context, orid: &String, v
|
||||||
});
|
});
|
||||||
ctx.request_repaint();
|
ctx.request_repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn shipping_req(
|
||||||
|
tx: Sender<models::Order>,
|
||||||
|
ctx: egui::Context,
|
||||||
|
orid: &String,
|
||||||
|
contact: &String,
|
||||||
|
jwp: &String,
|
||||||
|
) {
|
||||||
|
let ship_orid = String::from(orid);
|
||||||
|
let vendor_i2p = String::from(contact);
|
||||||
|
let v_jwp = String::from(jwp);
|
||||||
|
tokio::spawn(async move {
|
||||||
|
log::info!("shipping order req: {}", ship_orid);
|
||||||
|
let db_key: String = String::from(crate::GUI_OVL_DB_KEY);
|
||||||
|
let order = order::d_trigger_ship_request(&vendor_i2p, &db_key, &v_jwp, &ship_orid).await;
|
||||||
|
let _ = tx.send(order);
|
||||||
|
ctx.request_repaint();
|
||||||
|
});
|
||||||
|
}
|
||||||
// End Async fn requests
|
// End Async fn requests
|
||||||
|
|
||||||
fn validate_msig_step(
|
fn validate_msig_step(
|
||||||
|
|
|
@ -100,6 +100,23 @@ pub async fn sign_and_submit_multisig(
|
||||||
Custom(Status::Ok, Json(Default::default()))
|
Custom(Status::Ok, Json(Default::default()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// API for uploading delivery info in vendor mode
|
||||||
|
///
|
||||||
|
/// Protected: true
|
||||||
|
#[post("/<orid>", data = "<r_data>")]
|
||||||
|
pub async fn upload_delivery_info(
|
||||||
|
orid: String,
|
||||||
|
r_data: Json<reqres::FinalizeOrderResponse>,
|
||||||
|
_token: auth::BearerToken,
|
||||||
|
) -> Custom<Json<reqres::FinalizeOrderResponse>> {
|
||||||
|
let upload: reqres::FinalizeOrderResponse =
|
||||||
|
order::upload_delivery_info(&orid, &r_data.delivery_info).await;
|
||||||
|
if upload.delivery_info.is_empty() {
|
||||||
|
return Custom(Status::BadRequest, Json(Default::default()));
|
||||||
|
}
|
||||||
|
Custom(Status::Ok, Json(upload))
|
||||||
|
}
|
||||||
|
|
||||||
/// toggle vendor mode
|
/// toggle vendor mode
|
||||||
#[get("/")]
|
#[get("/")]
|
||||||
pub async fn toggle_vendor_mode(
|
pub async fn toggle_vendor_mode(
|
||||||
|
|
|
@ -38,4 +38,8 @@ async fn rocket() -> _ {
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.mount("/vendor/mode", routes![controller::toggle_vendor_mode])
|
.mount("/vendor/mode", routes![controller::toggle_vendor_mode])
|
||||||
|
.mount(
|
||||||
|
"/upload/delivery/info",
|
||||||
|
routes![controller::upload_delivery_info],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,40 +178,23 @@ pub async fn rx_multisig_message(
|
||||||
///
|
///
|
||||||
/// with the amount of the order. The vendor will then check
|
/// with the amount of the order. The vendor will then check
|
||||||
///
|
///
|
||||||
/// balance and sanity check `unlock_time`.
|
/// balance and sanity check `unlock_time`. The vendor also releases
|
||||||
|
///
|
||||||
|
/// the draft of the Msig TxSet for the customer to sign and submit
|
||||||
|
///
|
||||||
|
/// once they receive their order.
|
||||||
///
|
///
|
||||||
/// Protected: true
|
/// Protected: true
|
||||||
#[post("/ship/<orid>")]
|
#[post("/ship/<orid>")]
|
||||||
pub async fn request_shipment(
|
pub async fn request_shipment(
|
||||||
orid: String,
|
orid: String,
|
||||||
_jwp: proof::PaymentProof,
|
_jwp: proof::PaymentProof,
|
||||||
) -> Custom<Json<models::Message>> {
|
|
||||||
let is_ready: bool = order::validate_order_for_ship(&orid).await;
|
|
||||||
if !is_ready {
|
|
||||||
return Custom(Status::BadRequest, Json(Default::default()));
|
|
||||||
}
|
|
||||||
Custom(Status::Ok, Json(Default::default()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send tx_data_hex, which is the output from signing
|
|
||||||
///
|
|
||||||
/// a multisig transaction from the order wallet to the
|
|
||||||
///
|
|
||||||
/// vendor's subaddress. After that the vendor will submit the
|
|
||||||
///
|
|
||||||
/// transaction.
|
|
||||||
///
|
|
||||||
/// Protected: true
|
|
||||||
#[post("/finalize/<orid>")]
|
|
||||||
pub async fn finalize_order(
|
|
||||||
orid: String,
|
|
||||||
_jwp: proof::PaymentProof,
|
|
||||||
) -> Custom<Json<reqres::FinalizeOrderResponse>> {
|
) -> Custom<Json<reqres::FinalizeOrderResponse>> {
|
||||||
let is_ready: bool = order::validate_order_for_ship(&orid).await;
|
let finalize: reqres::FinalizeOrderResponse = order::validate_order_for_ship(&orid).await;
|
||||||
if !is_ready {
|
if finalize.delivery_info.is_empty() {
|
||||||
return Custom(Status::BadRequest, Json(Default::default()));
|
return Custom(Status::BadRequest, Json(Default::default()));
|
||||||
}
|
}
|
||||||
Custom(Status::Ok, Json(Default::default()))
|
Custom(Status::Ok, Json(finalize))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a dispute (customer)
|
/// Create a dispute (customer)
|
||||||
|
|
|
@ -42,7 +42,6 @@ async fn rocket() -> _ {
|
||||||
controller::create_dispute,
|
controller::create_dispute,
|
||||||
controller::get_product,
|
controller::get_product,
|
||||||
controller::get_products,
|
controller::get_products,
|
||||||
controller::finalize_order,
|
|
||||||
controller::request_shipment,
|
controller::request_shipment,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue