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 content_encryp: data["content_encryp"].to_string(),
33 }),
34 _ => Pay::None
35 }
36 }
37}
38impl PayMode for Pay {
39 fn login(&mut self, code: &str) -> Result<JsonValue, String> {
40 match self {
41 Self::Wechat(e) => e.login(code),
42 Self::Alipay(e) => e.login(code),
43 Pay::None => Err("No login data".to_owned())
44 }
45 }
46
47 fn jsapi(
49 &mut self,
50 sub_mchid: &str,
51 out_trade_no: &str,
52 description: &str,
53 total_fee: f64,
54 notify_url: &str,
55 sp_openid: &str,
56 ) -> Result<JsonValue, String> {
57 match self {
58 Self::Wechat(e) => e.jsapi(
59 sub_mchid,
60 out_trade_no,
61 description,
62 total_fee,
63 notify_url,
64 sp_openid,
65 ),
66 Self::Alipay(e) => e.jsapi(
67 sub_mchid,
68 out_trade_no,
69 description,
70 total_fee,
71 notify_url,
72 sp_openid,
73 ),
74 Pay::None => Err("No login data".to_owned())
75 }
76 }
77
78 fn pay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
79 match self {
80 Self::Wechat(e) => e.pay_query(
81 out_trade_no,
82 sub_mchid,
83 ),
84 Self::Alipay(e) => e.pay_query(
85 out_trade_no,
86 sub_mchid,
87 ),
88 Pay::None => Err("No login data".to_owned())
89 }
90 }
91
92 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> {
93 match self {
94 Self::Wechat(e) => e.refund(
95 sub_mchid,
96 out_trade_no,
97 transaction_id,
98 out_refund_no,
99 amount,
100 total,
101 currency,
102 ),
103 Self::Alipay(e) => e.refund(
104 sub_mchid,
105 out_trade_no,
106 transaction_id,
107 out_refund_no,
108 amount,
109 total,
110 currency,
111 ),
112 Pay::None => Err("No login data".to_owned())
113 }
114 }
115
116 fn pay_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String> {
117 match self {
118 Self::Wechat(e) => e.pay_notify(
119 nonce,
120 ciphertext,
121 associated_data,
122 ),
123 Self::Alipay(e) => e.pay_notify(
124 nonce,
125 ciphertext,
126 associated_data,
127 ),
128 Pay::None => Err("No login data".to_owned())
129 }
130 }
131
132 fn refund_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String> {
133 match self {
134 Self::Wechat(e) => e.refund_notify(
135 nonce,
136 ciphertext,
137 associated_data,
138 ),
139 Self::Alipay(e) => e.refund_notify(
140 nonce,
141 ciphertext,
142 associated_data,
143 ),
144 Pay::None => Err("No login data".to_owned())
145 }
146 }
147
148 fn refund_query(&mut self, out_refund_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
149 match self {
150 Self::Wechat(e) => e.refund_query(
151 out_refund_no,
152 sub_mchid,
153 ),
154 Self::Alipay(e) => e.refund_query(
155 out_refund_no,
156 sub_mchid,
157 ),
158 Pay::None => Err("No login data".to_owned())
159 }
160 }
161
162 fn auth(&mut self, code: &str) -> Result<JsonValue, String> {
163 match self {
164 Self::Wechat(e) => e.auth(
165 code
166 ),
167 Self::Alipay(e) => e.auth(
168 code
169 ),
170 Pay::None => Err("No login data".to_owned())
171 }
172 }
173
174 fn close(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
175 match self {
176 Self::Wechat(e) => e.close(
177 out_trade_no, sub_mchid,
178 ),
179 Self::Alipay(e) => e.close(
180 out_trade_no, sub_mchid,
181 ),
182 Pay::None => Err("No login data".to_owned())
183 }
184 }
185
186 fn config(&mut self) -> JsonValue {
187 match self {
188 Self::Wechat(e) => object! {
189 sp_mchid:e.mchid.clone(),
190 appid:e.appid.clone(),
191 },
192 Self::Alipay(e) => object! {
193 appid:e.appid.clone(),
194 sp_mchid:e.sp_mchid.clone()
195 },
196 Pay::None => object! {
197 appid:"",
198 sp_mchid:""
199 }
200 }
201 }
202
203 fn pay(&mut self, types: Types, sub_mchid: &str, out_trade_no: &str, description: &str, total_fee: f64, notify_url: &str, sp_openid: &str) -> Result<JsonValue, String> {
204 match self {
205 Self::Wechat(e) => e.pay(
206 types,
207 sub_mchid,
208 out_trade_no,
209 description,
210 total_fee,
211 notify_url,
212 sp_openid,
213 ),
214 Self::Alipay(e) => e.pay(
215 types,
216 sub_mchid,
217 out_trade_no,
218 description,
219 total_fee,
220 notify_url,
221 sp_openid,
222 ),
223 Pay::None => Err("No login data".to_owned())
224 }
225 }
226}
227
228pub trait PayMode {
229 fn config(&mut self) -> JsonValue;
230 fn login(&mut self, code: &str) -> Result<JsonValue, String>;
231 fn auth(&mut self, code: &str) -> Result<JsonValue, String>;
232
233 fn pay(&mut self, types: Types, sub_mchid: &str, out_trade_no: &str, description: &str, total_fee: f64, notify_url: &str, sp_openid: &str) -> Result<JsonValue, String>;
235
236 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>;
244 fn close(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
246 fn pay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
250 fn pay_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String>;
252
253 #[allow(clippy::too_many_arguments)]
254 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>;
256 fn refund_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String>;
258 fn refund_query(&mut self, out_refund_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
260}
261
262#[derive(Debug)]
264pub struct PayNotify {
265 trade_type: TradeType,
267 out_trade_no: String,
269 sp_mchid: String,
271 sub_mchid: String,
273 sp_appid: String,
275 transaction_id: String,
277 success_time: i64,
279 sp_openid: String,
281 sub_openid: String,
283 total: usize,
285 payer_total: usize,
287 currency: String,
289 payer_currency: String,
291 trade_state: TradeState,
293}
294impl PayNotify {
295 pub fn json(&self) -> JsonValue {
296 object! {
297 "trade_type" => self.trade_type.to_string(),
298 "out_trade_no" => self.out_trade_no.to_string(),
299 "sp_mchid" => self.sp_mchid.to_string(),
300 "sub_mchid" => self.sub_mchid.to_string(),
301 "sp_appid" => self.sp_appid.to_string(),
302 "transaction_id" => self.transaction_id.to_string(),
303 "success_time" => self.success_time,
304 "sp_openid" => self.sp_openid.to_string(),
305 "sub_openid" => self.sub_openid.to_string(),
306 "total" => self.total,
307 "payer_total" => self.payer_total,
308 "currency" => self.currency.clone(),
309 "payer_currency" => self.payer_currency.clone(),
310 "trade_state" => self.trade_state.to_string(),
311 }
312 }
313 pub fn success_time(datetime: &str) -> i64 {
314 if datetime.is_empty() {
315 return 0;
316 }
317 let datetime = DateTime::parse_from_rfc3339(datetime).unwrap();
318 datetime.timestamp()
319 }
320}
321#[derive(Debug)]
322pub enum TradeType {
323 JSAPI,
325 None,
326}
327impl TradeType {
328 fn from(code: &str) -> TradeType {
329 match code {
330 "JSAPI" => TradeType::JSAPI,
331 _ => TradeType::None
332 }
333 }
334 fn to_string(&self) -> &'static str {
335 match self {
336 TradeType::JSAPI => "JSAPI",
337 TradeType::None => ""
338 }
339 }
340}
341#[derive(Debug)]
342pub enum TradeState {
343 SUCCESS,
345 REFUND,
347 NOTPAY,
349 CLOSED,
351 REVOKED,
353 USERPAYING,
355 PAYERROR,
357 None,
358}
359impl TradeState {
360 fn from(code: &str) -> TradeState {
361 match code {
362 "SUCCESS" => TradeState::SUCCESS,
363 "REFUND" => TradeState::REFUND,
364 "NOTPAY" => TradeState::NOTPAY,
365 "CLOSED" => TradeState::CLOSED,
366 "REVOKED" => TradeState::REVOKED,
367 "USERPAYING" => TradeState::USERPAYING,
368 "PAYERROR" => TradeState::PAYERROR,
369 _ => TradeState::None
370 }
371 }
372 fn to_string(&self) -> &'static str {
373 match self {
374 TradeState::SUCCESS => "已支付",
375 TradeState::REFUND => "已支付",
376 TradeState::NOTPAY => "待支付",
377 TradeState::CLOSED => "已关闭",
378 TradeState::REVOKED => "已关闭",
379 TradeState::USERPAYING => "待支付",
380 TradeState::PAYERROR => "支付失败",
381 TradeState::None => "待支付"
382 }
383 }
384}
385
386#[derive(Debug)]
387pub enum RefundStatus {
388 SUCCESS,
390 CLOSED,
392 PROCESSING,
394 ABNORMAL,
396 None,
397}
398impl RefundStatus {
399 fn from(code: &str) -> RefundStatus {
400 match code {
401 "SUCCESS" => RefundStatus::SUCCESS,
402 "CLOSED" => RefundStatus::CLOSED,
403 "PROCESSING" => RefundStatus::PROCESSING,
404 "ABNORMAL" => RefundStatus::ABNORMAL,
405 _ => RefundStatus::None
406 }
407 }
408 fn to_string(&self) -> &'static str {
409 match self {
410 RefundStatus::SUCCESS => "已退款",
411 RefundStatus::None => "退款中",
412 RefundStatus::CLOSED => "已关闭",
413 RefundStatus::PROCESSING => "退款中",
414 RefundStatus::ABNORMAL => "退款异常"
415 }
416 }
417}
418#[derive(Debug)]
420pub struct RefundNotify {
421 out_trade_no: String,
423 refund_no: String,
424 sp_mchid: String,
426 sub_mchid: String,
428 transaction_id: String,
430 refund_id: String,
432 success_time: i64,
434 total: f64,
436 refund: f64,
438 payer_total: f64,
440 payer_refund: f64,
442 status: RefundStatus,
444}
445
446impl RefundNotify {
447 pub fn json(&self) -> JsonValue {
448 object! {
449 "out_trade_no" => self.out_trade_no.clone(),
450 "sp_mchid" => self.sp_mchid.clone(),
451 "sub_mchid" => self.sub_mchid.clone(),
452 "transaction_id" => self.transaction_id.clone(),
453 "success_time" => self.success_time,
454 "total" => self.total,
455 "refund" => self.refund,
456 "payer_total" => self.payer_total,
457 "payer_refund" => self.payer_refund,
458 "status" => self.status.to_string(),
459 "refund_no"=>self.refund_no.clone(),
460 "refund_id"=>self.refund_id.clone(),
461 }
462 }
463}
464
465pub enum Types {
466 Jsapi,
468 Native,
470 H5,
472 MiniJsapi,
474 App,
476 Micropay,
478}
479impl Types {
480 pub fn str(self) -> &'static str {
481 match self {
482 Types::Jsapi => "jsapi",
483 Types::Native => "native",
484 Types::H5 => "h5",
485 Types::MiniJsapi => "jsapi",
486 Types::App => "app",
487 Types::Micropay => "micropay"
488 }
489 }
490}