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 sp_mchid: data["sp_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 notify_url: data["notify_url"].to_string(),
27 }),
28 "alipay" => Pay::Alipay(AliPay {
29 appid: data["appid"].to_string(),
30 sp_mchid: data["sp_mchid"].to_string(),
31 app_private: data["app_private"].to_string(),
32 app_auth_token: data["app_auth_token"].as_str().unwrap_or("").to_string(),
33 content_encryp: data["content_encryp"].to_string(),
34 alipay_public_key: data["alipay_public_key"].to_string(),
35 notify_url: data["notify_url"].to_string(),
36 }),
37 _ => Pay::None
38 }
39 }
40}
41impl PayMode for Pay {
42 fn login(&mut self, code: &str) -> Result<JsonValue, String> {
43 match self {
44 Self::Wechat(e) => e.login(code),
45 Self::Alipay(e) => e.login(code),
46 Pay::None => Err("No login data".to_owned())
47 }
48 }
49
50 fn jsapi(
52 &mut self,
53 sub_mchid: &str,
54 out_trade_no: &str,
55 description: &str,
56 total_fee: f64,
57 notify_url: &str,
58 sp_openid: &str,
59 ) -> Result<JsonValue, String> {
60 match self {
61 Self::Wechat(e) => e.jsapi(
62 sub_mchid,
63 out_trade_no,
64 description,
65 total_fee,
66 notify_url,
67 sp_openid,
68 ),
69 Self::Alipay(e) => e.jsapi(
70 sub_mchid,
71 out_trade_no,
72 description,
73 total_fee,
74 notify_url,
75 sp_openid,
76 ),
77 Pay::None => Err("No login data".to_owned())
78 }
79 }
80
81 fn pay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
82 match self {
83 Self::Wechat(e) => e.pay_query(
84 out_trade_no,
85 sub_mchid,
86 ),
87 Self::Alipay(e) => e.pay_query(
88 out_trade_no,
89 sub_mchid,
90 ),
91 Pay::None => Err("No login data".to_owned())
92 }
93 }
94
95 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> {
96 match self {
97 Self::Wechat(e) => e.refund(
98 sub_mchid,
99 out_trade_no,
100 transaction_id,
101 out_refund_no,
102 amount,
103 total,
104 currency,
105 ),
106 Self::Alipay(e) => e.refund(
107 sub_mchid,
108 out_trade_no,
109 transaction_id,
110 out_refund_no,
111 amount,
112 total,
113 currency,
114 ),
115 Pay::None => Err("No login data".to_owned())
116 }
117 }
118
119 fn pay_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String> {
120 match self {
121 Self::Wechat(e) => e.pay_notify(
122 nonce,
123 ciphertext,
124 associated_data,
125 ),
126 Self::Alipay(e) => e.pay_notify(
127 nonce,
128 ciphertext,
129 associated_data,
130 ),
131 Pay::None => Err("No login data".to_owned())
132 }
133 }
134
135 fn refund_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String> {
136 match self {
137 Self::Wechat(e) => e.refund_notify(
138 nonce,
139 ciphertext,
140 associated_data,
141 ),
142 Self::Alipay(e) => e.refund_notify(
143 nonce,
144 ciphertext,
145 associated_data,
146 ),
147 Pay::None => Err("No login data".to_owned())
148 }
149 }
150
151 fn refund_query(&mut self, out_refund_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
152 match self {
153 Self::Wechat(e) => e.refund_query(
154 out_refund_no,
155 sub_mchid,
156 ),
157 Self::Alipay(e) => e.refund_query(
158 out_refund_no,
159 sub_mchid,
160 ),
161 Pay::None => Err("No login data".to_owned())
162 }
163 }
164
165 fn auth(&mut self, code: &str) -> Result<JsonValue, String> {
166 match self {
167 Self::Wechat(e) => e.auth(
168 code
169 ),
170 Self::Alipay(e) => e.auth(
171 code
172 ),
173 Pay::None => Err("No login data".to_owned())
174 }
175 }
176
177 fn close(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
178 match self {
179 Self::Wechat(e) => e.close(
180 out_trade_no, sub_mchid,
181 ),
182 Self::Alipay(e) => e.close(
183 out_trade_no, sub_mchid,
184 ),
185 Pay::None => Err("No login data".to_owned())
186 }
187 }
188
189 fn config(&mut self) -> JsonValue {
190 match self {
191 Self::Wechat(e) => object! {
192 sp_mchid:e.sp_mchid.clone(),
193 appid:e.appid.clone(),
194 },
195 Self::Alipay(e) => object! {
196 appid:e.appid.clone(),
197 sp_mchid:e.sp_mchid.clone()
198 },
199 Pay::None => object! {
200 appid:"",
201 sp_mchid:""
202 }
203 }
204 }
205
206 fn pay(&mut self, types: Types, sub_mchid: &str, out_trade_no: &str, description: &str, total_fee: f64, sp_openid: &str) -> Result<JsonValue, String> {
207 match self {
208 Self::Wechat(e) => e.pay(
209 types,
210 sub_mchid,
211 out_trade_no,
212 description,
213 total_fee,
214 sp_openid,
215 ),
216 Self::Alipay(e) => e.pay(
217 types,
218 sub_mchid,
219 out_trade_no,
220 description,
221 total_fee,
222 sp_openid,
223 ),
224 Pay::None => Err("No login data".to_owned())
225 }
226 }
227}
228
229pub trait PayMode {
230 fn config(&mut self) -> JsonValue;
231 fn login(&mut self, code: &str) -> Result<JsonValue, String>;
232 fn auth(&mut self, code: &str) -> Result<JsonValue, String>;
233
234 fn pay(&mut self, types: Types, sub_mchid: &str, out_trade_no: &str, description: &str, total_fee: f64, sp_openid: &str) -> Result<JsonValue, String>;
236
237 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>;
245 fn close(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
247 fn pay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
251 fn pay_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String>;
253
254 #[allow(clippy::too_many_arguments)]
255 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>;
257 fn refund_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String>;
259 fn refund_query(&mut self, out_refund_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
261}
262
263#[derive(Debug)]
265pub struct PayNotify {
266 trade_type: TradeType,
268 out_trade_no: String,
270 sp_mchid: String,
272 sub_mchid: String,
274 sp_appid: String,
276 transaction_id: String,
278 success_time: i64,
280 sp_openid: String,
282 sub_openid: String,
284 total: usize,
286 payer_total: usize,
288 currency: String,
290 payer_currency: String,
292 trade_state: TradeState,
294}
295impl PayNotify {
296 pub fn json(&self) -> JsonValue {
297 object! {
298 "trade_type" => self.trade_type.to_string(),
299 "out_trade_no" => self.out_trade_no.to_string(),
300 "sp_mchid" => self.sp_mchid.to_string(),
301 "sub_mchid" => self.sub_mchid.to_string(),
302 "sp_appid" => self.sp_appid.to_string(),
303 "transaction_id" => self.transaction_id.to_string(),
304 "success_time" => self.success_time,
305 "sp_openid" => self.sp_openid.to_string(),
306 "sub_openid" => self.sub_openid.to_string(),
307 "total" => self.total,
308 "payer_total" => self.payer_total,
309 "currency" => self.currency.clone(),
310 "payer_currency" => self.payer_currency.clone(),
311 "trade_state" => self.trade_state.to_string(),
312 }
313 }
314 pub fn success_time(datetime: &str) -> i64 {
315 if datetime.is_empty() {
316 return 0;
317 }
318 let datetime = DateTime::parse_from_rfc3339(datetime).unwrap();
319 datetime.timestamp()
320 }
321}
322#[derive(Debug)]
323pub enum TradeType {
324 JSAPI,
326 None,
327}
328impl TradeType {
329 fn from(code: &str) -> TradeType {
330 match code {
331 "JSAPI" => TradeType::JSAPI,
332 _ => TradeType::None
333 }
334 }
335 fn to_string(&self) -> &'static str {
336 match self {
337 TradeType::JSAPI => "JSAPI",
338 TradeType::None => ""
339 }
340 }
341}
342#[derive(Debug)]
343pub enum TradeState {
344 SUCCESS,
346 REFUND,
348 NOTPAY,
350 CLOSED,
352 REVOKED,
354 USERPAYING,
356 PAYERROR,
358 None,
359}
360impl TradeState {
361 fn from(code: &str) -> TradeState {
362 match code {
363 "SUCCESS" => TradeState::SUCCESS,
364 "REFUND" => TradeState::REFUND,
365 "NOTPAY" => TradeState::NOTPAY,
366 "CLOSED" => TradeState::CLOSED,
367 "REVOKED" => TradeState::REVOKED,
368 "USERPAYING" => TradeState::USERPAYING,
369 "PAYERROR" => TradeState::PAYERROR,
370 _ => TradeState::None
371 }
372 }
373 fn to_string(&self) -> &'static str {
374 match self {
375 TradeState::SUCCESS => "已支付",
376 TradeState::REFUND => "已支付",
377 TradeState::NOTPAY => "待支付",
378 TradeState::CLOSED => "已关闭",
379 TradeState::REVOKED => "已关闭",
380 TradeState::USERPAYING => "待支付",
381 TradeState::PAYERROR => "支付失败",
382 TradeState::None => "待支付"
383 }
384 }
385}
386
387#[derive(Debug)]
388pub enum RefundStatus {
389 SUCCESS,
391 CLOSED,
393 PROCESSING,
395 ABNORMAL,
397 None,
398}
399impl RefundStatus {
400 fn from(code: &str) -> RefundStatus {
401 match code {
402 "SUCCESS" => RefundStatus::SUCCESS,
403 "CLOSED" => RefundStatus::CLOSED,
404 "PROCESSING" => RefundStatus::PROCESSING,
405 "ABNORMAL" => RefundStatus::ABNORMAL,
406 _ => RefundStatus::None
407 }
408 }
409 fn to_string(&self) -> &'static str {
410 match self {
411 RefundStatus::SUCCESS => "已退款",
412 RefundStatus::None => "退款中",
413 RefundStatus::CLOSED => "已关闭",
414 RefundStatus::PROCESSING => "退款中",
415 RefundStatus::ABNORMAL => "退款异常"
416 }
417 }
418}
419#[derive(Debug)]
421pub struct RefundNotify {
422 out_trade_no: String,
424 refund_no: String,
425 sp_mchid: String,
427 sub_mchid: String,
429 transaction_id: String,
431 refund_id: String,
433 success_time: i64,
435 total: f64,
437 refund: f64,
439 payer_total: f64,
441 payer_refund: f64,
443 status: RefundStatus,
445}
446
447impl RefundNotify {
448 pub fn json(&self) -> JsonValue {
449 object! {
450 "out_trade_no" => self.out_trade_no.clone(),
451 "sp_mchid" => self.sp_mchid.clone(),
452 "sub_mchid" => self.sub_mchid.clone(),
453 "transaction_id" => self.transaction_id.clone(),
454 "success_time" => self.success_time,
455 "total" => self.total,
456 "refund" => self.refund,
457 "payer_total" => self.payer_total,
458 "payer_refund" => self.payer_refund,
459 "status" => self.status.to_string(),
460 "refund_no"=>self.refund_no.clone(),
461 "refund_id"=>self.refund_id.clone(),
462 }
463 }
464}
465
466pub enum Types {
467 Jsapi,
469 Native,
471 H5,
473 MiniJsapi,
475 App,
477 Micropay,
479}
480impl Types {
481 pub fn str(self) -> &'static str {
482 match self {
483 Types::Jsapi => "jsapi",
484 Types::Native => "native",
485 Types::H5 => "h5",
486 Types::MiniJsapi => "minijsapi",
487 Types::App => "app",
488 Types::Micropay => "micropay"
489 }
490 }
491 pub fn from(name: &str) -> Self {
492 match name {
493 "jsapi" => Types::Jsapi,
494 "native" => Types::Native,
495 "h5" => Types::H5,
496 "minijsapi" => Types::MiniJsapi,
497 "app" => Types::App,
498 "micropay" => Types::Micropay,
499 _ => Types::Jsapi
500 }
501 }
502}