当变体价格发生变化时,自动同步套装价格

当您使用 Shopify 的“捆绑包”应用 创建产品捆绑包时,若更改了组成产品的变体价格,捆绑包产品的变体价格并不会自动更新。来自 Workflow Trigger Extensions 的“产品变体价格变更”触发器可通过检测价格变化,自动重新计算并更新捆绑包的变体价格,从而解决此问题。


为了理解如何利用**“产品变体价格变更**”触发器来保持捆绑包价格的一致性,我们将假设以下场景。

场景:当组件变体价格发生变化时,自动更新捆绑包价格

假设您使用Shopify的“捆绑包”应用创建了一个捆绑产品(例如T恤捆绑包)。该捆绑包包含三个组成产品:黑色T恤、灰色T恤和白色T恤,每种变体的价格均为10.00欧元。 该套装变体的价格为 30.00 欧元(即所有组成产品价格的总和)。当您更改某款组成产品的变体价格时,此流程将自动更新相应的套装变体价格。

在应用设置 -> 产品变体 -> 变体价格变动 中启用此触发器

产品变体价格已更改

获取父级捆绑产品,计算更新后的变体价格,并通过管理 API 批量更新捆绑产品的变体价格

视频指南

您也可以通过这段视频直观地了解具体步骤(视频无声音,您可以根据需要调整播放速度)

我们将如何实现这一流程

了解设置

  • 我们有一款组件产品(例如灰色T恤),其变体包括S、M、L、XL和2XL,每款售价均为10.00欧元
  • 我们使用Shopify的**“捆绑包”应用创建了一个捆绑产品。该捆绑包包含3个捆绑商品(黑色T恤、灰色T恤、白色T恤),每个商品各有5种变体。该捆绑包的变体价格为30.00欧元**(各组成商品价格之和:3 × 10.00欧元)。

您可以在这里直观地查看操作步骤:

  • Workflow Trigger Extensions 中,打开**“触发器**”,搜索“价格”,然后启用**“产品变体价格变更**”功能。该功能需要“产品”、“变体”和“系列”数据访问权限;如果缺少这些权限,应用会提示您授予。
  • 在Shopify Flow应用中创建一个新的空白工作流,并从“Workflow Trigger Extensions应用中选择**“产品变体价格变更**”触发器
  • 添加一个“获取产品数据”操作,通过高级查询检索已修改的产品,并按**“创建时间**”升序排序。此步骤通过productParents字段获取产品的父包信息。查询语句如下:id:{{productVariant.product.id | split: "gid://shopify/Product/" | last}}
  • 添加一个**“运行代码**”步骤,从getProductData的结果中提取父级捆绑包的产品 ID。该代码会从productParents中提取父级产品 ID,并构建一个用于查询的idsCondition字符串。

“运行代码”步骤使用以下 GraphQL 输入、JavaScript 代码和输出结果来获取父产品 ID:

“运行代码”步骤,其中显示了 GraphQL 输入、JavaScript 代码以及预览输出

在“触发器”页面中搜索“价格”,且“产品变体价格发生变化”选项已启用
在应用中:进入“触发器”页面,搜索“价格”,然后开启“产品变体价格发生变化”功能。
Flow 的“产品变体价格变更”变量选择器,包含 oldPrice、newPrice、delta、percentChange 和 direction 等参数
“哪个产品变体价格发生了变化”会显示以下信息:价格变动前后的数值、差额、百分比以及变动方向。
bash
{
  getProductData {
    productParents {
      id
    }
  }
}
javascript
export default function main(input) {
  const productIds = input.getProductData[0]?.productParents?.map(p => p.id) ?? [];
  const productId = productIds[0] ?? null;

  const idsCondition = productIds
    .map(gid => "id:" + gid.split("gid://shopify/Product/").pop())
    .join(" OR ");

  return {
    productId: productId,
    productIds: productIds,
    idsCondition: idsCondition,
  };
}
typescript
type Output {
  productId: String
  productIds: [String!]!
  idsCondition: String!
}
  • 添加一个**“条件”**步骤,用于检查“运行代码”输出的productId是否不为空且存在。这可确保只有当已修改的产品确实属于某个捆绑包时,才继续执行后续操作。
  • → 继续更新捆绑包价格
  • false → 停止(该产品不是捆绑包的组成部分)
  • 如果条件为 True,请添加另一个**“获取产品数据 (1)**”操作,使用“运行代码”步骤中的idsCondition来获取父组合产品的变体和定价数据。
  • 添加第二个**“运行代码 (1)**”步骤,根据更新的组件价格计算新的捆绑包变体价格。该步骤会输出一个variantPrices数组,其中包含每个捆绑包变体的新价格。

“运行代码 (1)”步骤会根据更新后的组件价格重新计算套餐变体的价格。其具体操作如下:首先,它从触发器中获取两项关键信息:

  • changedVariantId 刚刚修改过的变体(...158920
  • newPrice 该变体的最新价格(11.00。然后,程序遍历每个捆绑包变体并重新计算其总价。每个捆绑包变体包含3个组成变体(黑色T恤、灰色T恤、白色T恤)。 对于每个组成商品,系统会检查:这是刚刚发生变化的变体吗?如果是,则使用 newPrice (11.00) 代替仍存储在 Shopify (10.00) 中的过时价格。如果不是,则使用现有的 component.productVariant.price.It 将各组成商品的价格相加,从而得到新的组合变体价格。您可以在输出数据中看到其运行效果。 观察变体 ...088840,其组件包括 ...158920(已更改的变体)。因此其价格为 11 + 10 + 10 = 31,而所有其他捆绑变体的总价仍为 30,因为它们的组件均未发生变化。这是该步骤的关键要点:Shopify 尚未更新捆绑包数据中的组件价格,因此代码不能简单地求和现有价格,而必须在运行时将已更改变体的价格替换为新价格。 如果没有这一处理,所有变体仍会显示为30。生成的variantPrices数组随后被传入For each循环,该循环调用productVariantsBulkUpdate方法,将这些重新计算的价格写回捆绑产品中。
bash
{
  productVariant {
    id
  }
  priceChange {
    oldPrice { amount }
    newPrice { amount }
  }
  getProductData1 {
    id
    variants {
      id
      productVariantComponents {
        productVariant {
          id
          price
        }
      }
    }
  }
}
javascript
export default function main(input) {
  const changedVariantId = input.productVariant.id;
  const newPrice = parseFloat(input.priceChange.newPrice.amount);

  const variantPrices = input.getProductData1.flatMap(product =>
    product.variants.map(variant => ({
      productId: product.id,
      id: variant.id,
      price: variant.productVariantComponents.reduce((sum, component) => {
        const p = component.productVariant.id === changedVariantId
          ? newPrice
          : parseFloat(component.productVariant.price);
        return sum + p;
      }, 0)
    }))
  );

  return { variantPrices };
}
yaml
type VariantPrice {
  productId: String!
  id: String!
  price: Float!
}
type Output {
  variantPrices: [VariantPrice!]!
}
  • 添加一个 For each 循环(迭代),用于遍历 runCode1.variantPrices 中的每个项目。对于每个变体价格,它都会使用 **productVariantsBulkUpdate** 突变执行**“发送管理 API 请求**”操作,以更新捆绑包变体的价格。 您可以将此输入用于“突变”功能:
json
{
  "variants": [
    {
      "id": "{{variantPricesForeachitem.id}}",
      "price": "{{variantPricesForeachitem.price}}"
    }
  ],
  "productId": "{{variantPricesForeachitem.productId}}",
  "allowPartialUpdates": true
}

这一切是如何协同运作的

当某款产品的变体价格发生变化时(例如,您将“灰色T恤 S”变体的价格从 10.00 欧元更新为 15.00 欧元):

  1. “产品变体价格变更”触发器被触发
  2. 该流程通过productParents获取产品的父级捆绑包
  3. “运行代码”步骤会提取捆绑产品 ID
  4. 该条件用于检查该产品是否属于某套组合产品
  5. 如果是,则获取该捆绑产品的数据
  6. 第二个“运行代码”步骤会重新计算捆绑变体价格
  7. 该循环遍历每个变体,并通过 productVariantsBulkUpdate 管理员 API 突变操作更新捆绑包价格

该套餐 S 版本的价格现将从 30.00 欧元调整为 35.00 欧元(15.00 欧元 + 10.00 欧元 + 10.00 欧元)。