Skip to content

Instantly share code, notes, and snippets.

@sjb9774
Created February 13, 2023 01:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sjb9774/caeda1946de4298100e2313cae0c9153 to your computer and use it in GitHub Desktop.
Save sjb9774/caeda1946de4298100e2313cae0c9153 to your computer and use it in GitHub Desktop.
Modified main.rs for Shopify Product Discount Function example
query Input {
discountNode {
metafield(namespace: "my-discount-namespace", key: "my-discount-amount") {
value
}
}
cart {
lines {
merchandise {
__typename
... on ProductVariant {
id
}
}
}
}
}
// compare to https://github.com/Shopify/shopify-function-rust/blob/main/example/src/main.rs
use shopify_function::prelude::*;
use shopify_function::Result;
use serde::{Deserialize, Serialize};
generate_types!(
query_path = "./input.graphql",
schema_path = "./schema.graphql"
);
type MyDiscountType = String;
#[derive(Serialize, Deserialize, Default, PartialEq)]
#[serde(rename_all(deserialize = "camelCase"))]
struct MyDiscountDetails {
discount_type: MyDiscountType,
value: String
}
// Use nested structs to mimic the JSON structure of the metafield so it can be deserialized into out types using serde_json::from_str
#[derive(Serialize, Deserialize, Default, PartialEq)]
#[serde(rename_all(deserialize = "camelCase"))]
struct Configuration {
discount: MyDiscountDetails
}
impl Configuration {
fn from_str(value: &str) -> Self {
serde_json::from_str(value).expect("Unable to parse configuration value from metafield")
}
}
#[shopify_function]
fn function(input: input::ResponseData) -> Result<output::FunctionResult> {
// Prep a response that indicates no discounts applied
let no_discount = output::FunctionResult {
discounts: vec![],
discount_application_strategy: output::DiscountApplicationStrategy::FIRST,
};
// If there is a metafield value defined, parse out our config otherwise immediately return "no discount" response
let config = match input.discount_node.metafield {
Some(input::InputDiscountNodeMetafield { value }) =>
Configuration::from_str(&value),
None => return Ok(no_discount),
};
let config_discount_type = &config.discount.discount_type;
let config_discount_amount = &config.discount.value;
let _p_string = "percentage".to_string();
// confirm we can match the discount type to "percentage" — notably nothing happens if the discount type is anything else
// assuming we have a "percentage" discount then output_discount is set as a Percentage object with a discount value equal to our configured value
let output_discount = match config_discount_type {
_p_string => output::Percentage { value: config_discount_amount.to_string() }
};
let first_merch = &input.cart.lines[0].merchandise;
// if there's at least one item in the cart (should always be) and if so track the id of that first item
let first_id = match first_merch {
input::InputCartLinesMerchandise::ProductVariant(variant) => &variant.id,
_ => ""
};
// Return a response applying our configured discount amount to the first line item in the cart with no quantity limit
return Ok(output::FunctionResult {
discounts: vec![output::Discount {
message: Some("Your Shopify Function is working!".to_string()),
targets: vec![
output::Target { product_variant: Some(output::ProductVariantTarget {id: first_id.to_string(), quantity: None }) }
],
value: output::Value { percentage: Some(output_discount), fixed_amount: None }
}],
discount_application_strategy: output::DiscountApplicationStrategy::FIRST,
});
}
#[cfg(test)]
mod tests;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment