import RequirementPartial from 'app/views/partials/apps/discounts/requirements_partial.mdx';
import CreateFunction from 'app/views/partials/apps/discounts/create-function.mdx';
import DeployAndReinstallApp from 'app/views/partials/apps/discounts/deploy-and-reinstall-app.mdx';
import RegenerateTypes from 'app/views/partials/apps/discounts/regenerate-types.mdx';
<Repo extension="rust" href="https://github.com/Shopify/tutorial-discount-functions-with-remix" />
<Repo extension="javascript" href="https://github.com/Shopify/tutorial-discount-functions-with-remix" />
<Picker name="extension">
<PickerOption name="javascript" />
<PickerOption name="rust" />
</Picker>
<Overview>
You can create a new type of discount that's applied to a particular product or product variant in the cart. In this tutorial, you'll use [Shopify Functions](/docs/apps/build/functions) to create a new discount type called "Volume discount" that offers a percentage off when customers purchase more than the minimum quantity of a product.
## What you'll learn
In this tutorial, you'll learn how to do the following tasks:
- Generate starter code for Shopify Functions.
- Use GraphQL to define the input of your Function.
- Deploy Functions to the Shopify platform.
- Review logs for your Function.
</Overview>
<Requirements>
<RequirementPartial />
</Requirements>
<StepSection>
<Step>
<CreateFunction functionName="Product Discount">
```bash
shopify app generate extension --template product_discounts --name product-discount
```
</CreateFunction>
</Step>
<Step>
## Update the configuration
<Substep>
### Replace the content of the `run.graphql` file
<CodeRef extension="rust" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/extensions/product-discount-start/src/run.graphql" tag="product-discount.configuration" />
<CodeRef extension="javascript" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/extensions/product-discount-start-js/src/run.graphql" tag="product-discount.configuration" />
Replace the contents of `run.graphql`. This file defines the input for the Function target.
</Substep>
<If extension="javascript">
<Substep>
Navigate to your extension's directory:
<Codeblock terminal>
```bash
cd extensions/product-discount
```
</Codeblock>
</Substep>
<Substep>
<RegenerateTypes />
</Substep>
</If>
</Step>
<Step>
## Update the Function logic
<Substep>
<CodeRef extension="rust" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/extensions/product-discount-start/src/run.rs" tag="product-discount-start" />
<CodeRef extension="javascript" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/extensions/product-discount-start-js/src/run.js" tag="product-discount-start" />
### Replace the content in <If extension="javascript">`run.js`</If> <If extension="rust"> `run.rs` </If>
This Function logic applies a 10% discount to any cart lines with a quantity of two or more.
</Substep>
<Substep>
<CodeRef extension="javascript" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/extensions/product-discount-start-js/src/run.js" tag="product-discount-start.cart-targets" />
<CodeRef extension="rust" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/extensions/product-discount-start/src/run.rs" tag="product-discount-start.cart-targets" />
Iterate through all cart lines to create discount targets, including only those with a quantity of two or more. Use the cart line ID to create each discount target.
</Substep>
<Substep>
<CodeRef extension="javascript" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/extensions/product-discount-start-js/src/run.js" tag="product-discount-start.discount" />
<CodeRef extension="rust" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/extensions/product-discount-start/src/run.rs" tag="product-discount-start.discount" />
Apply the discount to the collected targets by creating a discount object and define a percentage-based discount.
</Substep>
<br/>
<Notice type="info">
<If extension="rust">
The [shopify_function crate](https://crates.io/crates/shopify_function) serializes your [`FunctionRunResult`](/docs/api/functions/reference/product-discounts/graphql#functionrunresult) and writes it to STDOUT.
</If>
<If extension="javascript">
The [@shopify/shopify_function package](https://www.npmjs.com/package/@shopify/shopify_function) applies `JSON.stringify()` to your [`FunctionRunResult`](/docs/api/functions/reference/product-discounts/graphql#functionrunresult).
</If>
</Notice>
</Step>
<Step>
## Preview the Function on a development store
To test your Function, you need to make it available to your development store.
<If extension="rust">
1. Ensure you have configured `build.watch` in your [function extension configuration](/docs/api/functions/configuration#properties).
</If>
1. Use Shopify CLI's [`dev` command](/docs/api/shopify-cli/app/app-dev) to preview the app:
<Codeblock terminal>
```bash
shopify app dev
```
</Codeblock>
You can keep the preview running as you work on your Function. When you make changes to a watched file, Shopify CLI rebuilds your Function and updates the Function extension's drafts, so that you can immediately test your changes.
1. Follow the CLI prompts to preview your app, and install it on your development store.
</Step>
<Step>
## Update your app's access scopes
You must request the `write_discounts` [access scope](/docs/api/usage/access-scopes) to give your app the permissions that it needs to create and update discounts.
<Substep>
<CodeRef extension="rust" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/shopify.app.toml" tag="discount-allocator.access_scopes" />
<CodeRef extension="javascript" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/shopify.app.toml" tag="discount-allocator.access_scopes" />
In `shopify.app.toml`, located in the root of your app, add the `write_discounts` scope to the `access_scopes` array.
</Substep>
</Step>
<Step>
<DeployAndReinstallApp />
</Step>
<Step>
## Install the GraphiQL app
To activate your Function, you must create a product discount on the store where you installed your app. You can do this using the [`discountAutomaticAppCreate`](/docs/api/admin-graphql/latest/mutations/discountAutomaticAppCreate) or [`discountCodeAppCreate`](/docs/api/admin-graphql/latest/mutations/discountCodeAppCreate) GraphQL mutations.
1. Install the [Shopify GraphiQL app](https://shopify-graphiql-app.shopifycloud.com/) on your store.
1. Make sure to select the `write_discounts` access scopes for the Admin API.
1. In the GraphiQL app, in the **API Version** field, select the **2023-07** version or higher.
<Notice type="note">
If you've already installed GraphiQL, then uninstall and reinstall it so that you can select the `write_discounts` access scope.
</Notice>
</Step>
<Step>
## Create the product discount with GraphiQL
In this step, you'll use the Shopify GraphiQL app to create a product discount function on your store. This involves querying your Function's ID and using it to create the discount with the appropriate GraphQL mutation.
---
In subsequent tutorials, you'll use [metafields](/docs/api/checkout-ui-extensions/latest/apis/metafields) on this product discount function to configure your Function, and create an interface so that users can configure the Function themselves.
<Substep>
<CodeRef extension="rust" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/graphql_examples/find-function-query.graphql" tag="find-function-query" />
<CodeRef extension="javascript" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/graphql_examples/find-function-query.graphql" tag="find-function-query" />
### Query the shopify Function
Use the [`shopifyFunctions`](/docs/api/admin-graphql/latest/queries/shopifyFunctions) query to get the ID of your Function.
---
The result contains a node with your Function's ID.
<Codeblock>
```json
{
"app": {
"title": "your-app-name-here"
},
"apiType": "product_discounts",
"title": "product-discount",
"id": "YOUR_FUNCTION_ID_HERE"
}
```
</Codeblock>
</Substep>
<Substep>
<CodeRef extension="rust" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/graphql_examples/discountAutomaticAppCreate.graphql" tag="discount-automatic-app-create" />
<CodeRef extension="javascript" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/graphql_examples/discountAutomaticAppCreate.graphql" tag="discount-automatic-app-create" />
### Create the product discount function
Use the [`discountAutomaticAppCreate`](/docs/api/admin-graphql/latest/mutations/discountAutomaticAppCreate) mutation to create a product discount function.
</Substep>
<Substep>
<CodeRef extension="rust" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/graphql_examples/discountAutomaticAppCreate.graphql" tag="discount-automatic-app-create.add-function-id" />
<CodeRef extension="javascript" href="https://github.com/Shopify/tutorial-discount-functions-with-remix/blob/main/graphql_examples/discountAutomaticAppCreate.graphql" tag="discount-automatic-app-create.add-function-id" />
Add the Shopify Function ID from the [previous step](/docs/apps/build/discounts/build-discount-function?extension=rust#query-the-shopify-function) as the value for the `functionId` input.
</Substep>
<br/>
You should receive a GraphQL response that includes the ID of the created product discount. If the response includes any messages under `userErrors`, then review the errors, check that your mutation and `functionId` are correct, and try the request again.
<Troubleshooting>
If you receive a `Could not find Function` error, then confirm the following:
- The Function ID is correct.
- You've installed the app on your development store.
- [Development store preview](#preview-the-function-on-a-development-store) is enabled in the Partner Dashboard.
- Your app has the `write_discounts` access scope.
</Troubleshooting>
</Step>
<Step>
## Test the product discount
<Substep>
## Trigger the discount on your development store
1. From your Shopify admin, go to **Discounts**.
You should now see the **Volume discount** that you created.
![An image showing a list of all active discounts for the store.](/assets/apps/discounts/functions-discount-list.png)
1. Deactivate or delete all other discounts to ensure that the **Volume discount** is the only active discount.
1. Open your development store and build a cart with a single item in it.
No discounts should be applied to the cart.
1. Increase the item quantity to two.
The 10% **Volume discount** should now be applied to the cart.
</Substep>
<Substep>
## Review the function execution
1. Open your terminal where `shopify app dev` is running, and review your function executions.
---
When [testing functions on development stores](/docs/apps/build/functions/test-debug-functions#test-your-function-on-a-development-store), the output of `dev` includes executions of your functions, any debug logging you have added to them, and a link to a local file with the full function execution details.
1. In a new terminal window, use the Shopify CLI [`app function replay`](/docs/api/shopify-cli/app/app-function-replay) command to [replay a function execution locally](/docs/apps/build/functions/test-debug-functions#execute-the-function-locally-using-shopify-cli), and debug your function without the need to re-trigger the function execution on Shopify.
<Codeblock>
```bash
shopify app function replay
```
</Codeblock>
1. Select the function execution from the top of the list. Press `q` to quit when you are finished debugging.
</Substep>
</Step>
</StepSection>
<NextSteps>
## Tutorial complete!
You've successfully created a product discount function using Shopify Functions. You can now use this Function to apply discounts targeting cart lines with a quantity of two or more.
### Next Steps
<CardGrid>
<LinkCard href="/docs/apps/build/discounts/build-ui-with-remix">
#### Build a user interface for your discount Function
Add configuration to your discounts experience using metafields and build a user interface for your Function.
</LinkCard>
</CardGrid>
</NextSteps>