use chrono::Local;
use json::{object, JsonValue};
use crate::{PayMode, Types};
#[derive(Clone, Debug)]
pub struct Yrcc {
pub appid: String,
pub secret: String,
pub terminal_number: String,
pub sp_mchid: String,
pub service_provider: String,
pub key_name: String,
pub app_private: String,
pub app_public: String,
pub notify_url: String,
}
impl Yrcc {
pub fn http(&mut self, service: &str, mut body: JsonValue) -> Result<JsonValue, String> {
let now = Local::now();
let formatted = now.format("%Y%m%d%H%M%S").to_string();
body["seqNo"] = formatted.into();
let sign = self.sign(body.clone())?;
let mut http = br_reqwest::Client::new();
let url = format!("https://cloud.ynrcc.com/YNCashier/acqu/nosign/{service}");
let send = http.post(url.as_str()).raw_json(object! {
request:body
});
match send.header("ynrcc-cert", self.key_name.as_str()).header("ynrcc-sign", &sign).send()?.json() {
Ok(e) => {
if !e.has_key("response") {
return Err("响应格式错误".to_string());
}
let response = e["response"].clone();
let code = response["code"].as_str().unwrap_or("");
if code != "000000" {
return Err(response["msg"].to_string());
}
println!("{:#}", e["response"]);
Ok(e)
}
Err(e) => Err(e)
}
}
fn sign(&self, body: JsonValue) -> Result<String, String> {
let body_str = body.to_string();
let r = br_crypto::sha256::encrypt_byte(body_str.as_bytes());
let res = br_crypto::sm2::sign_rs(&self.app_private.clone(), &r);
println!("{}", res.len());
Ok(res.to_uppercase())
}
}
impl PayMode for Yrcc {
fn check(&mut self) -> Result<bool, String> {
todo!()
}
fn get_sub_mchid(&mut self, _sub_mchid: &str) -> Result<JsonValue, String> {
todo!()
}
fn config(&mut self) -> JsonValue {
todo!()
}
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> {
let service = match types {
Types::Jsapi => "MPCreateTrade",
Types::Native => "",
Types::H5 => "",
Types::MiniJsapi => "MPCreateTrade",
Types::App => "",
Types::Micropay => ""
};
let now = Local::now();
let formatted = now.format("%Y%m%d%H%M%S").to_string();
let total = format!("{:.0}", total_fee * 100.0);
let body = object! {
"service"=>service,
"apiVersion"=>"1.1.0",
"tranCode"=>"120201",
"merId"=>self.sp_mchid.clone(),
"temId"=>self.terminal_number.clone(),
"accessProviderCode" => self.service_provider.clone(),
"seqNo"=>"",
"txnTime"=> formatted,
"tradeNo"=>out_trade_no,
"tradeChannel"=>"01",
"businessType"=>"001",
"totalAmt"=> total,
"totalNum"=>1,
"orderDesc"=>description,
"onlineFlag"=>"1",
"eventFlag"=>"1",
"ccy"=>"156",
"subOpenId"=>sp_openid,
"subAppId"=>self.appid.clone(),
"notifyUrl"=>self.notify_url.clone(),
};
match self.http(service, body) {
Ok(e) => {
match types {
Types::Native => {
if e.has_key("code_url") {
Ok(e["code_url"].clone())
} else {
Err(e["message"].to_string())
}
}
Types::Jsapi | Types::MiniJsapi => {
if e.has_key("prepay_id") {
let signinfo = "".into();
Ok(signinfo)
} else {
Err(e["message"].to_string())
}
}
_ => {
Ok(e)
}
}
}
Err(e) => Err(e),
}
}
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> {
todo!()
}
fn close(&mut self, _out_trade_no: &str, _sub_mchid: &str) -> Result<JsonValue, String> {
todo!()
}
fn pay_query(&mut self, _out_trade_no: &str, _sub_mchid: &str) -> Result<JsonValue, String> {
todo!()
}
fn pay_micropay_query(&mut self, _out_trade_no: &str, _sub_mchid: &str, _channel: &str) -> Result<JsonValue, String> {
todo!()
}
fn pay_notify(&mut self, _nonce: &str, _ciphertext: &str, _associated_data: &str) -> Result<JsonValue, String> {
todo!()
}
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> {
todo!()
}
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> {
todo!()
}
fn refund_notify(&mut self, _nonce: &str, _ciphertext: &str, _associated_data: &str) -> Result<JsonValue, String> {
todo!()
}
fn refund_query(&mut self, _trade_no: &str, _out_refund_no: &str, _sub_mchid: &str) -> Result<JsonValue, String> {
todo!()
}
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> {
todo!()
}
}