1use crate::{order::Order, user::User, user::UserInfo};
2use chrono::Utc;
3use nostr_sdk::Timestamp;
4use serde::{Deserialize, Serialize};
5#[cfg(feature = "sqlx")]
6use sqlx::{FromRow, Type};
7#[cfg(feature = "sqlx")]
8use sqlx_crud::SqlxCrud;
9use std::{fmt::Display, str::FromStr};
10use uuid::Uuid;
11
12#[cfg_attr(feature = "sqlx", derive(Type))]
14#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
15#[serde(rename_all = "kebab-case")]
16pub enum Status {
17 #[default]
19 Initiated,
20 InProgress,
22 SellerRefunded,
24 Settled,
26 Released,
28}
29
30impl Display for Status {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 match self {
33 Status::Initiated => write!(f, "initiated"),
34 Status::InProgress => write!(f, "in-progress"),
35 Status::SellerRefunded => write!(f, "seller-refunded"),
36 Status::Settled => write!(f, "settled"),
37 Status::Released => write!(f, "released"),
38 }
39 }
40}
41
42impl FromStr for Status {
43 type Err = ();
44
45 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
46 match s {
47 "initiated" => std::result::Result::Ok(Self::Initiated),
48 "in-progress" => std::result::Result::Ok(Self::InProgress),
49 "seller-refunded" => std::result::Result::Ok(Self::SellerRefunded),
50 "settled" => std::result::Result::Ok(Self::Settled),
51 "released" => std::result::Result::Ok(Self::Released),
52 _ => Err(()),
53 }
54 }
55}
56
57#[cfg_attr(feature = "sqlx", derive(FromRow, SqlxCrud), external_id)]
59#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
60pub struct Dispute {
61 pub id: Uuid,
63 pub order_id: Uuid,
65 pub status: String,
67 pub order_previous_status: String,
69 pub solver_pubkey: Option<String>,
71 pub created_at: i64,
73 pub taken_at: i64,
75}
76
77#[derive(Debug, Default, Deserialize, Serialize, Clone)]
78pub struct SolverDisputeInfo {
79 pub id: Uuid,
80 pub kind: String,
81 pub status: String,
82 pub hash: Option<String>,
83 pub preimage: Option<String>,
84 pub order_previous_status: String,
85 pub initiator_pubkey: String,
86 pub buyer_pubkey: Option<String>,
87 pub seller_pubkey: Option<String>,
88 pub initiator_full_privacy: bool,
89 pub counterpart_full_privacy: bool,
90 pub initiator_info: Option<UserInfo>,
91 pub counterpart_info: Option<UserInfo>,
92 pub premium: i64,
93 pub payment_method: String,
94 pub amount: i64,
95 pub fiat_amount: i64,
96 pub fee: i64,
97 pub routing_fee: i64,
98 pub buyer_invoice: Option<String>,
99 pub invoice_held_at: i64,
100 pub taken_at: i64,
101 pub created_at: i64,
102}
103
104impl SolverDisputeInfo {
105 pub fn new(
106 order: &Order,
107 dispute: &Dispute,
108 initiator_tradekey: String,
109 counterpart: Option<User>,
110 initiator: Option<User>,
111 ) -> Self {
112 let mut initiator_info = None;
114 let mut counterpart_info = None;
115 let mut initiator_full_privacy = true;
116 let mut counterpart_full_privacy = true;
117
118 if let Some(initiator) = initiator {
119 let now = Timestamp::now();
120 let initiator_operating_days = (now.as_u64() - initiator.created_at as u64) / 86400;
121 initiator_info = Some(UserInfo {
122 rating: initiator.total_rating,
123 reviews: initiator.total_reviews,
124 operating_days: initiator_operating_days,
125 });
126 initiator_full_privacy = false;
127 }
128 if let Some(counterpart) = counterpart {
129 let now = Timestamp::now();
130 let couterpart_operating_days = (now.as_u64() - counterpart.created_at as u64) / 86400;
131 counterpart_info = Some(UserInfo {
132 rating: counterpart.total_rating,
133 reviews: counterpart.total_reviews,
134 operating_days: couterpart_operating_days,
135 });
136 counterpart_full_privacy = false;
137 }
138
139 Self {
140 id: order.id,
141 kind: order.kind.clone(),
142 status: order.status.clone(),
143 hash: order.hash.clone(),
144 preimage: order.preimage.clone(),
145 order_previous_status: dispute.order_previous_status.clone(),
146 initiator_pubkey: initiator_tradekey,
147 buyer_pubkey: order.buyer_pubkey.clone(),
148 seller_pubkey: order.seller_pubkey.clone(),
149 initiator_full_privacy,
150 counterpart_full_privacy,
151 counterpart_info,
152 initiator_info,
153 premium: order.premium,
154 payment_method: order.payment_method.clone(),
155 amount: order.amount,
156 fiat_amount: order.fiat_amount,
157 fee: order.fee,
158 routing_fee: order.routing_fee,
159 buyer_invoice: order.buyer_invoice.clone(),
160 invoice_held_at: order.invoice_held_at,
161 taken_at: order.taken_at,
162 created_at: order.created_at,
163 }
164 }
165}
166
167impl Dispute {
168 pub fn new(order_id: Uuid, order_status: String) -> Self {
169 Self {
170 id: Uuid::new_v4(),
171 order_id,
172 status: Status::Initiated.to_string(),
173 order_previous_status: order_status,
174 solver_pubkey: None,
175 created_at: Utc::now().timestamp(),
176 taken_at: 0,
177 }
178 }
179}