1#![allow(unused)]
3use std::collections::HashMap;
5use std::hash::BuildHasher;
6
7use std::borrow::{Borrow, BorrowMut};
10use std::sync::Arc;
11
12use crate::error::AliPaySDKError::AliPayError;
13use crate::error::{AliPayResult, AliPaySDKError};
14use crate::sign::{builder, Signer};
15use gostd::builtin::byte;
16use gostd::net::http;
17use gostd::net::url;
18use serde::{Deserialize, Serialize};
19
20use crate::biz::{
21 self, BizContenter, BizObject, TradeAppPayBiz, TradeCancelBiz, TradeCloseBiz, TradeCreateBiz,
22 TradeFastpayRefundQueryBiz, TradeOrderSettleBiz, TradeOrderSettleQueryBiz, TradePagePayBiz,
23 TradePageRefundBiz, TradePayBiz, TradePrecreateBiz, TradeQueryBiz, TradeRefundBiz,
24 TradeRoyaltyRelationBindBiz, TradeRoyaltyRelationUnBindBiz, TradeWapPayBiz,
25};
26use crate::request::{Request, Requester};
27use crate::response::{
28 self, TradeCancelResponse, TradeCloseResponse, TradeCreateResponse,
29 TradeFastpayRefundQueryResponse, TradeOrderSettleQueryResponse, TradeOrderSettleResponse,
30 TradePageRefundResponse, TradePayResponse, TradePrecreateResponse, TradeQueryResponse,
31 TradeRefundResponse, TradeRoyaltyRelationBindResponse, TradeRoyaltyRelationUnBindResponse,
32};
33use crate::util::{self, build_form, json_get};
34pub trait Payer {
35 fn trade_create(&self, biz_content: &TradeCreateBiz) -> AliPayResult<TradeCreateResponse>;
36
37 fn trade_pay(&self, biz_content: &TradePayBiz) -> AliPayResult<TradePayResponse>;
38
39 fn trade_precreate(
40 &self,
41 biz_content: &TradePrecreateBiz,
42 ) -> AliPayResult<TradePrecreateResponse>;
43
44 fn trade_app_pay(&self, biz_content: &TradeAppPayBiz) -> AliPayResult<String>;
45
46 fn trade_wap_pay(&self, biz_content: &TradeWapPayBiz) -> AliPayResult<String>;
47
48 fn trade_page_pay(&self, biz_content: &TradePagePayBiz) -> AliPayResult<String>;
49
50 fn trade_query(&self, biz_content: &TradeQueryBiz) -> AliPayResult<TradeQueryResponse>;
51
52 fn trade_cancel(&self, biz_content: &TradeCancelBiz) -> AliPayResult<TradeCancelResponse>;
53
54 fn trade_refund(&self, biz_content: &TradeRefundBiz) -> AliPayResult<TradeRefundResponse>;
55
56 fn trade_page_refund(
57 &self,
58 biz_content: &TradePageRefundBiz,
59 ) -> AliPayResult<TradePageRefundResponse>;
60 fn trade_fastpay_refund_query(
61 &self,
62 biz_content: &TradeFastpayRefundQueryBiz,
63 ) -> AliPayResult<TradeFastpayRefundQueryResponse>;
64
65 fn trade_order_settle(
66 &self,
67 biz_content: &TradeOrderSettleBiz,
68 ) -> AliPayResult<TradeOrderSettleResponse>;
69
70 fn trade_order_settle_query(
71 &self,
72 biz_content: &TradeOrderSettleQueryBiz,
73 ) -> AliPayResult<TradeOrderSettleQueryResponse>;
74
75 fn trade_royalty_relation_bind(
76 &self,
77 biz_content: &TradeRoyaltyRelationBindBiz,
78 ) -> AliPayResult<TradeRoyaltyRelationBindResponse>;
79
80 fn trade_royalty_relation_unbind(
81 &self,
82 biz_content: &TradeRoyaltyRelationUnBindBiz,
83 ) -> AliPayResult<TradeRoyaltyRelationUnBindResponse>;
84
85 fn trade_close(&self, biz_content: &TradeCloseBiz) -> AliPayResult<TradeCloseResponse>;
86 fn async_verify_sign(&self, raw_body: &[u8]) -> AliPayResult<bool>;
87}
88
89#[derive(Debug, Default)]
120pub struct PayClient {
121 api_url: String, private_key: String, public_key: String, alipay_public_key: String, app_cert_sn: String, alipay_root_cert_sn: String, app_id: String, format: String, charset: String, sign_type: String, version: String, return_url: String, notify_url: String, }
135
136impl Payer for PayClient {
137 fn trade_create(&self, biz_content: &TradeCreateBiz) -> AliPayResult<TradeCreateResponse> {
141 let body = self.do_alipay(biz_content)?;
142 let res: TradeCreateResponse = serde_json::from_slice(&body)?;
143 if res.response.code != Some("10000".to_string()) {
144 log::debug!("{}", serde_json::to_string(&res)?);
145 return Err(AliPayError(format!(
146 "trade_create failed: {} code:{}",
147 res.response.sub_msg.unwrap().as_str(),
148 res.response.sub_code.unwrap().as_str()
149 )));
150 }
151 Ok(res)
152 }
153
154 fn trade_pay(&self, biz_content: &TradePayBiz) -> AliPayResult<TradePayResponse> {
158 let body = self.do_alipay(biz_content)?;
159 let res: TradePayResponse = serde_json::from_slice(&body)?;
160 if res.response.code != Some("10000".to_string()) {
161 log::debug!("{}", serde_json::to_string(&res)?);
162 return Err(AliPayError(format!(
163 "trade_pay failed: {} code:{}",
164 res.response.sub_msg.unwrap().as_str(),
165 res.response.sub_code.unwrap().as_str()
166 )));
167 }
168 Ok(res)
169 }
170
171 fn trade_precreate(
175 &self,
176 biz_content: &TradePrecreateBiz,
177 ) -> AliPayResult<TradePrecreateResponse> {
178 let body = self.do_alipay(biz_content)?;
179 let res: TradePrecreateResponse = serde_json::from_slice(&body)?;
180 if res.response.code != Some("10000".to_string()) {
181 log::debug!("{}", serde_json::to_string(&res)?);
182 return Err(AliPayError(format!(
183 "trade_precreate failed: {} code:{}",
184 res.response.sub_msg.unwrap().as_str(),
185 res.response.sub_code.unwrap().as_str()
186 )));
187 }
188 Ok(res)
189 }
190
191 fn trade_app_pay(&self, biz_content: &TradeAppPayBiz) -> AliPayResult<String> {
195 let body = self.do_alipay(biz_content)?;
196 let res = String::from_utf8(body)?;
197 Ok(res)
198 }
199
200 fn trade_wap_pay(&self, biz_content: &TradeWapPayBiz) -> AliPayResult<String> {
204 let body = self.do_alipay(biz_content)?;
205 let res = String::from_utf8(body)?;
206 Ok(res)
207 }
208
209 fn trade_page_pay(&self, biz_content: &TradePagePayBiz) -> AliPayResult<String> {
213 let body = self.do_alipay(biz_content)?;
214 let res = String::from_utf8(body)?;
215 Ok(res)
216 }
217
218 fn trade_query(&self, biz_content: &TradeQueryBiz) -> AliPayResult<TradeQueryResponse> {
222 let body = self.do_alipay(biz_content)?;
223 let res: TradeQueryResponse = serde_json::from_slice(&body)?;
224 if res.response.code != Some("10000".to_string()) {
225 log::debug!("{}", serde_json::to_string(&res)?);
226 return Err(AliPayError(format!(
227 "trade_query failed: {} code:{}",
228 res.response.sub_msg.unwrap().as_str(),
229 res.response.sub_code.unwrap().as_str()
230 )));
231 }
232 Ok(res)
233 }
234
235 fn trade_cancel(&self, biz_content: &TradeCancelBiz) -> AliPayResult<TradeCancelResponse> {
239 let body = self.do_alipay(biz_content)?;
240 let res: TradeCancelResponse = serde_json::from_slice(&body)?;
241 if res.response.code != Some("10000".to_string()) {
242 log::debug!("{}", serde_json::to_string(&res)?);
243 return Err(AliPayError(format!(
244 "trade_cancel failed: {} code:{}",
245 res.response.sub_msg.unwrap().as_str(),
246 res.response.sub_code.unwrap().as_str()
247 )));
248 }
249 Ok(res)
250 }
251
252 fn trade_refund(&self, biz_content: &TradeRefundBiz) -> AliPayResult<TradeRefundResponse> {
256 let body = self.do_alipay(biz_content)?;
257 let res: TradeRefundResponse = serde_json::from_slice(&body)?;
258 if res.response.code != Some("10000".to_string()) {
259 log::debug!("{}", serde_json::to_string(&res)?);
260 return Err(AliPayError(format!(
261 "trade_refund failed: {} code:{}",
262 res.response.sub_msg.unwrap().as_str(),
263 res.response.sub_code.unwrap().as_str()
264 )));
265 }
266 Ok(res)
267 }
268
269 fn trade_page_refund(
273 &self,
274 biz_content: &TradePageRefundBiz,
275 ) -> AliPayResult<TradePageRefundResponse> {
276 let body = self.do_alipay(biz_content)?;
277 let res: TradePageRefundResponse = serde_json::from_slice(&body)?;
278 if res.response.code != Some("10000".to_string()) {
279 log::debug!("{}", serde_json::to_string(&res)?);
280 return Err(AliPayError(format!(
281 "trade_page_refund failed: {} code:{}",
282 res.response.sub_msg.unwrap().as_str(),
283 res.response.sub_code.unwrap().as_str()
284 )));
285 }
286 Ok(res)
287 }
288 fn trade_fastpay_refund_query(
292 &self,
293 biz_content: &TradeFastpayRefundQueryBiz,
294 ) -> AliPayResult<TradeFastpayRefundQueryResponse> {
295 let body = self.do_alipay(biz_content)?;
296 let res: TradeFastpayRefundQueryResponse = serde_json::from_slice(&body)?;
297 if res.response.code != Some("10000".to_string()) {
298 log::debug!("{}", serde_json::to_string(&res)?);
299 return Err(AliPayError(format!(
300 "trade_fastpay_refund_query failed: {} code:{}",
301 res.response.sub_msg.unwrap().as_str(),
302 res.response.sub_code.unwrap().as_str()
303 )));
304 }
305 Ok(res)
306 }
307
308 fn trade_order_settle(
312 &self,
313 biz_content: &TradeOrderSettleBiz,
314 ) -> AliPayResult<TradeOrderSettleResponse> {
315 let body = self.do_alipay(biz_content)?;
316 let res: TradeOrderSettleResponse = serde_json::from_slice(&body)?;
317 if res.response.code != Some("10000".to_string()) {
318 log::debug!("{}", serde_json::to_string(&res)?);
319 return Err(AliPayError(format!(
320 "trade_order_settle failed: {} code:{}",
321 res.response.sub_msg.unwrap().as_str(),
322 res.response.sub_code.unwrap().as_str()
323 )));
324 }
325 Ok(res)
326 }
327
328 fn trade_order_settle_query(
332 &self,
333 biz_content: &TradeOrderSettleQueryBiz,
334 ) -> AliPayResult<TradeOrderSettleQueryResponse> {
335 let body = self.do_alipay(biz_content)?;
336 let res: TradeOrderSettleQueryResponse = serde_json::from_slice(&body)?;
337 if res.response.code != Some("10000".to_string()) {
338 log::debug!("{}", serde_json::to_string(&res)?);
339 return Err(AliPayError(format!(
340 "trade_order_settle_query failed: {} code:{}",
341 res.response.msg.unwrap().as_str(),
342 res.response.code.unwrap().as_str()
343 )));
344 }
345 Ok(res)
346 }
347
348 fn trade_royalty_relation_bind(
352 &self,
353 biz_content: &TradeRoyaltyRelationBindBiz,
354 ) -> AliPayResult<TradeRoyaltyRelationBindResponse> {
355 let body = self.do_alipay(biz_content)?;
356 let res: TradeRoyaltyRelationBindResponse = serde_json::from_slice(&body)?;
357 if res.response.code != Some("10000".to_string()) {
358 log::debug!("{}", serde_json::to_string(&res)?);
359 return Err(AliPayError(format!(
360 "trade_royalty_relation_bind failed: {} code:{}",
361 res.response.msg.unwrap().as_str(),
362 res.response.code.unwrap().as_str()
363 )));
364 }
365 Ok(res)
366 }
367
368 fn trade_royalty_relation_unbind(
372 &self,
373 biz_content: &TradeRoyaltyRelationUnBindBiz,
374 ) -> AliPayResult<TradeRoyaltyRelationUnBindResponse> {
375 let body = self.do_alipay(biz_content)?;
376 let res: TradeRoyaltyRelationUnBindResponse = serde_json::from_slice(&body)?;
377 if res.response.code != Some("10000".to_string()) {
378 log::debug!("{}", serde_json::to_string(&res)?);
379 return Err(AliPayError(format!(
380 "trade_royalty_relation_unbind failed: {} code:{}",
381 res.response.msg.unwrap().as_str(),
382 res.response.code.unwrap().as_str()
383 )));
384 }
385 Ok(res)
386 }
387
388 fn trade_close(&self, biz_content: &TradeCloseBiz) -> AliPayResult<TradeCloseResponse> {
392 let body = self.do_alipay(biz_content)?;
393 let res: TradeCloseResponse = serde_json::from_slice(&body)?;
394 if res.response.code != Some("10000".to_string()) {
395 log::debug!("{}", serde_json::to_string(&res)?);
396 return Err(AliPayError(format!(
397 "trade_close failed: {} code:{}",
398 res.response.sub_msg.unwrap().as_str(),
399 res.response.sub_code.unwrap().as_str(),
400 )));
401 }
402 Ok(res)
403 }
404 fn async_verify_sign(&self, raw_body: &[u8]) -> AliPayResult<bool> {
408 let (source, sign, sign_type) = util::get_async_callback_msg_source(raw_body)?;
409 let mut singer = builder().set_sign_type(&sign_type).build();
410 singer.set_public_key(&self.alipay_public_key())?;
411 return Ok(singer.verify(&source, &sign)?);
412 }
413}
414
415#[derive(Debug, Default, Clone, Copy)]
417pub struct PayClientBuilder<'a> {
418 api_url: Option<&'a str>, private_key: Option<&'a str>, public_key: Option<&'a str>, alipay_public_key: Option<&'a str>, app_cert_sn: Option<&'a str>, alipay_root_cert_sn: Option<&'a str>, app_id: Option<&'a str>, format: Option<&'a str>, charset: Option<&'a str>, sign_type: Option<&'a str>, version: Option<&'a str>, return_url: Option<&'a str>, notify_url: Option<&'a str>, }
432
433impl PayClient {
434 pub fn builder<'a>() -> PayClientBuilder<'a> {
435 PayClientBuilder::default()
436 }
437
438 pub fn api_url(&self) -> String {
439 self.api_url.to_owned()
440 }
441
442 pub fn private_key(&self) -> String {
443 self.private_key.to_owned()
444 }
445
446 pub fn public_key(&self) -> String {
447 self.public_key.to_owned()
448 }
449
450 pub fn app_cert_sn(&self) -> String {
451 self.app_cert_sn.to_owned()
452 }
453
454 pub fn alipay_root_cert_sn(&self) -> String {
455 self.alipay_root_cert_sn.to_owned()
456 }
457
458 pub fn alipay_public_key(&self) -> String {
459 self.alipay_public_key.to_owned()
460 }
461
462 pub fn app_id(&self) -> String {
463 self.app_id.to_owned()
464 }
465
466 pub fn format(&self) -> String {
467 self.format.to_owned()
468 }
469
470 pub fn charset(&self) -> String {
471 self.charset.to_owned()
472 }
473
474 pub fn sign_type(&self) -> String {
475 self.sign_type.to_owned()
476 }
477
478 pub fn version(&self) -> String {
479 self.version.to_owned()
480 }
481
482 pub fn return_url(&self) -> String {
483 self.return_url.to_owned()
484 }
485
486 pub fn notify_url(&self) -> String {
487 self.notify_url.to_owned()
488 }
489
490 pub fn set_notify_url(&mut self, notify_url: &str) {
491 self.notify_url = notify_url.to_owned()
492 }
493
494 pub fn set_sign_type(&mut self, sign_type: &str) {
495 self.sign_type = sign_type.to_owned()
496 }
497
498 pub fn set_charset(&mut self, charset: &str) {
499 self.charset = charset.to_owned()
500 }
501
502 pub fn execute(&self, req: &mut impl Requester) -> AliPayResult<Vec<byte>> {
503 let method = req.method();
504 let payload = req.encode_payload()?;
505 let mut request = http::Request::default();
506 let mut client = http::Client::New();
507 if method == "alipay.trade.precreate" {
508 request = http::Request::New(
509 http::Method::Get,
510 &format!("{}?{}", self.api_url, payload),
511 None,
512 )?;
513 } else {
514 request = http::Request::New(http::Method::Post, &self.api_url, Some(payload.into()))?;
515 }
516 request.Header.Set(
518 "Content-Type",
519 "application/x-www-form-urlencoded;charset=utf-8",
520 );
521 request
523 .Header
524 .Set("Accept", "application/json;charset=utf-8");
525
526 let res = client.Do(request.borrow_mut())?;
527 match res.Body {
528 Some(body) => Ok(body.into()),
529 None => Err(AliPaySDKError::AliPayError("body is NONE".to_string())),
530 }
531 }
532 pub fn do_alipay(&self, biz_content: &impl BizContenter) -> AliPayResult<Vec<byte>> {
534 let sync_verigy_sign = |response: &[byte]| -> AliPayResult<bool> {
536 let result = std::str::from_utf8(response)?;
537 let get_raw_source = || -> String {
538 let key = biz::get_response_key(biz_content);
539 json_get(result, &key)
540 };
541
542 let get_signture = || -> String { json_get(result, "sign") };
543
544 let mut singer = builder().set_sign_type(self.sign_type().as_str()).build();
545
546 singer.set_public_key(self.alipay_public_key().as_str())?;
547 let passed = singer.verify(&get_raw_source(), &get_signture())?;
548 if !passed {
549 return Ok(false);
550 }
551 Ok(true)
552 };
553 match biz_content.method().as_str() {
554 "alipay.trade.wap.pay" | "alipay.trade.page.pay" => {
555 Ok(self.create_clien_page_form(biz_content)?)
556 }
557 "alipay.trade.app.pay" => self.create_clien_sdk_request(biz_content),
558 _ => {
559 let mut request = Request::new_with_config(self);
560 request
561 .set_biz_content(biz_content)
562 .set_method(biz_content.method().as_str());
563 let res = self.execute(&mut request)?;
564 let is_pass = sync_verigy_sign(&res)?;
566 if !is_pass {
567 return Err(AliPayError("syncVerifySign no passed!".to_string()));
568 }
569 Ok(res)
570 }
571 }
572 }
573
574 fn create_clien_page_form(&self, biz: &impl BizContenter) -> AliPayResult<Vec<byte>> {
575 let encode_query = Request::new_with_config(self)
576 .set_biz_content(biz)
577 .set_method(biz.method().as_str())
578 .encode_payload()?;
579
580 let values = url::ParseQuery(encode_query.as_str())?;
581 let mut parameters: HashMap<String, String> = HashMap::new();
582 for (k, v) in values {
583 parameters.insert(k, v[0].to_string());
584 }
585
586 let form = build_form(&self.api_url(), &mut parameters)?
587 .as_bytes()
588 .to_vec();
589 Ok(form)
590 }
591
592 fn create_clien_sdk_request(&self, biz: &impl BizContenter) -> AliPayResult<Vec<byte>> {
593 let client_sdk_request = Request::new_with_config(self)
594 .set_biz_content(biz)
595 .set_method(biz.method().as_str())
596 .encode_payload()?;
597 let form = client_sdk_request.as_bytes().to_vec();
598 Ok(form)
599 }
600}
601
602impl<'a> PayClientBuilder<'a> {
603 pub fn api_url(&mut self, api_url: &'a str) -> &mut Self {
605 self.api_url = Some(api_url);
606 self.borrow_mut()
607 }
608
609 pub fn private_key(&mut self, private_key: &'a str) -> &mut Self {
611 self.private_key = Some(private_key);
612 self.borrow_mut()
613 }
614 pub fn public_key(&mut self, public_key: &'a str) -> &mut Self {
616 self.public_key = Some(public_key);
617 self.borrow_mut()
618 }
619 pub fn alipay_public_key(&mut self, alipay_public_key: &'a str) -> &mut Self {
621 self.alipay_public_key = Some(alipay_public_key);
622 self.borrow_mut()
623 }
624 pub fn app_cert_sn(&mut self, app_cert_sn: &'a str) -> &mut Self {
626 self.app_cert_sn = Some(app_cert_sn);
627 self.borrow_mut()
628 }
629 pub fn alipay_root_cert_sn(&mut self, alipay_root_cert_sn: &'a str) -> &mut Self {
631 self.alipay_root_cert_sn = Some(alipay_root_cert_sn);
632 self.borrow_mut()
633 }
634 pub fn app_id(&mut self, app_id: &'a str) -> &mut Self {
636 self.app_id = Some(app_id);
637 self.borrow_mut()
638 }
639 pub fn format_json(&mut self) -> &mut Self {
641 self.format = Some("JSON");
642 self.borrow_mut()
643 }
644 pub fn charset_utf8(&mut self) -> &mut Self {
646 self.charset = Some("utf-8");
647 self.borrow_mut()
648 }
649 pub fn sign_type_rsa2(&mut self) -> &mut Self {
651 self.sign_type = Some("RSA2");
652 self.borrow_mut()
653 }
654 pub fn version_1_0(&mut self) -> &mut Self {
656 self.version = Some("1.0");
657 self.borrow_mut()
658 }
659 pub fn return_url(&mut self, return_url: &'a str) -> &mut Self {
661 self.return_url = Some(return_url);
662 self.borrow_mut()
663 }
664 pub fn notify_url(&mut self, notify_url: &'a str) -> &mut Self {
666 self.notify_url = Some(notify_url);
667 self.borrow_mut()
668 }
669
670 pub fn build(self) -> AliPayResult<impl Payer> {
672 let mut p = PayClient::default();
673 if let Some(api_url) = self.api_url {
674 p.api_url = api_url.to_owned();
675 } else {
676 return Err(AliPaySDKError::AliPayError(
677 "api_url is required".to_string(),
678 ));
679 }
680
681 if let Some(private_key) = self.private_key {
682 p.private_key = private_key.to_owned();
683 } else {
684 return Err(AliPaySDKError::AliPayError(
685 "private_key is required".to_string(),
686 ));
687 }
688
689 if let Some(public_key) = self.public_key {
690 p.public_key = public_key.to_owned();
691 } else {
692 return Err(AliPaySDKError::AliPayError(
693 "public_key is required".to_string(),
694 ));
695 }
696
697 if let Some(app_cert_sn) = self.app_cert_sn {
698 p.app_cert_sn = app_cert_sn.to_owned();
699 } else {
700 return Err(AliPaySDKError::AliPayError(
701 "app_cert_sn is required".to_string(),
702 ));
703 }
704
705 if let Some(alipay_root_cert_sn) = self.alipay_root_cert_sn {
706 p.alipay_root_cert_sn = alipay_root_cert_sn.to_owned();
707 } else {
708 return Err(AliPayError("alipay_root_cert_sn is required".to_string()));
709 }
710
711 if let Some(app_id) = self.app_id {
712 p.app_id = app_id.to_owned();
713 } else {
714 return Err(AliPayError("app_id is required".to_string()));
715 }
716
717 if let Some(alipay_public_key) = self.alipay_public_key {
718 p.alipay_public_key = alipay_public_key.to_owned();
719 } else {
720 return Err(AliPayError("alipay_public_key is required".to_string()));
721 }
722
723 if let Some(format) = self.format {
724 p.format = format.to_owned();
725 } else {
726 p.format = "JSON".to_owned();
727 }
728
729 if let Some(charset) = self.charset {
730 p.charset = charset.to_owned();
731 } else {
732 p.charset = "utf-8".to_owned();
733 }
734
735 if let Some(sign_type) = self.sign_type {
736 p.sign_type = sign_type.to_owned();
737 } else {
738 p.sign_type = "RSA2".to_owned();
739 }
740
741 if let Some(version) = self.version {
742 p.version = version.to_owned();
743 } else {
744 p.version = "1.0".to_owned()
745 }
746
747 if let Some(return_url) = self.return_url {
748 p.return_url = return_url.to_owned();
749 }
750
751 if let Some(notify_url) = self.notify_url {
752 p.notify_url = notify_url.to_owned()
753 }
754
755 Ok(p)
756 }
757}