use std::collections::BTreeMap;
use serde::{Serialize, Deserialize};
use crate::{LabradorResult, LabraError};
use crate::util::get_sign;
use crate::wechat::pay::TradeType;
#[derive(Debug, Serialize, Deserialize)]
pub struct WechatPayRequest {
pub appid: Option<String>,
pub trade_type: TradeType,
pub mch_id: String,
pub openid: String,
pub notify_url: Option<String>,
pub body: String,
pub detail: String,
pub attach: String,
pub out_trade_no: String,
pub total_fee: String,
pub spbill_create_ip: String,
pub sign: String,
pub nonce_str: Option<String>,
pub device_info: String,
pub product_id: String,
pub auth_code: String,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct WechatPayRequestV3 {
#[serde(skip_serializing_if = "Option::is_none")]
pub appid: Option<String>,
#[serde(rename = "mchid")]
pub mch_id: String,
pub description: String,
pub out_trade_no: String,
pub time_expire: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub attach: Option<String>,
pub notify_url: String,
pub amount: Amount,
#[serde(skip_serializing_if = "Option::is_none")]
pub payer: Option<Payer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<Discount>,
#[serde(skip_serializing_if = "Option::is_none")]
pub scene_info: Option<SceneInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
pub settle_info: Option<SettleInfo>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct IsvWechatPayRequestV3 {
#[serde(skip_serializing_if = "Option::is_none")]
pub sp_appid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sp_mchid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sub_appid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sub_mchid: Option<String>,
pub description: String,
pub out_trade_no: String,
pub time_expire: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub attach: Option<String>,
pub notify_url: String,
pub amount: Amount,
#[serde(skip_serializing_if = "Option::is_none")]
pub payer: Option<Payer>,
#[serde(skip_serializing_if = "Option::is_none")]
pub detail: Option<Discount>,
#[serde(skip_serializing_if = "Option::is_none")]
pub scene_info: Option<SceneInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
pub settle_info: Option<SettleInfo>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Amount {
pub total: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub currency: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub payer_total: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub payer_currency: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SettleInfo {
pub profit_sharing: Option<bool>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct SceneInfo {
pub payer_client_ip: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub device_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub store_info: Option<StoreInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
pub h5_info: Option<H5Info>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct H5Info {
#[serde(rename = "type")]
pub r#type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub app_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub app_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bundle_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub package_name: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct StoreInfo {
pub id: String,
pub address: String,
pub name: Option<String>,
pub area_code: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Payer {
pub openid: String,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Discount {
pub cost_price: Option<i32>,
pub invoice_id: Option<i32>,
pub goods_detail: Option<Vec<GoodsDetail>>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GoodsDetail {
pub merchant_goods_id: String,
pub wechatpay_goods_id: Option<String>,
pub goods_name: Option<String>,
pub quantity: i32,
pub unit_price: i32,
pub refund_amount: Option<i32>,
pub refund_quantity: Option<i32>,
}
#[allow(unused)]
impl WechatPayRequest {
pub fn parse_xml(&self) -> String {
let msg = format!(
"<xml>\n\
<appid>{appid}</appid>\n\
<attach>{attach}</attach>\n\
<body>{body}</body>\n\
<mch_id>{mch_id}</mch_id>\n\
<detail><![CDATA[{detail}]]></detail>\n\
<nonce_str>{nonce_str}</nonce_str>\n\
<notify_url>{notify_url}</notify_url>\n\
<openid>{openid}</openid>\n\
<out_trade_no>{out_trade_no}</out_trade_no>\n\
<spbill_create_ip>{spbill_create_ip}</spbill_create_ip>\n\
<total_fee>{total_fee}</total_fee>\n\
<trade_type>{trade_type}</trade_type>\n\
<sign>{sign}</sign>\n\
</xml>",
appid=self.appid.to_owned().unwrap_or_default(),
attach=self.attach,
body=self.body,
detail= self.detail,
mch_id=self.mch_id,
nonce_str=self.nonce_str.to_owned().unwrap_or_default(),
notify_url=self.notify_url.to_owned().unwrap_or_default(),
openid=self.openid,
out_trade_no=self.out_trade_no,
spbill_create_ip=self.spbill_create_ip,
total_fee=self.total_fee,
trade_type=self.trade_type.get_trade_type(),
sign=self.sign,
);
msg
}
pub fn get_sign(&mut self, appkey: &str) {
let mut pairs = BTreeMap::new();
if let Some(appid) = self.appid.to_owned() {
pairs.insert("appid".to_string(), appid);
}
pairs.insert("attach".to_string(), self.attach.to_owned());
pairs.insert("auth_code".to_string(), self.auth_code.to_owned());
pairs.insert("body".to_string(), self.body.to_owned());
pairs.insert("total_fee".to_string(), self.total_fee.to_owned());
pairs.insert("detail".to_string(), self.detail.to_owned());
pairs.insert("device_info".to_string(), self.device_info.to_owned());
pairs.insert("mch_id".to_string(), self.mch_id.to_owned());
pairs.insert("openid".to_string(), self.openid.to_owned());
pairs.insert("out_trade_no".to_string(), self.out_trade_no.to_owned());
pairs.insert("product_id".to_string(), self.product_id.to_owned());
pairs.insert("spbill_create_ip".to_string(), self.spbill_create_ip.to_owned());
pairs.insert("trade_type".to_string(), self.trade_type.get_trade_type().to_string());
if let Some(nonce_str) = self.nonce_str.to_owned() {
pairs.insert("nonce_str".to_string(), nonce_str);
}
if let Some(notify_url) = self.notify_url.to_owned() {
pairs.insert("notify_url".to_string(), notify_url);
}
self.sign = get_sign(&pairs, appkey);
}
pub(crate) fn check_params(&self) -> LabradorResult<()> {
if self.sign.is_empty() || self.body.is_empty() || self.out_trade_no.is_empty() || self.total_fee.is_empty() || self.spbill_create_ip.is_empty() {
return Err(LabraError::MissingField("参数不能为空".to_string()));
}
match self.trade_type {
TradeType::Native => {
if self.product_id.is_empty() {
return Err(LabraError::MissingField("商品ID不能为空".to_string()));
}
}
TradeType::Jsapi => {
if self.openid.is_empty() {
return Err(LabraError::MissingField("openid不能为空".to_string()));
}
}
TradeType::Micro => {
if self.auth_code.is_empty() {
return Err(LabraError::MissingField("openid不能为空".to_string()));
}
}
_ => {}
}
Ok(())
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WechatCloseOrderRequest {
pub appid: Option<String>,
pub mch_id: String,
pub out_trade_no: String,
pub sign: String,
pub nonce_str: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WechatCloseOrderRequestV3 {
pub mchid: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub out_trade_no: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WechatQueryOrderRequest {
pub transaction_id: Option<String>,
pub out_trade_no: Option<String>,
pub appid: Option<String>,
pub mch_id: String,
pub sign: String,
pub nonce_str: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WechatQueryOrderRequestV3 {
pub mchid: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub transaction_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub out_trade_no: Option<String>,
}
#[allow(unused)]
impl WechatCloseOrderRequest {
pub fn parse_xml(&self) -> String {
let msg = format!(
"<xml>\n\
<appid>{appid}</appid>\n\
<mch_id>{mch_id}</mch_id>\n\
<nonce_str>{nonce_str}</nonce_str>\n\
<out_trade_no>{out_trade_no}</out_trade_no>\n\
<sign>{sign}</sign>\n\
</xml>",
appid=self.appid.to_owned().unwrap_or_default(),
mch_id=self.mch_id,
nonce_str=self.nonce_str.to_owned().unwrap_or_default(),
out_trade_no=self.out_trade_no,
sign=self.sign,
);
msg
}
pub fn get_sign(&mut self, appkey: &str) {
let mut pairs = BTreeMap::new();
if let Some(appid) = self.appid.to_owned() {
pairs.insert("appid".to_string(), appid);
}
pairs.insert("mch_id".to_string(), self.mch_id.to_owned());
pairs.insert("out_trade_no".to_string(), self.out_trade_no.to_owned());
if let Some(nonce_str) = self.nonce_str.to_owned() {
pairs.insert("nonce_str".to_string(), nonce_str);
}
self.sign = get_sign(&pairs, appkey);
}
}
#[allow(unused)]
impl WechatQueryOrderRequest {
pub fn parse_xml(&self) -> String {
let msg = format!(
"<xml>\n\
<appid>{appid}</appid>\n\
<mch_id>{mch_id}</mch_id>\n\
<nonce_str>{nonce_str}</nonce_str>\n\
<out_trade_no>{out_trade_no}</out_trade_no>\n\
<transaction_id>{transaction_id}</transaction_id>\n\
<sign>{sign}</sign>\n\
</xml>",
appid=self.appid.to_owned().unwrap_or_default(),
mch_id=self.mch_id.to_owned(),
nonce_str=self.nonce_str.to_owned().unwrap_or_default(),
out_trade_no=self.out_trade_no.to_owned().unwrap_or_default(),
transaction_id=self.transaction_id.to_owned().unwrap_or_default(),
sign=self.sign,
);
msg
}
pub fn get_sign(&mut self, appkey: &str) {
let mut pairs = BTreeMap::new();
if let Some(appid) = self.appid.to_owned() {
pairs.insert("appid".to_string(), appid);
}
pairs.insert("mch_id".to_string(), self.mch_id.to_owned());
pairs.insert("out_trade_no".to_string(), self.out_trade_no.to_owned().unwrap_or_default());
pairs.insert("transaction_id".to_string(), self.transaction_id.to_owned().unwrap_or_default());
if let Some(nonce_str) = self.nonce_str.to_owned() {
pairs.insert("nonce_str".to_string(), nonce_str);
}
self.sign = get_sign(&pairs, appkey);
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct RefundAmount {
pub refund: i64,
pub total: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub payer_total: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub payer_refund: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub currency: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WechatRefundRequestV3 {
#[serde(skip_serializing_if = "Option::is_none")]
pub transaction_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub out_trade_no: Option<String>,
pub out_refund_no: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub reason: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub notify_url: Option<String>,
pub amount: RefundAmount,
#[serde(skip_serializing_if = "Option::is_none")]
pub goods_detail: Option<Vec<GoodsDetail>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WechatRefundRequest {
pub appid: Option<String>,
pub mch_id: String,
pub out_trade_no: String,
pub out_refund_no: String,
pub transaction_id: String,
pub notify_url: Option<String>,
pub refund_fee: String,
pub total_fee: String,
pub sign: String,
pub nonce_str: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WechatOrderReverseRequest {
pub appid: Option<String>,
pub mch_id: String,
pub out_trade_no: String,
pub transaction_id: String,
pub sign: String,
pub nonce_str: Option<String>,
}
#[allow(unused)]
impl WechatRefundRequest {
pub fn parse_xml(&self) -> String {
let msg = format!(
"<xml>\n\
<appid>{appid}</appid>\n\
<mch_id>{mch_id}</mch_id>\n\
<nonce_str>{nonce_str}</nonce_str>\n\
<out_refund_no>{out_refund_no}</out_refund_no>\n\
<out_trade_no>{out_trade_no}</out_trade_no>\n\
<refund_fee>{refund_fee}</refund_fee>\n\
<total_fee>{total_fee}</total_fee>\n\
<notify_url>{notify_url}</notify_url>\n\
<transaction_id>{transaction_id}</transaction_id>\n\
<sign>{sign}</sign>\n\
</xml>",
appid=self.appid.to_owned().unwrap_or_default(),
mch_id=self.mch_id,
nonce_str=self.nonce_str.to_owned().unwrap_or_default(),
transaction_id=self.transaction_id,
out_trade_no=self.out_trade_no,
out_refund_no=self.out_refund_no,
refund_fee=self.refund_fee,
total_fee=self.total_fee,
notify_url=self.notify_url.to_owned().unwrap_or_default(),
sign=self.sign,
);
msg
}
pub fn get_sign(&mut self, appkey: &str) {
let mut pairs = BTreeMap::new();
if let Some(appid) = self.appid.to_owned() {
pairs.insert("appid".to_string(), appid);
}
pairs.insert("mch_id".to_string(), self.mch_id.to_owned());
pairs.insert("out_trade_no".to_string(), self.out_trade_no.to_owned());
pairs.insert("out_refund_no".to_string(), self.out_refund_no.to_owned());
pairs.insert("transaction_id".to_string(), self.transaction_id.to_owned());
pairs.insert("refund_fee".to_string(), self.refund_fee.to_owned());
pairs.insert("total_fee".to_string(), self.total_fee.to_owned());
if let Some(notify_url) = self.notify_url.to_owned() {
pairs.insert("notify_url".to_string(), notify_url);
}
if let Some(nonce_str) = self.nonce_str.to_owned() {
pairs.insert("nonce_str".to_string(), nonce_str);
}
self.sign = get_sign(&pairs, appkey);
}
}
#[allow(unused)]
impl WechatOrderReverseRequest {
pub fn parse_xml(&self) -> String {
let msg = format!(
"<xml>\n\
<appid>{appid}</appid>\n\
<mch_id>{mch_id}</mch_id>\n\
<nonce_str>{nonce_str}</nonce_str>\n\
<out_trade_no>{out_trade_no}</out_trade_no>\n\
<transaction_id>{transaction_id}</transaction_id>\n\
<sign>{sign}</sign>\n\
</xml>",
appid=self.appid.to_owned().unwrap_or_default(),
mch_id=self.mch_id,
nonce_str=self.nonce_str.to_owned().unwrap_or_default(),
transaction_id=self.transaction_id,
out_trade_no=self.out_trade_no,
sign=self.sign,
);
msg
}
pub fn get_sign(&mut self, appkey: &str) {
let mut pairs = BTreeMap::new();
if let Some(appid) = self.appid.to_owned() {
pairs.insert("appid".to_string(), appid);
}
pairs.insert("mch_id".to_string(), self.mch_id.to_owned());
pairs.insert("out_trade_no".to_string(), self.out_trade_no.to_owned());
pairs.insert("transaction_id".to_string(), self.transaction_id.to_owned());
self.sign = get_sign(&pairs, appkey);
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WechatQueryRefundOrderRequest {
pub appid: Option<String>,
pub mch_id: String,
pub out_refund_no: Option<String>,
pub transaction_id: Option<String>,
pub out_trade_no: Option<String>,
pub refund_id: Option<String>,
pub sign: String,
pub nonce_str: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WechatQueryRefundOrderRequestV3 {
#[serde(skip_serializing_if = "Option::is_none")]
pub out_refund_no: Option<String>,
}
#[allow(unused)]
impl WechatQueryRefundOrderRequest {
pub fn parse_xml(&self) -> String {
let msg = format!(
"<xml>\n\
<appid>{appid}</appid>\n\
<mch_id>{mch_id}</mch_id>\n\
<nonce_str>{nonce_str}</nonce_str>\n\
<out_refund_no>{out_refund_no}</out_refund_no>\n\
<out_trade_no>{out_trade_no}</out_trade_no>\n\
<refund_id>{refund_id}</refund_id>\n\
<transaction_id>{transaction_id}</transaction_id>\n\
<sign>{sign}</sign>\n\
</xml>",
appid=self.appid.to_owned().unwrap_or_default(),
mch_id=self.mch_id,
nonce_str=self.nonce_str.to_owned().unwrap_or_default(),
transaction_id=self.transaction_id.to_owned().unwrap_or_default(),
out_trade_no=self.out_trade_no.to_owned().unwrap_or_default(),
out_refund_no=self.out_refund_no.to_owned().unwrap_or_default(),
refund_id=self.refund_id.to_owned().unwrap_or_default(),
sign=self.sign,
);
msg
}
pub fn get_sign(&mut self, appkey: &str) {
let mut pairs = BTreeMap::new();
if let Some(appid) = self.appid.to_owned() {
pairs.insert("appid".to_string(), appid);
}
pairs.insert("mch_id".to_string(), self.mch_id.to_owned());
pairs.insert("out_trade_no".to_string(), self.out_trade_no.to_owned().unwrap_or_default());
pairs.insert("out_refund_no".to_string(), self.out_refund_no.to_owned().unwrap_or_default());
pairs.insert("transaction_id".to_string(), self.transaction_id.to_owned().unwrap_or_default());
pairs.insert("refund_id".to_string(), self.refund_id.to_owned().unwrap_or_default());
if let Some(nonce_str) = self.nonce_str.to_owned() {
pairs.insert("nonce_str".to_string(), nonce_str);
}
self.sign = get_sign(&pairs, appkey);
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct WxPayShorturlRequest {
pub long_url: Option<String>,
pub appid: Option<String>,
pub mch_id: String,
pub sign: String,
pub nonce_str: Option<String>,
}
#[allow(unused)]
impl WxPayShorturlRequest {
pub fn parse_xml(&self) -> String {
let msg = format!(
"<xml>\n\
<appid>{appid}</appid>\n\
<mch_id>{mch_id}</mch_id>\n\
<nonce_str>{nonce_str}</nonce_str>\n\
<long_url>{long_url}</long_url>\n\
<sign>{sign}</sign>\n\
</xml>",
appid=self.appid.to_owned().unwrap_or_default(),
mch_id=self.mch_id,
nonce_str=self.nonce_str.to_owned().unwrap_or_default(),
long_url=self.long_url.to_owned().unwrap_or_default(),
sign=self.sign,
);
msg
}
pub fn get_sign(&mut self, appkey: &str) {
let mut pairs = BTreeMap::new();
if let Some(appid) = self.appid.to_owned() {
pairs.insert("appid".to_string(), appid);
}
pairs.insert("mch_id".to_string(), self.mch_id.to_owned());
pairs.insert("long_url".to_string(), self.long_url.to_owned().unwrap_or_default());
if let Some(nonce_str) = self.nonce_str.to_owned() {
pairs.insert("nonce_str".to_string(), nonce_str);
}
self.sign = get_sign(&pairs, appkey);
}
}