stripe_shared/
issuing_dispute.rs

1/// As a [card issuer](https://stripe.com/docs/issuing), you can dispute transactions that the cardholder does not recognize, suspects to be fraudulent, or has other issues with.
2///
3/// Related guide: [Issuing disputes](https://stripe.com/docs/issuing/purchases/disputes)
4///
5/// For more details see <<https://stripe.com/docs/api/issuing/disputes/object>>.
6#[derive(Clone, Debug)]
7#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
8pub struct IssuingDispute {
9    /// Disputed amount in the card's currency and in the [smallest currency unit](https://stripe.com/docs/currencies#zero-decimal).
10    /// Usually the amount of the `transaction`, but can differ (usually because of currency fluctuation).
11    pub amount: i64,
12    /// List of balance transactions associated with the dispute.
13    pub balance_transactions: Option<Vec<stripe_shared::BalanceTransaction>>,
14    /// Time at which the object was created. Measured in seconds since the Unix epoch.
15    pub created: stripe_types::Timestamp,
16    /// The currency the `transaction` was made in.
17    pub currency: stripe_types::Currency,
18    pub evidence: stripe_shared::IssuingDisputeEvidence,
19    /// Unique identifier for the object.
20    pub id: stripe_shared::IssuingDisputeId,
21    /// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode.
22    pub livemode: bool,
23    /// The enum that describes the dispute loss outcome.
24    /// If the dispute is not lost, this field will be absent.
25    /// New enum values may be added in the future, so be sure to handle unknown values.
26    pub loss_reason: Option<IssuingDisputeLossReason>,
27    /// Set of [key-value pairs](https://stripe.com/docs/api/metadata) that you can attach to an object.
28    /// This can be useful for storing additional information about the object in a structured format.
29    pub metadata: std::collections::HashMap<String, String>,
30    /// Current status of the dispute.
31    pub status: stripe_shared::IssuingDisputeStatus,
32    /// The transaction being disputed.
33    pub transaction: stripe_types::Expandable<stripe_shared::IssuingTransaction>,
34    /// [Treasury](https://stripe.com/docs/api/treasury) details related to this dispute if it was created on a [FinancialAccount](/docs/api/treasury/financial_accounts.
35    pub treasury: Option<stripe_shared::IssuingDisputeTreasury>,
36}
37#[doc(hidden)]
38pub struct IssuingDisputeBuilder {
39    amount: Option<i64>,
40    balance_transactions: Option<Option<Vec<stripe_shared::BalanceTransaction>>>,
41    created: Option<stripe_types::Timestamp>,
42    currency: Option<stripe_types::Currency>,
43    evidence: Option<stripe_shared::IssuingDisputeEvidence>,
44    id: Option<stripe_shared::IssuingDisputeId>,
45    livemode: Option<bool>,
46    loss_reason: Option<Option<IssuingDisputeLossReason>>,
47    metadata: Option<std::collections::HashMap<String, String>>,
48    status: Option<stripe_shared::IssuingDisputeStatus>,
49    transaction: Option<stripe_types::Expandable<stripe_shared::IssuingTransaction>>,
50    treasury: Option<Option<stripe_shared::IssuingDisputeTreasury>>,
51}
52
53#[allow(
54    unused_variables,
55    irrefutable_let_patterns,
56    clippy::let_unit_value,
57    clippy::match_single_binding,
58    clippy::single_match
59)]
60const _: () = {
61    use miniserde::de::{Map, Visitor};
62    use miniserde::json::Value;
63    use miniserde::{Deserialize, Result, make_place};
64    use stripe_types::miniserde_helpers::FromValueOpt;
65    use stripe_types::{MapBuilder, ObjectDeser};
66
67    make_place!(Place);
68
69    impl Deserialize for IssuingDispute {
70        fn begin(out: &mut Option<Self>) -> &mut dyn Visitor {
71            Place::new(out)
72        }
73    }
74
75    struct Builder<'a> {
76        out: &'a mut Option<IssuingDispute>,
77        builder: IssuingDisputeBuilder,
78    }
79
80    impl Visitor for Place<IssuingDispute> {
81        fn map(&mut self) -> Result<Box<dyn Map + '_>> {
82            Ok(Box::new(Builder {
83                out: &mut self.out,
84                builder: IssuingDisputeBuilder::deser_default(),
85            }))
86        }
87    }
88
89    impl MapBuilder for IssuingDisputeBuilder {
90        type Out = IssuingDispute;
91        fn key(&mut self, k: &str) -> Result<&mut dyn Visitor> {
92            Ok(match k {
93                "amount" => Deserialize::begin(&mut self.amount),
94                "balance_transactions" => Deserialize::begin(&mut self.balance_transactions),
95                "created" => Deserialize::begin(&mut self.created),
96                "currency" => Deserialize::begin(&mut self.currency),
97                "evidence" => Deserialize::begin(&mut self.evidence),
98                "id" => Deserialize::begin(&mut self.id),
99                "livemode" => Deserialize::begin(&mut self.livemode),
100                "loss_reason" => Deserialize::begin(&mut self.loss_reason),
101                "metadata" => Deserialize::begin(&mut self.metadata),
102                "status" => Deserialize::begin(&mut self.status),
103                "transaction" => Deserialize::begin(&mut self.transaction),
104                "treasury" => Deserialize::begin(&mut self.treasury),
105                _ => <dyn Visitor>::ignore(),
106            })
107        }
108
109        fn deser_default() -> Self {
110            Self {
111                amount: Deserialize::default(),
112                balance_transactions: Deserialize::default(),
113                created: Deserialize::default(),
114                currency: Deserialize::default(),
115                evidence: Deserialize::default(),
116                id: Deserialize::default(),
117                livemode: Deserialize::default(),
118                loss_reason: Deserialize::default(),
119                metadata: Deserialize::default(),
120                status: Deserialize::default(),
121                transaction: Deserialize::default(),
122                treasury: Deserialize::default(),
123            }
124        }
125
126        fn take_out(&mut self) -> Option<Self::Out> {
127            let (
128                Some(amount),
129                Some(balance_transactions),
130                Some(created),
131                Some(currency),
132                Some(evidence),
133                Some(id),
134                Some(livemode),
135                Some(loss_reason),
136                Some(metadata),
137                Some(status),
138                Some(transaction),
139                Some(treasury),
140            ) = (
141                self.amount,
142                self.balance_transactions.take(),
143                self.created,
144                self.currency.take(),
145                self.evidence.take(),
146                self.id.take(),
147                self.livemode,
148                self.loss_reason.take(),
149                self.metadata.take(),
150                self.status,
151                self.transaction.take(),
152                self.treasury.take(),
153            )
154            else {
155                return None;
156            };
157            Some(Self::Out {
158                amount,
159                balance_transactions,
160                created,
161                currency,
162                evidence,
163                id,
164                livemode,
165                loss_reason,
166                metadata,
167                status,
168                transaction,
169                treasury,
170            })
171        }
172    }
173
174    impl Map for Builder<'_> {
175        fn key(&mut self, k: &str) -> Result<&mut dyn Visitor> {
176            self.builder.key(k)
177        }
178
179        fn finish(&mut self) -> Result<()> {
180            *self.out = self.builder.take_out();
181            Ok(())
182        }
183    }
184
185    impl ObjectDeser for IssuingDispute {
186        type Builder = IssuingDisputeBuilder;
187    }
188
189    impl FromValueOpt for IssuingDispute {
190        fn from_value(v: Value) -> Option<Self> {
191            let Value::Object(obj) = v else {
192                return None;
193            };
194            let mut b = IssuingDisputeBuilder::deser_default();
195            for (k, v) in obj {
196                match k.as_str() {
197                    "amount" => b.amount = FromValueOpt::from_value(v),
198                    "balance_transactions" => b.balance_transactions = FromValueOpt::from_value(v),
199                    "created" => b.created = FromValueOpt::from_value(v),
200                    "currency" => b.currency = FromValueOpt::from_value(v),
201                    "evidence" => b.evidence = FromValueOpt::from_value(v),
202                    "id" => b.id = FromValueOpt::from_value(v),
203                    "livemode" => b.livemode = FromValueOpt::from_value(v),
204                    "loss_reason" => b.loss_reason = FromValueOpt::from_value(v),
205                    "metadata" => b.metadata = FromValueOpt::from_value(v),
206                    "status" => b.status = FromValueOpt::from_value(v),
207                    "transaction" => b.transaction = FromValueOpt::from_value(v),
208                    "treasury" => b.treasury = FromValueOpt::from_value(v),
209                    _ => {}
210                }
211            }
212            b.take_out()
213        }
214    }
215};
216#[cfg(feature = "serialize")]
217impl serde::Serialize for IssuingDispute {
218    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
219        use serde::ser::SerializeStruct;
220        let mut s = s.serialize_struct("IssuingDispute", 13)?;
221        s.serialize_field("amount", &self.amount)?;
222        s.serialize_field("balance_transactions", &self.balance_transactions)?;
223        s.serialize_field("created", &self.created)?;
224        s.serialize_field("currency", &self.currency)?;
225        s.serialize_field("evidence", &self.evidence)?;
226        s.serialize_field("id", &self.id)?;
227        s.serialize_field("livemode", &self.livemode)?;
228        s.serialize_field("loss_reason", &self.loss_reason)?;
229        s.serialize_field("metadata", &self.metadata)?;
230        s.serialize_field("status", &self.status)?;
231        s.serialize_field("transaction", &self.transaction)?;
232        s.serialize_field("treasury", &self.treasury)?;
233
234        s.serialize_field("object", "issuing.dispute")?;
235        s.end()
236    }
237}
238/// The enum that describes the dispute loss outcome.
239/// If the dispute is not lost, this field will be absent.
240/// New enum values may be added in the future, so be sure to handle unknown values.
241#[derive(Clone, Eq, PartialEq)]
242#[non_exhaustive]
243pub enum IssuingDisputeLossReason {
244    CardholderAuthenticationIssuerLiability,
245    Eci5TokenTransactionWithTavv,
246    ExcessDisputesInTimeframe,
247    HasNotMetTheMinimumDisputeAmountRequirements,
248    InvalidDuplicateDispute,
249    InvalidIncorrectAmountDispute,
250    InvalidNoAuthorization,
251    InvalidUseOfDisputes,
252    MerchandiseDeliveredOrShipped,
253    MerchandiseOrServiceAsDescribed,
254    NotCancelled,
255    Other,
256    RefundIssued,
257    SubmittedBeyondAllowableTimeLimit,
258    Transaction3dsRequired,
259    TransactionApprovedAfterPriorFraudDispute,
260    TransactionAuthorized,
261    TransactionElectronicallyRead,
262    TransactionQualifiesForVisaEasyPaymentService,
263    TransactionUnattended,
264    /// An unrecognized value from Stripe. Should not be used as a request parameter.
265    Unknown(String),
266}
267impl IssuingDisputeLossReason {
268    pub fn as_str(&self) -> &str {
269        use IssuingDisputeLossReason::*;
270        match self {
271            CardholderAuthenticationIssuerLiability => "cardholder_authentication_issuer_liability",
272            Eci5TokenTransactionWithTavv => "eci5_token_transaction_with_tavv",
273            ExcessDisputesInTimeframe => "excess_disputes_in_timeframe",
274            HasNotMetTheMinimumDisputeAmountRequirements => {
275                "has_not_met_the_minimum_dispute_amount_requirements"
276            }
277            InvalidDuplicateDispute => "invalid_duplicate_dispute",
278            InvalidIncorrectAmountDispute => "invalid_incorrect_amount_dispute",
279            InvalidNoAuthorization => "invalid_no_authorization",
280            InvalidUseOfDisputes => "invalid_use_of_disputes",
281            MerchandiseDeliveredOrShipped => "merchandise_delivered_or_shipped",
282            MerchandiseOrServiceAsDescribed => "merchandise_or_service_as_described",
283            NotCancelled => "not_cancelled",
284            Other => "other",
285            RefundIssued => "refund_issued",
286            SubmittedBeyondAllowableTimeLimit => "submitted_beyond_allowable_time_limit",
287            Transaction3dsRequired => "transaction_3ds_required",
288            TransactionApprovedAfterPriorFraudDispute => {
289                "transaction_approved_after_prior_fraud_dispute"
290            }
291            TransactionAuthorized => "transaction_authorized",
292            TransactionElectronicallyRead => "transaction_electronically_read",
293            TransactionQualifiesForVisaEasyPaymentService => {
294                "transaction_qualifies_for_visa_easy_payment_service"
295            }
296            TransactionUnattended => "transaction_unattended",
297            Unknown(v) => v,
298        }
299    }
300}
301
302impl std::str::FromStr for IssuingDisputeLossReason {
303    type Err = std::convert::Infallible;
304    fn from_str(s: &str) -> Result<Self, Self::Err> {
305        use IssuingDisputeLossReason::*;
306        match s {
307            "cardholder_authentication_issuer_liability" => {
308                Ok(CardholderAuthenticationIssuerLiability)
309            }
310            "eci5_token_transaction_with_tavv" => Ok(Eci5TokenTransactionWithTavv),
311            "excess_disputes_in_timeframe" => Ok(ExcessDisputesInTimeframe),
312            "has_not_met_the_minimum_dispute_amount_requirements" => {
313                Ok(HasNotMetTheMinimumDisputeAmountRequirements)
314            }
315            "invalid_duplicate_dispute" => Ok(InvalidDuplicateDispute),
316            "invalid_incorrect_amount_dispute" => Ok(InvalidIncorrectAmountDispute),
317            "invalid_no_authorization" => Ok(InvalidNoAuthorization),
318            "invalid_use_of_disputes" => Ok(InvalidUseOfDisputes),
319            "merchandise_delivered_or_shipped" => Ok(MerchandiseDeliveredOrShipped),
320            "merchandise_or_service_as_described" => Ok(MerchandiseOrServiceAsDescribed),
321            "not_cancelled" => Ok(NotCancelled),
322            "other" => Ok(Other),
323            "refund_issued" => Ok(RefundIssued),
324            "submitted_beyond_allowable_time_limit" => Ok(SubmittedBeyondAllowableTimeLimit),
325            "transaction_3ds_required" => Ok(Transaction3dsRequired),
326            "transaction_approved_after_prior_fraud_dispute" => {
327                Ok(TransactionApprovedAfterPriorFraudDispute)
328            }
329            "transaction_authorized" => Ok(TransactionAuthorized),
330            "transaction_electronically_read" => Ok(TransactionElectronicallyRead),
331            "transaction_qualifies_for_visa_easy_payment_service" => {
332                Ok(TransactionQualifiesForVisaEasyPaymentService)
333            }
334            "transaction_unattended" => Ok(TransactionUnattended),
335            v => Ok(Unknown(v.to_owned())),
336        }
337    }
338}
339impl std::fmt::Display for IssuingDisputeLossReason {
340    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
341        f.write_str(self.as_str())
342    }
343}
344
345impl std::fmt::Debug for IssuingDisputeLossReason {
346    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
347        f.write_str(self.as_str())
348    }
349}
350#[cfg(feature = "serialize")]
351impl serde::Serialize for IssuingDisputeLossReason {
352    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
353    where
354        S: serde::Serializer,
355    {
356        serializer.serialize_str(self.as_str())
357    }
358}
359impl miniserde::Deserialize for IssuingDisputeLossReason {
360    fn begin(out: &mut Option<Self>) -> &mut dyn miniserde::de::Visitor {
361        crate::Place::new(out)
362    }
363}
364
365impl miniserde::de::Visitor for crate::Place<IssuingDisputeLossReason> {
366    fn string(&mut self, s: &str) -> miniserde::Result<()> {
367        use std::str::FromStr;
368        self.out = Some(IssuingDisputeLossReason::from_str(s).unwrap());
369        Ok(())
370    }
371}
372
373stripe_types::impl_from_val_with_from_str!(IssuingDisputeLossReason);
374#[cfg(feature = "deserialize")]
375impl<'de> serde::Deserialize<'de> for IssuingDisputeLossReason {
376    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
377        use std::str::FromStr;
378        let s: std::borrow::Cow<'de, str> = serde::Deserialize::deserialize(deserializer)?;
379        Ok(Self::from_str(&s).unwrap())
380    }
381}
382impl stripe_types::Object for IssuingDispute {
383    type Id = stripe_shared::IssuingDisputeId;
384    fn id(&self) -> &Self::Id {
385        &self.id
386    }
387
388    fn into_id(self) -> Self::Id {
389        self.id
390    }
391}
392stripe_types::def_id!(IssuingDisputeId);
393#[derive(Copy, Clone, Eq, PartialEq)]
394pub enum IssuingDisputeStatus {
395    Expired,
396    Lost,
397    Submitted,
398    Unsubmitted,
399    Won,
400}
401impl IssuingDisputeStatus {
402    pub fn as_str(self) -> &'static str {
403        use IssuingDisputeStatus::*;
404        match self {
405            Expired => "expired",
406            Lost => "lost",
407            Submitted => "submitted",
408            Unsubmitted => "unsubmitted",
409            Won => "won",
410        }
411    }
412}
413
414impl std::str::FromStr for IssuingDisputeStatus {
415    type Err = stripe_types::StripeParseError;
416    fn from_str(s: &str) -> Result<Self, Self::Err> {
417        use IssuingDisputeStatus::*;
418        match s {
419            "expired" => Ok(Expired),
420            "lost" => Ok(Lost),
421            "submitted" => Ok(Submitted),
422            "unsubmitted" => Ok(Unsubmitted),
423            "won" => Ok(Won),
424            _ => Err(stripe_types::StripeParseError),
425        }
426    }
427}
428impl std::fmt::Display for IssuingDisputeStatus {
429    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
430        f.write_str(self.as_str())
431    }
432}
433
434impl std::fmt::Debug for IssuingDisputeStatus {
435    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
436        f.write_str(self.as_str())
437    }
438}
439impl serde::Serialize for IssuingDisputeStatus {
440    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
441    where
442        S: serde::Serializer,
443    {
444        serializer.serialize_str(self.as_str())
445    }
446}
447impl miniserde::Deserialize for IssuingDisputeStatus {
448    fn begin(out: &mut Option<Self>) -> &mut dyn miniserde::de::Visitor {
449        crate::Place::new(out)
450    }
451}
452
453impl miniserde::de::Visitor for crate::Place<IssuingDisputeStatus> {
454    fn string(&mut self, s: &str) -> miniserde::Result<()> {
455        use std::str::FromStr;
456        self.out = Some(IssuingDisputeStatus::from_str(s).map_err(|_| miniserde::Error)?);
457        Ok(())
458    }
459}
460
461stripe_types::impl_from_val_with_from_str!(IssuingDisputeStatus);
462#[cfg(feature = "deserialize")]
463impl<'de> serde::Deserialize<'de> for IssuingDisputeStatus {
464    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
465        use std::str::FromStr;
466        let s: std::borrow::Cow<'de, str> = serde::Deserialize::deserialize(deserializer)?;
467        Self::from_str(&s)
468            .map_err(|_| serde::de::Error::custom("Unknown value for IssuingDisputeStatus"))
469    }
470}