1use chrono::DateTime;
2use crate::wechat::Wechat;
3use json::{object, JsonValue};
4
5pub mod alipay;
6pub mod wechat;
7
8#[derive(Clone)]
9pub enum Pay {
10 Wechat(Wechat),
11 Alipay,
12}
13
14impl Pay {
15 pub fn new(data: JsonValue) -> Self {
16 match data["mode"].as_str().unwrap_or("") {
17 "wechat" => Pay::Wechat(Wechat {
18 appid: data["appid"].to_string(),
19 mchid: data["mchid"].to_string(),
20 serial_no: data["serial_no"].to_string(),
21 cert_path: data["cert_path"].to_string(),
22 secret: data["secret"].to_string(),
23 apikey: data["apikey"].to_string(),
24 }),
25 _ => Pay::Alipay,
26 }
27 }
28}
29impl PayMode for Pay {
30 fn login(&self, code: &str) -> Result<JsonValue, String> {
31 match self {
32 Self::Wechat(e) => e.login(code),
33 Self::Alipay => Err("Alipay alipay".to_string()),
34 }
35 }
36
37 fn jsapi(
39 &mut self,
40 sub_mchid: &str,
41 out_trade_no: &str,
42 description: &str,
43 total_fee: f64,
44 notify_url: &str,
45 sp_openid: &str,
46 ) -> Result<JsonValue, String> {
47 match self {
48 Self::Wechat(e) => e.jsapi(
49 sub_mchid,
50 out_trade_no,
51 description,
52 total_fee,
53 notify_url,
54 sp_openid,
55 ),
56 Self::Alipay => Err("Alipay alipay".to_string()),
57 }
58 }
59
60 fn pay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
61 match self {
62 Self::Wechat(e) => e.pay_query(
63 out_trade_no,
64 sub_mchid,
65 ),
66 Self::Alipay => Err("Alipay alipay".to_string()),
67 }
68 }
69
70 fn refund(&mut self, sub_mchid: &str, out_trade_no: &str, transaction_id: &str, out_refund_no: &str, amount: f64, total: f64, currency: &str) -> Result<JsonValue, String> {
71 match self {
72 Self::Wechat(e) => e.refund(
73 sub_mchid,
74 out_trade_no,
75 transaction_id,
76 out_refund_no,
77 amount,
78 total,
79 currency,
80 ),
81 Self::Alipay => Err("Alipay alipay".to_string()),
82 }
83 }
84
85 fn pay_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String> {
86 match self {
87 Self::Wechat(e) => e.pay_notify(
88 nonce,
89 ciphertext,
90 associated_data,
91 ),
92 Self::Alipay => Err("Alipay alipay".to_string()),
93 }
94 }
95
96 fn refund_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String> {
97 match self {
98 Self::Wechat(e) => e.refund_notify(
99 nonce,
100 ciphertext,
101 associated_data,
102 ),
103 Self::Alipay => Err("Alipay alipay".to_string()),
104 }
105 }
106
107 fn refund_query(&mut self, out_refund_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
108 match self {
109 Self::Wechat(e) => e.refund_query(
110 out_refund_no,
111 sub_mchid,
112 ),
113 Self::Alipay => Err("Alipay alipay".to_string()),
114 }
115 }
116}
117
118pub trait PayMode {
119 fn login(&self, code: &str) -> Result<JsonValue, String>;
120 fn jsapi(&mut self, sub_mchid: &str, out_trade_no: &str, description: &str, total_fee: f64, notify_url: &str, sp_openid: &str) -> Result<JsonValue, String>;
128 fn pay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
132 fn pay_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String>;
134
135 #[allow(clippy::too_many_arguments)]
136 fn refund(&mut self, sub_mchid: &str, out_trade_no: &str, transaction_id: &str, out_refund_no: &str, amount: f64, total: f64, currency: &str) -> Result<JsonValue, String>;
138 fn refund_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String>;
140 fn refund_query(&mut self, out_refund_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
142}
143
144#[derive(Debug)]
146pub struct PayNotify {
147 trade_type: TradeType,
149 out_trade_no: String,
151 sp_mchid: String,
153 sub_mchid: String,
155 sp_appid: String,
157 transaction_id: String,
159 success_time: i64,
161 sp_openid: String,
163 sub_openid: String,
165 total: usize,
167 payer_total: usize,
169 currency: String,
171 payer_currency: String,
173 trade_state: TradeState,
175}
176impl PayNotify {
177 pub fn json(&self) -> JsonValue {
178 object! {
179 "trade_type" => self.trade_type.to_string(),
180 "out_trade_no" => self.out_trade_no.to_string(),
181 "sp_mchid" => self.sp_mchid.to_string(),
182 "sub_mchid" => self.sub_mchid.to_string(),
183 "sp_appid" => self.sp_appid.to_string(),
184 "transaction_id" => self.transaction_id.to_string(),
185 "success_time" => self.success_time,
186 "sp_openid" => self.sp_openid.to_string(),
187 "sub_openid" => self.sub_openid.to_string(),
188 "total" => self.total,
189 "payer_total" => self.payer_total,
190 "currency" => self.currency.clone(),
191 "payer_currency" => self.payer_currency.clone(),
192 "trade_state" => self.trade_state.to_string(),
193 }
194 }
195 pub fn success_time(datetime: &str) -> i64 {
196 if datetime.is_empty() {
197 return 0;
198 }
199 let datetime = DateTime::parse_from_rfc3339(datetime).unwrap();
200 datetime.timestamp()
201 }
202}
203#[derive(Debug)]
204pub enum TradeType {
205 JSAPI,
207 None,
208}
209impl TradeType {
210 fn from(code: &str) -> TradeType {
211 match code {
212 "JSAPI" => TradeType::JSAPI,
213 _ => TradeType::None
214 }
215 }
216 fn to_string(&self) -> &'static str {
217 match self {
218 TradeType::JSAPI => "JSAPI",
219 TradeType::None => ""
220 }
221 }
222}
223#[derive(Debug)]
224pub enum TradeState {
225 SUCCESS,
227 None,
228}
229impl TradeState {
230 fn from(code: &str) -> TradeState {
231 match code {
232 "SUCCESS" => TradeState::SUCCESS,
233 _ => TradeState::None
234 }
235 }
236 fn to_string(&self) -> &'static str {
237 match self {
238 TradeState::SUCCESS => "支付成功",
239 TradeState::None => "未知"
240 }
241 }
242}
243
244#[derive(Debug)]
245pub enum RefundStatus {
246 SUCCESS,
248 None,
249}
250impl RefundStatus {
251 fn from(code: &str) -> RefundStatus {
252 match code {
253 "SUCCESS" => RefundStatus::SUCCESS,
254 _ => RefundStatus::None
255 }
256 }
257 fn to_string(&self) -> &'static str {
258 match self {
259 RefundStatus::SUCCESS => "已退款",
260 RefundStatus::None => "退款中"
261 }
262 }
263}
264#[derive(Debug)]
266pub struct RefundNotify {
267 out_trade_no: String,
269 refund_no: String,
270 sp_mchid: String,
272 sub_mchid: String,
274 transaction_id: String,
276 refund_id: String,
278 success_time: i64,
280 total: f64,
282 refund: f64,
284 payer_total: f64,
286 payer_refund: f64,
288 refund_status: RefundStatus,
290}
291
292impl RefundNotify {
293 pub fn json(&self) -> JsonValue {
294 object! {
295 "out_trade_no" => self.out_trade_no.clone(),
296 "sp_mchid" => self.sp_mchid.clone(),
297 "sub_mchid" => self.sub_mchid.clone(),
298 "transaction_id" => self.transaction_id.clone(),
299 "success_time" => self.success_time,
300 "total" => self.total,
301 "refund" => self.refund,
302 "payer_total" => self.payer_total,
303 "payer_refund" => self.payer_refund,
304 "refund_status" => self.refund_status.to_string(),
305 "refund_no"=>self.refund_no.clone(),
306 "refund_id"=>self.refund_id.clone(),
307 }
308 }
309}