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::{make_place, Deserialize, Result};
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
106                _ => <dyn Visitor>::ignore(),
107            })
108        }
109
110        fn deser_default() -> Self {
111            Self {
112                amount: Deserialize::default(),
113                balance_transactions: Deserialize::default(),
114                created: Deserialize::default(),
115                currency: Deserialize::default(),
116                evidence: Deserialize::default(),
117                id: Deserialize::default(),
118                livemode: Deserialize::default(),
119                loss_reason: Deserialize::default(),
120                metadata: Deserialize::default(),
121                status: Deserialize::default(),
122                transaction: Deserialize::default(),
123                treasury: Deserialize::default(),
124            }
125        }
126
127        fn take_out(&mut self) -> Option<Self::Out> {
128            let (
129                Some(amount),
130                Some(balance_transactions),
131                Some(created),
132                Some(currency),
133                Some(evidence),
134                Some(id),
135                Some(livemode),
136                Some(loss_reason),
137                Some(metadata),
138                Some(status),
139                Some(transaction),
140                Some(treasury),
141            ) = (
142                self.amount,
143                self.balance_transactions.take(),
144                self.created,
145                self.currency.take(),
146                self.evidence.take(),
147                self.id.take(),
148                self.livemode,
149                self.loss_reason.take(),
150                self.metadata.take(),
151                self.status,
152                self.transaction.take(),
153                self.treasury.take(),
154            )
155            else {
156                return None;
157            };
158            Some(Self::Out {
159                amount,
160                balance_transactions,
161                created,
162                currency,
163                evidence,
164                id,
165                livemode,
166                loss_reason,
167                metadata,
168                status,
169                transaction,
170                treasury,
171            })
172        }
173    }
174
175    impl Map for Builder<'_> {
176        fn key(&mut self, k: &str) -> Result<&mut dyn Visitor> {
177            self.builder.key(k)
178        }
179
180        fn finish(&mut self) -> Result<()> {
181            *self.out = self.builder.take_out();
182            Ok(())
183        }
184    }
185
186    impl ObjectDeser for IssuingDispute {
187        type Builder = IssuingDisputeBuilder;
188    }
189
190    impl FromValueOpt for IssuingDispute {
191        fn from_value(v: Value) -> Option<Self> {
192            let Value::Object(obj) = v else {
193                return None;
194            };
195            let mut b = IssuingDisputeBuilder::deser_default();
196            for (k, v) in obj {
197                match k.as_str() {
198                    "amount" => b.amount = FromValueOpt::from_value(v),
199                    "balance_transactions" => b.balance_transactions = FromValueOpt::from_value(v),
200                    "created" => b.created = FromValueOpt::from_value(v),
201                    "currency" => b.currency = FromValueOpt::from_value(v),
202                    "evidence" => b.evidence = FromValueOpt::from_value(v),
203                    "id" => b.id = FromValueOpt::from_value(v),
204                    "livemode" => b.livemode = FromValueOpt::from_value(v),
205                    "loss_reason" => b.loss_reason = FromValueOpt::from_value(v),
206                    "metadata" => b.metadata = FromValueOpt::from_value(v),
207                    "status" => b.status = FromValueOpt::from_value(v),
208                    "transaction" => b.transaction = FromValueOpt::from_value(v),
209                    "treasury" => b.treasury = FromValueOpt::from_value(v),
210
211                    _ => {}
212                }
213            }
214            b.take_out()
215        }
216    }
217};
218#[cfg(feature = "serialize")]
219impl serde::Serialize for IssuingDispute {
220    fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
221        use serde::ser::SerializeStruct;
222        let mut s = s.serialize_struct("IssuingDispute", 13)?;
223        s.serialize_field("amount", &self.amount)?;
224        s.serialize_field("balance_transactions", &self.balance_transactions)?;
225        s.serialize_field("created", &self.created)?;
226        s.serialize_field("currency", &self.currency)?;
227        s.serialize_field("evidence", &self.evidence)?;
228        s.serialize_field("id", &self.id)?;
229        s.serialize_field("livemode", &self.livemode)?;
230        s.serialize_field("loss_reason", &self.loss_reason)?;
231        s.serialize_field("metadata", &self.metadata)?;
232        s.serialize_field("status", &self.status)?;
233        s.serialize_field("transaction", &self.transaction)?;
234        s.serialize_field("treasury", &self.treasury)?;
235
236        s.serialize_field("object", "issuing.dispute")?;
237        s.end()
238    }
239}
240/// The enum that describes the dispute loss outcome.
241/// If the dispute is not lost, this field will be absent.
242/// New enum values may be added in the future, so be sure to handle unknown values.
243#[derive(Clone, Eq, PartialEq)]
244#[non_exhaustive]
245pub enum IssuingDisputeLossReason {
246    CardholderAuthenticationIssuerLiability,
247    Eci5TokenTransactionWithTavv,
248    ExcessDisputesInTimeframe,
249    HasNotMetTheMinimumDisputeAmountRequirements,
250    InvalidDuplicateDispute,
251    InvalidIncorrectAmountDispute,
252    InvalidNoAuthorization,
253    InvalidUseOfDisputes,
254    MerchandiseDeliveredOrShipped,
255    MerchandiseOrServiceAsDescribed,
256    NotCancelled,
257    Other,
258    RefundIssued,
259    SubmittedBeyondAllowableTimeLimit,
260    Transaction3dsRequired,
261    TransactionApprovedAfterPriorFraudDispute,
262    TransactionAuthorized,
263    TransactionElectronicallyRead,
264    TransactionQualifiesForVisaEasyPaymentService,
265    TransactionUnattended,
266    /// An unrecognized value from Stripe. Should not be used as a request parameter.
267    Unknown(String),
268}
269impl IssuingDisputeLossReason {
270    pub fn as_str(&self) -> &str {
271        use IssuingDisputeLossReason::*;
272        match self {
273            CardholderAuthenticationIssuerLiability => "cardholder_authentication_issuer_liability",
274            Eci5TokenTransactionWithTavv => "eci5_token_transaction_with_tavv",
275            ExcessDisputesInTimeframe => "excess_disputes_in_timeframe",
276            HasNotMetTheMinimumDisputeAmountRequirements => {
277                "has_not_met_the_minimum_dispute_amount_requirements"
278            }
279            InvalidDuplicateDispute => "invalid_duplicate_dispute",
280            InvalidIncorrectAmountDispute => "invalid_incorrect_amount_dispute",
281            InvalidNoAuthorization => "invalid_no_authorization",
282            InvalidUseOfDisputes => "invalid_use_of_disputes",
283            MerchandiseDeliveredOrShipped => "merchandise_delivered_or_shipped",
284            MerchandiseOrServiceAsDescribed => "merchandise_or_service_as_described",
285            NotCancelled => "not_cancelled",
286            Other => "other",
287            RefundIssued => "refund_issued",
288            SubmittedBeyondAllowableTimeLimit => "submitted_beyond_allowable_time_limit",
289            Transaction3dsRequired => "transaction_3ds_required",
290            TransactionApprovedAfterPriorFraudDispute => {
291                "transaction_approved_after_prior_fraud_dispute"
292            }
293            TransactionAuthorized => "transaction_authorized",
294            TransactionElectronicallyRead => "transaction_electronically_read",
295            TransactionQualifiesForVisaEasyPaymentService => {
296                "transaction_qualifies_for_visa_easy_payment_service"
297            }
298            TransactionUnattended => "transaction_unattended",
299            Unknown(v) => v,
300        }
301    }
302}
303
304impl std::str::FromStr for IssuingDisputeLossReason {
305    type Err = std::convert::Infallible;
306    fn from_str(s: &str) -> Result<Self, Self::Err> {
307        use IssuingDisputeLossReason::*;
308        match s {
309            "cardholder_authentication_issuer_liability" => {
310                Ok(CardholderAuthenticationIssuerLiability)
311            }
312            "eci5_token_transaction_with_tavv" => Ok(Eci5TokenTransactionWithTavv),
313            "excess_disputes_in_timeframe" => Ok(ExcessDisputesInTimeframe),
314            "has_not_met_the_minimum_dispute_amount_requirements" => {
315                Ok(HasNotMetTheMinimumDisputeAmountRequirements)
316            }
317            "invalid_duplicate_dispute" => Ok(InvalidDuplicateDispute),
318            "invalid_incorrect_amount_dispute" => Ok(InvalidIncorrectAmountDispute),
319            "invalid_no_authorization" => Ok(InvalidNoAuthorization),
320            "invalid_use_of_disputes" => Ok(InvalidUseOfDisputes),
321            "merchandise_delivered_or_shipped" => Ok(MerchandiseDeliveredOrShipped),
322            "merchandise_or_service_as_described" => Ok(MerchandiseOrServiceAsDescribed),
323            "not_cancelled" => Ok(NotCancelled),
324            "other" => Ok(Other),
325            "refund_issued" => Ok(RefundIssued),
326            "submitted_beyond_allowable_time_limit" => Ok(SubmittedBeyondAllowableTimeLimit),
327            "transaction_3ds_required" => Ok(Transaction3dsRequired),
328            "transaction_approved_after_prior_fraud_dispute" => {
329                Ok(TransactionApprovedAfterPriorFraudDispute)
330            }
331            "transaction_authorized" => Ok(TransactionAuthorized),
332            "transaction_electronically_read" => Ok(TransactionElectronicallyRead),
333            "transaction_qualifies_for_visa_easy_payment_service" => {
334                Ok(TransactionQualifiesForVisaEasyPaymentService)
335            }
336            "transaction_unattended" => Ok(TransactionUnattended),
337            v => Ok(Unknown(v.to_owned())),
338        }
339    }
340}
341impl std::fmt::Display for IssuingDisputeLossReason {
342    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
343        f.write_str(self.as_str())
344    }
345}
346
347impl std::fmt::Debug for IssuingDisputeLossReason {
348    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
349        f.write_str(self.as_str())
350    }
351}
352#[cfg(feature = "serialize")]
353impl serde::Serialize for IssuingDisputeLossReason {
354    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
355    where
356        S: serde::Serializer,
357    {
358        serializer.serialize_str(self.as_str())
359    }
360}
361impl miniserde::Deserialize for IssuingDisputeLossReason {
362    fn begin(out: &mut Option<Self>) -> &mut dyn miniserde::de::Visitor {
363        crate::Place::new(out)
364    }
365}
366
367impl miniserde::de::Visitor for crate::Place<IssuingDisputeLossReason> {
368    fn string(&mut self, s: &str) -> miniserde::Result<()> {
369        use std::str::FromStr;
370        self.out = Some(IssuingDisputeLossReason::from_str(s).unwrap());
371        Ok(())
372    }
373}
374
375stripe_types::impl_from_val_with_from_str!(IssuingDisputeLossReason);
376#[cfg(feature = "deserialize")]
377impl<'de> serde::Deserialize<'de> for IssuingDisputeLossReason {
378    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
379        use std::str::FromStr;
380        let s: std::borrow::Cow<'de, str> = serde::Deserialize::deserialize(deserializer)?;
381        Ok(Self::from_str(&s).unwrap())
382    }
383}
384impl stripe_types::Object for IssuingDispute {
385    type Id = stripe_shared::IssuingDisputeId;
386    fn id(&self) -> &Self::Id {
387        &self.id
388    }
389
390    fn into_id(self) -> Self::Id {
391        self.id
392    }
393}
394stripe_types::def_id!(IssuingDisputeId);
395#[derive(Copy, Clone, Eq, PartialEq)]
396pub enum IssuingDisputeStatus {
397    Expired,
398    Lost,
399    Submitted,
400    Unsubmitted,
401    Won,
402}
403impl IssuingDisputeStatus {
404    pub fn as_str(self) -> &'static str {
405        use IssuingDisputeStatus::*;
406        match self {
407            Expired => "expired",
408            Lost => "lost",
409            Submitted => "submitted",
410            Unsubmitted => "unsubmitted",
411            Won => "won",
412        }
413    }
414}
415
416impl std::str::FromStr for IssuingDisputeStatus {
417    type Err = stripe_types::StripeParseError;
418    fn from_str(s: &str) -> Result<Self, Self::Err> {
419        use IssuingDisputeStatus::*;
420        match s {
421            "expired" => Ok(Expired),
422            "lost" => Ok(Lost),
423            "submitted" => Ok(Submitted),
424            "unsubmitted" => Ok(Unsubmitted),
425            "won" => Ok(Won),
426            _ => Err(stripe_types::StripeParseError),
427        }
428    }
429}
430impl std::fmt::Display for IssuingDisputeStatus {
431    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
432        f.write_str(self.as_str())
433    }
434}
435
436impl std::fmt::Debug for IssuingDisputeStatus {
437    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
438        f.write_str(self.as_str())
439    }
440}
441impl serde::Serialize for IssuingDisputeStatus {
442    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
443    where
444        S: serde::Serializer,
445    {
446        serializer.serialize_str(self.as_str())
447    }
448}
449impl miniserde::Deserialize for IssuingDisputeStatus {
450    fn begin(out: &mut Option<Self>) -> &mut dyn miniserde::de::Visitor {
451        crate::Place::new(out)
452    }
453}
454
455impl miniserde::de::Visitor for crate::Place<IssuingDisputeStatus> {
456    fn string(&mut self, s: &str) -> miniserde::Result<()> {
457        use std::str::FromStr;
458        self.out = Some(IssuingDisputeStatus::from_str(s).map_err(|_| miniserde::Error)?);
459        Ok(())
460    }
461}
462
463stripe_types::impl_from_val_with_from_str!(IssuingDisputeStatus);
464#[cfg(feature = "deserialize")]
465impl<'de> serde::Deserialize<'de> for IssuingDisputeStatus {
466    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
467        use std::str::FromStr;
468        let s: std::borrow::Cow<'de, str> = serde::Deserialize::deserialize(deserializer)?;
469        Self::from_str(&s)
470            .map_err(|_| serde::de::Error::custom("Unknown value for IssuingDisputeStatus"))
471    }
472}