1use crate::client::{Client, Response};
6use crate::ids::{CreditNoteId, CustomerId, InvoiceId, RefundId};
7use crate::params::{Expand, Expandable, List, Metadata, Object, Paginable, Timestamp};
8use crate::resources::{
9 CreditNoteLineItem, Currency, Customer, CustomerBalanceTransaction, Discount, Invoice,
10 InvoicesShippingCost, Refund, TaxRate,
11};
12use serde::{Deserialize, Serialize};
13
14#[derive(Clone, Debug, Default, Deserialize, Serialize)]
18pub struct CreditNote {
19 pub id: CreditNoteId,
21
22 pub amount: i64,
24
25 pub amount_shipping: i64,
27
28 pub created: Timestamp,
32
33 pub currency: Currency,
37
38 pub customer: Expandable<Customer>,
40
41 pub customer_balance_transaction: Option<Expandable<CustomerBalanceTransaction>>,
43
44 pub discount_amount: i64,
46
47 pub discount_amounts: Vec<DiscountsResourceDiscountAmount>,
49
50 pub effective_at: Option<Timestamp>,
55
56 pub invoice: Expandable<Invoice>,
58
59 pub lines: List<CreditNoteLineItem>,
61
62 pub livemode: bool,
64
65 pub memo: Option<String>,
67
68 pub metadata: Option<Metadata>,
72
73 pub number: String,
75
76 pub out_of_band_amount: Option<i64>,
78
79 pub pdf: String,
81
82 pub reason: Option<CreditNoteReason>,
84
85 pub refund: Option<Expandable<Refund>>,
87
88 pub shipping_cost: Option<InvoicesShippingCost>,
90
91 pub status: CreditNoteStatus,
95
96 pub subtotal: i64,
98
99 pub subtotal_excluding_tax: Option<i64>,
101
102 pub tax_amounts: Vec<CreditNoteTaxAmount>,
104
105 pub total: i64,
107
108 pub total_excluding_tax: Option<i64>,
110
111 #[serde(rename = "type")]
116 pub type_: CreditNoteType,
117
118 pub voided_at: Option<Timestamp>,
120}
121
122impl CreditNote {
123 pub fn list(client: &Client, params: &ListCreditNotes<'_>) -> Response<List<CreditNote>> {
125 client.get_query("/credit_notes", params)
126 }
127
128 pub fn create(client: &Client, params: CreateCreditNote<'_>) -> Response<CreditNote> {
135 #[allow(clippy::needless_borrows_for_generic_args)]
136 client.post_form("/credit_notes", ¶ms)
137 }
138
139 pub fn retrieve(client: &Client, id: &CreditNoteId, expand: &[&str]) -> Response<CreditNote> {
141 client.get_query(&format!("/credit_notes/{}", id), Expand { expand })
142 }
143
144 pub fn update(
146 client: &Client,
147 id: &CreditNoteId,
148 params: UpdateCreditNote<'_>,
149 ) -> Response<CreditNote> {
150 #[allow(clippy::needless_borrows_for_generic_args)]
151 client.post_form(&format!("/credit_notes/{}", id), ¶ms)
152 }
153}
154
155impl Object for CreditNote {
156 type Id = CreditNoteId;
157 fn id(&self) -> Self::Id {
158 self.id.clone()
159 }
160 fn object(&self) -> &'static str {
161 "credit_note"
162 }
163}
164
165#[derive(Clone, Debug, Default, Deserialize, Serialize)]
166pub struct CreditNoteTaxAmount {
167 pub amount: i64,
169
170 pub inclusive: bool,
172
173 pub tax_rate: Expandable<TaxRate>,
175
176 pub taxability_reason: Option<CreditNoteTaxAmountTaxabilityReason>,
180
181 pub taxable_amount: Option<i64>,
183}
184
185#[derive(Clone, Debug, Default, Deserialize, Serialize)]
186pub struct DiscountsResourceDiscountAmount {
187 pub amount: i64,
189
190 pub discount: Expandable<Discount>,
192}
193
194#[derive(Clone, Debug, Serialize)]
196pub struct CreateCreditNote<'a> {
197 #[serde(skip_serializing_if = "Option::is_none")]
199 pub amount: Option<i64>,
200
201 #[serde(skip_serializing_if = "Option::is_none")]
203 pub credit_amount: Option<i64>,
204
205 #[serde(skip_serializing_if = "Option::is_none")]
210 pub effective_at: Option<Timestamp>,
211
212 #[serde(skip_serializing_if = "Expand::is_empty")]
214 pub expand: &'a [&'a str],
215
216 pub invoice: InvoiceId,
218
219 #[serde(skip_serializing_if = "Option::is_none")]
221 pub lines: Option<Vec<CreateCreditNoteLines>>,
222
223 #[serde(skip_serializing_if = "Option::is_none")]
225 pub memo: Option<&'a str>,
226
227 #[serde(skip_serializing_if = "Option::is_none")]
233 pub metadata: Option<Metadata>,
234
235 #[serde(skip_serializing_if = "Option::is_none")]
237 pub out_of_band_amount: Option<i64>,
238
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub reason: Option<CreditNoteReason>,
242
243 #[serde(skip_serializing_if = "Option::is_none")]
245 pub refund: Option<RefundId>,
246
247 #[serde(skip_serializing_if = "Option::is_none")]
251 pub refund_amount: Option<i64>,
252
253 #[serde(skip_serializing_if = "Option::is_none")]
255 pub shipping_cost: Option<CreateCreditNoteShippingCost>,
256}
257
258impl<'a> CreateCreditNote<'a> {
259 pub fn new(invoice: InvoiceId) -> Self {
260 CreateCreditNote {
261 amount: Default::default(),
262 credit_amount: Default::default(),
263 effective_at: Default::default(),
264 expand: Default::default(),
265 invoice,
266 lines: Default::default(),
267 memo: Default::default(),
268 metadata: Default::default(),
269 out_of_band_amount: Default::default(),
270 reason: Default::default(),
271 refund: Default::default(),
272 refund_amount: Default::default(),
273 shipping_cost: Default::default(),
274 }
275 }
276}
277
278#[derive(Clone, Debug, Serialize, Default)]
280pub struct ListCreditNotes<'a> {
281 #[serde(skip_serializing_if = "Option::is_none")]
283 pub customer: Option<CustomerId>,
284
285 #[serde(skip_serializing_if = "Option::is_none")]
290 pub ending_before: Option<CreditNoteId>,
291
292 #[serde(skip_serializing_if = "Expand::is_empty")]
294 pub expand: &'a [&'a str],
295
296 #[serde(skip_serializing_if = "Option::is_none")]
298 pub invoice: Option<InvoiceId>,
299
300 #[serde(skip_serializing_if = "Option::is_none")]
304 pub limit: Option<u64>,
305
306 #[serde(skip_serializing_if = "Option::is_none")]
311 pub starting_after: Option<CreditNoteId>,
312}
313
314impl<'a> ListCreditNotes<'a> {
315 pub fn new() -> Self {
316 ListCreditNotes {
317 customer: Default::default(),
318 ending_before: Default::default(),
319 expand: Default::default(),
320 invoice: Default::default(),
321 limit: Default::default(),
322 starting_after: Default::default(),
323 }
324 }
325}
326impl Paginable for ListCreditNotes<'_> {
327 type O = CreditNote;
328 fn set_last(&mut self, item: Self::O) {
329 self.starting_after = Some(item.id());
330 }
331}
332#[derive(Clone, Debug, Serialize, Default)]
334pub struct UpdateCreditNote<'a> {
335 #[serde(skip_serializing_if = "Expand::is_empty")]
337 pub expand: &'a [&'a str],
338
339 #[serde(skip_serializing_if = "Option::is_none")]
341 pub memo: Option<&'a str>,
342
343 #[serde(skip_serializing_if = "Option::is_none")]
349 pub metadata: Option<Metadata>,
350}
351
352impl<'a> UpdateCreditNote<'a> {
353 pub fn new() -> Self {
354 UpdateCreditNote {
355 expand: Default::default(),
356 memo: Default::default(),
357 metadata: Default::default(),
358 }
359 }
360}
361
362#[derive(Clone, Debug, Default, Deserialize, Serialize)]
363pub struct CreateCreditNoteLines {
364 #[serde(skip_serializing_if = "Option::is_none")]
368 pub amount: Option<i64>,
369
370 #[serde(skip_serializing_if = "Option::is_none")]
374 pub description: Option<String>,
375
376 #[serde(skip_serializing_if = "Option::is_none")]
380 pub invoice_line_item: Option<String>,
381
382 #[serde(skip_serializing_if = "Option::is_none")]
384 pub quantity: Option<u64>,
385
386 #[serde(skip_serializing_if = "Option::is_none")]
390 pub tax_amounts: Option<Vec<CreateCreditNoteLinesTaxAmounts>>,
391
392 #[serde(skip_serializing_if = "Option::is_none")]
396 pub tax_rates: Option<Vec<String>>,
397
398 #[serde(rename = "type")]
400 pub type_: CreateCreditNoteLinesType,
401
402 #[serde(skip_serializing_if = "Option::is_none")]
407 pub unit_amount: Option<i64>,
408
409 #[serde(skip_serializing_if = "Option::is_none")]
413 pub unit_amount_decimal: Option<String>,
414}
415
416#[derive(Clone, Debug, Default, Deserialize, Serialize)]
417pub struct CreateCreditNoteShippingCost {
418 #[serde(skip_serializing_if = "Option::is_none")]
420 pub shipping_rate: Option<String>,
421}
422
423#[derive(Clone, Debug, Default, Deserialize, Serialize)]
424pub struct CreateCreditNoteLinesTaxAmounts {
425 pub amount: i64,
427
428 pub tax_rate: String,
432
433 pub taxable_amount: i64,
435}
436
437#[derive(Copy, Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
439#[serde(rename_all = "snake_case")]
440pub enum CreateCreditNoteLinesType {
441 CustomLineItem,
442 InvoiceLineItem,
443}
444
445impl CreateCreditNoteLinesType {
446 pub fn as_str(self) -> &'static str {
447 match self {
448 CreateCreditNoteLinesType::CustomLineItem => "custom_line_item",
449 CreateCreditNoteLinesType::InvoiceLineItem => "invoice_line_item",
450 }
451 }
452}
453
454impl AsRef<str> for CreateCreditNoteLinesType {
455 fn as_ref(&self) -> &str {
456 self.as_str()
457 }
458}
459
460impl std::fmt::Display for CreateCreditNoteLinesType {
461 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
462 self.as_str().fmt(f)
463 }
464}
465impl std::default::Default for CreateCreditNoteLinesType {
466 fn default() -> Self {
467 Self::CustomLineItem
468 }
469}
470
471#[derive(Copy, Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
473#[serde(rename_all = "snake_case")]
474pub enum CreditNoteReason {
475 Duplicate,
476 Fraudulent,
477 OrderChange,
478 ProductUnsatisfactory,
479}
480
481impl CreditNoteReason {
482 pub fn as_str(self) -> &'static str {
483 match self {
484 CreditNoteReason::Duplicate => "duplicate",
485 CreditNoteReason::Fraudulent => "fraudulent",
486 CreditNoteReason::OrderChange => "order_change",
487 CreditNoteReason::ProductUnsatisfactory => "product_unsatisfactory",
488 }
489 }
490}
491
492impl AsRef<str> for CreditNoteReason {
493 fn as_ref(&self) -> &str {
494 self.as_str()
495 }
496}
497
498impl std::fmt::Display for CreditNoteReason {
499 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
500 self.as_str().fmt(f)
501 }
502}
503impl std::default::Default for CreditNoteReason {
504 fn default() -> Self {
505 Self::Duplicate
506 }
507}
508
509#[derive(Copy, Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
511#[serde(rename_all = "snake_case")]
512pub enum CreditNoteStatus {
513 Issued,
514 Void,
515}
516
517impl CreditNoteStatus {
518 pub fn as_str(self) -> &'static str {
519 match self {
520 CreditNoteStatus::Issued => "issued",
521 CreditNoteStatus::Void => "void",
522 }
523 }
524}
525
526impl AsRef<str> for CreditNoteStatus {
527 fn as_ref(&self) -> &str {
528 self.as_str()
529 }
530}
531
532impl std::fmt::Display for CreditNoteStatus {
533 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
534 self.as_str().fmt(f)
535 }
536}
537impl std::default::Default for CreditNoteStatus {
538 fn default() -> Self {
539 Self::Issued
540 }
541}
542
543#[derive(Copy, Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
545#[serde(rename_all = "snake_case")]
546pub enum CreditNoteTaxAmountTaxabilityReason {
547 CustomerExempt,
548 NotCollecting,
549 NotSubjectToTax,
550 NotSupported,
551 PortionProductExempt,
552 PortionReducedRated,
553 PortionStandardRated,
554 ProductExempt,
555 ProductExemptHoliday,
556 ProportionallyRated,
557 ReducedRated,
558 ReverseCharge,
559 StandardRated,
560 TaxableBasisReduced,
561 ZeroRated,
562}
563
564impl CreditNoteTaxAmountTaxabilityReason {
565 pub fn as_str(self) -> &'static str {
566 match self {
567 CreditNoteTaxAmountTaxabilityReason::CustomerExempt => "customer_exempt",
568 CreditNoteTaxAmountTaxabilityReason::NotCollecting => "not_collecting",
569 CreditNoteTaxAmountTaxabilityReason::NotSubjectToTax => "not_subject_to_tax",
570 CreditNoteTaxAmountTaxabilityReason::NotSupported => "not_supported",
571 CreditNoteTaxAmountTaxabilityReason::PortionProductExempt => "portion_product_exempt",
572 CreditNoteTaxAmountTaxabilityReason::PortionReducedRated => "portion_reduced_rated",
573 CreditNoteTaxAmountTaxabilityReason::PortionStandardRated => "portion_standard_rated",
574 CreditNoteTaxAmountTaxabilityReason::ProductExempt => "product_exempt",
575 CreditNoteTaxAmountTaxabilityReason::ProductExemptHoliday => "product_exempt_holiday",
576 CreditNoteTaxAmountTaxabilityReason::ProportionallyRated => "proportionally_rated",
577 CreditNoteTaxAmountTaxabilityReason::ReducedRated => "reduced_rated",
578 CreditNoteTaxAmountTaxabilityReason::ReverseCharge => "reverse_charge",
579 CreditNoteTaxAmountTaxabilityReason::StandardRated => "standard_rated",
580 CreditNoteTaxAmountTaxabilityReason::TaxableBasisReduced => "taxable_basis_reduced",
581 CreditNoteTaxAmountTaxabilityReason::ZeroRated => "zero_rated",
582 }
583 }
584}
585
586impl AsRef<str> for CreditNoteTaxAmountTaxabilityReason {
587 fn as_ref(&self) -> &str {
588 self.as_str()
589 }
590}
591
592impl std::fmt::Display for CreditNoteTaxAmountTaxabilityReason {
593 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
594 self.as_str().fmt(f)
595 }
596}
597impl std::default::Default for CreditNoteTaxAmountTaxabilityReason {
598 fn default() -> Self {
599 Self::CustomerExempt
600 }
601}
602
603#[derive(Copy, Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
605#[serde(rename_all = "snake_case")]
606pub enum CreditNoteType {
607 PostPayment,
608 PrePayment,
609}
610
611impl CreditNoteType {
612 pub fn as_str(self) -> &'static str {
613 match self {
614 CreditNoteType::PostPayment => "post_payment",
615 CreditNoteType::PrePayment => "pre_payment",
616 }
617 }
618}
619
620impl AsRef<str> for CreditNoteType {
621 fn as_ref(&self) -> &str {
622 self.as_str()
623 }
624}
625
626impl std::fmt::Display for CreditNoteType {
627 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
628 self.as_str().fmt(f)
629 }
630}
631impl std::default::Default for CreditNoteType {
632 fn default() -> Self {
633 Self::PostPayment
634 }
635}