wechat_pay_rust_sdk_gs/
model.rs

1use serde::{Deserialize, Serialize};
2use std::fmt::{Display, Formatter};
3
4pub trait ParamsTrait {
5    fn to_json(&self) -> String;
6}
7
8#[derive(Serialize, Debug, Clone)]
9pub enum Currency {
10    CNY,
11}
12
13impl Display for Currency {
14    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
15        match self {
16            Currency::CNY => write!(f, "CNY"),
17        }
18    }
19}
20
21unsafe impl Send for Currency {}
22
23unsafe impl Sync for Currency {}
24
25#[derive(Serialize, Deserialize, Debug, Clone)]
26pub struct AmountInfo {
27    ///【标价金额】 订单总金额,单位为分。
28    pub total: i32,
29}
30
31impl From<i32> for AmountInfo {
32    fn from(value: i32) -> Self {
33        Self { total: value }
34    }
35}
36
37unsafe impl Send for AmountInfo {}
38
39unsafe impl Sync for AmountInfo {}
40
41#[derive(Serialize, Deserialize, Debug, Clone)]
42pub struct PayerInfo {
43    ///【用户标识】 用户在直连商户appid下的唯一标识。
44    pub openid: String,
45}
46
47impl From<&str> for PayerInfo {
48    fn from(value: &str) -> Self {
49        Self {
50            openid: value.to_string(),
51        }
52    }
53}
54
55unsafe impl Send for PayerInfo {}
56
57unsafe impl Sync for PayerInfo {}
58
59#[derive(Serialize, Debug, Clone)]
60pub struct GoodsDetail {
61    ///【商户侧商品编码】 由半角的大小写字母、数字、中划线、下划线中的一种或几种组成。
62    pub merchant_goods_id: String,
63    ///【商品数量】 用户购买的数量
64    pub quantity: i32,
65    ///【商品单价】 单位为:分。如果商户有优惠,需传输商户优惠后的单价(例如:用户对一笔100元的订单使用了商场发的纸质优惠券100-50,则活动商品的单价应为原单价-50)
66    pub unit_price: i32,
67    ///【微信支付商品编码】 微信支付定义的统一商品编号(没有可不传)
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub wechatpay_goods_id: Option<String>,
70    ///【商品名称】 商品的实际名称
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub goods_name: Option<String>,
73}
74
75unsafe impl Send for GoodsDetail {}
76
77unsafe impl Sync for GoodsDetail {}
78
79#[derive(Serialize, Debug, Clone)]
80pub struct OrderDetail {
81    ///【订单原价】
82    /// 1、商户侧一张小票订单可能被分多次支付,订单原价用于记录整张小票的交易金额。
83    /// 2、当订单原价与支付金额不相等,则不享受优惠。
84    /// 3、该字段主要用于防止同一张小票分多次支付,以享受多次优惠的情况,正常支付订单不必上传此参数。
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub cost_price: Option<i32>,
87    ///【商品小票ID】 商家小票ID
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub invoice_id: Option<String>,
90    ///【单品列表】 单品列表信息,条目个数限制:【1,6000】
91    pub goods_detail: Vec<GoodsDetail>,
92}
93
94unsafe impl Send for OrderDetail {}
95
96unsafe impl Sync for OrderDetail {}
97
98#[derive(Serialize, Debug, Clone)]
99pub struct StoreInfo {
100    ///【门店编号】 商户侧门店编号
101    pub id: String,
102    ///【门店名称】 商户侧门店名称
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub name: Option<String>,
105    ///【地区编码】 地区编码,详细请见省市区编号对照表。
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub area_code: Option<String>,
108    ///【详细地址】 详细的商户门店地址
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub address: Option<String>,
111}
112
113#[derive(Serialize, Debug, Clone)]
114pub struct SceneInfo {
115    ///【用户终端IP】 用户的客户端IP,支持IPv4和IPv6两种格式的IP地址。
116    pub payer_client_ip: String,
117    ///【商户端设备号】 商户端设备号(门店号或收银设备ID)。
118    #[serde(skip_serializing_if = "Option::is_none")]
119    pub device_id: Option<String>,
120    ///【商户门店信息】 商户门店信息
121    #[serde(skip_serializing_if = "Option::is_none")]
122    pub store_info: Option<StoreInfo>,
123}
124
125#[derive(Serialize, Debug, Clone)]
126pub enum H5Type {
127    Ios,
128    Android,
129    Wap,
130}
131
132impl Display for H5Type {
133    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
134        match self {
135            H5Type::Ios => write!(f, "iOS"),
136            H5Type::Android => write!(f, "Android"),
137            H5Type::Wap => write!(f, "Wap"),
138        }
139    }
140}
141
142#[derive(Serialize, Debug, Clone)]
143pub struct H5Info {
144    ///【场景类型】 场景类型
145    #[serde(rename = "type")]
146    pub h5_type: String,
147    ///【应用名称】 应用名称
148    #[serde(skip_serializing_if = "Option::is_none")]
149    pub app_name: Option<String>,
150    ///【网站URL】 网站URL
151    #[serde(skip_serializing_if = "Option::is_none")]
152    pub app_url: Option<String>,
153    ///【iOS平台BundleID】 iOS平台BundleID
154    #[serde(skip_serializing_if = "Option::is_none")]
155    pub bundle_id: Option<String>,
156    ///【Android平台PackageName】 Android平台PackageName
157    #[serde(skip_serializing_if = "Option::is_none")]
158    pub package_name: Option<String>,
159}
160
161#[derive(Serialize, Debug, Clone)]
162pub struct H5SceneInfo {
163    ///【用户终端IP】 用户的客户端IP,支持IPv4和IPv6两种格式的IP地址。
164    pub payer_client_ip: String,
165    ///【H5场景信息】
166    pub h5_info: H5Info,
167    ///【商户端设备号】 商户端设备号(门店号或收银设备ID)。
168    #[serde(skip_serializing_if = "Option::is_none")]
169    pub device_id: Option<String>,
170    ///【商户门店信息】 商户门店信息
171    #[serde(skip_serializing_if = "Option::is_none")]
172    pub store_info: Option<StoreInfo>,
173}
174
175impl H5SceneInfo {
176    pub fn new<S: AsRef<str>>(payer_client_ip: S, app_name: S, app_url: S) -> Self {
177        Self {
178            payer_client_ip: payer_client_ip.as_ref().to_string(),
179            h5_info: H5Info {
180                h5_type: H5Type::Wap.to_string(),
181                app_name: Some(app_name.as_ref().to_string()),
182                app_url: Some(app_url.as_ref().to_string()),
183                bundle_id: None,
184                package_name: None,
185            },
186            device_id: None,
187            store_info: None,
188        }
189    }
190}
191
192unsafe impl Send for SceneInfo {}
193
194unsafe impl Sync for SceneInfo {}
195
196impl ParamsTrait for SceneInfo {
197    fn to_json(&self) -> String {
198        serde_json::to_string(self).unwrap()
199    }
200}
201
202#[derive(Serialize, Debug, Clone)]
203pub struct JsapiParams {
204    ///【商品描述】 商品描述
205    pub description: String,
206    ///【商户订单号】 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
207    pub out_trade_no: String,
208    ///【订单金额】 订单金额信息
209    pub amount: AmountInfo,
210    ///【支付者】 支付者信息
211    pub payer: PayerInfo,
212    ///【附加数据】 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用,实际情况下只有支付完成状态才会返回该字段。
213    #[serde(skip_serializing_if = "Option::is_none")]
214    pub attach: Option<String>,
215    ///【优惠功能】 优惠功能
216    #[serde(skip_serializing_if = "Option::is_none")]
217    pub detail: Option<OrderDetail>,
218    ///【交易结束时间】 订单失效时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日13点29分35秒。
219    #[serde(skip_serializing_if = "Option::is_none")]
220    pub time_expire: Option<String>,
221    ///【场景信息】 支付场景描述
222    #[serde(skip_serializing_if = "Option::is_none")]
223    pub scene_info: Option<SceneInfo>,
224}
225
226impl ParamsTrait for JsapiParams {
227    fn to_json(&self) -> String {
228        serde_json::to_string(self).unwrap()
229    }
230}
231
232#[derive(Serialize, Debug, Clone)]
233pub struct MicroParams {
234    ///【商品描述】 商品描述
235    pub description: String,
236    ///【商户订单号】 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
237    pub out_trade_no: String,
238    ///【订单金额】 订单金额信息
239    pub amount: AmountInfo,
240    ///【支付者】 支付者信息
241    pub payer: PayerInfo,
242    ///【附加数据】 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用,实际情况下只有支付完成状态才会返回该字段。
243    #[serde(skip_serializing_if = "Option::is_none")]
244    pub attach: Option<String>,
245    ///【优惠功能】 优惠功能
246    #[serde(skip_serializing_if = "Option::is_none")]
247    pub detail: Option<OrderDetail>,
248    ///【交易结束时间】 订单失效时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日13点29分35秒。
249    #[serde(skip_serializing_if = "Option::is_none")]
250    pub time_expire: Option<String>,
251    ///【场景信息】 支付场景描述
252    #[serde(skip_serializing_if = "Option::is_none")]
253    pub scene_info: Option<SceneInfo>,
254}
255
256impl ParamsTrait for MicroParams {
257    fn to_json(&self) -> String {
258        serde_json::to_string(self).unwrap()
259    }
260}
261
262impl MicroParams {
263    pub fn new<S: AsRef<str>>(
264        description: S,
265        out_trade_no: S,
266        amount: AmountInfo,
267        payer: PayerInfo,
268    ) -> Self {
269        Self {
270            description: description.as_ref().to_string(),
271            out_trade_no: out_trade_no.as_ref().to_string(),
272            amount,
273            payer,
274            time_expire: None,
275            attach: None,
276            detail: None,
277            scene_info: None,
278        }
279    }
280}
281
282impl JsapiParams {
283    pub fn new<S: AsRef<str>>(
284        description: S,
285        out_trade_no: S,
286        amount: AmountInfo,
287        payer: PayerInfo,
288    ) -> Self {
289        Self {
290            description: description.as_ref().to_string(),
291            out_trade_no: out_trade_no.as_ref().to_string(),
292            amount,
293            payer,
294            time_expire: None,
295            attach: None,
296            detail: None,
297            scene_info: None,
298        }
299    }
300}
301
302#[derive(Serialize, Debug, Clone)]
303pub struct SettleInfo {
304    ///【是否指定分账】 是否指定分账,
305    #[serde(skip_serializing_if = "Option::is_none")]
306    pub profit_sharing: Option<bool>,
307}
308
309unsafe impl Send for SettleInfo {}
310
311unsafe impl Sync for SettleInfo {}
312
313#[derive(Serialize, Debug, Clone)]
314pub struct NativeParams {
315    ///【商品描述】 商品描述
316    pub description: String,
317    ///【通知地址】 异步接收微信支付结果通知的回调地址,通知URL必须为外网可访问的URL,不能携带参数。 公网域名必须为HTTPS,如果是走专线接入,使用专线NAT IP或者私有回调域名可使用HTTP
318    /// pub notify_url: String,
319    ///【商户订单号】 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
320    pub out_trade_no: String,
321    ///【订单金额】 订单金额信息
322    pub amount: AmountInfo,
323    ///【交易结束时间】 订单失效时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日13点29分35秒。
324    #[serde(skip_serializing_if = "Option::is_none")]
325    pub time_expire: Option<String>,
326    ///【附加数据】 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用,实际情况下只有支付完成状态才会返回该字段。
327    #[serde(skip_serializing_if = "Option::is_none")]
328    pub attach: Option<String>,
329    ///【订单优惠标记】 商品标记,代金券或立减优惠功能的参数。
330    #[serde(skip_serializing_if = "Option::is_none")]
331    pub goods_tag: Option<String>,
332    ///【电子发票入口开放标识】 传入true时,支付成功消息和支付详情页将出现开票入口。需要在微信支付商户平台或微信公众平台开通电子发票功能,传此字段才可生效。
333    #[serde(skip_serializing_if = "Option::is_none")]
334    pub support_fapiao: Option<bool>,
335    ///【场景信息】 支付场景描述
336    #[serde(skip_serializing_if = "Option::is_none")]
337    pub scene_info: Option<SceneInfo>,
338    ///【结算信息】 结算信息
339    #[serde(skip_serializing_if = "Option::is_none")]
340    pub settle_info: Option<SettleInfo>,
341}
342
343impl ParamsTrait for NativeParams {
344    fn to_json(&self) -> String {
345        serde_json::to_string(self).unwrap()
346    }
347}
348
349#[derive(Serialize, Debug, Clone)]
350pub struct AppParams {
351    ///【商品描述】 商品描述
352    pub description: String,
353    ///【通知地址】 异步接收微信支付结果通知的回调地址,通知URL必须为外网可访问的URL,不能携带参数。 公网域名必须为HTTPS,如果是走专线接入,使用专线NAT IP或者私有回调域名可使用HTTP
354    /// pub notify_url: String,
355    ///【商户订单号】 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
356    pub out_trade_no: String,
357    ///【订单金额】 订单金额信息
358    pub amount: AmountInfo,
359    ///【交易结束时间】 订单失效时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日13点29分35秒。
360    #[serde(skip_serializing_if = "Option::is_none")]
361    pub time_expire: Option<String>,
362    ///【附加数据】 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用,实际情况下只有支付完成状态才会返回该字段。
363    #[serde(skip_serializing_if = "Option::is_none")]
364    pub attach: Option<String>,
365    ///【订单优惠标记】 商品标记,代金券或立减优惠功能的参数。
366    #[serde(skip_serializing_if = "Option::is_none")]
367    pub goods_tag: Option<String>,
368    ///【电子发票入口开放标识】 传入true时,支付成功消息和支付详情页将出现开票入口。需要在微信支付商户平台或微信公众平台开通电子发票功能,传此字段才可生效。
369    #[serde(skip_serializing_if = "Option::is_none")]
370    pub support_fapiao: Option<bool>,
371    ///【优惠功能】 优惠功能
372    #[serde(skip_serializing_if = "Option::is_none")]
373    pub detail: Option<OrderDetail>,
374    ///【场景信息】 支付场景描述
375    #[serde(skip_serializing_if = "Option::is_none")]
376    pub scene_info: Option<SceneInfo>,
377    ///【结算信息】 结算信息
378    #[serde(skip_serializing_if = "Option::is_none")]
379    pub settle_info: Option<SettleInfo>,
380}
381
382impl ParamsTrait for AppParams {
383    fn to_json(&self) -> String {
384        serde_json::to_string(self).unwrap()
385    }
386}
387
388impl AppParams {
389    pub fn new<S: AsRef<str>>(description: S, out_trade_no: S, amount: AmountInfo) -> Self {
390        Self {
391            description: description.as_ref().to_string(),
392            out_trade_no: out_trade_no.as_ref().to_string(),
393            amount,
394            time_expire: None,
395            attach: None,
396            goods_tag: None,
397            support_fapiao: None,
398            detail: None,
399            scene_info: None,
400            settle_info: None,
401        }
402    }
403}
404
405#[derive(Serialize, Debug, Clone)]
406pub struct H5Params {
407    ///【商品描述】 商品描述
408    pub description: String,
409    ///【通知地址】 异步接收微信支付结果通知的回调地址,通知URL必须为外网可访问的URL,不能携带参数。 公网域名必须为HTTPS,如果是走专线接入,使用专线NAT IP或者私有回调域名可使用HTTP
410    /// pub notify_url: String,
411    ///【商户订单号】 商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。
412    pub out_trade_no: String,
413    ///【订单金额】 订单金额信息
414    pub amount: AmountInfo,
415    ///【交易结束时间】 订单失效时间,遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,HH:mm:ss表示时分秒,TIMEZONE表示时区(+08:00表示东八区时间,领先UTC8小时,即北京时间)。例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日13点29分35秒。
416    #[serde(skip_serializing_if = "Option::is_none")]
417    pub time_expire: Option<String>,
418    ///【附加数据】 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用,实际情况下只有支付完成状态才会返回该字段。
419    #[serde(skip_serializing_if = "Option::is_none")]
420    pub attach: Option<String>,
421    ///【订单优惠标记】 商品标记,代金券或立减优惠功能的参数。
422    #[serde(skip_serializing_if = "Option::is_none")]
423    pub goods_tag: Option<String>,
424    ///【电子发票入口开放标识】 传入true时,支付成功消息和支付详情页将出现开票入口。需要在微信支付商户平台或微信公众平台开通电子发票功能,传此字段才可生效。
425    #[serde(skip_serializing_if = "Option::is_none")]
426    pub support_fapiao: Option<bool>,
427    ///【场景信息】 支付场景描述
428    pub scene_info: H5SceneInfo,
429    ///【结算信息】 结算信息
430    #[serde(skip_serializing_if = "Option::is_none")]
431    pub settle_info: Option<SettleInfo>,
432}
433
434impl ParamsTrait for H5Params {
435    fn to_json(&self) -> String {
436        serde_json::to_string(self).unwrap()
437    }
438}
439
440impl H5Params {
441    pub fn new<S: AsRef<str>>(
442        description: S,
443        out_trade_no: S,
444        amount: AmountInfo,
445        scene_info: H5SceneInfo,
446    ) -> Self {
447        Self {
448            description: description.as_ref().to_string(),
449            out_trade_no: out_trade_no.as_ref().to_string(),
450            amount,
451            time_expire: None,
452            attach: None,
453            goods_tag: None,
454            support_fapiao: None,
455            scene_info,
456            settle_info: None,
457        }
458    }
459}
460
461impl NativeParams {
462    pub fn new<S: AsRef<str>>(description: S, out_trade_no: S, amount: AmountInfo) -> Self {
463        Self {
464            description: description.as_ref().to_string(),
465            out_trade_no: out_trade_no.as_ref().to_string(),
466            amount,
467            time_expire: None,
468            attach: None,
469            goods_tag: None,
470            support_fapiao: None,
471            scene_info: None,
472            settle_info: None,
473        }
474    }
475}
476
477unsafe impl Send for NativeParams {}
478
479unsafe impl Sync for NativeParams {}
480
481unsafe impl Send for JsapiParams {}
482
483unsafe impl Sync for JsapiParams {}
484
485#[derive(Serialize, Deserialize, Debug, Clone)]
486pub struct WechatPayNotifySource {
487    pub algorithm: String,
488    pub ciphertext: String,
489    pub associated_data: Option<String>,
490    pub original_type: String,
491    pub nonce: String,
492}
493
494#[derive(Serialize, Deserialize, Debug, Clone)]
495pub struct WechatPayNotify {
496    pub id: String,
497    pub create_time: String,
498    pub event_type: String,
499    pub resource_type: String,
500    pub resource: WechatPayNotifySource,
501    pub summary: String,
502}
503
504#[derive(Serialize, Deserialize, Debug, Clone)]
505pub struct WechatPayDecodeData {
506    pub mchid: String,
507    pub appid: String,
508    pub out_trade_no: String,
509    pub transaction_id: String,
510    pub trade_type: String,
511    pub trade_state: String,
512    pub trade_state_desc: String,
513    pub bank_type: String,
514    pub attach: String,
515    pub success_time: String,
516    pub payer: PayerInfo,
517    pub amount: AmountInfo,
518}