stripe_shared/
refund.rs

1/// Refund objects allow you to refund a previously created charge that isn't
2/// refunded yet. Funds are refunded to the credit or debit card that's
3/// initially charged.
4///
5/// Related guide: [Refunds](https://stripe.com/docs/refunds)
6///
7/// For more details see <<https://stripe.com/docs/api/refunds/object>>.
8#[derive(Clone, Debug)]
9#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
10pub struct Refund {
11    /// Amount, in cents (or local equivalent).
12    pub amount: i64,
13    /// Balance transaction that describes the impact on your account balance.
14    pub balance_transaction: Option<stripe_types::Expandable<stripe_shared::BalanceTransaction>>,
15    /// ID of the charge that's refunded.
16    pub charge: Option<stripe_types::Expandable<stripe_shared::Charge>>,
17    /// Time at which the object was created. Measured in seconds since the Unix epoch.
18    pub created: stripe_types::Timestamp,
19    /// Three-letter [ISO currency code](https://www.iso.org/iso-4217-currency-codes.html), in lowercase.
20    /// Must be a [supported currency](https://stripe.com/docs/currencies).
21    pub currency: stripe_types::Currency,
22    /// An arbitrary string attached to the object.
23    /// You can use this for displaying to users (available on non-card refunds only).
24    pub description: Option<String>,
25    pub destination_details: Option<stripe_shared::RefundDestinationDetails>,
26    /// After the refund fails, this balance transaction describes the adjustment made on your account balance that reverses the initial balance transaction.
27    pub failure_balance_transaction:
28        Option<stripe_types::Expandable<stripe_shared::BalanceTransaction>>,
29    /// Provides the reason for the refund failure.
30    /// Possible values are: `lost_or_stolen_card`, `expired_or_canceled_card`, `charge_for_pending_refund_disputed`, `insufficient_funds`, `declined`, `merchant_request`, or `unknown`.
31    pub failure_reason: Option<String>,
32    /// Unique identifier for the object.
33    pub id: stripe_shared::RefundId,
34    /// For payment methods without native refund support (for example, Konbini, PromptPay), provide an email address for the customer to receive refund instructions.
35    pub instructions_email: Option<String>,
36    /// Set of [key-value pairs](https://stripe.com/docs/api/metadata) that you can attach to an object.
37    /// This can be useful for storing additional information about the object in a structured format.
38    pub metadata: Option<std::collections::HashMap<String, String>>,
39    pub next_action: Option<stripe_shared::RefundNextAction>,
40    /// ID of the PaymentIntent that's refunded.
41    pub payment_intent: Option<stripe_types::Expandable<stripe_shared::PaymentIntent>>,
42    /// Provides the reason for why the refund is pending.
43    /// Possible values are: `processing`, `insufficient_funds`, or `charge_pending`.
44    pub pending_reason: Option<RefundPendingReason>,
45    pub presentment_details: Option<stripe_shared::PaymentFlowsPaymentIntentPresentmentDetails>,
46    /// Reason for the refund, which is either user-provided (`duplicate`, `fraudulent`, or `requested_by_customer`) or generated by Stripe internally (`expired_uncaptured_charge`).
47    pub reason: Option<RefundReason>,
48    /// This is the transaction number that appears on email receipts sent for this refund.
49    pub receipt_number: Option<String>,
50    /// The transfer reversal that's associated with the refund.
51    /// Only present if the charge came from another Stripe account.
52    pub source_transfer_reversal: Option<stripe_types::Expandable<stripe_shared::TransferReversal>>,
53    /// Status of the refund.
54    /// This can be `pending`, `requires_action`, `succeeded`, `failed`, or `canceled`.
55    /// Learn more about [failed refunds](https://stripe.com/docs/refunds#failed-refunds).
56    pub status: Option<String>,
57    /// This refers to the transfer reversal object if the accompanying transfer reverses.
58    /// This is only applicable if the charge was created using the destination parameter.
59    pub transfer_reversal: Option<stripe_types::Expandable<stripe_shared::TransferReversal>>,
60}
61#[doc(hidden)]
62pub struct RefundBuilder {
63    amount: Option<i64>,
64    balance_transaction:
65        Option<Option<stripe_types::Expandable<stripe_shared::BalanceTransaction>>>,
66    charge: Option<Option<stripe_types::Expandable<stripe_shared::Charge>>>,
67    created: Option<stripe_types::Timestamp>,
68    currency: Option<stripe_types::Currency>,
69    description: Option<Option<String>>,
70    destination_details: Option<Option<stripe_shared::RefundDestinationDetails>>,
71    failure_balance_transaction:
72        Option<Option<stripe_types::Expandable<stripe_shared::BalanceTransaction>>>,
73    failure_reason: Option<Option<String>>,
74    id: Option<stripe_shared::RefundId>,
75    instructions_email: Option<Option<String>>,
76    metadata: Option<Option<std::collections::HashMap<String, String>>>,
77    next_action: Option<Option<stripe_shared::RefundNextAction>>,
78    payment_intent: Option<Option<stripe_types::Expandable<stripe_shared::PaymentIntent>>>,
79    pending_reason: Option<Option<RefundPendingReason>>,
80    presentment_details: Option<Option<stripe_shared::PaymentFlowsPaymentIntentPresentmentDetails>>,
81    reason: Option<Option<RefundReason>>,
82    receipt_number: Option<Option<String>>,
83    source_transfer_reversal:
84        Option<Option<stripe_types::Expandable<stripe_shared::TransferReversal>>>,
85    status: Option<Option<String>>,
86    transfer_reversal: Option<Option<stripe_types::Expandable<stripe_shared::TransferReversal>>>,
87}
88
89#[allow(
90    unused_variables,
91    irrefutable_let_patterns,
92    clippy::let_unit_value,
93    clippy::match_single_binding,
94    clippy::single_match
95)]
96const _: () = {
97    use miniserde::de::{Map, Visitor};
98    use miniserde::json::Value;
99    use miniserde::{Deserialize, Result, make_place};
100    use stripe_types::miniserde_helpers::FromValueOpt;
101    use stripe_types::{MapBuilder, ObjectDeser};
102
103    make_place!(Place);
104
105    impl Deserialize for Refund {
106        fn begin(out: &mut Option<Self>) -> &mut dyn Visitor {
107            Place::new(out)
108        }
109    }
110
111    struct Builder<'a> {
112        out: &'a mut Option<Refund>,
113        builder: RefundBuilder,
114    }
115
116    impl Visitor for Place<Refund> {
117        fn map(&mut self) -> Result<Box<dyn Map + '_>> {
118            Ok(Box::new(Builder { out: &mut self.out, builder: RefundBuilder::deser_default() }))
119        }
120    }
121
122    impl MapBuilder for RefundBuilder {
123        type Out = Refund;
124        fn key(&mut self, k: &str) -> Result<&mut dyn Visitor> {
125            Ok(match k {
126                "amount" => Deserialize::begin(&mut self.amount),
127                "balance_transaction" => Deserialize::begin(&mut self.balance_transaction),
128                "charge" => Deserialize::begin(&mut self.charge),
129                "created" => Deserialize::begin(&mut self.created),
130                "currency" => Deserialize::begin(&mut self.currency),
131                "description" => Deserialize::begin(&mut self.description),
132                "destination_details" => Deserialize::begin(&mut self.destination_details),
133                "failure_balance_transaction" => {
134                    Deserialize::begin(&mut self.failure_balance_transaction)
135                }
136                "failure_reason" => Deserialize::begin(&mut self.failure_reason),
137                "id" => Deserialize::begin(&mut self.id),
138                "instructions_email" => Deserialize::begin(&mut self.instructions_email),
139                "metadata" => Deserialize::begin(&mut self.metadata),
140                "next_action" => Deserialize::begin(&mut self.next_action),
141                "payment_intent" => Deserialize::begin(&mut self.payment_intent),
142                "pending_reason" => Deserialize::begin(&mut self.pending_reason),
143                "presentment_details" => Deserialize::begin(&mut self.presentment_details),
144                "reason" => Deserialize::begin(&mut self.reason),
145                "receipt_number" => Deserialize::begin(&mut self.receipt_number),
146                "source_transfer_reversal" => {
147                    Deserialize::begin(&mut self.source_transfer_reversal)
148                }
149                "status" => Deserialize::begin(&mut self.status),
150                "transfer_reversal" => Deserialize::begin(&mut self.transfer_reversal),
151                _ => <dyn Visitor>::ignore(),
152            })
153        }
154
155        fn deser_default() -> Self {
156            Self {
157                amount: Deserialize::default(),
158                balance_transaction: Deserialize::default(),
159                charge: Deserialize::default(),
160                created: Deserialize::default(),
161                currency: Deserialize::default(),
162                description: Deserialize::default(),
163                destination_details: Deserialize::default(),
164                failure_balance_transaction: Deserialize::default(),
165                failure_reason: Deserialize::default(),
166                id: Deserialize::default(),
167                instructions_email: Deserialize::default(),
168                metadata: Deserialize::default(),
169                next_action: Deserialize::default(),
170                payment_intent: Deserialize::default(),
171                pending_reason: Deserialize::default(),
172                presentment_details: Deserialize::default(),
173                reason: Deserialize::default(),
174                receipt_number: Deserialize::default(),
175                source_transfer_reversal: Deserialize::default(),
176                status: Deserialize::default(),
177                transfer_reversal: Deserialize::default(),
178            }
179        }
180
181        fn take_out(&mut self) -> Option<Self::Out> {
182            let (
183                Some(amount),
184                Some(balance_transaction),
185                Some(charge),
186                Some(created),
187                Some(currency),
188                Some(description),
189                Some(destination_details),
190                Some(failure_balance_transaction),
191                Some(failure_reason),
192                Some(id),
193                Some(instructions_email),
194                Some(metadata),
195                Some(next_action),
196                Some(payment_intent),
197                Some(pending_reason),
198                Some(presentment_details),
199                Some(reason),
200                Some(receipt_number),
201                Some(source_transfer_reversal),
202                Some(status),
203                Some(transfer_reversal),
204            ) = (
205                self.amount,
206                self.balance_transaction.take(),
207                self.charge.take(),
208                self.created,
209                self.currency.take(),
210                self.description.take(),
211                self.destination_details.take(),
212                self.failure_balance_transaction.take(),
213                self.failure_reason.take(),
214                self.id.take(),
215                self.instructions_email.take(),
216                self.metadata.take(),
217                self.next_action.take(),
218                self.payment_intent.take(),
219                self.pending_reason.take(),
220                self.presentment_details.take(),
221                self.reason.take(),
222                self.receipt_number.take(),
223                self.source_transfer_reversal.take(),
224                self.status.take(),
225                self.transfer_reversal.take(),
226            )
227            else {
228                return None;
229            };
230            Some(Self::Out {
231                amount,
232                balance_transaction,
233                charge,
234                created,
235                currency,
236                description,
237                destination_details,
238                failure_balance_transaction,
239                failure_reason,
240                id,
241                instructions_email,
242                metadata,
243                next_action,
244                payment_intent,
245                pending_reason,
246                presentment_details,
247                reason,
248                receipt_number,
249                source_transfer_reversal,
250                status,
251                transfer_reversal,
252            })
253        }
254    }
255
256    impl Map for Builder<'_> {
257        fn key(&mut self, k: &str) -> Result<&mut dyn Visitor> {
258            self.builder.key(k)
259        }
260
261        fn finish(&mut self) -> Result<()> {
262            *self.out = self.builder.take_out();
263            Ok(())
264        }
265    }
266
267    impl ObjectDeser for Refund {
268        type Builder = RefundBuilder;
269    }
270
271    impl FromValueOpt for Refund {
272        fn from_value(v: Value) -> Option<Self> {
273            let Value::Object(obj) = v else {
274                return None;
275            };
276            let mut b = RefundBuilder::deser_default();
277            for (k, v) in obj {
278                match k.as_str() {
279                    "amount" => b.amount = FromValueOpt::from_value(v),
280                    "balance_transaction" => b.balance_transaction = FromValueOpt::from_value(v),
281                    "charge" => b.charge = FromValueOpt::from_value(v),
282                    "created" => b.created = FromValueOpt::from_value(v),
283                    "currency" => b.currency = FromValueOpt::from_value(v),
284                    "description" => b.description = FromValueOpt::from_value(v),
285                    "destination_details" => b.destination_details = FromValueOpt::from_value(v),
286                    "failure_balance_transaction" => {
287                        b.failure_balance_transaction = FromValueOpt::from_value(v)
288                    }
289                    "failure_reason" => b.failure_reason = FromValueOpt::from_value(v),
290                    "id" => b.id = FromValueOpt::from_value(v),
291                    "instructions_email" => b.instructions_email = FromValueOpt::from_value(v),
292                    "metadata" => b.metadata = FromValueOpt::from_value(v),
293                    "next_action" => b.next_action = FromValueOpt::from_value(v),
294                    "payment_intent" => b.payment_intent = FromValueOpt::from_value(v),
295                    "pending_reason" => b.pending_reason = FromValueOpt::from_value(v),
296                    "presentment_details" => b.presentment_details = FromValueOpt::from_value(v),
297                    "reason" => b.reason = FromValueOpt::from_value(v),
298                    "receipt_number" => b.receipt_number = FromValueOpt::from_value(v),
299                    "source_transfer_reversal" => {
300                        b.source_transfer_reversal = FromValueOpt::from_value(v)
301                    }
302                    "status" => b.status = FromValueOpt::from_value(v),
303                    "transfer_reversal" => b.transfer_reversal = FromValueOpt::from_value(v),
304                    _ => {}
305                }
306            }
307            b.take_out()
308        }
309    }
310};
311#[cfg(feature = "serialize")]
312impl serde::Serialize for Refund {
313    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
314        use serde::ser::SerializeStruct;
315        let mut s = s.serialize_struct("Refund", 22)?;
316        s.serialize_field("amount", &self.amount)?;
317        s.serialize_field("balance_transaction", &self.balance_transaction)?;
318        s.serialize_field("charge", &self.charge)?;
319        s.serialize_field("created", &self.created)?;
320        s.serialize_field("currency", &self.currency)?;
321        s.serialize_field("description", &self.description)?;
322        s.serialize_field("destination_details", &self.destination_details)?;
323        s.serialize_field("failure_balance_transaction", &self.failure_balance_transaction)?;
324        s.serialize_field("failure_reason", &self.failure_reason)?;
325        s.serialize_field("id", &self.id)?;
326        s.serialize_field("instructions_email", &self.instructions_email)?;
327        s.serialize_field("metadata", &self.metadata)?;
328        s.serialize_field("next_action", &self.next_action)?;
329        s.serialize_field("payment_intent", &self.payment_intent)?;
330        s.serialize_field("pending_reason", &self.pending_reason)?;
331        s.serialize_field("presentment_details", &self.presentment_details)?;
332        s.serialize_field("reason", &self.reason)?;
333        s.serialize_field("receipt_number", &self.receipt_number)?;
334        s.serialize_field("source_transfer_reversal", &self.source_transfer_reversal)?;
335        s.serialize_field("status", &self.status)?;
336        s.serialize_field("transfer_reversal", &self.transfer_reversal)?;
337
338        s.serialize_field("object", "refund")?;
339        s.end()
340    }
341}
342/// Provides the reason for why the refund is pending.
343/// Possible values are: `processing`, `insufficient_funds`, or `charge_pending`.
344#[derive(Clone, Eq, PartialEq)]
345#[non_exhaustive]
346pub enum RefundPendingReason {
347    ChargePending,
348    InsufficientFunds,
349    Processing,
350    /// An unrecognized value from Stripe. Should not be used as a request parameter.
351    Unknown(String),
352}
353impl RefundPendingReason {
354    pub fn as_str(&self) -> &str {
355        use RefundPendingReason::*;
356        match self {
357            ChargePending => "charge_pending",
358            InsufficientFunds => "insufficient_funds",
359            Processing => "processing",
360            Unknown(v) => v,
361        }
362    }
363}
364
365impl std::str::FromStr for RefundPendingReason {
366    type Err = std::convert::Infallible;
367    fn from_str(s: &str) -> Result<Self, Self::Err> {
368        use RefundPendingReason::*;
369        match s {
370            "charge_pending" => Ok(ChargePending),
371            "insufficient_funds" => Ok(InsufficientFunds),
372            "processing" => Ok(Processing),
373            v => {
374                tracing::warn!("Unknown value '{}' for enum '{}'", v, "RefundPendingReason");
375                Ok(Unknown(v.to_owned()))
376            }
377        }
378    }
379}
380impl std::fmt::Display for RefundPendingReason {
381    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
382        f.write_str(self.as_str())
383    }
384}
385
386impl std::fmt::Debug for RefundPendingReason {
387    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
388        f.write_str(self.as_str())
389    }
390}
391#[cfg(feature = "serialize")]
392impl serde::Serialize for RefundPendingReason {
393    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
394    where
395        S: serde::Serializer,
396    {
397        serializer.serialize_str(self.as_str())
398    }
399}
400impl miniserde::Deserialize for RefundPendingReason {
401    fn begin(out: &mut Option<Self>) -> &mut dyn miniserde::de::Visitor {
402        crate::Place::new(out)
403    }
404}
405
406impl miniserde::de::Visitor for crate::Place<RefundPendingReason> {
407    fn string(&mut self, s: &str) -> miniserde::Result<()> {
408        use std::str::FromStr;
409        self.out = Some(RefundPendingReason::from_str(s).expect("infallible"));
410        Ok(())
411    }
412}
413
414stripe_types::impl_from_val_with_from_str!(RefundPendingReason);
415#[cfg(feature = "deserialize")]
416impl<'de> serde::Deserialize<'de> for RefundPendingReason {
417    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
418        use std::str::FromStr;
419        let s: std::borrow::Cow<'de, str> = serde::Deserialize::deserialize(deserializer)?;
420        Ok(Self::from_str(&s).expect("infallible"))
421    }
422}
423/// Reason for the refund, which is either user-provided (`duplicate`, `fraudulent`, or `requested_by_customer`) or generated by Stripe internally (`expired_uncaptured_charge`).
424#[derive(Clone, Eq, PartialEq)]
425#[non_exhaustive]
426pub enum RefundReason {
427    Duplicate,
428    ExpiredUncapturedCharge,
429    Fraudulent,
430    RequestedByCustomer,
431    /// An unrecognized value from Stripe. Should not be used as a request parameter.
432    Unknown(String),
433}
434impl RefundReason {
435    pub fn as_str(&self) -> &str {
436        use RefundReason::*;
437        match self {
438            Duplicate => "duplicate",
439            ExpiredUncapturedCharge => "expired_uncaptured_charge",
440            Fraudulent => "fraudulent",
441            RequestedByCustomer => "requested_by_customer",
442            Unknown(v) => v,
443        }
444    }
445}
446
447impl std::str::FromStr for RefundReason {
448    type Err = std::convert::Infallible;
449    fn from_str(s: &str) -> Result<Self, Self::Err> {
450        use RefundReason::*;
451        match s {
452            "duplicate" => Ok(Duplicate),
453            "expired_uncaptured_charge" => Ok(ExpiredUncapturedCharge),
454            "fraudulent" => Ok(Fraudulent),
455            "requested_by_customer" => Ok(RequestedByCustomer),
456            v => {
457                tracing::warn!("Unknown value '{}' for enum '{}'", v, "RefundReason");
458                Ok(Unknown(v.to_owned()))
459            }
460        }
461    }
462}
463impl std::fmt::Display for RefundReason {
464    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
465        f.write_str(self.as_str())
466    }
467}
468
469impl std::fmt::Debug for RefundReason {
470    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
471        f.write_str(self.as_str())
472    }
473}
474#[cfg(feature = "serialize")]
475impl serde::Serialize for RefundReason {
476    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
477    where
478        S: serde::Serializer,
479    {
480        serializer.serialize_str(self.as_str())
481    }
482}
483impl miniserde::Deserialize for RefundReason {
484    fn begin(out: &mut Option<Self>) -> &mut dyn miniserde::de::Visitor {
485        crate::Place::new(out)
486    }
487}
488
489impl miniserde::de::Visitor for crate::Place<RefundReason> {
490    fn string(&mut self, s: &str) -> miniserde::Result<()> {
491        use std::str::FromStr;
492        self.out = Some(RefundReason::from_str(s).expect("infallible"));
493        Ok(())
494    }
495}
496
497stripe_types::impl_from_val_with_from_str!(RefundReason);
498#[cfg(feature = "deserialize")]
499impl<'de> serde::Deserialize<'de> for RefundReason {
500    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
501        use std::str::FromStr;
502        let s: std::borrow::Cow<'de, str> = serde::Deserialize::deserialize(deserializer)?;
503        Ok(Self::from_str(&s).expect("infallible"))
504    }
505}
506impl stripe_types::Object for Refund {
507    type Id = stripe_shared::RefundId;
508    fn id(&self) -> &Self::Id {
509        &self.id
510    }
511
512    fn into_id(self) -> Self::Id {
513        self.id
514    }
515}
516stripe_types::def_id!(RefundId);