Java tutorial
/* * Copyright 2009 Denys Pavlov, Igor Azarnyi * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.yes.cart.web.service.rest; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.yes.cart.domain.dto.ProductSearchResultDTO; import org.yes.cart.domain.entity.*; import org.yes.cart.domain.misc.Pair; import org.yes.cart.domain.ro.*; import org.yes.cart.service.domain.BrandService; import org.yes.cart.shoppingcart.ShoppingCart; import org.yes.cart.shoppingcart.ShoppingCartCommand; import org.yes.cart.shoppingcart.ShoppingCartCommandFactory; import org.yes.cart.web.service.rest.impl.BookmarkMixin; import org.yes.cart.web.service.rest.impl.CartMixin; import org.yes.cart.web.service.rest.impl.RoMappingMixin; import org.yes.cart.web.support.constants.WebParametersKeys; import org.yes.cart.web.support.service.CentralViewResolver; import org.yes.cart.web.support.service.CurrencySymbolService; import org.yes.cart.web.support.service.ProductServiceFacade; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * User: denispavlov * Date: 24/03/2015 * Time: 10:43 */ @Controller public class ProductController { @Autowired private CentralViewResolver centralViewResolver; @Autowired private BrandService brandService; @Autowired private ProductServiceFacade productServiceFacade; @Autowired private CurrencySymbolService currencySymbolService; @Autowired private ShoppingCartCommandFactory shoppingCartCommandFactory; @Autowired private CartMixin cartMixin; @Autowired @Qualifier("restRoMappingMixin") private RoMappingMixin mappingMixin; @Autowired private BookmarkMixin bookmarkMixin; private ProductRO viewProductInternal(final String product, final boolean recordViewed) { final long productId = bookmarkMixin.resolveProductId(product); final Product productEntity = productServiceFacade.getProductById(productId); if (productEntity != null) { final ShoppingCart cart = cartMixin.getCurrentCart(); final Pair<String, Boolean> symbol = currencySymbolService.getCurrencySymbol(cart.getCurrencyCode()); final ProductRO prodRO = mappingMixin.map(productEntity, ProductRO.class, Product.class); final Pair<String, String> templates = resolveTemplate(prodRO); if (templates != null) { prodRO.setUitemplate(templates.getFirst()); prodRO.setUitemplateFallback(templates.getSecond()); } // Brand is lazy so need to retrieve name manually final Brand brand = brandService.findById(prodRO.getBrandId()); prodRO.setBrandName(brand.getName()); final ProductAvailabilityModel skuPam = productServiceFacade.getProductAvailability(productEntity, cart.getShoppingContext().getShopId()); final ProductAvailabilityModelRO amRo = mappingMixin.map(skuPam, ProductAvailabilityModelRO.class, ProductAvailabilityModel.class); prodRO.setProductAvailabilityModel(amRo); final SkuPrice price = productServiceFacade.getSkuPrice(productEntity.getProductId(), null, BigDecimal.ONE, cart.getCurrencyCode(), cart.getShoppingContext().getShopId()); final SkuPriceRO priceRo = mappingMixin.map(price, SkuPriceRO.class, SkuPrice.class); priceRo.setSymbol(symbol.getFirst()); priceRo.setSymbolPosition(symbol.getSecond() != null && symbol.getSecond() ? "after" : "before"); prodRO.setPrice(priceRo); final List<ProductSkuRO> skuRo = new ArrayList<ProductSkuRO>(); if (CollectionUtils.isNotEmpty(productEntity.getSku())) { for (final ProductSku sku : productEntity.getSku()) { final ProductSkuRO skuRoItem = viewSkuInternal(sku, cart.getShoppingContext().getShopId(), cart.getCurrencyCode(), symbol); if (skuRoItem != null) { skuRo.add(skuRoItem); } } } prodRO.setSkus(skuRo); if (recordViewed) { executeViewProductCommand(productEntity); } return prodRO; } return null; } private Pair<String, String> resolveTemplate(final ProductRO prodRO) { final Map params = new HashMap(); params.put(WebParametersKeys.PRODUCT_ID, String.valueOf(prodRO.getProductId())); return centralViewResolver.resolveMainPanelRendererLabel(params); } /** * Interface: GET /product/{id} * <p> * <p> * Display full product details. * <p> * <p> * <h3>Headers for operation</h3><p> * <table border="1"> * <tr><td>Accept</td><td>application/json or application/xml</td></tr> * <tr><td>yc</td><td>token uuid (optional)</td></tr> * </table> * <p> * <p> * <h3>Parameters for operation</h3><p> * <table border="1"> * <tr><td>id</td><td>SEO URI or product PK</td></tr> * </table> * <p> * <p> * <h3>Output</h3><p> * <table border="1"> * <tr><td>JSON example</td><td> * <pre><code> * { * "displayNames" : { * "uk" : "Mini Mouse M187", * "ru" : "Mini Mouse M187", * "en" : "Mini Mouse M187" * }, * "maxOrderQuantity" : null, * "productTypeId" : 5, * "minOrderQuantity" : null, * "availability" : 1, * "code" : "910-002", * "title" : null, * "attributes" : [ * { * "attrvalueId" : 891, * "productId" : 297, * "val" : "Logitech Wireless Mini Mouse M187...", * "displayVals" : null, * "attributeName" : "? (uk)", * "attributeId" : 11022, * "attributeDisplayNames" : null * }, * { * "attrvalueId" : 19865, * "productId" : 297, * "val" : "Y", * "displayVals" : { * "uk" : "", * "ru" : "", * "en" : "Y" * }, * "attributeName" : "Receiver included", * "attributeId" : 1423, * "attributeDisplayNames" : { * "uk" : "?, ????", * "ru" : "?? ?", * "en" : "Receiver included" * } * }, * ... * ], * "displayMetadescriptions" : {}, * "displayTitles" : {}, * "productId" : 297, * "name" : "Mini Mouse M187", * "stepOrderQuantity" : null, * "tag" : "multisku", * "brandName" : "Logitech", * "brandId" : 5, * "availablefrom" : null, * "uri" : null, * "availableto" : null, * "productTypeName" : "Mice", * "metakeywords" : null, * "manufacturerCode" : "M001", * "productAvailabilityModel" : { * "firstAvailableSkuCode" : "910-002-741", * "available" : true, * "defaultSkuCode" : "910-002-741", * "inStock" : true, * "skuCodes" : [ * "910-002-741", * "910-002-742", * "910-002-743", * "910-002-744" * ], * "perpetual" : false, * "availableToSellQuantity" : { * "910-002-742" : 300, * "910-002-744" : 300, * "910-002-741" : 300, * "910-002-743" : 300 * } * }, * "skus" : [ * { * "metakeywords" : null, * "productId" : 297, * "description" : "", * "metadescription" : null, * "uri" : null, * "price" : { * "symbol" : "", * "quantity" : 1, * "regularPrice" : 387.56, * "salePrice" : null, * "discount" : null, * "currency" : "EUR", * "symbolPosition" : "before" * }, * "attributes" : [ * { * "attrvalueId" : 948, * "val" : "White", * "displayVals" : { * "uk" : "", * "ru" : "", * "en" : "White" * }, * "attributeName" : "Color of product", * "attributeId" : 532, * "attributeDisplayNames" : { * "uk" : " ", * "ru" : " ", * "en" : "Color of product" * }, * "skuId" : 308 * }, * ... * ], * "title" : null, * "manufacturerCode" : null, * "code" : "910-002-744", * "skuId" : 308, * "rank" : 0, * "displayTitles" : null, * "displayNames" : { * "uk" : "M187 ", * "ru" : "M187 ", * "en" : "M187 White" * }, * "productAvailabilityModel" : { * "firstAvailableSkuCode" : "910-002-744", * "available" : true, * "defaultSkuCode" : "910-002-744", * "inStock" : true, * "skuCodes" : [ * "910-002-744" * ], * "perpetual" : false, * "availableToSellQuantity" : { * "910-002-744" : 300 * } * }, * "barCode" : "", * "displayMetakeywords" : null, * "name" : "M187 White", * "displayMetadescriptions" : null * }, * ... * ], * "price" : { * "symbol" : "", * "quantity" : 1, * "regularPrice" : 387.56, * "salePrice" : null, * "discount" : null, * "currency" : "EUR", * "symbolPosition" : "before" * }, * "featured" : false, * "displayMetakeywords" : {}, * "metadescription" : null, * "description" : "Logitech Wireless Mini ..." * } * </code></pre> * </td></tr> * <tr><td>XML example</td><td> * <pre><code> * <product> * <attribute-values> * <attribute-value attribute-id="11022" attrvalue-id="891" product-id="297"> * <attribute-name>? (uk)</attribute-name> * <val>Logitech Wireless Mini Mouse M187...</val> * </attribute-value> * <attribute-value attribute-id="1423" attrvalue-id="19865" product-id="297"> * <attribute-display-names> * <entry lang="uk">?, ????</entry> * <entry lang="en">Receiver included</entry> * <entry lang="ru">?? ?</entry> * </attribute-display-names> * <attribute-name>Receiver included</attribute-name> * <display-vals> * <entry lang="uk"></entry> * <entry lang="en">Y</entry> * <entry lang="ru"></entry> * </display-vals> * <val>Y</val> * </attribute-value> * <attribute-value attribute-id="11008" attrvalue-id="20509" product-id="297"> * <attribute-name>Product default image</attribute-name> * <val>Logitech-M187_910-002-744_a.jpg</val> * </attribute-value> * ... * </attribute-values> * <availability>1</availability> * <brand-id>5</brand-id> * <brand-name>Logitech</brand-name> * <code>910-002</code> * <description>Logitech Wireless Mini Mouse M187...</description> * <display-metadescription/> * <display-metakeywords/> * <display-names> * <entry lang="uk">Mini Mouse M187</entry> * <entry lang="en">Mini Mouse M187</entry> * <entry lang="ru">Mini Mouse M187</entry> * </display-names> * <display-titles/> * <featured>false</featured> * <manufacturer-code>M001</manufacturer-code> * <name>Mini Mouse M187</name> * <price> * <currency>EUR</currency> * <quantity>1.00</quantity> * <regular-price>387.56</regular-price> * <symbol></symbol> * <symbol-position>before</symbol-position> * </price> * <product-availability> * <available>true</available> * <ats-quantity> * <entry sku="910-002-742">300.00</entry> * <entry sku="910-002-741">300.00</entry> * <entry sku="910-002-744">300.00</entry> * <entry sku="910-002-743">300.00</entry> * </ats-quantity> * <default-sku>910-002-741</default-sku> * <first-available-sku>910-002-741</first-available-sku> * <in-stock>true</in-stock> * <perpetual>false</perpetual> * <sku-codes>910-002-741</sku-codes> * <sku-codes>910-002-742</sku-codes> * <sku-codes>910-002-743</sku-codes> * <sku-codes>910-002-744</sku-codes> * </product-availability> * <product-id>297</product-id> * <product-type-id>5</product-type-id> * <product-type-name>Mice</product-type-name> * <skus> * <sku> * <attribute-values> * <attribute-value attribute-id="532" attrvalue-id="948" sku-id="308"> * <attribute-display-names> * <entry lang="uk"> </entry> * <entry lang="en">Color of product</entry> * <entry lang="ru"> </entry> * </attribute-display-names> * <attribute-name>Color of product</attribute-name> * <display-vals> * <entry lang="uk"></entry> * <entry lang="en">White</entry> * <entry lang="ru"></entry> * </display-vals> * <val>White</val> * </attribute-value> * ... * </attribute-values> * <barcode></barcode> * <code>910-002-744</code> * <description></description> * <display-names> * <entry lang="uk">M187 </entry> * <entry lang="en">M187 White</entry> * <entry lang="ru">M187 </entry> * </display-names> * <name>M187 White</name> * <price> * <currency>EUR</currency> * <quantity>1.00</quantity> * <regular-price>387.56</regular-price> * <symbol></symbol> * <symbol-position>before</symbol-position> * </price> * <product-availability> * <available>true</available> * <ats-quantity> * <entry sku="910-002-744">300.00</entry> * </ats-quantity> * <default-sku>910-002-744</default-sku> * <first-available-sku>910-002-744</first-available-sku> * <in-stock>true</in-stock> * <perpetual>false</perpetual> * <sku-codes>910-002-744</sku-codes> * </product-availability> * <product-id>297</product-id> * <rank>0</rank> * <sku-id>308</sku-id> * </sku> * ... * </skus> * <tag>multisku</tag> * </product> * </code></pre> * </td></tr> * </table> * * @param product PK or SEO URI * @param request request * @param response response * * @return product */ @RequestMapping(value = "/product/{id}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }) public @ResponseBody ProductRO viewProduct(@PathVariable(value = "id") final String product, final HttpServletRequest request, final HttpServletResponse response) { final ProductRO ro = viewProductInternal(product, true); cartMixin.persistShoppingCart(request, response); return ro; } private List<ProductRO> viewProductsInternal(final String products) { final String[] productsIds = StringUtils.split(products, '|'); final List<ProductRO> ros = new ArrayList<ProductRO>(productsIds.length); for (final String productId : productsIds) { final ProductRO ro = viewProductInternal(productId, false); if (ro != null) { ros.add(ro); } } return ros; } /** * Interface: GET /products/{id} * <p> * <p> * Display full product details. * <p> * <p> * <h3>Headers for operation</h3><p> * <table border="1"> * <tr><td>Accept</td><td>application/json</td></tr> * <tr><td>yc</td><td>token uuid (optional)</td></tr> * </table> * <p> * <p> * <h3>Parameters for operation</h3><p> * <table border="1"> * <tr><td>ids</td><td>SEO URI or product PK separated by pipe character ('|')</td></tr> * </table> * <p> * <p> * <h3>Output</h3><p> * <table border="1"> * <tr><td>JSON example</td><td> * <pre><code> * [{ * "displayNames" : { * "uk" : "Mini Mouse M187", * "ru" : "Mini Mouse M187", * "en" : "Mini Mouse M187" * }, * "maxOrderQuantity" : null, * "productTypeId" : 5, * "minOrderQuantity" : null, * "availability" : 1, * "code" : "910-002", * "title" : null, * "attributes" : [ * { * "attrvalueId" : 891, * "productId" : 297, * "val" : "Logitech Wireless Mini Mouse M187...", * "displayVals" : null, * "attributeName" : "? (uk)", * "attributeId" : 11022, * "attributeDisplayNames" : null * }, * { * "attrvalueId" : 19865, * "productId" : 297, * "val" : "Y", * "displayVals" : { * "uk" : "", * "ru" : "", * "en" : "Y" * }, * "attributeName" : "Receiver included", * "attributeId" : 1423, * "attributeDisplayNames" : { * "uk" : "?, ????", * "ru" : "?? ?", * "en" : "Receiver included" * } * }, * ... * ], * "displayMetadescriptions" : {}, * "displayTitles" : {}, * "productId" : 297, * "name" : "Mini Mouse M187", * "stepOrderQuantity" : null, * "tag" : "multisku", * "brandName" : "Logitech", * "brandId" : 5, * "availablefrom" : null, * "uri" : null, * "availableto" : null, * "productTypeName" : "Mice", * "metakeywords" : null, * "manufacturerCode" : "M001", * "productAvailabilityModel" : { * "firstAvailableSkuCode" : "910-002-741", * "available" : true, * "defaultSkuCode" : "910-002-741", * "inStock" : true, * "skuCodes" : [ * "910-002-741", * "910-002-742", * "910-002-743", * "910-002-744" * ], * "perpetual" : false, * "availableToSellQuantity" : { * "910-002-742" : 300, * "910-002-744" : 300, * "910-002-741" : 300, * "910-002-743" : 300 * } * }, * "skus" : [ * { * "metakeywords" : null, * "productId" : 297, * "description" : "", * "metadescription" : null, * "uri" : null, * "price" : { * "symbol" : "", * "quantity" : 1, * "regularPrice" : 387.56, * "salePrice" : null, * "discount" : null, * "currency" : "EUR", * "symbolPosition" : "before" * }, * "attributes" : [ * { * "attrvalueId" : 948, * "val" : "White", * "displayVals" : { * "uk" : "", * "ru" : "", * "en" : "White" * }, * "attributeName" : "Color of product", * "attributeId" : 532, * "attributeDisplayNames" : { * "uk" : " ", * "ru" : " ", * "en" : "Color of product" * }, * "skuId" : 308 * }, * ... * ], * "title" : null, * "manufacturerCode" : null, * "code" : "910-002-744", * "skuId" : 308, * "rank" : 0, * "displayTitles" : null, * "displayNames" : { * "uk" : "M187 ", * "ru" : "M187 ", * "en" : "M187 White" * }, * "productAvailabilityModel" : { * "firstAvailableSkuCode" : "910-002-744", * "available" : true, * "defaultSkuCode" : "910-002-744", * "inStock" : true, * "skuCodes" : [ * "910-002-744" * ], * "perpetual" : false, * "availableToSellQuantity" : { * "910-002-744" : 300 * } * }, * "barCode" : "", * "displayMetakeywords" : null, * "name" : "M187 White", * "displayMetadescriptions" : null * }, * ... * ], * "price" : { * "symbol" : "", * "quantity" : 1, * "regularPrice" : 387.56, * "salePrice" : null, * "discount" : null, * "currency" : "EUR", * "symbolPosition" : "before" * }, * "featured" : false, * "displayMetakeywords" : {}, * "metadescription" : null, * "description" : "Logitech Wireless Mini ..." * }] * </code></pre> * </td></tr> * </table> * * @param products PK or SEO URI * @param request request * @param response response * * @return product */ @RequestMapping(value = "/products/{ids}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE }) public @ResponseBody List<ProductRO> viewProducts(@PathVariable(value = "ids") final String products, final HttpServletRequest request, final HttpServletResponse response) { cartMixin.persistShoppingCart(request, response); return viewProductsInternal(products); } /** * Interface: GET /products/{id} * <p> * <p> * Display full product details. * <p> * <p> * <h3>Headers for operation</h3><p> * <table border="1"> * <tr><td>Accept</td><td>application/xml</td></tr> * <tr><td>yc</td><td>token uuid (optional)</td></tr> * </table> * <p> * <p> * <h3>Parameters for operation</h3><p> * <table border="1"> * <tr><td>ids</td><td>SEO URI or product PK separated by pipe character ('|')</td></tr> * </table> * <p> * <p> * <h3>Output</h3><p> * <table border="1"> * <tr><td>XML example</td><td> * <pre><code> * <products> * <product> * <attribute-values> * <attribute-value attribute-id="11022" attrvalue-id="891" product-id="297"> * <attribute-name>? (uk)</attribute-name> * <val>Logitech Wireless Mini Mouse M187...</val> * </attribute-value> * <attribute-value attribute-id="1423" attrvalue-id="19865" product-id="297"> * <attribute-display-names> * <entry lang="uk">?, ????</entry> * <entry lang="en">Receiver included</entry> * <entry lang="ru">?? ?</entry> * </attribute-display-names> * <attribute-name>Receiver included</attribute-name> * <display-vals> * <entry lang="uk"></entry> * <entry lang="en">Y</entry> * <entry lang="ru"></entry> * </display-vals> * <val>Y</val> * </attribute-value> * <attribute-value attribute-id="11008" attrvalue-id="20509" product-id="297"> * <attribute-name>Product default image</attribute-name> * <val>Logitech-M187_910-002-744_a.jpg</val> * </attribute-value> * ... * </attribute-values> * <availability>1</availability> * <brand-id>5</brand-id> * <brand-name>Logitech</brand-name> * <code>910-002</code> * <description>Logitech Wireless Mini Mouse M187...</description> * <display-metadescription/> * <display-metakeywords/> * <display-names> * <entry lang="uk">Mini Mouse M187</entry> * <entry lang="en">Mini Mouse M187</entry> * <entry lang="ru">Mini Mouse M187</entry> * </display-names> * <display-titles/> * <featured>false</featured> * <manufacturer-code>M001</manufacturer-code> * <name>Mini Mouse M187</name> * <price> * <currency>EUR</currency> * <quantity>1.00</quantity> * <regular-price>387.56</regular-price> * <symbol></symbol> * <symbol-position>before</symbol-position> * </price> * <product-availability> * <available>true</available> * <ats-quantity> * <entry sku="910-002-742">300.00</entry> * <entry sku="910-002-741">300.00</entry> * <entry sku="910-002-744">300.00</entry> * <entry sku="910-002-743">300.00</entry> * </ats-quantity> * <default-sku>910-002-741</default-sku> * <first-available-sku>910-002-741</first-available-sku> * <in-stock>true</in-stock> * <perpetual>false</perpetual> * <sku-codes>910-002-741</sku-codes> * <sku-codes>910-002-742</sku-codes> * <sku-codes>910-002-743</sku-codes> * <sku-codes>910-002-744</sku-codes> * </product-availability> * <product-id>297</product-id> * <product-type-id>5</product-type-id> * <product-type-name>Mice</product-type-name> * <skus> * <sku> * <attribute-values> * <attribute-value attribute-id="532" attrvalue-id="948" sku-id="308"> * <attribute-display-names> * <entry lang="uk"> </entry> * <entry lang="en">Color of product</entry> * <entry lang="ru"> </entry> * </attribute-display-names> * <attribute-name>Color of product</attribute-name> * <display-vals> * <entry lang="uk"></entry> * <entry lang="en">White</entry> * <entry lang="ru"></entry> * </display-vals> * <val>White</val> * </attribute-value> * ... * </attribute-values> * <barcode></barcode> * <code>910-002-744</code> * <description></description> * <display-names> * <entry lang="uk">M187 </entry> * <entry lang="en">M187 White</entry> * <entry lang="ru">M187 </entry> * </display-names> * <name>M187 White</name> * <price> * <currency>EUR</currency> * <quantity>1.00</quantity> * <regular-price>387.56</regular-price> * <symbol></symbol> * <symbol-position>before</symbol-position> * </price> * <product-availability> * <available>true</available> * <ats-quantity> * <entry sku="910-002-744">300.00</entry> * </ats-quantity> * <default-sku>910-002-744</default-sku> * <first-available-sku>910-002-744</first-available-sku> * <in-stock>true</in-stock> * <perpetual>false</perpetual> * <sku-codes>910-002-744</sku-codes> * </product-availability> * <product-id>297</product-id> * <rank>0</rank> * <sku-id>308</sku-id> * </sku> * ... * </skus> * <tag>multisku</tag> * </product> * </products> * </code></pre> * </td></tr> * </table> * * @param products PK or SEO URI * @param request request * @param response response * * @return product */ @RequestMapping(value = "/products/{ids}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_XML_VALUE }) public @ResponseBody ProductListRO viewProductsXML(@PathVariable(value = "ids") final String products, final HttpServletRequest request, final HttpServletResponse response) { cartMixin.persistShoppingCart(request, response); return new ProductListRO(viewProductsInternal(products)); } private List<ProductSearchResultRO> viewProductAssociationsInternal(final String product, final String type) { final long productId = bookmarkMixin.resolveProductId(product); final ShoppingCart cart = cartMixin.getCurrentCart(); final List<ProductSearchResultDTO> productAssociations = productServiceFacade .getProductAssociations(productId, cart.getShoppingContext().getShopId(), type); final List<ProductSearchResultRO> ros = new ArrayList<ProductSearchResultRO>(); if (CollectionUtils.isNotEmpty(productAssociations)) { final Pair<String, Boolean> symbol = currencySymbolService.getCurrencySymbol(cart.getCurrencyCode()); for (final ProductSearchResultDTO hit : productAssociations) { final ProductAvailabilityModel skuPam = productServiceFacade.getProductAvailability(hit, cart.getShoppingContext().getShopId()); final ProductSearchResultRO ro = mappingMixin.map(hit, ProductSearchResultRO.class, ProductSearchResultDTO.class); final ProductAvailabilityModelRO amRo = mappingMixin.map(skuPam, ProductAvailabilityModelRO.class, ProductAvailabilityModel.class); ro.setProductAvailabilityModel(amRo); final SkuPrice price = productServiceFacade.getSkuPrice(null, skuPam.getFirstAvailableSkuCode(), BigDecimal.ONE, cart.getCurrencyCode(), cart.getShoppingContext().getShopId()); final SkuPriceRO priceRo = mappingMixin.map(price, SkuPriceRO.class, SkuPrice.class); priceRo.setSymbol(symbol.getFirst()); priceRo.setSymbolPosition(symbol.getSecond() != null && symbol.getSecond() ? "after" : "before"); ro.setPrice(priceRo); ros.add(ro); } return ros; } return ros; } /** * Interface: GET /product/{id}/associations/{type} * <p> * <p> * Display list of associated products. * <p> * <p> * <h3>Headers for operation</h3><p> * <table border="1"> * <tr><td>Accept</td><td>application/json</td></tr> * <tr><td>yc</td><td>token uuid (optional)</td></tr> * </table> * <p> * <p> * <h3>Parameters for operation</h3><p> * <table border="1"> * <tr><td>id</td><td>SEO URI or product PK</td></tr> * <tr><td>type</td><td>association type see {@link Association}</td></tr> * </table> * <p> * <p> * <h3>Output</h3><p> * <table border="1"> * <tr><td>JSON array of object ProductSearchResultRO</td><td> * <pre><code> * [ * { * "maxOrderQuantity" : null, * "minOrderQuantity" : null, * "displayDescription" : { * "uk" : "Trust Isotto Wired Mini Mouse...", * "ru" : "Trust Isotto Wired Mini Mouse...", * "en" : "Trust Isotto Wired Mini Mouse..." * }, * "code" : "19733", * "availability" : 1, * "displayName" : { * "uk" : "Isotto Wired Mini Mouse", * "ru" : "Isotto Wired Mini Mouse", * "en" : "Isotto Wired Mini Mouse" * }, * "defaultSkuCode" : "19733", * "name" : "Isotto Wired Mini Mouse", * "stepOrderQuantity" : null, * "availablefrom" : null, * "id" : 184, * "availableto" : null, * "manufacturerCode" : null, * "skus" : null, * "productAvailabilityModel" : { * "firstAvailableSkuCode" : "19733", * "available" : true, * "defaultSkuCode" : "19733", * "inStock" : true, * "skuCodes" : [ * "19733" * ], * "perpetual" : false, * "availableToSellQuantity" : { * "19733" : 99 * } * }, * "price" : { * "symbol" : "", * "quantity" : 1, * "regularPrice" : 643.2, * "salePrice" : null, * "discount" : null, * "currency" : "EUR", * "symbolPosition" : "before" * }, * "featured" : false, * "defaultImage" : "Trust-Isotto-Wired-Mini-Mouse_19733_a.jpg", * "multisku" : false, * "description" : "Trust Isotto Wired Mini Mouse..." * }, * ... * ] * </code></pre> * </td></tr> * </table> * * @param product PK or SEO URI * @param type association type see {@link Association} * @param request request * @param response response * * @return list of products */ @RequestMapping(value = "/product/{id}/associations/{type}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE }) public @ResponseBody List<ProductSearchResultRO> viewProductAssociations( @PathVariable(value = "id") final String product, @PathVariable(value = "type") final String type, final HttpServletRequest request, final HttpServletResponse response) { cartMixin.persistShoppingCart(request, response); return viewProductAssociationsInternal(product, type); } /** * Interface: GET /product/{id}/associations/{type} * <p> * <p> * Display list of associated products. * <p> * <p> * <h3>Headers for operation</h3><p> * <table border="1"> * <tr><td>Accept</td><td>application/xml</td></tr> * <tr><td>yc</td><td>token uuid (optional)</td></tr> * </table> * <p> * <p> * <h3>Parameters for operation</h3><p> * <table border="1"> * <tr><td>id</td><td>SEO URI or product PK</td></tr> * <tr><td>type</td><td>association type see {@link Association}</td></tr> * </table> * <p> * <p> * <h3>Output</h3><p> * <table border="1"> * <tr><td>XML array of object ProductSearchResultRO</td><td> * <pre><code> * <products> * <product> * <availability>1</availability> * <code>19733</code> * <default-image>Trust-Isotto-Wired-Mini-Mouse_19733_a.jpg</default-image> * <default-sku-code>19733</default-sku-code> * <description>Trust Isotto Wired Mini Mouse...</description> * <display-descriptions> * <entry lang="uk">Trust Isotto Wired Mini Mouse...</entry> * <entry lang="en">Trust Isotto Wired Mini Mouse...</entry> * <entry lang="ru">Trust Isotto Wired Mini Mouse...</entry> * </display-descriptions> * <display-names> * <entry lang="uk">Isotto Wired Mini Mouse</entry> * <entry lang="en">Isotto Wired Mini Mouse</entry> * <entry lang="ru">Isotto Wired Mini Mouse</entry> * </display-names> * <featured>false</featured> * <id>184</id> * <multisku>false</multisku> * <name>Isotto Wired Mini Mouse</name> * <price> * <currency>EUR</currency> * <quantity>1.00</quantity> * <regular-price>643.20</regular-price> * <symbol></symbol> * <symbol-position>before</symbol-position> * </price> * <product-availability> * <available>true</available> * <ats-quantity> * <entry sku="19733">99.000</entry> * </ats-quantity> * <default-sku>19733</default-sku> * <first-available-sku>19733</first-available-sku> * <in-stock>true</in-stock> * <perpetual>false</perpetual> * <sku-codes>19733</sku-codes> * </product-availability> * </product> * ... * </products> * </code></pre> * </td></tr> * </table> * * @param product PK or SEO URI * @param type association type see {@link Association} * @param request request * @param response response * * @return list of products */ @RequestMapping(value = "/product/{id}/associations/{type}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_XML_VALUE }) public @ResponseBody ProductSearchResultListRO viewProductAssociationsXML( @PathVariable(value = "id") final String product, @PathVariable(value = "type") final String type, final HttpServletRequest request, final HttpServletResponse response) { cartMixin.persistShoppingCart(request, response); return new ProductSearchResultListRO(viewProductAssociationsInternal(product, type)); } private ProductSkuRO viewSkuInternal(final ProductSku productSku, final long shopId, final String currencyCode, final Pair<String, Boolean> symbol) { final ProductSkuRO skuRO = mappingMixin.map(productSku, ProductSkuRO.class, ProductSku.class); final Pair<String, String> templates = resolveTemplate(skuRO); if (templates != null) { skuRO.setUitemplate(templates.getFirst()); skuRO.setUitemplateFallback(templates.getSecond()); } final ProductAvailabilityModel skuPam = productServiceFacade.getProductAvailability(productSku, shopId); final ProductAvailabilityModelRO amRo = mappingMixin.map(skuPam, ProductAvailabilityModelRO.class, ProductAvailabilityModel.class); skuRO.setProductAvailabilityModel(amRo); final SkuPrice price = productServiceFacade.getSkuPrice(null, skuPam.getFirstAvailableSkuCode(), BigDecimal.ONE, currencyCode, shopId); final SkuPriceRO priceRo = mappingMixin.map(price, SkuPriceRO.class, SkuPrice.class); priceRo.setSymbol(symbol.getFirst()); priceRo.setSymbolPosition(symbol.getSecond() != null && symbol.getSecond() ? "after" : "before"); skuRO.setPrice(priceRo); return skuRO; } private Pair<String, String> resolveTemplate(final ProductSkuRO skuRO) { final Map params = new HashMap(); params.put(WebParametersKeys.SKU_ID, String.valueOf(skuRO.getSkuId())); return centralViewResolver.resolveMainPanelRendererLabel(params); } private ProductSkuRO viewSkuInternal(final String sku, final boolean recordViewed) { final long productId = bookmarkMixin.resolveSkuId(sku); final ProductSku skuEntity; if (productId > 0L) { skuEntity = productServiceFacade.getSkuById(productId); } else { skuEntity = productServiceFacade.getProductSkuBySkuCode(sku); } if (skuEntity != null) { final ShoppingCart cart = cartMixin.getCurrentCart(); final Pair<String, Boolean> symbol = currencySymbolService.getCurrencySymbol(cart.getCurrencyCode()); if (recordViewed) { executeViewProductCommand(skuEntity.getProduct()); } return viewSkuInternal(skuEntity, cart.getShoppingContext().getShopId(), cart.getCurrencyCode(), symbol); } return null; } /** * Interface: GET /sku/{id} * <p> * <p> * Display full product details. * <p> * <p> * <h3>Headers for operation</h3><p> * <table border="1"> * <tr><td>Accept</td><td>application/json or application/xml</td></tr> * <tr><td>yc</td><td>token uuid (optional)</td></tr> * </table> * <p> * <p> * <h3>Parameters for operation</h3><p> * <table border="1"> * <tr><td>id</td><td>SEO URI or sku PK or sku code</td></tr> * </table> * <p> * <p> * <h3>Output</h3><p> * <table border="1"> * <tr><td>JSON example</td><td> * <pre><code> * { * "metakeywords" : null, * "productId" : 297, * "description" : "", * "metadescription" : null, * "uri" : null, * "price" : { * "symbol" : "", * "quantity" : 1, * "regularPrice" : 387.56, * "salePrice" : null, * "discount" : null, * "currency" : "EUR", * "symbolPosition" : "before" * }, * "attributes" : [ * { * "attrvalueId" : 948, * "val" : "White", * "displayVals" : { * "uk" : "", * "ru" : "", * "en" : "White" * }, * "attributeName" : "Color of product", * "attributeId" : 532, * "attributeDisplayNames" : { * "uk" : " ", * "ru" : " ", * "en" : "Color of product" * }, * "skuId" : 308 * }, * ... * ], * "title" : null, * "manufacturerCode" : null, * "code" : "910-002-744", * "skuId" : 308, * "rank" : 0, * "displayTitles" : null, * "displayNames" : { * "uk" : "M187 ", * "ru" : "M187 ", * "en" : "M187 White" * }, * "productAvailabilityModel" : { * "firstAvailableSkuCode" : "910-002-744", * "available" : true, * "defaultSkuCode" : "910-002-744", * "inStock" : true, * "skuCodes" : [ * "910-002-744" * ], * "perpetual" : false, * "availableToSellQuantity" : { * "910-002-744" : 300 * } * }, * "barCode" : "", * "displayMetakeywords" : null, * "name" : "M187 White", * "displayMetadescriptions" : null * } * </code></pre> * </td></tr> * <tr><td>XML example</td><td> * <pre><code> * <sku> * <attribute-values> * <attribute-value attribute-id="532" attrvalue-id="948" sku-id="308"> * <attribute-display-names> * <entry lang="uk"> </entry> * <entry lang="en">Color of product</entry> * <entry lang="ru"> </entry> * </attribute-display-names> * <attribute-name>Color of product</attribute-name> * <display-vals> * <entry lang="uk"></entry> * <entry lang="en">White</entry> * <entry lang="ru"></entry> * </display-vals> * <val>White</val> * </attribute-value> * ... * </attribute-values> * <barcode></barcode> * <code>910-002-744</code> * <description></description> * <display-names> * <entry lang="uk">M187 </entry> * <entry lang="en">M187 White</entry> * <entry lang="ru">M187 </entry> * </display-names> * <name>M187 White</name> * <price> * <currency>EUR</currency> * <quantity>1.00</quantity> * <regular-price>387.56</regular-price> * <symbol></symbol> * <symbol-position>before</symbol-position> * </price> * <product-availability> * <available>true</available> * <ats-quantity> * <entry sku="910-002-744">300.00</entry> * </ats-quantity> * <default-sku>910-002-744</default-sku> * <first-available-sku>910-002-744</first-available-sku> * <in-stock>true</in-stock> * <perpetual>false</perpetual> * <sku-codes>910-002-744</sku-codes> * </product-availability> * <product-id>297</product-id> * <rank>0</rank> * <sku-id>308</sku-id> * </sku> * </code></pre> * </td></tr> * </table> * * @param sku PK or SEO URI * @param request request * @param response response * * @return product sku */ @RequestMapping(value = "/sku/{id}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }) public @ResponseBody ProductSkuRO viewSku(@PathVariable(value = "id") final String sku, final HttpServletRequest request, final HttpServletResponse response) { final ProductSkuRO ro = viewSkuInternal(sku, true); cartMixin.persistShoppingCart(request, response); return ro; } private List<ProductSkuRO> viewProductSkusInternal(final String skus) { final String[] skuIds = StringUtils.split(skus, '|'); final List<ProductSkuRO> ros = new ArrayList<ProductSkuRO>(skuIds.length); for (final String skuId : skuIds) { final ProductSkuRO ro = viewSkuInternal(skuId, false); if (ro != null) { ros.add(ro); } } return ros; } /** * Interface: GET /skus/{id} * <p> * <p> * Display full product details. * <p> * <p> * <h3>Headers for operation</h3><p> * <table border="1"> * <tr><td>Accept</td><td>application/json</td></tr> * <tr><td>yc</td><td>token uuid (optional)</td></tr> * </table> * <p> * <p> * <h3>Parameters for operation</h3><p> * <table border="1"> * <tr><td>ids</td><td>SEO URI or sku PK or sku code separated by pipe character ('|')</td></tr> * </table> * <p> * <p> * <h3>Output</h3><p> * <table border="1"> * <tr><td>JSON example</td><td> * <pre><code> * [ { * "metakeywords" : null, * "productId" : 297, * "description" : "", * "metadescription" : null, * "uri" : null, * "price" : { * "symbol" : "", * "quantity" : 1, * "regularPrice" : 387.56, * "salePrice" : null, * "discount" : null, * "currency" : "EUR", * "symbolPosition" : "before" * }, * "attributes" : [ * { * "attrvalueId" : 948, * "val" : "White", * "displayVals" : { * "uk" : "", * "ru" : "", * "en" : "White" * }, * "attributeName" : "Color of product", * "attributeId" : 532, * "attributeDisplayNames" : { * "uk" : " ", * "ru" : " ", * "en" : "Color of product" * }, * "skuId" : 308 * }, * ... * ], * "title" : null, * "manufacturerCode" : null, * "code" : "910-002-744", * "skuId" : 308, * "rank" : 0, * "displayTitles" : null, * "displayNames" : { * "uk" : "M187 ", * "ru" : "M187 ", * "en" : "M187 White" * }, * "productAvailabilityModel" : { * "firstAvailableSkuCode" : "910-002-744", * "available" : true, * "defaultSkuCode" : "910-002-744", * "inStock" : true, * "skuCodes" : [ * "910-002-744" * ], * "perpetual" : false, * "availableToSellQuantity" : { * "910-002-744" : 300 * } * }, * "barCode" : "", * "displayMetakeywords" : null, * "name" : "M187 White", * "displayMetadescriptions" : null * } ] * </code></pre> * </td></tr> * </table> * * @param skus PK or SEO URI or code * @param request request * @param response response * * @return product sku */ @RequestMapping(value = "/skus/{ids}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE }) public @ResponseBody List<ProductSkuRO> viewSkus(@PathVariable(value = "ids") final String skus, final HttpServletRequest request, final HttpServletResponse response) { cartMixin.persistShoppingCart(request, response); return viewProductSkusInternal(skus); } /** * Interface: GET /skus/{id} * <p> * <p> * Display full product details. * <p> * <p> * <h3>Headers for operation</h3><p> * <table border="1"> * <tr><td>Accept</td><td>application/xml</td></tr> * <tr><td>yc</td><td>token uuid (optional)</td></tr> * </table> * <p> * <p> * <h3>Parameters for operation</h3><p> * <table border="1"> * <tr><td>ids</td><td>SEO URI or sku PK or sku code separated by pipe character ('|')</td></tr> * </table> * <p> * <p> * <h3>Output</h3><p> * <table border="1"> * <tr><td>XML example</td><td> * <pre><code> * <skus> * <sku> * <attribute-values> * <attribute-value attribute-id="532" attrvalue-id="948" sku-id="308"> * <attribute-display-names> * <entry lang="uk"> </entry> * <entry lang="en">Color of product</entry> * <entry lang="ru"> </entry> * </attribute-display-names> * <attribute-name>Color of product</attribute-name> * <display-vals> * <entry lang="uk"></entry> * <entry lang="en">White</entry> * <entry lang="ru"></entry> * </display-vals> * <val>White</val> * </attribute-value> * ... * </attribute-values> * <barcode></barcode> * <code>910-002-744</code> * <description></description> * <display-names> * <entry lang="uk">M187 </entry> * <entry lang="en">M187 White</entry> * <entry lang="ru">M187 </entry> * </display-names> * <name>M187 White</name> * <price> * <currency>EUR</currency> * <quantity>1.00</quantity> * <regular-price>387.56</regular-price> * <symbol></symbol> * <symbol-position>before</symbol-position> * </price> * <product-availability> * <available>true</available> * <ats-quantity> * <entry sku="910-002-744">300.00</entry> * </ats-quantity> * <default-sku>910-002-744</default-sku> * <first-available-sku>910-002-744</first-available-sku> * <in-stock>true</in-stock> * <perpetual>false</perpetual> * <sku-codes>910-002-744</sku-codes> * </product-availability> * <product-id>297</product-id> * <rank>0</rank> * <sku-id>308</sku-id> * </sku> * </skus> * </code></pre> * </td></tr> * </table> * * @param skus PK or SEO URI or code * @param request request * @param response response * * @return product sku */ @RequestMapping(value = "/skus/{ids}", method = RequestMethod.GET, produces = { MediaType.APPLICATION_XML_VALUE }) public @ResponseBody ProductSkuListRO viewSkusXML(@PathVariable(value = "ids") final String skus, final HttpServletRequest request, final HttpServletResponse response) { cartMixin.persistShoppingCart(request, response); return new ProductSkuListRO(viewProductSkusInternal(skus)); } /** * Execute view product command. * * @param product product. */ protected void executeViewProductCommand(final Product product) { shoppingCartCommandFactory.execute(ShoppingCartCommand.CMD_INTERNAL_VIEWSKU, cartMixin.getCurrentCart(), new HashMap<String, Object>() { { put(ShoppingCartCommand.CMD_INTERNAL_VIEWSKU, product); } }); } }