use shopify_function::prelude::*;
use shopify_function::Result;
// Input/Output types generated from GraphQL schema
use super::input::*;
use super::output::*;
#[shopify_function]
fn run(input: input::ResponseData) -> Result<output::FunctionResult> {
// Parse configuration from metafield
let config = parse_configuration(&input)?;
// Business logic
let discount_percentage = config.percentage.unwrap_or(10.0);
let minimum_amount = config.minimum_amount.unwrap_or(0.0);
// Check cart total
let cart_total = input.cart.cost.subtotal_amount.amount;
if cart_total < minimum_amount {
// No discount - return empty result
return Ok(output::FunctionResult {
discounts: vec![],
discount_application_strategy: output::DiscountApplicationStrategy::FIRST,
});
}
// Apply discount
let targets = vec![output::Target {
product_variant: Some(output::ProductVariantTarget {
id: input.cart.lines[0].merchandise.id.clone(),
quantity: None,
}),
}];
Ok(output::FunctionResult {
discounts: vec![output::Discount {
message: Some(format!("{}% off", discount_percentage)),
targets,
value: output::Value {
percentage: Some(output::Percentage {
value: discount_percentage.to_string(),
}),
fixed_amount: None,
},
}],
discount_application_strategy: output::DiscountApplicationStrategy::FIRST,
})
}
// Helper to parse configuration JSON from metafield
fn parse_configuration(input: &input::ResponseData) -> Result<Configuration> {
let config_value = input
.discount_node
.metafield
.as_ref()
.and_then(|m| m.value.as_ref())
.ok_or("Missing configuration")?;
serde_json::from_str(config_value)
.map_err(|_| "Invalid configuration JSON".into())
}
#[derive(serde::Deserialize)]
struct Configuration {
percentage: Option<f64>,
minimum_amount: Option<f64>,
}