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 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 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 pub merchant_goods_id: String,
63 pub quantity: i32,
65 pub unit_price: i32,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub wechatpay_goods_id: Option<String>,
70 #[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 #[serde(skip_serializing_if = "Option::is_none")]
86 pub cost_price: Option<i32>,
87 #[serde(skip_serializing_if = "Option::is_none")]
89 pub invoice_id: Option<String>,
90 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 pub id: String,
102 #[serde(skip_serializing_if = "Option::is_none")]
104 pub name: Option<String>,
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub area_code: Option<String>,
108 #[serde(skip_serializing_if = "Option::is_none")]
110 pub address: Option<String>,
111}
112
113#[derive(Serialize, Debug, Clone)]
114pub struct SceneInfo {
115 pub payer_client_ip: String,
117 #[serde(skip_serializing_if = "Option::is_none")]
119 pub device_id: Option<String>,
120 #[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 #[serde(rename = "type")]
146 pub h5_type: String,
147 #[serde(skip_serializing_if = "Option::is_none")]
149 pub app_name: Option<String>,
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub app_url: Option<String>,
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub bundle_id: Option<String>,
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub package_name: Option<String>,
159}
160
161#[derive(Serialize, Debug, Clone)]
162pub struct H5SceneInfo {
163 pub payer_client_ip: String,
165 pub h5_info: H5Info,
167 #[serde(skip_serializing_if = "Option::is_none")]
169 pub device_id: Option<String>,
170 #[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 pub description: String,
206 pub out_trade_no: String,
208 pub amount: AmountInfo,
210 pub payer: PayerInfo,
212 #[serde(skip_serializing_if = "Option::is_none")]
214 pub attach: Option<String>,
215 #[serde(skip_serializing_if = "Option::is_none")]
217 pub detail: Option<OrderDetail>,
218 #[serde(skip_serializing_if = "Option::is_none")]
220 pub time_expire: Option<String>,
221 #[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 pub description: String,
236 pub out_trade_no: String,
238 pub amount: AmountInfo,
240 pub payer: PayerInfo,
242 #[serde(skip_serializing_if = "Option::is_none")]
244 pub attach: Option<String>,
245 #[serde(skip_serializing_if = "Option::is_none")]
247 pub detail: Option<OrderDetail>,
248 #[serde(skip_serializing_if = "Option::is_none")]
250 pub time_expire: Option<String>,
251 #[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 #[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 pub description: String,
317 pub out_trade_no: String,
321 pub amount: AmountInfo,
323 #[serde(skip_serializing_if = "Option::is_none")]
325 pub time_expire: Option<String>,
326 #[serde(skip_serializing_if = "Option::is_none")]
328 pub attach: Option<String>,
329 #[serde(skip_serializing_if = "Option::is_none")]
331 pub goods_tag: Option<String>,
332 #[serde(skip_serializing_if = "Option::is_none")]
334 pub support_fapiao: Option<bool>,
335 #[serde(skip_serializing_if = "Option::is_none")]
337 pub scene_info: Option<SceneInfo>,
338 #[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 pub description: String,
353 pub out_trade_no: String,
357 pub amount: AmountInfo,
359 #[serde(skip_serializing_if = "Option::is_none")]
361 pub time_expire: Option<String>,
362 #[serde(skip_serializing_if = "Option::is_none")]
364 pub attach: Option<String>,
365 #[serde(skip_serializing_if = "Option::is_none")]
367 pub goods_tag: Option<String>,
368 #[serde(skip_serializing_if = "Option::is_none")]
370 pub support_fapiao: Option<bool>,
371 #[serde(skip_serializing_if = "Option::is_none")]
373 pub detail: Option<OrderDetail>,
374 #[serde(skip_serializing_if = "Option::is_none")]
376 pub scene_info: Option<SceneInfo>,
377 #[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 pub description: String,
409 pub out_trade_no: String,
413 pub amount: AmountInfo,
415 #[serde(skip_serializing_if = "Option::is_none")]
417 pub time_expire: Option<String>,
418 #[serde(skip_serializing_if = "Option::is_none")]
420 pub attach: Option<String>,
421 #[serde(skip_serializing_if = "Option::is_none")]
423 pub goods_tag: Option<String>,
424 #[serde(skip_serializing_if = "Option::is_none")]
426 pub support_fapiao: Option<bool>,
427 pub scene_info: H5SceneInfo,
429 #[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}