1use chrono::{DateTime, NaiveDateTime};
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 apiv2: data["apiv2"].to_string(),
27 notify_url: data["notify_url"].to_string(),
28 access_token: "".to_string(),
29 expires_in: 0,
30 }),
31 "alipay" => Pay::Alipay(AliPay {
32 appid: data["appid"].to_string(),
33 sp_mchid: data["sp_mchid"].to_string(),
34 app_private: data["app_private"].to_string(),
35 app_auth_token: data["app_auth_token"].as_str().unwrap_or("").to_string(),
36 content_encryp: data["content_encryp"].to_string(),
37 alipay_public_key: data["alipay_public_key"].to_string(),
38 notify_url: data["notify_url"].to_string(),
39 }),
40 _ => Pay::None
41 }
42 }
43}
44impl PayMode for Pay {
45 fn jsapi_ticket(&mut self,url:&str) -> Result<JsonValue, String> {
46 match self {
47 Self::Wechat(e) => e.jsapi_ticket(url),
48 _ => Err("No login data".to_owned())
49 }
50 }
51
52 fn get_openid(&mut self, code: &str) -> Result<JsonValue, String> {
53 match self {
54 Self::Wechat(e) => e.get_openid(code),
55 _ => Err("No login data".to_owned())
56 }
57 }
58
59 fn get_sub_mchid(&mut self, sub_mchid: &str) -> Result<JsonValue, String> {
60 match self {
61 Self::Wechat(e) => e.get_sub_mchid(sub_mchid),
62 Self::Alipay(e) => e.get_sub_mchid(sub_mchid),
63 Pay::None => Err("No login data".to_owned())
64 }
65 }
66
67 fn notify(&mut self, data: JsonValue) -> Result<JsonValue, String> {
68 match self {
69 Self::Wechat(e) => e.notify(data),
70 Self::Alipay(e) => e.notify(data),
71 Pay::None => Err("No login data".to_owned())
72 }
73 }
74
75 fn config(&mut self) -> JsonValue {
76 match self {
77 Self::Wechat(e) => object! {
78 sp_mchid:e.sp_mchid.clone(),
79 appid:e.appid.clone(),
80 },
81 Self::Alipay(e) => object! {
82 appid:e.appid.clone(),
83 sp_mchid:e.sp_mchid.clone()
84 },
85 Pay::None => object! {
86 appid:"",
87 sp_mchid:""
88 }
89 }
90 }
91
92 fn login(&mut self, code: &str) -> Result<JsonValue, String> {
93 match self {
94 Self::Wechat(e) => e.login(code),
95 Self::Alipay(e) => e.login(code),
96 Pay::None => Err("No login data".to_owned())
97 }
98 }
99
100 fn auth(&mut self, code: &str) -> Result<JsonValue, String> {
101 match self {
102 Self::Wechat(e) => e.auth(code),
103 Self::Alipay(e) => e.auth(code),
104 Pay::None => Err("No login data".to_owned())
105 }
106 }
107
108 fn pay(&mut self, types: Types, sub_mchid: &str, out_trade_no: &str, description: &str, total_fee: f64, sp_openid: &str) -> Result<JsonValue, String> {
109 match self {
110 Self::Wechat(e) => e.pay(
111 types,
112 sub_mchid,
113 out_trade_no,
114 description,
115 total_fee,
116 sp_openid,
117 ),
118 Self::Alipay(e) => e.pay(
119 types,
120 sub_mchid,
121 out_trade_no,
122 description,
123 total_fee,
124 sp_openid,
125 ),
126 Pay::None => Err("No login data".to_owned())
127 }
128 }
129
130 fn micropay(&mut self, auth_code: &str, sub_mchid: &str, out_trade_no: &str, description: &str, total_fee: f64, org_openid: &str, ip: &str) -> Result<JsonValue, String> {
131 match self {
132 Self::Wechat(e) => e.micropay(
133 auth_code,
134 sub_mchid,
135 out_trade_no,
136 description,
137 total_fee,
138 org_openid,
139 ip,
140 ),
141 Self::Alipay(e) => e.micropay(
142 auth_code,
143 sub_mchid,
144 out_trade_no,
145 description,
146 total_fee,
147 org_openid,
148 ip,
149 ),
150 Pay::None => Err("No login data".to_owned())
151 }
152 }
153
154 fn close(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
155 match self {
156 Self::Wechat(e) => e.close(
157 out_trade_no, sub_mchid,
158 ),
159 Self::Alipay(e) => e.close(
160 out_trade_no, sub_mchid,
161 ),
162 Pay::None => Err("No login data".to_owned())
163 }
164 }
165
166 fn pay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
167 match self {
168 Self::Wechat(e) => e.pay_query(
169 out_trade_no,
170 sub_mchid,
171 ),
172 Self::Alipay(e) => e.pay_query(
173 out_trade_no,
174 sub_mchid,
175 ),
176 Pay::None => Err("No login data".to_owned())
177 }
178 }
179 fn pay_micropay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
180 match self {
181 Self::Wechat(e) => e.pay_micropay_query(
182 out_trade_no,
183 sub_mchid,
184 ),
185 Self::Alipay(e) => e.pay_query(
186 out_trade_no,
187 sub_mchid,
188 ),
189 Pay::None => Err("No login data".to_owned())
190 }
191 }
192
193 fn pay_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String> {
194 match self {
195 Self::Wechat(e) => e.pay_notify(
196 nonce,
197 ciphertext,
198 associated_data,
199 ),
200 Self::Alipay(e) => e.pay_notify(
201 nonce,
202 ciphertext,
203 associated_data,
204 ),
205 Pay::None => Err("No login data".to_owned())
206 }
207 }
208
209 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> {
210 match self {
211 Self::Wechat(e) => e.refund(
212 sub_mchid,
213 out_trade_no,
214 transaction_id,
215 out_refund_no,
216 amount,
217 total,
218 currency,
219 ),
220 Self::Alipay(e) => e.refund(
221 sub_mchid,
222 out_trade_no,
223 transaction_id,
224 out_refund_no,
225 amount,
226 total,
227 currency,
228 ),
229 Pay::None => Err("No login data".to_owned())
230 }
231 }
232
233 fn micropay_refund(&mut self, sub_mchid: &str, out_trade_no: &str, transaction_id: &str, out_refund_no: &str, amount: f64, total: f64, currency: &str, refund_text: &str) -> Result<JsonValue, String> {
234 match self {
235 Self::Wechat(e) => e.micropay_refund(
236 sub_mchid,
237 out_trade_no,
238 transaction_id,
239 out_refund_no,
240 amount,
241 total,
242 currency,
243 refund_text,
244 ),
245 Self::Alipay(e) => e.refund(
246 sub_mchid,
247 out_trade_no,
248 transaction_id,
249 out_refund_no,
250 amount,
251 total,
252 currency,
253 ),
254 Pay::None => Err("No login data".to_owned())
255 }
256 }
257
258 fn refund_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String> {
259 match self {
260 Self::Wechat(e) => e.refund_notify(
261 nonce,
262 ciphertext,
263 associated_data,
264 ),
265 Self::Alipay(e) => e.refund_notify(
266 nonce,
267 ciphertext,
268 associated_data,
269 ),
270 Pay::None => Err("No login data".to_owned())
271 }
272 }
273
274 fn refund_query(&mut self, trade_no: &str, out_refund_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
275 match self {
276 Self::Wechat(e) => e.refund_query(
277 trade_no,
278 out_refund_no,
279 sub_mchid,
280 ),
281 Self::Alipay(e) => e.refund_query(
282 trade_no,
283 out_refund_no,
284 sub_mchid,
285 ),
286 Pay::None => Err("No login data".to_owned())
287 }
288 }
289}
290
291pub trait PayMode {
292 fn jsapi_ticket(&mut self,url:&str) -> Result<JsonValue, String>;
294 fn get_openid(&mut self,code:&str) -> Result<JsonValue, String>;
295 fn get_sub_mchid(&mut self, sub_mchid: &str) -> Result<JsonValue, String>;
297 fn notify(&mut self, data: JsonValue) -> Result<JsonValue, String>;
298 fn config(&mut self) -> JsonValue;
299 fn login(&mut self, code: &str) -> Result<JsonValue, String>;
300 fn auth(&mut self, code: &str) -> Result<JsonValue, String>;
301
302 fn pay(&mut self, types: Types, sub_mchid: &str, out_trade_no: &str, description: &str, total_fee: f64, sp_openid: &str) -> Result<JsonValue, String>;
310
311 #[allow(clippy::too_many_arguments)]
312 fn micropay(&mut self, auth_code: &str, sub_mchid: &str, out_trade_no: &str, description: &str, total_fee: f64, org_openid: &str, ip: &str) -> Result<JsonValue, String>;
313 fn close(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
315 fn pay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
319 fn pay_micropay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
320 fn pay_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String>;
322
323 #[allow(clippy::too_many_arguments)]
324 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>;
326 #[allow(clippy::too_many_arguments)]
327 fn micropay_refund(&mut self, sub_mchid: &str, out_trade_no: &str, transaction_id: &str, out_refund_no: &str, amount: f64, total: f64, currency: &str, refund_text: &str) -> Result<JsonValue, String>;
328 fn refund_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String>;
330 fn refund_query(&mut self, trade_no: &str, out_refund_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
332}
333
334#[derive(Debug)]
336pub struct PayNotify {
337 trade_type: TradeType,
339 out_trade_no: String,
341 sp_mchid: String,
343 sub_mchid: String,
345 sp_appid: String,
347 transaction_id: String,
349 success_time: i64,
351 sp_openid: String,
353 sub_openid: String,
355 total: f64,
357 payer_total: f64,
359 currency: String,
361 payer_currency: String,
363 trade_state: TradeState,
365}
366impl PayNotify {
367 pub fn json(&self) -> JsonValue {
368 object! {
369 "trade_type" => self.trade_type.to_string(),
370 "out_trade_no" => self.out_trade_no.to_string(),
371 "sp_mchid" => self.sp_mchid.to_string(),
372 "sub_mchid" => self.sub_mchid.to_string(),
373 "sp_appid" => self.sp_appid.to_string(),
374 "transaction_id" => self.transaction_id.to_string(),
375 "success_time" => self.success_time,
376 "sp_openid" => self.sp_openid.to_string(),
377 "sub_openid" => self.sub_openid.to_string(),
378 "total" => self.total,
379 "payer_total" => self.payer_total,
380 "currency" => self.currency.clone(),
381 "payer_currency" => self.payer_currency.clone(),
382 "trade_state" => self.trade_state.to_string(),
383 }
384 }
385 pub fn success_time(datetime: &str) -> i64 {
386 if datetime.is_empty() {
387 return 0;
388 }
389 let datetime = DateTime::parse_from_rfc3339(datetime).unwrap();
390 datetime.timestamp()
391 }
392 pub fn alipay_time(datetime: &str) -> i64 {
393 if datetime.is_empty() {
394 return 0;
395 }
396 let t = NaiveDateTime::parse_from_str(datetime, "%Y-%m-%d %H:%M:%S").unwrap();
397 t.and_utc().timestamp()
398 }
399 pub fn micropay_time(datetime: &str) -> i64 {
400 if datetime.is_empty() {
401 return 0;
402 }
403 let t = NaiveDateTime::parse_from_str(datetime, "%Y%m%d%H%M%S").unwrap();
404 t.and_utc().timestamp()
405 }
406}
407#[derive(Debug)]
408pub enum TradeType {
409 JSAPI,
411 MICROPAY,
412 None,
413}
414impl TradeType {
415 fn from(code: &str) -> TradeType {
416 match code {
417 "JSAPI" => TradeType::JSAPI,
418 "MICROPAY" => TradeType::MICROPAY,
419 _ => TradeType::None
420 }
421 }
422 fn to_string(&self) -> &'static str {
423 match self {
424 TradeType::JSAPI => "JSAPI",
425 TradeType::MICROPAY => "MICROPAY",
426 TradeType::None => ""
427 }
428 }
429}
430#[derive(Debug)]
431pub enum TradeState {
432 SUCCESS,
434 REFUND,
436 NOTPAY,
438 CLOSED,
440 REVOKED,
442 USERPAYING,
444 PAYERROR,
446 None,
447}
448impl TradeState {
449 fn from(code: &str) -> TradeState {
450 match code {
451 "SUCCESS" | "TRADE_SUCCESS" => TradeState::SUCCESS,
452 "REFUND" => TradeState::REFUND,
453 "NOTPAY" | "WAIT_BUYER_PAY" => TradeState::NOTPAY,
454 "CLOSED" | "TRADE_CLOSED" => TradeState::CLOSED,
455 "REVOKED" => TradeState::REVOKED,
456 "USERPAYING" => TradeState::USERPAYING,
457 "PAYERROR" | "TRADE_FINISHED" => TradeState::PAYERROR,
458 _ => TradeState::None
459 }
460 }
461
462 fn to_string(&self) -> &'static str {
463 match self {
464 TradeState::SUCCESS => "已支付",
465 TradeState::REFUND => "已支付",
466 TradeState::NOTPAY => "待支付",
467 TradeState::CLOSED => "已关闭",
468 TradeState::REVOKED => "已关闭",
469 TradeState::USERPAYING => "待支付",
470 TradeState::PAYERROR => "支付失败",
471 TradeState::None => "待支付"
472 }
473 }
474}
475
476#[derive(Debug)]
477pub enum RefundStatus {
478 SUCCESS,
480 CLOSED,
482 PROCESSING,
484 ABNORMAL,
486 None,
487}
488impl RefundStatus {
489 fn from(code: &str) -> RefundStatus {
490 match code {
491 "SUCCESS" | "Y" | "REFUND_SUCCESS" => RefundStatus::SUCCESS,
492 "CLOSED" => RefundStatus::CLOSED,
493 "PROCESSING" | "N" => RefundStatus::PROCESSING,
494 "ABNORMAL" => RefundStatus::ABNORMAL,
495 _ => RefundStatus::None
496 }
497 }
498 fn to_string(&self) -> &'static str {
499 match self {
500 RefundStatus::SUCCESS => "已退款",
501 RefundStatus::None => "退款中",
502 RefundStatus::CLOSED => "已关闭",
503 RefundStatus::PROCESSING => "退款中",
504 RefundStatus::ABNORMAL => "退款异常"
505 }
506 }
507}
508#[derive(Debug)]
510pub struct RefundNotify {
511 out_trade_no: String,
513 refund_no: String,
514 sp_mchid: String,
516 sub_mchid: String,
518 transaction_id: String,
520 refund_id: String,
522 success_time: i64,
524 total: f64,
526 refund: f64,
528 payer_total: f64,
530 payer_refund: f64,
532 status: RefundStatus,
534}
535
536impl RefundNotify {
537 pub fn json(&self) -> JsonValue {
538 object! {
539 "out_trade_no" => self.out_trade_no.clone(),
540 "sp_mchid" => self.sp_mchid.clone(),
541 "sub_mchid" => self.sub_mchid.clone(),
542 "transaction_id" => self.transaction_id.clone(),
543 "success_time" => self.success_time,
544 "total" => self.total,
545 "refund" => self.refund,
546 "payer_total" => self.payer_total,
547 "payer_refund" => self.payer_refund,
548 "status" => self.status.to_string(),
549 "refund_no"=>self.refund_no.clone(),
550 "refund_id"=>self.refund_id.clone()
551 }
552 }
553}
554
555pub enum Types {
556 Jsapi,
558 Native,
560 H5,
562 MiniJsapi,
564 App,
566 Micropay,
568}
569impl Types {
570 pub fn str(self) -> &'static str {
571 match self {
572 Types::Jsapi => "jsapi",
573 Types::Native => "native",
574 Types::H5 => "h5",
575 Types::MiniJsapi => "minijsapi",
576 Types::App => "app",
577 Types::Micropay => "micropay"
578 }
579 }
580 pub fn from(name: &str) -> Self {
581 match name {
582 "jsapi" => Types::Jsapi,
583 "native" => Types::Native,
584 "h5" => Types::H5,
585 "minijsapi" => Types::MiniJsapi,
586 "app" => Types::App,
587 "micropay" => Types::Micropay,
588 _ => Types::Jsapi
589 }
590 }
591}