wave-api 0.1.0

Typed Rust client for the Wave Accounting GraphQL API
Documentation
use serde::Deserialize;
use serde_json::json;

use crate::client::WaveClient;
use crate::error::WaveError;
use crate::inputs::*;
use crate::models::*;
use crate::mutations::{account, customer, invoice, product, sales_tax, transaction};

// ── Mutation response wrappers ──

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct CustomerMutationResult {
    customer: Option<Customer>,
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct InvoiceMutationResult {
    invoice: Option<Invoice>,
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct AccountMutationResult {
    account: Option<Account>,
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct ProductMutationResult {
    product: Option<Product>,
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct SalesTaxMutationResult {
    sales_tax: Option<SalesTax>,
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct TransactionMutationResult {
    transaction: Option<Transaction>,
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct TransactionsMutationResult {
    transactions: Option<Vec<Transaction>>,
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct DeleteResult {}

impl WaveClient {
    // ── Customer Mutations ──

    /// Create a customer.
    pub async fn create_customer(
        &self,
        input: CustomerCreateInput,
    ) -> Result<Customer, WaveError> {
        let vars = json!({ "input": input });
        let result: CustomerMutationResult = self
            .execute_mutation(customer::CUSTOMER_CREATE, vars, "customerCreate")
            .await?;
        result
            .customer
            .ok_or_else(|| WaveError::Auth("missing customer in response".into()))
    }

    /// Patch a customer.
    pub async fn patch_customer(
        &self,
        input: CustomerPatchInput,
    ) -> Result<Customer, WaveError> {
        let vars = json!({ "input": input });
        let result: CustomerMutationResult = self
            .execute_mutation(customer::CUSTOMER_PATCH, vars, "customerPatch")
            .await?;
        result
            .customer
            .ok_or_else(|| WaveError::Auth("missing customer in response".into()))
    }

    /// Delete a customer.
    pub async fn delete_customer(&self, input: CustomerDeleteInput) -> Result<(), WaveError> {
        let vars = json!({ "input": input });
        let _: DeleteResult = self
            .execute_mutation(customer::CUSTOMER_DELETE, vars, "customerDelete")
            .await?;
        Ok(())
    }

    // ── Invoice Mutations ──

    /// Create an invoice.
    pub async fn create_invoice(
        &self,
        input: InvoiceCreateInput,
    ) -> Result<Invoice, WaveError> {
        let vars = json!({ "input": input });
        let result: InvoiceMutationResult = self
            .execute_mutation(invoice::INVOICE_CREATE, vars, "invoiceCreate")
            .await?;
        result
            .invoice
            .ok_or_else(|| WaveError::Auth("missing invoice in response".into()))
    }

    /// Patch an invoice.
    pub async fn patch_invoice(
        &self,
        input: InvoicePatchInput,
    ) -> Result<Invoice, WaveError> {
        let vars = json!({ "input": input });
        let result: InvoiceMutationResult = self
            .execute_mutation(invoice::INVOICE_PATCH, vars, "invoicePatch")
            .await?;
        result
            .invoice
            .ok_or_else(|| WaveError::Auth("missing invoice in response".into()))
    }

    /// Delete an invoice.
    pub async fn delete_invoice(&self, invoice_id: &str) -> Result<(), WaveError> {
        let vars = json!({ "input": { "invoiceId": invoice_id } });
        let _: DeleteResult = self
            .execute_mutation(invoice::INVOICE_DELETE, vars, "invoiceDelete")
            .await?;
        Ok(())
    }

    /// Clone an invoice.
    pub async fn clone_invoice(&self, invoice_id: &str) -> Result<Invoice, WaveError> {
        let vars = json!({ "input": { "invoiceId": invoice_id } });
        let result: InvoiceMutationResult = self
            .execute_mutation(invoice::INVOICE_CLONE, vars, "invoiceClone")
            .await?;
        result
            .invoice
            .ok_or_else(|| WaveError::Auth("missing invoice in response".into()))
    }

    /// Approve an invoice.
    pub async fn approve_invoice(&self, invoice_id: &str) -> Result<Invoice, WaveError> {
        let vars = json!({ "input": { "invoiceId": invoice_id } });
        let result: InvoiceMutationResult = self
            .execute_mutation(invoice::INVOICE_APPROVE, vars, "invoiceApprove")
            .await?;
        result
            .invoice
            .ok_or_else(|| WaveError::Auth("missing invoice in response".into()))
    }

    /// Mark an invoice as sent.
    pub async fn mark_invoice_sent(
        &self,
        input: InvoiceMarkSentInput,
    ) -> Result<Invoice, WaveError> {
        let vars = json!({ "input": input });
        let result: InvoiceMutationResult = self
            .execute_mutation(invoice::INVOICE_MARK_SENT, vars, "invoiceMarkSent")
            .await?;
        result
            .invoice
            .ok_or_else(|| WaveError::Auth("missing invoice in response".into()))
    }

    /// Send an invoice via email.
    pub async fn send_invoice(
        &self,
        input: InvoiceSendInput,
    ) -> Result<Invoice, WaveError> {
        let vars = json!({ "input": input });
        let result: InvoiceMutationResult = self
            .execute_mutation(invoice::INVOICE_SEND, vars, "invoiceSend")
            .await?;
        result
            .invoice
            .ok_or_else(|| WaveError::Auth("missing invoice in response".into()))
    }

    // ── Account Mutations ──

    /// Create an account.
    pub async fn create_account(
        &self,
        input: AccountCreateInput,
    ) -> Result<Account, WaveError> {
        let vars = json!({ "input": input });
        let result: AccountMutationResult = self
            .execute_mutation(account::ACCOUNT_CREATE, vars, "accountCreate")
            .await?;
        result
            .account
            .ok_or_else(|| WaveError::Auth("missing account in response".into()))
    }

    /// Patch an account.
    pub async fn patch_account(
        &self,
        input: AccountPatchInput,
    ) -> Result<Account, WaveError> {
        let vars = json!({ "input": input });
        let result: AccountMutationResult = self
            .execute_mutation(account::ACCOUNT_PATCH, vars, "accountPatch")
            .await?;
        result
            .account
            .ok_or_else(|| WaveError::Auth("missing account in response".into()))
    }

    /// Archive an account.
    pub async fn archive_account(&self, input: AccountArchiveInput) -> Result<(), WaveError> {
        let vars = json!({ "input": input });
        let _: DeleteResult = self
            .execute_mutation(account::ACCOUNT_ARCHIVE, vars, "accountArchive")
            .await?;
        Ok(())
    }

    // ── Product Mutations ──

    /// Create a product.
    pub async fn create_product(
        &self,
        input: ProductCreateInput,
    ) -> Result<Product, WaveError> {
        let vars = json!({ "input": input });
        let result: ProductMutationResult = self
            .execute_mutation(product::PRODUCT_CREATE, vars, "productCreate")
            .await?;
        result
            .product
            .ok_or_else(|| WaveError::Auth("missing product in response".into()))
    }

    /// Patch a product.
    pub async fn patch_product(
        &self,
        input: ProductPatchInput,
    ) -> Result<Product, WaveError> {
        let vars = json!({ "input": input });
        let result: ProductMutationResult = self
            .execute_mutation(product::PRODUCT_PATCH, vars, "productPatch")
            .await?;
        result
            .product
            .ok_or_else(|| WaveError::Auth("missing product in response".into()))
    }

    /// Archive a product.
    pub async fn archive_product(&self, input: ProductArchiveInput) -> Result<(), WaveError> {
        let vars = json!({ "input": input });
        let _: DeleteResult = self
            .execute_mutation(product::PRODUCT_ARCHIVE, vars, "productArchive")
            .await?;
        Ok(())
    }

    // ── Sales Tax Mutations ──

    /// Create a sales tax.
    pub async fn create_sales_tax(
        &self,
        input: SalesTaxCreateInput,
    ) -> Result<SalesTax, WaveError> {
        let vars = json!({ "input": input });
        let result: SalesTaxMutationResult = self
            .execute_mutation(sales_tax::SALES_TAX_CREATE, vars, "salesTaxCreate")
            .await?;
        result
            .sales_tax
            .ok_or_else(|| WaveError::Auth("missing salesTax in response".into()))
    }

    /// Patch a sales tax.
    pub async fn patch_sales_tax(
        &self,
        input: SalesTaxPatchInput,
    ) -> Result<SalesTax, WaveError> {
        let vars = json!({ "input": input });
        let result: SalesTaxMutationResult = self
            .execute_mutation(sales_tax::SALES_TAX_PATCH, vars, "salesTaxPatch")
            .await?;
        result
            .sales_tax
            .ok_or_else(|| WaveError::Auth("missing salesTax in response".into()))
    }

    /// Archive a sales tax.
    pub async fn archive_sales_tax(
        &self,
        input: SalesTaxArchiveInput,
    ) -> Result<(), WaveError> {
        let vars = json!({ "input": input });
        let _: DeleteResult = self
            .execute_mutation(sales_tax::SALES_TAX_ARCHIVE, vars, "salesTaxArchive")
            .await?;
        Ok(())
    }

    // ── Transaction Mutations ──

    /// Create a single money transaction.
    pub async fn create_money_transaction(
        &self,
        input: MoneyTransactionCreateInput,
    ) -> Result<Transaction, WaveError> {
        let vars = json!({ "input": input });
        let result: TransactionMutationResult = self
            .execute_mutation(
                transaction::MONEY_TRANSACTION_CREATE,
                vars,
                "moneyTransactionCreate",
            )
            .await?;
        result
            .transaction
            .ok_or_else(|| WaveError::Auth("missing transaction in response".into()))
    }

    /// Bulk create money transactions.
    pub async fn create_money_transactions(
        &self,
        input: MoneyTransactionsCreateInput,
    ) -> Result<Vec<Transaction>, WaveError> {
        let vars = json!({ "input": input });
        let result: TransactionsMutationResult = self
            .execute_mutation(
                transaction::MONEY_TRANSACTIONS_CREATE,
                vars,
                "moneyTransactionsCreate",
            )
            .await?;
        Ok(result.transactions.unwrap_or_default())
    }
}