Skip to content

Commit

Permalink
Merge pull request #74 from yalla-coop/implement-gql
Browse files Browse the repository at this point in the history
Implement-gql
  • Loading branch information
dupreesi authored Jul 30, 2024
2 parents a591c35 + 8cc3b8a commit 425d737
Show file tree
Hide file tree
Showing 14 changed files with 726 additions and 317 deletions.
26 changes: 13 additions & 13 deletions web/connector/mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ export function exportedDFCProducerProducts(stockLimitation = 55) {
"dfc-b:name": "Camelina Seed"
}
]
}`
};
}`;
}

export const importedShopifyProductsFromDFC = [
{
id: '7898317750424',
title: 'Camelina Seed',
body_html:
descriptionHtml:
'<p><strong>Camelina, also known as Gold of Pleasure, has been grown in England for thousands of years for its tasty seeds and oil. Sprinkle on salads, use in baking, add to smoothies, or use as a vegan egg replacement. </strong></p>\n' +
'<!-- split --><h3>Complete Product Details</h3><p>Sprinkle on salads, add to smoothies, use in baking.</p>\n' +
'<h5 class="product-detail-title">Cooking instructions</h5>\n' +
Expand Down Expand Up @@ -101,12 +101,12 @@ export const importedShopifyProductsFromDFC = [
'</tbody>\n' +
'</table><p>Camelina Seeds are high in protein, a good source of Omega 3 oils and rich in antioxidants such as vitamin E</p><h5 class="product-detail-title">More</h5>\n' +
'<p>Grown by Peter Fairs in Essex and Andy Howard in Kent.</p>',
product_type: 'Savory Snacks',
productType: 'Savory Snacks',
handle: 'camelina-seed-trade',
image: {
id: '44001459765400',
src: 'https://cdn.shopify.com/s/files/1/0587/9735/9256/products/Cameilna-Seeds-1800x1200_8c00a108-d8f7-4920-9bac-758a2c6a8b56.jpg?v=1706882031',
alt: 'Camelina Seed'
altText: 'Camelina Seed'
},
variants: [
{
Expand All @@ -116,25 +116,25 @@ export const importedShopifyProductsFromDFC = [
title: 'Retail pack, 300g',
price: 2.49,
weight: 0,
weight_unit: 'kg',
inventory_quantity: 55,
weightUnit: 'kg',
inventoryQuantity: 55,
sku: undefined,
taxable: true,
tracked: undefined,
inventory_policy: 'deny',
fulfillment_service: 'manual',
inventory_management: 'shopify',
inventoryPolicy: 'deny',
fulfillmentService: 'manual',
inventoryManagement: 'shopify',
image: {
id: '44001459798168',
src: 'https://cdn.shopify.com/s/files/1/0587/9735/9256/products/37-cammalina-fron.jpg?v=1706882031',
alt: 'Retail pack, 300g'
altText: 'Retail pack, 300g'
}
}
],
images: [
{
id: '44001459765400',
alt: 'Camelina Seed',
altText: 'Camelina Seed',
position: 1,
product_id: '7898317750424',
admin_graphql_api_id: 'gid://shopify/ProductImage/44001459765400',
Expand All @@ -143,7 +143,7 @@ export const importedShopifyProductsFromDFC = [
},
{
id: '44001459798168',
alt: 'Retail pack, 300g',
altText: 'Retail pack, 300g',
position: 2,
product_id: '7898317750424',
admin_graphql_api_id: 'gid://shopify/ProductImage/44001459798168',
Expand Down
73 changes: 36 additions & 37 deletions web/connector/productUtils.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,27 @@
import {
throwError
} from '../utils/index.js';
import { getTargetStringFromSemanticId, throwError } from '../utils/index.js';

import { loadConnectorWithResources, PlannedTransformation } from './index.js';
import { loadProductTypes, loadQuantityUnits } from './mappings.js';

function extractId(dfcSemanticId) {
return dfcSemanticId.substring(dfcSemanticId.lastIndexOf('/') + 1);
}

async function getSingleSuppliedProduct(suppliedProduct) {
try {
const productTypesObj = await loadProductTypes();
const productType = await suppliedProduct.getProductType();
const semanticId = suppliedProduct.getSemanticId();

const images = suppliedProduct.getImages();

const suppliedProductDetails = {
id: extractId(semanticId),
id: getTargetStringFromSemanticId(semanticId, 'SuppliedProducts'),
title: suppliedProduct.getName(),
body_html: suppliedProduct.getDescription(),
product_type: productTypesObj[productType],
descriptionHtml: suppliedProduct.getDescription(),
productType: productTypesObj[productType]
};

if (images.length) {
suppliedProductDetails.image = {
src: images[0],
alt: suppliedProduct.getName()
altText: suppliedProduct.getName()
};
}

Expand All @@ -40,7 +35,6 @@ async function getSingleVariantSuppliedProduct(suppliedProduct) {
try {
const semanticId = suppliedProduct.getSemanticId();


const productName = suppliedProduct.getName();
const [quantity, catalogItems] = await Promise.all([
suppliedProduct.getQuantity(),
Expand All @@ -65,34 +59,27 @@ async function getSingleVariantSuppliedProduct(suppliedProduct) {
const priceVatRate = price.getVatRate();
const hasVat = priceVatRate && Number(priceVatRate) > 0;
const images = suppliedProduct.getImages();

const quantityUnitsObj = await loadQuantityUnits();

const isContinueSelling = stockLimitation === -1;

const variantSuppliedProduct = {
id: extractId(semanticId),
id: getTargetStringFromSemanticId(semanticId, 'SuppliedProducts'),
title: productName,
price: priceValue,
weight: quantityValue,
weight_unit: quantityUnitsObj[quantityUnit],
inventory_quantity: isContinueSelling ? 0 : stockLimitation,
weightUnit: quantityUnitsObj[quantityUnit],
inventoryQuantity: isContinueSelling ? 0 : stockLimitation,
sku,
taxable: hasVat,
tracked: true,
inventory_policy: isContinueSelling ? 'continue' : 'deny',
// TODO check if these are needed and make these dynamic
fulfillment_service: 'manual',
inventory_management: 'shopify'
// compare_at_price: '2.99',
// old_inventory_quantity: -15,
// requires_shipping: true
inventoryPolicy: isContinueSelling ? 'continue' : 'deny'
};

if (images.length) {
variantSuppliedProduct.image = {
src: images[0],
alt: productName
altText: productName
};
}

Expand All @@ -118,7 +105,6 @@ async function importSuppliedProducts(dfcProducts) {
}

async function getSuppliedProductDetailsFromImports(dfcExportsArray) {

const dfcImports = await importSuppliedProducts(dfcExportsArray);

const dfcRetailWholesalePairs = dfcImports.filter(
Expand All @@ -129,26 +115,41 @@ async function getSuppliedProductDetailsFromImports(dfcExportsArray) {
}

async function toShopifyProduct(retailWholesalePair) {
const consumptionFlows = await retailWholesalePair.getPlannedConsumptionFlows();
const consumptionFlows =
await retailWholesalePair.getPlannedConsumptionFlows();
const productionFlows = await retailWholesalePair.getPlannedProductionFlows();

if (consumptionFlows.length !== 1 || productionFlows.length !== 1) {
console.error(`Error handling the following PlannedTransformation. Dont know how to handle case where production/consumption is not 1-1`, retailWholesalePair)
console.error(
`Error handling the following PlannedTransformation. Dont know how to handle case where production/consumption is not 1-1`,
retailWholesalePair
);
}


const wholesaleProduct = await productionFlows[0].getProducedProduct();
const retailProduct = await consumptionFlows[0].getConsumedProduct();


const retailShopifyProduct = await getSingleVariantSuppliedProduct(retailProduct);
const wholesaleShopifyProduct = await getSingleVariantSuppliedProduct(wholesaleProduct);
const itemsPerWholesaleVariant = await (await consumptionFlows[0].getQuantity().getQuantityValue());
const retailShopifyProduct =
await getSingleVariantSuppliedProduct(retailProduct);
const wholesaleShopifyProduct =
await getSingleVariantSuppliedProduct(wholesaleProduct);
const itemsPerWholesaleVariant = await await consumptionFlows[0]
.getQuantity()
.getQuantityValue();

const parentShopifyProduct = await getSingleSuppliedProduct(retailProduct);
parentShopifyProduct.variants = [retailShopifyProduct];
parentShopifyProduct.images = retailShopifyProduct.image ? [createImageObject(retailShopifyProduct.image, retailShopifyProduct.id, 1)] : [];


parentShopifyProduct.images = retailShopifyProduct.image
? [
createImageObject(
retailShopifyProduct.image,
retailShopifyProduct.id,
1
)
]
: [];

return {
parentProduct: parentShopifyProduct,
retailProduct: retailShopifyProduct,
Expand All @@ -159,11 +160,9 @@ async function toShopifyProduct(retailWholesalePair) {

function createImageObject(image, productId, position, variantIds = []) {
return {
id: image.id,
alt: image.alt,
altText: image.altText,
position,
product_id: productId,
admin_graphql_api_id: `gid://shopify/ProductImage/${image.id}`,
src: image.src,
variant_ids: variantIds
};
Expand Down
6 changes: 3 additions & 3 deletions web/connector/productUtils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ describe('generateShopifyFDCProducts', () => {
exportedDFCProducerProducts(-1)
);

const variant = result[0].variants[0]
const variant = result[0].variants[0];

expect(variant.inventory_quantity).toEqual(0);
expect(variant.inventory_policy).toEqual('continue');
expect(variant.inventoryQuantity).toEqual(0);
expect(variant.inventoryPolicy).toEqual('continue');
});
});
19 changes: 16 additions & 3 deletions web/frontend/components/VariantCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,28 @@ function VariantCard({ variant, index }) {

<p>
<strong>inventoryPolicy:</strong>
{variant.inventory_policy}
{variant.inventoryPolicy}
</p>

{variant?.inventory_policy?.toUpperCase() !== 'CONTINUE' && (
{/* add sku */}
{variant.sku && (
<p>
<strong>sku:</strong>
{variant.sku}
</p>
)}
{variant?.inventoryPolicy?.toUpperCase() !== 'CONTINUE' && (
<p>
<strong>inventory Quantity:</strong>
{variant.inventory_quantity}
{variant.inventoryQuantity}
</p>
)}

<p>
<strong>weight:</strong>
{variant.weight}
{variant.weightUnit}
</p>
</div>
);
}
Expand Down
17 changes: 13 additions & 4 deletions web/frontend/pages/ProductsList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,7 @@ export default function ProductsList() {

useLayoutEffect(() => {
if (producerProductsData) {
setProducerProducts((prev) => [
...prev,
...producerProductsData
]);
setProducerProducts((prev) => [...prev, ...producerProductsData]);
}
}, [producerProductsData]);

Expand Down Expand Up @@ -294,6 +291,18 @@ export default function ProductsList() {
</Alert>
)}

{!producerProducts.length && (
<Alert
severity="warning"
sx={{
typography: 'body1',
fontSize: '20px'
}}
>
No products available
</Alert>
)}

<Stack spacing="12px" px="60px" py="12px">
{producerProducts.map((product) => (
<ProductsCard
Expand Down
Loading

0 comments on commit 425d737

Please sign in to comment.