Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: adds new pricing field to product variants in order to correctly display prices #6159

Merged
merged 6 commits into from
Mar 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/plugins/simple-pricing/i18n/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[{
"i18n": "en",
"ns": "reaction-simple-pricing",
"translation": {
"reaction-simple-pricing": {
"productVariant": {
"noPriceTracking": "Prices are tracked only for sellable variants. Select an option to manage prices for it."
}
}
}
}]
10 changes: 10 additions & 0 deletions src/plugins/simple-pricing/i18n/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import en from "./en.json";

//
// we want all the files in individual
// imports for easier handling by
// automated translation software
//
export default {
translations: [...en]
};
2 changes: 2 additions & 0 deletions src/plugins/simple-pricing/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import i18n from "./i18n/index.js";
import policies from "./policies.json";
import preStartup from "./preStartup.js";
import mutations from "./mutations/index.js";
Expand All @@ -21,6 +22,7 @@ export default async function register(app) {
label: "Pricing",
name: "reaction-pricing",
version: app.context.appVersion,
i18n,
functionsByType: {
getMinPriceSortByFieldPath: [getMinPriceSortByFieldPath],
mutateNewProductBeforeCreate: [mutateNewProductBeforeCreate],
Expand Down
7 changes: 7 additions & 0 deletions src/plugins/simple-pricing/resolvers/Product.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import xformProductPricing from "../xforms/xformProductPricing.js";
import xformProductPrice from "../xforms/xformProductPrice.js";

export default {
price: (node) => xformProductPrice(node),
pricing: (node, _, context) => xformProductPricing(node, context)
};
9 changes: 9 additions & 0 deletions src/plugins/simple-pricing/resolvers/ProductVariant.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import xformProductVariantPricing from "../xforms/xformProductVariantPricing.js";
import xformProductVariantPrice from "../xforms/xformProductVariantPrice.js";
import xformProductVariantCompareAtPrice from "../xforms/xformProductVariantCompareAtPrice.js";

export default {
compareAtPrice: (node) => xformProductVariantCompareAtPrice(node),
price: (node) => xformProductVariantPrice(node),
willopez marked this conversation as resolved.
Show resolved Hide resolved
pricing: (node, _, context) => xformProductVariantPricing(node, context)
};
4 changes: 4 additions & 0 deletions src/plugins/simple-pricing/resolvers/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import CatalogProduct from "./CatalogProduct.js";
import CatalogProductVariant from "./CatalogProductVariant.js";
import Mutation from "./Mutation/index.js";
import ProductVariant from "./ProductVariant.js";
import Product from "./Product.js";
import ProductPricingInfo from "./ProductPricingInfo.js";

export default {
CatalogProduct,
CatalogProductVariant,
Mutation,
Product,
ProductVariant,
ProductPricingInfo
};
12 changes: 9 additions & 3 deletions src/plugins/simple-pricing/schemas/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,22 @@ extend type CatalogProductVariant {
}

extend type Product {
"Price range"
"Deprecated, please use the `pricing` field. Price range"
price: ProductPriceRange

"Pricing information"
pricing: ProductPricingInfo!
}

extend type ProductVariant {
"Compare at price of the variant"
"Deprecated, please use the `pricing` field. Compare at price of the variant"
compareAtPrice: Float

"Price of the variant"
"Deprecated please use the `pricing` field. Price of the variant"
price: Float

"Pricing information"
pricing: ProductPricingInfo!
}

extend input ProductVariantInput {
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/simple-pricing/util/getProductPriceRange.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import getVariantPriceRange from "./getVariantPriceRange.js";
export default function getProductPriceRange(productId, variants) {
const visibleVariants = variants.filter((option) => option.ancestors.length === 1 &&
option.isVisible && !option.isDeleted);

// If there are no visible variants, set price range to 0
if (visibleVariants.length === 0) return getPriceRange([0]);

const variantPrices = [];
Expand Down
8 changes: 8 additions & 0 deletions src/plugins/simple-pricing/util/getVariantPriceRange.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ import getPriceRange from "./getPriceRange.js";
export default function getVariantPriceRange(variantId, variants) {
const visibleOptions = variants.filter((option) => option.ancestors.includes(variantId) &&
option.isVisible && !option.isDeleted);

const allOptions = variants.filter((option) => option.ancestors.includes(variantId));

// If the variant has options, but they are not visible return a price range of 0
if (allOptions.length && visibleOptions.length === 0) {
return getPriceRange([0]);
}

if (visibleOptions.length === 0) {
const thisVariant = variants.find((option) => option._id === variantId);
return getPriceRange([(thisVariant && thisVariant.price) || 0]);
Expand Down
7 changes: 7 additions & 0 deletions src/plugins/simple-pricing/xforms/xformProductPrice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Logger from "@reactioncommerce/logger";

export default (node) => {
Logger.warn("Using deprecated field `price` on type `Product`, please use field `pricing` instead.");

return node.price;
};
17 changes: 17 additions & 0 deletions src/plugins/simple-pricing/xforms/xformProductPricing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import getCurrencyDefinitionByCode from "@reactioncommerce/api-utils/getCurrencyDefinitionByCode.js";
import getDisplayPrice from "../util/getDisplayPrice.js";

export default async (node, context) => {
const { price } = node;
const { Shops } = context.collections;
const shop = await Shops.findOne({ _id: node.shopId }, { projection: { currency: 1 } });
const currencyDefinition = getCurrencyDefinitionByCode(shop.currency);

const pricing = {
displayPrice: getDisplayPrice(price.min, price.max, currencyDefinition),
maxPrice: price.max,
minPrice: price.min
};

return pricing;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Logger from "@reactioncommerce/logger";

export default (node) => {
Logger.warn("Using deprecated field `compareAtPrice` on type `ProductVariant`, please use field `pricing` instead.");

return node.compareAtPrice;
};
19 changes: 19 additions & 0 deletions src/plugins/simple-pricing/xforms/xformProductVariantPrice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Logger from "@reactioncommerce/logger";

export default (node) => {
let { price } = node;
mikemurray marked this conversation as resolved.
Show resolved Hide resolved
// If a variant has options, then its price will become an object
// that includes the following props: min, max and range. This change
// in the underlying data structure will break the API as the variant
// field `price` will attempt to return an `Object` for a field that previously
// expected a `Float`. This field resolver mitigates this problem by returning
// a `Float` as expected. This will prevent the API and UI from breaking. Further,
// this field, is now deprecated in favor of the new `pricing` field.
if (typeof price === "object") {
price = null;
}

Logger.warn("Using deprecated field `price` on type `ProductVariant`, please use field `pricing` instead.");

return price;
};
31 changes: 31 additions & 0 deletions src/plugins/simple-pricing/xforms/xformProductVariantPricing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import accounting from "accounting-js";
import getCurrencyDefinitionByCode from "@reactioncommerce/api-utils/getCurrencyDefinitionByCode.js";
import getDisplayPrice from "../util/getDisplayPrice.js";

export default async (node, context) => {
const { Shops } = context.collections;
const shop = await Shops.findOne({ _id: node.shopId }, { projection: { currency: 1 } });
const currencyDefinition = getCurrencyDefinitionByCode(shop.currency);

let pricing = {};
const { price } = node;
if (typeof price === "object") {
pricing = {
compareAtPrice: null,
displayPrice: getDisplayPrice(price.min, price.max, currencyDefinition),
maxPrice: price.max,
minPrice: price.min,
price: null
};
} else {
pricing = {
compareAtPrice: node.compareAtPrice || 0,
displayPrice: accounting.formatMoney(price, currencyDefinition.symbol),
maxPrice: price || 0,
minPrice: price || 0,
price: price || 0
};
}

return pricing;
};