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 app_private: data["app_private"].to_string(),
30 app_auth_token: data["app_auth_token"].as_str().unwrap_or("").to_string(),
31 }),
32 _=>Pay::None
33 }
34 }
35}
36impl PayMode for Pay {
37 fn login(&mut self, code: &str) -> Result<JsonValue, String> {
38 match self {
39 Self::Wechat(e) => e.login(code),
40 Self::Alipay(e) => e.login(code),
41 Pay::None => Err("No login data".to_owned())
42 }
43 }
44
45 fn jsapi(
47 &mut self,
48 sub_mchid: &str,
49 out_trade_no: &str,
50 description: &str,
51 total_fee: f64,
52 notify_url: &str,
53 sp_openid: &str,
54 ) -> Result<JsonValue, String> {
55 match self {
56 Self::Wechat(e) => e.jsapi(
57 sub_mchid,
58 out_trade_no,
59 description,
60 total_fee,
61 notify_url,
62 sp_openid,
63 ),
64 Self::Alipay(e) => e.jsapi(
65 sub_mchid,
66 out_trade_no,
67 description,
68 total_fee,
69 notify_url,
70 sp_openid,
71 ),
72 Pay::None => Err("No login data".to_owned())
73 }
74 }
75
76 fn pay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
77 match self {
78 Self::Wechat(e) => e.pay_query(
79 out_trade_no,
80 sub_mchid,
81 ),
82 Self::Alipay(e) => e.pay_query(
83 out_trade_no,
84 sub_mchid,
85 ),
86 Pay::None => Err("No login data".to_owned())
87
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
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
133 fn refund_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String> {
134 match self {
135 Self::Wechat(e) => e.refund_notify(
136 nonce,
137 ciphertext,
138 associated_data,
139 ),
140 Self::Alipay(e) => e.refund_notify(
141 nonce,
142 ciphertext,
143 associated_data,
144 ),
145 Pay::None => Err("No login data".to_owned())
146
147 }
148 }
149
150 fn refund_query(&mut self, out_refund_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
151 match self {
152 Self::Wechat(e) => e.refund_query(
153 out_refund_no,
154 sub_mchid,
155 ),
156 Self::Alipay(e) => e.refund_query(
157 out_refund_no,
158 sub_mchid,
159 ),
160 Pay::None => Err("No login data".to_owned())
161 }
162 }
163
164 fn auth(&mut self, code: &str) -> Result<JsonValue, String> {
165 match self {
166 Self::Wechat(e) => e.auth(
167 code
168 ),
169 Self::Alipay(e) => e.auth(
170 code
171 ),
172 Pay::None => Err("No login data".to_owned())
173 }
174 }
175
176 fn close(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String> {
177 match self {
178 Self::Wechat(e) => e.close(
179 out_trade_no,sub_mchid
180 ),
181 Self::Alipay(e) => e.close(
182 out_trade_no,sub_mchid
183 ),
184 Pay::None => Err("No login data".to_owned())
185 }
186 }
187}
188
189pub trait PayMode {
190 fn login(&mut self, code: &str) -> Result<JsonValue, String>;
191 fn auth(&mut self, code: &str) -> Result<JsonValue, String>;
192 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>;
200 fn close(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
202 fn pay_query(&mut self, out_trade_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
206 fn pay_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String>;
208
209 #[allow(clippy::too_many_arguments)]
210 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>;
212 fn refund_notify(&mut self, nonce: &str, ciphertext: &str, associated_data: &str) -> Result<JsonValue, String>;
214 fn refund_query(&mut self, out_refund_no: &str, sub_mchid: &str) -> Result<JsonValue, String>;
216}
217
218#[derive(Debug)]
220pub struct PayNotify {
221 trade_type: TradeType,
223 out_trade_no: String,
225 sp_mchid: String,
227 sub_mchid: String,
229 sp_appid: String,
231 transaction_id: String,
233 success_time: i64,
235 sp_openid: String,
237 sub_openid: String,
239 total: usize,
241 payer_total: usize,
243 currency: String,
245 payer_currency: String,
247 trade_state: TradeState,
249}
250impl PayNotify {
251 pub fn json(&self) -> JsonValue {
252 object! {
253 "trade_type" => self.trade_type.to_string(),
254 "out_trade_no" => self.out_trade_no.to_string(),
255 "sp_mchid" => self.sp_mchid.to_string(),
256 "sub_mchid" => self.sub_mchid.to_string(),
257 "sp_appid" => self.sp_appid.to_string(),
258 "transaction_id" => self.transaction_id.to_string(),
259 "success_time" => self.success_time,
260 "sp_openid" => self.sp_openid.to_string(),
261 "sub_openid" => self.sub_openid.to_string(),
262 "total" => self.total,
263 "payer_total" => self.payer_total,
264 "currency" => self.currency.clone(),
265 "payer_currency" => self.payer_currency.clone(),
266 "trade_state" => self.trade_state.to_string(),
267 }
268 }
269 pub fn success_time(datetime: &str) -> i64 {
270 if datetime.is_empty() {
271 return 0;
272 }
273 let datetime = DateTime::parse_from_rfc3339(datetime).unwrap();
274 datetime.timestamp()
275 }
276}
277#[derive(Debug)]
278pub enum TradeType {
279 JSAPI,
281 None,
282}
283impl TradeType {
284 fn from(code: &str) -> TradeType {
285 match code {
286 "JSAPI" => TradeType::JSAPI,
287 _ => TradeType::None
288 }
289 }
290 fn to_string(&self) -> &'static str {
291 match self {
292 TradeType::JSAPI => "JSAPI",
293 TradeType::None => ""
294 }
295 }
296}
297#[derive(Debug)]
298pub enum TradeState {
299 SUCCESS,
301 REFUND,
303 NOTPAY,
305 CLOSED,
307 REVOKED,
309 USERPAYING,
311 PAYERROR,
313 None,
314}
315impl TradeState {
316 fn from(code: &str) -> TradeState {
317 match code {
318 "SUCCESS" => TradeState::SUCCESS,
319 "REFUND" => TradeState::REFUND,
320 "NOTPAY" => TradeState::NOTPAY,
321 "CLOSED" => TradeState::CLOSED,
322 "REVOKED" => TradeState::REVOKED,
323 "USERPAYING" => TradeState::USERPAYING,
324 "PAYERROR" => TradeState::PAYERROR,
325 _ => TradeState::None
326 }
327 }
328 fn to_string(&self) -> &'static str {
329 match self {
330 TradeState::SUCCESS => "已支付",
331 TradeState::REFUND => "已支付",
332 TradeState::NOTPAY => "待支付",
333 TradeState::CLOSED => "已关闭",
334 TradeState::REVOKED => "已关闭",
335 TradeState::USERPAYING => "待支付",
336 TradeState::PAYERROR => "支付失败",
337 TradeState::None => "待支付"
338 }
339 }
340}
341
342#[derive(Debug)]
343pub enum RefundStatus {
344 SUCCESS,
346 CLOSED,
348 PROCESSING,
350 ABNORMAL,
352 None,
353}
354impl RefundStatus {
355 fn from(code: &str) -> RefundStatus {
356 match code {
357 "SUCCESS" => RefundStatus::SUCCESS,
358 "CLOSED" => RefundStatus::CLOSED,
359 "PROCESSING" => RefundStatus::PROCESSING,
360 "ABNORMAL" => RefundStatus::ABNORMAL,
361 _ => RefundStatus::None
362 }
363 }
364 fn to_string(&self) -> &'static str {
365 match self {
366 RefundStatus::SUCCESS => "已退款",
367 RefundStatus::None => "退款中",
368 RefundStatus::CLOSED => "已关闭",
369 RefundStatus::PROCESSING => "退款中",
370 RefundStatus::ABNORMAL => "退款异常"
371 }
372 }
373}
374#[derive(Debug)]
376pub struct RefundNotify {
377 out_trade_no: String,
379 refund_no: String,
380 sp_mchid: String,
382 sub_mchid: String,
384 transaction_id: String,
386 refund_id: String,
388 success_time: i64,
390 total: f64,
392 refund: f64,
394 payer_total: f64,
396 payer_refund: f64,
398 status: RefundStatus,
400}
401
402impl RefundNotify {
403 pub fn json(&self) -> JsonValue {
404 object! {
405 "out_trade_no" => self.out_trade_no.clone(),
406 "sp_mchid" => self.sp_mchid.clone(),
407 "sub_mchid" => self.sub_mchid.clone(),
408 "transaction_id" => self.transaction_id.clone(),
409 "success_time" => self.success_time,
410 "total" => self.total,
411 "refund" => self.refund,
412 "payer_total" => self.payer_total,
413 "payer_refund" => self.payer_refund,
414 "status" => self.status.to_string(),
415 "refund_no"=>self.refund_no.clone(),
416 "refund_id"=>self.refund_id.clone(),
417 }
418 }
419}