br_pay/
yrcc.rs

1use chrono::Local;
2use json::{object, JsonValue};
3use crate::{PayMode, Types};
4
5/// 农村商业银行
6#[derive(Clone, Debug)]
7pub struct Yrcc {
8    /// 服务商APPID
9    pub appid: String,
10    /// 密钥
11    pub secret: String,
12    /// 终端号
13    pub terminal_number: String,
14    /// 服务商商户号
15    pub sp_mchid: String,
16    /// 服务商号
17    pub service_provider: String,
18    /// 密钥名称
19    pub key_name: String,
20    /// SM2私钥
21    pub app_private: String,
22    /// 银行公钥
23    pub app_public: String,
24    /// 通知
25    pub notify_url: String,
26
27}
28impl Yrcc {
29    pub fn http(&mut self, service: &str, mut body: JsonValue) -> Result<JsonValue, String> {
30
31        // 获取当前本地时间
32        let now = Local::now();
33        let formatted = now.format("%Y%m%d%H%M%S").to_string();
34        body["seqNo"] = formatted.into();
35        //let _sign = "4A227003C3D07580397471B80E4B8384D036BBB7D5D8A7B1A84173EA555455EC688C04E9B3F2AF0E0FEE7C349E6D1252859FDA66A928123F70BCD68064AAAC83";
36        let sign = self.sign(body.clone())?;
37        // 交易时间,格式:YYYYMMDDhhmmss
38        //let headers = object! {
39        //    "service" => service,
40        //    "apiVersion"=> "1.1.0",
41        //    "seqNo"=>"",
42        //    "txnTime"=>formatted
43        //};
44
45
46        let mut http = br_reqwest::Client::new();
47        let url = format!("https://cloud.ynrcc.com/YNCashier/acqu/nosign/{service}");
48        //let url = format!("https://cloud.ynrcc.com/YNCashier/acqu/{service}");
49        let send = http.post(url.as_str()).raw_json(object! {
50            request:body
51        });
52        match send.header("ynrcc-cert", self.key_name.as_str()).header("ynrcc-sign", &sign).send()?.json() {
53            Ok(e) => {
54                if !e.has_key("response") {
55                    return Err("响应格式错误".to_string());
56                }
57                let response = e["response"].clone();
58                let code = response["code"].as_str().unwrap_or("");
59                if code != "000000" {
60                    return Err(response["msg"].to_string());
61                }
62                println!("{:#}", e["response"]);
63                Ok(e)
64            }
65            Err(e) => Err(e)
66        }
67    }
68
69    fn sign(&self, body: JsonValue) -> Result<String, String> {
70        let body_str = body.to_string();
71        let r = br_crypto::sha256::encrypt_byte(body_str.as_bytes());
72        let res = br_crypto::sm2::sign_rs(&self.app_private.clone(), &r);
73        println!("{}", res.len());
74        Ok(res.to_uppercase())
75    }
76}
77impl PayMode for Yrcc {
78    fn check(&mut self) -> Result<bool, String> {
79        todo!()
80    }
81
82    fn get_sub_mchid(&mut self, _sub_mchid: &str) -> Result<JsonValue, String> {
83        todo!()
84    }
85
86    fn notify(&mut self, _data: JsonValue) -> Result<JsonValue, String> {
87        todo!()
88    }
89
90    fn config(&mut self) -> JsonValue {
91        todo!()
92    }
93
94    fn login(&mut self, _code: &str) -> Result<JsonValue, String> {
95        todo!()
96    }
97
98    fn auth(&mut self, _code: &str) -> Result<JsonValue, String> {
99        todo!()
100    }
101
102    fn pay(&mut self, _channel: &str, types: Types, _sub_mchid: &str, out_trade_no: &str, description: &str, total_fee: f64, sp_openid: &str) -> Result<JsonValue, String> {
103        let service = match types {
104            Types::Jsapi => "MPCreateTrade",
105            Types::Native => "",
106            Types::H5 => "",
107            Types::MiniJsapi => "MPCreateTrade",
108            Types::App => "",
109            Types::Micropay => ""
110        };
111        // 获取当前本地时间
112        let now = Local::now();
113        let formatted = now.format("%Y%m%d%H%M%S").to_string();
114
115        let total = format!("{:.0}", total_fee * 100.0);
116        let body = object! {
117            "service"=>service,
118            "apiVersion"=>"1.1.0",
119            "tranCode"=>"120201",
120            "merId"=>self.sp_mchid.clone(),
121            "temId"=>self.terminal_number.clone(),
122            "accessProviderCode" => self.service_provider.clone(),
123            "seqNo"=>"",
124            "txnTime"=> formatted,
125            "tradeNo"=>out_trade_no,
126            "tradeChannel"=>"01",
127            "businessType"=>"001",
128            "totalAmt"=> total,
129            "totalNum"=>1,
130            "orderDesc"=>description,
131            "onlineFlag"=>"1",
132            "eventFlag"=>"1",
133            "ccy"=>"156",
134            "subOpenId"=>sp_openid,
135            "subAppId"=>self.appid.clone(),
136            "notifyUrl"=>self.notify_url.clone(),
137        };
138        match self.http(service, body) {
139            Ok(e) => {
140                match types {
141                    Types::Native => {
142                        if e.has_key("code_url") {
143                            Ok(e["code_url"].clone())
144                        } else {
145                            Err(e["message"].to_string())
146                        }
147                    }
148                    Types::Jsapi | Types::MiniJsapi => {
149                        if e.has_key("prepay_id") {
150                            //let signinfo = self.paysign(format!("prepay_id={}", e["prepay_id"]).as_str())?;
151                            let signinfo = "".into();
152                            Ok(signinfo)
153                        } else {
154                            Err(e["message"].to_string())
155                        }
156                    }
157                    _ => {
158                        Ok(e)
159                    }
160                }
161            }
162            Err(e) => Err(e),
163        }
164    }
165
166    fn micropay(&mut self, _channel: &str, _auth_code: &str, _sub_mchid: &str, _out_trade_no: &str, _description: &str, _total_fee: f64, _org_openid: &str, _ip: &str) -> Result<JsonValue, String> {
167        todo!()
168    }
169
170    fn close(&mut self, _out_trade_no: &str, _sub_mchid: &str) -> Result<JsonValue, String> {
171        todo!()
172    }
173
174    fn pay_query(&mut self, _out_trade_no: &str, _sub_mchid: &str) -> Result<JsonValue, String> {
175        todo!()
176    }
177
178    fn pay_micropay_query(&mut self, _out_trade_no: &str, _sub_mchid: &str) -> Result<JsonValue, String> {
179        todo!()
180    }
181
182    fn pay_notify(&mut self, _nonce: &str, _ciphertext: &str, _associated_data: &str) -> Result<JsonValue, String> {
183        todo!()
184    }
185
186    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> {
187        todo!()
188    }
189
190    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> {
191        todo!()
192    }
193
194    fn refund_notify(&mut self, _nonce: &str, _ciphertext: &str, _associated_data: &str) -> Result<JsonValue, String> {
195        todo!()
196    }
197
198    fn refund_query(&mut self, _trade_no: &str, _out_refund_no: &str, _sub_mchid: &str) -> Result<JsonValue, String> {
199        todo!()
200    }
201    fn incoming(&mut self, _business_code: &str, _contact_info: JsonValue, _subject_info: JsonValue, _business_info: JsonValue, _settlement_info: JsonValue, _bank_account_info: JsonValue) -> Result<JsonValue, String> {
202        todo!()
203    }
204}