1use chrono::DateTime;
2use crate::wechat::Wechat;
3use json::{object, JsonValue};
4use crate::alipay::AliPay;
5
6pub mod alipay;
7pub mod wechat;
8
9#[derive(Clone)]
10pub enum Pay {
11 Wechat(Wechat),
12 Alipay(AliPay),
13 None,
14}
15
16impl Pay {
17 pub fn new(data: JsonValue) -> Self {
18 match data["mode"].as_str().unwrap_or("") {
19 "wechat" => Pay::Wechat(Wechat {
20 appid: data["appid"].to_string(),
21 mchid: data["mchid"].to_string(),
22 serial_no: data["serial_no"].to_string(),
23 app_private: data["app_private"].to_string(),
24 secret: data["secret"].to_string(),
25 apikey: data["apikey"].to_string(),
26 }),
27 "alipay" => Pay::Alipay(AliPay {
28 appid: data["appid"].to_string(),
29 sp_mchid: data["sp_mchid"].to_string(),
30 app_private: data["app_private"].to_string(),
31 app_auth_token: data["app_auth_token"].as_str().unwrap_or("").to_string(),
32 }),
33 _ => Pay::None
34 }
35 }
36}
37impl PayMode for Pay {
38 fn login(&mut self, code: &str) -> Result<JsonValue, String> {
39 match self {
40 Self::Wechat(e) => e.login(code),
41 Self::Alipay(e) => e.login(code),
42 Pay::None => Err("No login data".to_owned())
43 }
44 }
45
46 fn jsapi(
48 &mut self,
49 sub_mchid: &str,
50 out_trade_no: &str,
51 description: &str,
52 total_fee: f64,
53 notify_url: &str,
54 sp_openid: &str,
55 ) -> Result<JsonValue, String> {
56 match self {
57 Self::Wechat(e) => e.jsapi(
58 sub_mchid,
59 out_trade_no,
60 description,
61 total_fee,
62 notify_url,
63 sp_openid,
64 ),
65 Self::Alipay(e) => e.jsapi(
66 sub_mchid,
67 out_trade_no,
68 description,
69 total_fee,
70 notify_url,
71 sp_openid,
72 ),
73 Pay::None => Err("No login data".to_owned())
74 }
75 }
76
77 fn pay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
78 match self {
79 Self::Wechat(e) => e.pay_query(
80 out_trade_no,
81 sub_mchid,
82 ),
83 Self::Alipay(e) => e.pay_query(
84 out_trade_no,
85 sub_mchid,
86 ),
87 Pay::None => Err("No login data".to_owned())
88 }
89 }
90
91 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> {
92 match self {
93 Self::Wechat(e) => e.refund(
94 sub_mchid,
95 out_trade_no,
96 transaction_id,
97 out_refund_no,
98 amount,
99 total,
100 currency,
101 ),
102 Self::Alipay(e) => e.refund(
103 sub_mchid,
104 out_trade_no,
105 transaction_id,
106 out_refund_no,
107 amount,
108 total,
109 currency,
110 ),
111 Pay::None => Err("No login data".to_owned())
112 }
113 }
114
115 fn pay_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String> {
116 match self {
117 Self::Wechat(e) => e.pay_notify(
118 nonce,
119 ciphertext,
120 associated_data,
121 ),
122 Self::Alipay(e) => e.pay_notify(
123 nonce,
124 ciphertext,
125 associated_data,
126 ),
127 Pay::None => Err("No login data".to_owned())
128 }
129 }
130
131 fn refund_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String> {
132 match self {
133 Self::Wechat(e) => e.refund_notify(
134 nonce,
135 ciphertext,
136 associated_data,
137 ),
138 Self::Alipay(e) => e.refund_notify(
139 nonce,
140 ciphertext,
141 associated_data,
142 ),
143 Pay::None => Err("No login data".to_owned())
144 }
145 }
146
147 fn refund_query(&mut self, out_refund_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
148 match self {
149 Self::Wechat(e) => e.refund_query(
150 out_refund_no,
151 sub_mchid,
152 ),
153 Self::Alipay(e) => e.refund_query(
154 out_refund_no,
155 sub_mchid,
156 ),
157 Pay::None => Err("No login data".to_owned())
158 }
159 }
160
161 fn auth(&mut self, code: &str) -> Result<JsonValue, String> {
162 match self {
163 Self::Wechat(e) => e.auth(
164 code
165 ),
166 Self::Alipay(e) => e.auth(
167 code
168 ),
169 Pay::None => Err("No login data".to_owned())
170 }
171 }
172
173 fn close(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
174 match self {
175 Self::Wechat(e) => e.close(
176 out_trade_no, sub_mchid,
177 ),
178 Self::Alipay(e) => e.close(
179 out_trade_no, sub_mchid,
180 ),
181 Pay::None => Err("No login data".to_owned())
182 }
183 }
184
185 fn config(&mut self) -> JsonValue {
186 match self {
187 Self::Wechat(e) => object! {
188 sp_mchid:e.mchid.clone(),
189 appid:e.appid.clone(),
190 },
191 Self::Alipay(e) => object! {
192 appid:e.appid.clone(),
193 sp_mchid:e.sp_mchid.clone()
194 },
195 Pay::None => object! {
196 appid:"",
197 sp_mchid:""
198 }
199 }
200 }
201}
202
203pub trait PayMode {
204 fn config(&mut self) -> JsonValue;
205 fn login(&mut self, code: &str) -> Result<JsonValue, String>;
206 fn auth(&mut self, code: &str) -> Result<JsonValue, String>;
207 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>;
215 fn close(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
217 fn pay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
221 fn pay_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String>;
223
224 #[allow(clippy::too_many_arguments)]
225 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>;
227 fn refund_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String>;
229 fn refund_query(&mut self, out_refund_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
231}
232
233#[derive(Debug)]
235pub struct PayNotify {
236 trade_type: TradeType,
238 out_trade_no: String,
240 sp_mchid: String,
242 sub_mchid: String,
244 sp_appid: String,
246 transaction_id: String,
248 success_time: i64,
250 sp_openid: String,
252 sub_openid: String,
254 total: usize,
256 payer_total: usize,
258 currency: String,
260 payer_currency: String,
262 trade_state: TradeState,
264}
265impl PayNotify {
266 pub fn json(&self) -> JsonValue {
267 object! {
268 "trade_type" => self.trade_type.to_string(),
269 "out_trade_no" => self.out_trade_no.to_string(),
270 "sp_mchid" => self.sp_mchid.to_string(),
271 "sub_mchid" => self.sub_mchid.to_string(),
272 "sp_appid" => self.sp_appid.to_string(),
273 "transaction_id" => self.transaction_id.to_string(),
274 "success_time" => self.success_time,
275 "sp_openid" => self.sp_openid.to_string(),
276 "sub_openid" => self.sub_openid.to_string(),
277 "total" => self.total,
278 "payer_total" => self.payer_total,
279 "currency" => self.currency.clone(),
280 "payer_currency" => self.payer_currency.clone(),
281 "trade_state" => self.trade_state.to_string(),
282 }
283 }
284 pub fn success_time(datetime: &str) -> i64 {
285 if datetime.is_empty() {
286 return 0;
287 }
288 let datetime = DateTime::parse_from_rfc3339(datetime).unwrap();
289 datetime.timestamp()
290 }
291}
292#[derive(Debug)]
293pub enum TradeType {
294 JSAPI,
296 None,
297}
298impl TradeType {
299 fn from(code: &str) -> TradeType {
300 match code {
301 "JSAPI" => TradeType::JSAPI,
302 _ => TradeType::None
303 }
304 }
305 fn to_string(&self) -> &'static str {
306 match self {
307 TradeType::JSAPI => "JSAPI",
308 TradeType::None => ""
309 }
310 }
311}
312#[derive(Debug)]
313pub enum TradeState {
314 SUCCESS,
316 REFUND,
318 NOTPAY,
320 CLOSED,
322 REVOKED,
324 USERPAYING,
326 PAYERROR,
328 None,
329}
330impl TradeState {
331 fn from(code: &str) -> TradeState {
332 match code {
333 "SUCCESS" => TradeState::SUCCESS,
334 "REFUND" => TradeState::REFUND,
335 "NOTPAY" => TradeState::NOTPAY,
336 "CLOSED" => TradeState::CLOSED,
337 "REVOKED" => TradeState::REVOKED,
338 "USERPAYING" => TradeState::USERPAYING,
339 "PAYERROR" => TradeState::PAYERROR,
340 _ => TradeState::None
341 }
342 }
343 fn to_string(&self) -> &'static str {
344 match self {
345 TradeState::SUCCESS => "已支付",
346 TradeState::REFUND => "已支付",
347 TradeState::NOTPAY => "待支付",
348 TradeState::CLOSED => "已关闭",
349 TradeState::REVOKED => "已关闭",
350 TradeState::USERPAYING => "待支付",
351 TradeState::PAYERROR => "支付失败",
352 TradeState::None => "待支付"
353 }
354 }
355}
356
357#[derive(Debug)]
358pub enum RefundStatus {
359 SUCCESS,
361 CLOSED,
363 PROCESSING,
365 ABNORMAL,
367 None,
368}
369impl RefundStatus {
370 fn from(code: &str) -> RefundStatus {
371 match code {
372 "SUCCESS" => RefundStatus::SUCCESS,
373 "CLOSED" => RefundStatus::CLOSED,
374 "PROCESSING" => RefundStatus::PROCESSING,
375 "ABNORMAL" => RefundStatus::ABNORMAL,
376 _ => RefundStatus::None
377 }
378 }
379 fn to_string(&self) -> &'static str {
380 match self {
381 RefundStatus::SUCCESS => "已退款",
382 RefundStatus::None => "退款中",
383 RefundStatus::CLOSED => "已关闭",
384 RefundStatus::PROCESSING => "退款中",
385 RefundStatus::ABNORMAL => "退款异常"
386 }
387 }
388}
389#[derive(Debug)]
391pub struct RefundNotify {
392 out_trade_no: String,
394 refund_no: String,
395 sp_mchid: String,
397 sub_mchid: String,
399 transaction_id: String,
401 refund_id: String,
403 success_time: i64,
405 total: f64,
407 refund: f64,
409 payer_total: f64,
411 payer_refund: f64,
413 status: RefundStatus,
415}
416
417impl RefundNotify {
418 pub fn json(&self) -> JsonValue {
419 object! {
420 "out_trade_no" => self.out_trade_no.clone(),
421 "sp_mchid" => self.sp_mchid.clone(),
422 "sub_mchid" => self.sub_mchid.clone(),
423 "transaction_id" => self.transaction_id.clone(),
424 "success_time" => self.success_time,
425 "total" => self.total,
426 "refund" => self.refund,
427 "payer_total" => self.payer_total,
428 "payer_refund" => self.payer_refund,
429 "status" => self.status.to_string(),
430 "refund_no"=>self.refund_no.clone(),
431 "refund_id"=>self.refund_id.clone(),
432 }
433 }
434}