use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use crate::MetaData;
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RefundCreate {
amount: Option<String>,
reason: Option<String>,
refunded_by: Option<i32>,
meta_data: Option<Vec<MetaData>>,
line_items: Option<Vec<OrderRefundLineItemCreate>>,
api_refund: Option<bool>,
api_restock: Option<bool>,
}
impl RefundCreate {
pub fn builder() -> RefundCreateBuilder<NoAmount, NoItems> {
RefundCreateBuilder {
amount: NoAmount,
line_items: NoItems,
..Default::default()
}
}
}
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OrderRefundLineItemCreate {
id: i32,
name: Option<String>,
product_id: Option<i32>,
variation_id: Option<i32>,
quantity: i32,
total: Option<String>,
total_tax: Option<String>,
meta_data: Option<Vec<MetaData>>,
refund_total: Option<f64>,
}
impl OrderRefundLineItemCreate {
pub fn builder() -> OrderRefundLineItemCreateBuilder<NoId, NoQuantity> {
OrderRefundLineItemCreateBuilder {
id: NoId,
quantity: NoQuantity,
..Default::default()
}
}
}
#[derive(Default, Clone)]
pub struct RefundCreateBuilder<A, I> {
amount: A,
reason: Option<String>,
refunded_by: Option<i32>,
meta_data: Option<Vec<MetaData>>,
line_items: I,
api_refund: Option<bool>,
api_restock: Option<bool>,
}
#[derive(Default, Clone)]
pub struct NoAmount;
#[derive(Default, Clone)]
pub struct NoItems;
#[derive(Default, Clone)]
pub struct WithAmount(String);
#[derive(Default, Clone)]
pub struct WithItems(Vec<OrderRefundLineItemCreate>);
#[derive(Default, Clone)]
pub struct NoId;
#[derive(Default, Clone)]
pub struct NoQuantity;
#[derive(Default, Clone)]
pub struct WithId(i32);
#[derive(Default, Clone)]
pub struct WithQuantity(i32);
impl<A, I> RefundCreateBuilder<A, I> {
pub fn amount(self, amount: impl Into<String>) -> RefundCreateBuilder<WithAmount, I> {
RefundCreateBuilder {
amount: WithAmount(amount.into()),
reason: self.reason,
refunded_by: self.refunded_by,
meta_data: self.meta_data,
line_items: self.line_items,
api_refund: self.api_refund,
api_restock: self.api_restock,
}
}
pub fn reason(mut self, reason: impl Into<String>) -> Self {
let _ = self.reason.insert(reason.into());
self
}
pub fn refunded_by(mut self, refunded_by: i32) -> Self {
let _ = self.refunded_by.insert(refunded_by);
self
}
pub fn meta_data(mut self, key: impl Into<String>, value: impl Serialize) -> Self {
self.meta_data.get_or_insert(vec![]).push(MetaData {
id: None,
key: key.into(),
value: serde_json::json!(value),
});
self
}
pub fn api_refund(mut self) -> Self {
let _ = self.api_refund.insert(false);
self
}
pub fn api_restock(mut self) -> Self {
let _ = self.api_restock.insert(false);
self
}
}
impl<A> RefundCreateBuilder<A, NoItems> {
pub fn line_item(self, line_item_id: i32, quatnity: i32) -> RefundCreateBuilder<A, WithItems> {
let l = OrderRefundLineItemCreate::builder()
.id(line_item_id)
.quantity(quatnity)
.build();
RefundCreateBuilder {
amount: self.amount,
reason: self.reason,
refunded_by: self.refunded_by,
meta_data: self.meta_data,
line_items: WithItems(vec![l]),
api_refund: self.api_refund,
api_restock: self.api_restock,
}
}
}
impl<A> RefundCreateBuilder<A, WithItems> {
pub fn line_item(mut self, line_item_id: i32, quatnity: i32) -> Self {
let line_item = OrderRefundLineItemCreate::builder()
.id(line_item_id)
.quantity(quatnity)
.build();
self.line_items.0.push(line_item);
self
}
}
impl RefundCreateBuilder<NoAmount, WithItems> {
pub fn build(self) -> RefundCreate {
RefundCreate {
amount: None,
reason: self.reason,
refunded_by: self.refunded_by,
meta_data: self.meta_data,
line_items: Some(self.line_items.0),
api_refund: self.api_refund,
api_restock: self.api_restock,
}
}
}
impl RefundCreateBuilder<WithAmount, WithItems> {
pub fn build(self) -> RefundCreate {
RefundCreate {
amount: Some(self.amount.0),
reason: self.reason,
refunded_by: self.refunded_by,
meta_data: self.meta_data,
line_items: Some(self.line_items.0),
api_refund: self.api_refund,
api_restock: self.api_restock,
}
}
}
impl RefundCreateBuilder<WithAmount, NoItems> {
pub fn build(self) -> RefundCreate {
RefundCreate {
amount: Some(self.amount.0),
reason: self.reason,
refunded_by: self.refunded_by,
meta_data: self.meta_data,
line_items: None,
api_refund: self.api_refund,
api_restock: self.api_restock,
}
}
}
#[derive(Default, Clone)]
pub struct OrderRefundLineItemCreateBuilder<I, Q> {
pub id: I,
pub name: Option<String>,
pub product_id: Option<i32>,
pub variation_id: Option<i32>,
pub quantity: Q,
pub total: Option<String>,
pub total_tax: Option<String>,
pub meta_data: Option<Vec<MetaData>>,
pub refund_total: Option<f64>,
}
impl<I, Q> OrderRefundLineItemCreateBuilder<I, Q> {
pub fn id(self, id: i32) -> OrderRefundLineItemCreateBuilder<WithId, Q> {
OrderRefundLineItemCreateBuilder {
id: WithId(id),
name: self.name,
product_id: self.product_id,
variation_id: self.variation_id,
quantity: self.quantity,
total: self.total,
total_tax: self.total_tax,
meta_data: self.meta_data,
refund_total: self.refund_total,
}
}
pub fn name(mut self, name: impl Into<String>) -> Self {
let _ = self.name.insert(name.into());
self
}
pub fn product_id(mut self, product_id: i32) -> Self {
let _ = self.product_id.insert(product_id);
self
}
pub fn variation_id(mut self, variation_id: i32) -> Self {
let _ = self.variation_id.insert(variation_id);
self
}
pub fn quantity(self, quantity: i32) -> OrderRefundLineItemCreateBuilder<I, WithQuantity> {
OrderRefundLineItemCreateBuilder {
id: self.id,
name: self.name,
product_id: self.product_id,
variation_id: self.variation_id,
quantity: WithQuantity(quantity),
total: self.total,
total_tax: self.total_tax,
meta_data: self.meta_data,
refund_total: self.refund_total,
}
}
pub fn total(mut self, total: impl Into<String>) -> Self {
let _ = self.total.insert(total.into());
self
}
pub fn total_tax(mut self, total_tax: impl Into<String>) -> Self {
let _ = self.total_tax.insert(total_tax.into());
self
}
pub fn meta_data(mut self, key: impl Into<String>, value: impl Serialize) -> Self {
self.meta_data.get_or_insert(vec![]).push(MetaData {
id: None,
key: key.into(),
value: serde_json::json!(value),
});
self
}
pub fn refund_total(mut self, refund_total: f64) -> Self {
let _ = self.refund_total.insert(refund_total);
self
}
}
impl OrderRefundLineItemCreateBuilder<WithId, WithQuantity> {
pub fn build(self) -> OrderRefundLineItemCreate {
OrderRefundLineItemCreate {
id: self.id.0,
name: self.name,
product_id: self.product_id,
variation_id: self.variation_id,
quantity: self.quantity.0,
total: self.total,
total_tax: self.total_tax,
meta_data: self.meta_data,
refund_total: self.refund_total,
}
}
}
#[cfg(test)]
mod tests {
use crate::{controllers::orders::ORDER_ID, refunds::Refund, ApiClient, Entity, SubEntity};
#[tokio::test]
async fn test_list_all_refunds() {
let client = ApiClient::from_env().unwrap();
let order_refunds: Vec<Refund> = client
.list_all_subentities(Entity::Order, ORDER_ID, SubEntity::Refund)
.await
.unwrap();
assert!(!order_refunds.is_empty());
}
#[tokio::test]
async fn test_retrieve_refund() {
let client = ApiClient::from_env().unwrap();
let order_refunds: Vec<Refund> = client
.list_all_subentities(Entity::Order, ORDER_ID, SubEntity::Refund)
.await
.unwrap();
let id = order_refunds.last().unwrap().id;
let order_refund: Refund = client
.retrieve_subentity(Entity::Order, ORDER_ID, SubEntity::Refund, id)
.await
.unwrap();
assert_eq!(id, order_refund.id);
}
}