Glue API - Measurement units feature integration

Edit on GitHub

Follow the steps below to install Measurement units feature API.

Prerequisites

To start the feature integration, overview and install the necessary features:

NAME VERSION LINK
Spryker Core 202108.0 Glue API: Spryker Core feature integration
Product Measurement Units 202108.0 Product Measurement Units feature integration

1) Install the required modules using Composer

Run the following command to install the required modules:

composer require spryker/product-measurement-units-rest-api:"^1.0.0" --update-with-dependencies
Verification

Make sure that the following modules have been installed:

MODULE EXPECTED DIRECTORY
ProductMeasurementUnitsRestApi vendor/spryker/product-measurement-units-rest-api

2) Set up database schema and transfer objects

Run the following command to generate the transfer changes:

console transfer:generate
console propel:install
console transfer:generate
Verification

Make sure that SpyProductMeasurementUnitStorage and SpyProductConcreteStorage have been extended with synchronization behavior, namely with the methods:

ENTITY TYPE EVENT PATH METHODS
SpyProductMeasurementUnitStorage class extended src/Orm/Zed/ProductMeasurementUnitStorage/Persistence/Base/SpyProductMeasurementUnitStorage syncPublishedMessageForMappings(), syncUnpublishedMessageForMappings()
SpyProductConcreteStorage class extended src/Orm/Zed/ProductStorage/Persistence/Base/SpyProductConcreteStorage syncPublishedMessageForMappings(), syncUnpublishedMessageForMappings()
Verification

Make sure that the following changes have occurred:

TRANSFER TYPE EVENT PATH
RestProductMeasurementUnitsAttributesTransfer class created src/Generated/Shared/Transfer/RestProductMeasurementUnitsAttributesTransfer
RestSalesUnitsAttributesTransfer class created src/Generated/Shared/Transfer/RestSalesUnitsAttributesTransfer
RestCartItemsSalesUnitAttributesTransfer class created src/Generated/Shared/Transfer/RestCartItemsSalesUnitAttributesTransfer
RestOrdersProductMeasurementUnitsAttributesTransfer class created src/Generated/Shared/Transfer/RestOrdersProductMeasurementUnitsAttributesTransfer
RestOrdersSalesUnitAttributesTransfer class created src/Generated/Shared/Transfer/RestOrdersSalesUnitAttributesTransfer
RestCartItemsAttributesTransfer.salesUnit property added src/Generated/Shared/Transfer/RestCartItemsAttributesTransfer
RestItemsAttributesTransfer.salesUnit property added src/Generated/Shared/Transfer/RestItemsAttributesTransfer
RestItemsAttributesTransfer.sku property added src/Generated/Shared/Transfer/RestItemsAttributesTransfer
RestOrderItemsAttributesTransfer.salesUnit property added src/Generated/Shared/Transfer/RestOrderItemsAttributesTransfer

3) Set up behavior

Set up the following behaviors.

Re-export data to storage

Run the following commands to reload abstract and concrete product data to the Storage:

console event:trigger -r product_measurement_unit
console event:trigger -r product_concrete
Verification

Make sure that the following Redis keys exist and there is data in them:

  • kv:product_measurement_unit:code:{{product_measurement_unit_code}}

  • kv:product_concrete:{{locale_name}}:sku:{{sku_product_concrete}}

Enable resources and relationships

Activate the following plugins:

PLUGIN SPECIFICATION PREREQUISITES NAMESPACE
ProductMeasurementUnitsResourceRoutePlugin Registers the product-measurement-units resource. None Spryker\Glue\ProductMeasurementUnitsApi\Plugin
SalesUnitsResourceRoutePlugin Registers the sales-units resource. None Spryker\Glue\ProductMeasurementUnitsApi\Plugin
ProductMeasurementUnitsByProductConcreteResourceRelationshipPlugin Adds the product-measurement-units resource as a relationship of the product-concrete resource. None Spryker\Glue\ProductMeasurementUnitsApi\Plugin\GlueApplication
SalesUnitsByProductConcreteResourceRelationshipPlugin Adds the sales-units resource as a relationship of the product-concrete resource. None Spryker\Glue\ProductMeasurementUnitsApi\Plugin\GlueApplication
ProductMeasurementUnitsBySalesUnitResourceRelationshipPlugin Adds the product-measurement-units resource as a relationship of the sales-units resource. None Spryker\Glue\ProductMeasurementUnitsApi\Plugin\GlueApplication
SalesUnitsByCartItemResourceRelationshipPlugin Adds the sales-units resource as relationship of the item resource. None Spryker\Glue\ProductMeasurementUnitsApi\Plugin\GlueApplication
src/Pyz/Glue/GlueApplication/GlueApplicationDependencyProvider.php
<?php
 
namespace Pyz\Glue\GlueApplication;
 
use Spryker\Glue\CartsRestApi\CartsRestApiConfig;
use Spryker\Glue\GlueApplication\GlueApplicationDependencyProvider as SprykerGlueApplicationDependencyProvider;
use Spryker\Glue\GlueApplicationExtension\Dependency\Plugin\ResourceRelationshipCollectionInterface;
use Spryker\Glue\ProductMeasurementUnitsRestApi\Plugin\GlueApplication\ProductMeasurementUnitsByProductConcreteResourceRelationshipPlugin;
use Spryker\Glue\ProductMeasurementUnitsRestApi\Plugin\GlueApplication\ProductMeasurementUnitsBySalesUnitResourceRelationshipPlugin;
use Spryker\Glue\ProductMeasurementUnitsRestApi\Plugin\GlueApplication\ProductMeasurementUnitsResourceRoutePlugin;
use Spryker\Glue\ProductMeasurementUnitsRestApi\Plugin\GlueApplication\SalesUnitsByCartItemResourceRelationshipPlugin;
use Spryker\Glue\ProductMeasurementUnitsRestApi\Plugin\GlueApplication\SalesUnitsByProductConcreteResourceRelationshipPlugin;
use Spryker\Glue\ProductMeasurementUnitsRestApi\Plugin\GlueApplication\SalesUnitsResourceRoutePlugin;
use Spryker\Glue\ProductMeasurementUnitsRestApi\ProductMeasurementUnitsRestApiConfig;
use Spryker\Glue\ProductsRestApi\ProductsRestApiConfig;
 
class GlueApplicationDependencyProvider extends SprykerGlueApplicationDependencyProvider
{
    /**
     * @return \Spryker\Glue\GlueApplicationExtension\Dependency\Plugin\ResourceRoutePluginInterface[]
     */
    protected function getResourceRoutePlugins(): array
    {
        return [
            new ProductMeasurementUnitsResourceRoutePlugin(),
            new SalesUnitsResourceRoutePlugin(),
        ];
    }
 
    /**
     * @param \Spryker\Glue\GlueApplicationExtension\Dependency\Plugin\ResourceRelationshipCollectionInterface $resourceRelationshipCollection
     *
     * @return \Spryker\Glue\GlueApplicationExtension\Dependency\Plugin\ResourceRelationshipCollectionInterface
     */
    protected function getResourceRelationshipPlugins(
        ResourceRelationshipCollectionInterface $resourceRelationshipCollection
    ): ResourceRelationshipCollectionInterface {
         $resourceRelationshipCollection->addRelationship(
            ProductsRestApiConfig::RESOURCE_CONCRETE_PRODUCTS,
            new ProductMeasurementUnitsByProductConcreteResourceRelationshipPlugin()
        );
        $resourceRelationshipCollection->addRelationship(
            ProductsRestApiConfig::RESOURCE_CONCRETE_PRODUCTS,
            new SalesUnitsByProductConcreteResourceRelationshipPlugin()
        );
        $resourceRelationshipCollection->addRelationship(
            ProductMeasurementUnitsRestApiConfig::RESOURCE_SALES_UNITS,
            new ProductMeasurementUnitsBySalesUnitResourceRelationshipPlugin()
        );
        $resourceRelationshipCollection->addRelationship(
            CartsRestApiConfig::RESOURCE_CART_ITEMS,
            new SalesUnitsByCartItemResourceRelationshipPlugin()
        );
        $resourceRelationshipCollection->addRelationship(
            CartsRestApiConfig::RESOURCE_GUEST_CARTS_ITEMS,
            new SalesUnitsByCartItemResourceRelationshipPlugin()
        );
         
        return $resourceRelationshipCollection;
    }
}
Verification

Make sure that the ProductMeasurementUnitsResourceRoutePlugin plugin is set up:

  1. Send the request GET http://glue.mysprykershop.com/product-measurement-units/{{product_measurement_unit_code}}.

  2. You should get a valid response, similar to the following:

{
    "data": {
        "type": "product-measurement-units",
        "id": "METR",
        "attributes": {
            "name": "Meter",
            "defaultPrecision": 100
        },
        "links": {
            "self": "http://glue.mysprykershop.com/product-measurement-units/METR"
        }
    }
}
Verification

Make sure that the SalesUnitsResourceRoutePlugin and ProductMeasurementUnitsBySalesUnitResourceRelationshipPlugin plugins are set up:

  1. Send the request GET http://glue.mysprykershop.com/concrete-products/{{concrete_product_sku}}/sales-units?include=product-measurement-units.

  2. You should get a valid response, similar to the following:

Response sample
{
    "data": [
        {
            "type": "sales-units",
            "id": "5",
            "attributes": {
                "conversion": 0.30480000000000002,
                "precision": 100,
                "isDisplayed": true,
                "isDefault": true,
                "productMeasurementUnitCode": "FOOT"
            },
            "links": {
                "self": "http://glue.de.suite-nonsplit.local/concrete-products/215_124/sales-units/5"
            },
            "relationships": {
                "product-measurement-units": {
                    "data": [
                        {
                            "type": "product-measurement-units",
                            "id": "FOOT"
                        }
                    ]
                }
            }
        }
    ],
    "links": {
        "self": "http://glue.de.suite-nonsplit.local/concrete-products/215_124/sales-units?include=product-measurement-units&amp;XDEBUG_SESSION_START=PHPHSTORM"
    },
    "included": [
        {
            "type": "product-measurement-units",
            "id": "FOOT",
            "attributes": {
                "name": "Foot",
                "defaultPrecision": 100
            },
            "links": {
                "self": "http://glue.de.suite-nonsplit.local/product-measurement-units/FOOT"
            }
        }
    ]
}
Verification

Make sure that the ProductMeasurementUnitsByProductConcreteResourceRelationshipPlugin and SalesUnitsByProductConcreteResourceRelationshipPlugin relationship plugins are set up:

  1. Send the request GET http://glue.mysprykershop.com/concrete-products/{{concrete_product_sku}}?include=product-measurement-units,sales-units.

  2. You should get a valid response, similar to the following:

Response sample
{
    "data": {
        "type": "concrete-products",
        "id": "215_123",
        "attributes": {
            "sku": "215_123",
            "isDiscontinued": false,
            "discontinuedNote": null,
            "averageRating": null,
            "reviewCount": 0,
            "name": "ASUS HDMI-HDMI Black",
            "description": "HDMI to HDMI High Speed Cable",
            "attributes": {
                "brand": "ASUS",
                "color": "Black",
                "packaging_unit": "Item"
            },
            "superAttributesDefinition": [
                "color",
                "packaging_unit"
            ],
            "metaTitle": "Asus HDMI - HDMI",
            "metaKeywords": "Asus, Cable, HDMI",
            "metaDescription": "The perfect cable for your home",
            "attributeNames": {
                "brand": "Brand",
                "color": "Color",
                "packaging_unit": "Packaging unit"
            }
        },
        "links": {
            "self": "http://glue.mysprykershop.com/concrete-products/215_123?include=product-measurement-units,sales-units"
        },
        "relationships": {
            "product-measurement-units": {
                "data": [
                    {
                        "type": "product-measurement-units",
                        "id": "METR"
                    }
                ]
            },
            "sales-units": {
                "data": [
                    {
                        "type": "sales-units",
                        "id": "1"
                    },
                    {
                        "type": "sales-units",
                        "id": "2"
                    }
                ]
            }
        }
    },
    "included": [
        {
            "type": "product-measurement-units",
            "id": "METR",
            "attributes": {
                "name": "Meter",
                "defaultPrecision": 100
            },
            "links": {
                "self": "http://glue.mysprykershop.com/product-measurement-units/METR"
            }
        },
        {
            "type": "sales-units",
            "id": "1",
            "attributes": {
                "conversion": 1,
                "precision": 100,
                "isDisplayed": true,
                "isDefault": true,
                "productMeasurementUnitCode": "METR"
            },
            "links": {
                "self": "http://glue.mysprykershop.com/concrete-products/215_123/sales-units/1"
            },
            "relationships": {
                "product-measurement-units": {
                    "data": [
                        {
                            "type": "product-measurement-units",
                            "id": "METR"
                        }
                    ]
                }
            }
        },
        {
            "type": "product-measurement-units",
            "id": "CMET",
            "attributes": {
                "name": "Centimeter",
                "defaultPrecision": 10
            },
            "links": {
                "self": "http://glue.mysprykershop.com/product-measurement-units/CMET"
            }
        },
        {
            "type": "sales-units",
            "id": "2",
            "attributes": {
                "conversion": 0.01,
                "precision": 10,
                "isDisplayed": true,
                "isDefault": false,
                "productMeasurementUnitCode": "CMET"
            },
            "links": {
                "self": "http://glue.mysprykershop.com/concrete-products/215_123/sales-units/2"
            },
            "relationships": {
                "product-measurement-units": {
                    "data": [
                        {
                            "type": "product-measurement-units",
                            "id": "CMET"
                        }
                    ]
                }
            }
        }
    ]
}
Verification

Make sure that the SalesUnitsByCartItemResourceRelationshipPlugin relationship plugin is set up:

  1. Send the request GET http://glue.mysprykershop.com/carts/{{cart_uuid}}?include=items,sales-units.

  2. You should get a valid response, similar to the following:

Response sample
{
    "data": {
        "type": "carts",
        "id": "1ce91011-8d60-59ef-9fe0-4493ef3628b2",
        "attributes": {
            "priceMode": "GROSS_MODE",
            "currency": "EUR",
            "store": "DE",
            "name": "My Cart",
            "isDefault": true,
            "totals": {
                "expenseTotal": 0,
                "discountTotal": 0,
                "taxTotal": 798,
                "subtotal": 5000,
                "grandTotal": 5000
            },
            "discounts": []
        },
        "links": {
            "self": "http://glue.mysprykershop.com/carts/1ce91011-8d60-59ef-9fe0-4493ef3628b2?include=items,sales-units"
        },
        "relationships": {
            "items": {
                "data": [
                    {
                        "type": "items",
                        "id": "215_124_quantity_sales_unit_id_4_amount_5_sales_unit_id_4"
                    }
                ]
            }
        }
    },
    "included": [
        {
            "type": "sales-units",
            "id": "4",
            "attributes": {
                "conversion": 0.01,
                "precision": 1,
                "isDisplayed": true,
                "isDefault": false,
                "productMeasurementUnitCode": "CMET"
            },
            "links": {
                "self": "http://glue.mysprykershop.com/concrete-products/215_124/sales-units/4"
            }
        },
        {
            "type": "items",
            "id": "215_124_quantity_sales_unit_id_4_amount_5_sales_unit_id_4",
            "attributes": {
                "sku": "215_124",
                "quantity": 4,
                "groupKey": "215_124_quantity_sales_unit_id_4_amount_5_sales_unit_id_4",
                "abstractSku": "215",
                "amount": "20",
                "calculations": {
                    "unitPrice": 1250,
                    "sumPrice": 5000,
                    "taxRate": 19,
                    "unitNetPrice": 0,
                    "sumNetPrice": 0,
                    "unitGrossPrice": 1250,
                    "sumGrossPrice": 5000,
                    "unitTaxAmountFullAggregation": 200,
                    "sumTaxAmountFullAggregation": 798,
                    "sumSubtotalAggregation": 5000,
                    "unitSubtotalAggregation": 1250,
                    "unitProductOptionPriceAggregation": 0,
                    "sumProductOptionPriceAggregation": 0,
                    "unitDiscountAmountAggregation": 0,
                    "sumDiscountAmountAggregation": 0,
                    "unitDiscountAmountFullAggregation": 0,
                    "sumDiscountAmountFullAggregation": 0,
                    "unitPriceToPayAggregation": 1250,
                    "sumPriceToPayAggregation": 5000
                },
                "salesUnit": {
                    "id": 4,
                    "amount": "20"
                },
                "selectedProductOptions": []
            },
            "links": {
                "self": "http://glue.mysprykershop.com/carts/1ce91011-8d60-59ef-9fe0-4493ef3628b2/items/215_124_quantity_sales_unit_id_4_amount_5_sales_unit_id_4"
            },
            "relationships": {
                "sales-units": {
                    "data": [
                        {
                            "type": "sales-units",
                            "id": "4"
                        }
                    ]
                }
            }
        }
    ]
}

Provide dependencies for the CartsRestApi module

Activate the following plugins:

PLUGIN SPECIFICATION PREREQUISITES NAMESPACE
SalesUnitsRestCartItemsAttributesMapperPlugin Maps ItemTransfer::$amountSalesUnit to RestItemsAttributesTransfer::$salesUnit. None Spryker\Glue\ProductMeasurementUnitsApi\Plugin\CartsRestApi
SalesUnitCartItemExpanderPlugin Expands CartItemRequestTransfer with amount and idProductMeasurementSalesUnit. None Spryker\Glue\ProductMeasurementUnitsApi\Plugin\CartsRestApi
SalesUnitCartItemMapperPlugin Maps CartItemRequestTransfer::$idProductMeasurementSalesUnit, CartItemRequestTransfer::$amount to PersistentCartChangeTransfer::$items. None Spryker\Zed\ProductMeasurementUnitsRestApi\Communication\Plugin\CartsRestApi

src/Pyz/Glue/CartsRestApi/CartsRestApiDependencyProvider.php

<?php

namespace Pyz\Glue\CartsRestApi;

use Spryker\Glue\CartsRestApi\CartsRestApiDependencyProvider as SprykerCartsRestApiDependencyProvider;
use Spryker\Glue\ProductMeasurementUnitsRestApi\Plugin\CartsRestApi\SalesUnitCartItemExpanderPlugin;
use Spryker\Glue\ProductMeasurementUnitsRestApi\Plugin\CartsRestApi\SalesUnitsRestCartItemsAttributesMapperPlugin;

class CartsRestApiDependencyProvider extends SprykerCartsRestApiDependencyProvider
{
    /**
     * @return \Spryker\Glue\CartsRestApiExtension\Dependency\Plugin\RestCartItemsAttributesMapperPluginInterface[]
     */
    protected function getRestCartItemsAttributesMapperPlugins(): array
    {
        return [
            new SalesUnitsRestCartItemsAttributesMapperPlugin(),
        ];
    }

    /**
     * @return \Spryker\Glue\CartsRestApiExtension\Dependency\Plugin\CartItemExpanderPluginInterface[]
     */
    protected function getCartItemExpanderPlugins(): array
    {
        return [
            new SalesUnitCartItemExpanderPlugin(),
        ];
    }
}

src/Pyz/Zed/CartsRestApi/CartsRestApiDependencyProvider.php

<?php

namespace Pyz\Zed\CartsRestApi;

use Spryker\Zed\CartsRestApi\CartsRestApiDependencyProvider as SprykerCartsRestApiDependencyProvider;
use Spryker\Zed\ProductMeasurementUnitsRestApi\Communication\Plugin\CartsRestApi\SalesUnitCartItemMapperPlugin;

class CartsRestApiDependencyProvider extends SprykerCartsRestApiDependencyProvider
{
    /**
     * @return \Spryker\Zed\CartsRestApiExtension\Dependency\Plugin\CartItemMapperPluginInterface[]
     */
    protected function getCartItemMapperPlugins(): array
    {
        return [
            new SalesUnitCartItemMapperPlugin(),
        ];
    }
}
Verification

Make sure that the plugins have been set up:

  1. Send the request POST http://glue.mysprykershop.com/carts/{{cart_uuid}}/items with the request body:
{
    "data": {
        "type": "items",
        "attributes": {
            "sku": "{{concrete_sku}}",
            "quantity": {{quantity}},
            "salesUnit": {
            	"id": {{sales_unit_id}},
                "amount": {{amount}}
            }
        }
    }
}
  1. Send the request GET http://glue.mysprykershop.com/carts?include=items and make sure that the following attributes are included:
    • salesUnits.id
    • salesUnits.amount

Provide dependencies for the OrdersRestApi module

Activate the following plugin:

PLUGIN SPECIFICATION PREREQUISITES NAMESPACE
SalesUnitRestOrderItemsAttributesMapperPlugin Maps ItemTransfer::$amountSalesUnit to RestOrderItemsAttributesTransfer::$salesUnit. None Spryker\Glue\ProductMeasurementUnitsRestApi\Plugin\OrdersRestApi

src/Pyz/Glue/CartsRestApi/CartsRestApiDependencyProvider.php

<?php

namespace Pyz\Glue\OrdersRestApi;

use Spryker\Glue\OrdersRestApi\OrdersRestApiDependencyProvider as SprykerOrdersRestApiDependencyProvider;
use Spryker\Glue\ProductMeasurementUnitsRestApi\Plugin\OrdersRestApi\SalesUnitRestOrderItemsAttributesMapperPlugin;

class OrdersRestApiDependencyProvider extends SprykerOrdersRestApiDependencyProvider
{
    /**
     * @return \Spryker\Glue\OrdersRestApiExtension\Dependency\Plugin\RestOrderItemsAttributesMapperPluginInterface[]
     */
    protected function getRestOrderItemsAttributesMapperPlugins(): array
    {
        return [
            new SalesUnitRestOrderItemsAttributesMapperPlugin(),
        ];
    }
}
Verification

Send the request GET http://glue.mysprykershop.com/orders/{{order_uuid}} and make sure that the order items have salesUnits and salesUnits.amount properties in the response.