Broadleaf 5.2 - Как мне установить ProductOptions во вновь созданный продукт через API?
Проблема:
Я вижу, что метод Product " setProductOptions ()" устарел и что " setProductOptionXrefs ()" является предпочтительным. Проблема в том, что я не могу найти какой-либо пример того, как установить ProductOptionXrefs.
Я искал примеры в проектах Broadleaf " BroadleafCommerce-develop-5.2.x " и " DemoSite-broadleaf-5.2.2.1-GA ", а также прочесал галактику для примера. Неудачно.
Цель (X):
Я создаю конечную точку, которая будет принимать объект JSON и принимать два параметра (categoryName и price).
Конечная точка будет:
- Найдите категорию, к которой будет принадлежать продукт.
- Создайте новый объект Sku и заполните некоторые поля ввода оболочки.
- Создайте новый объект Product и заполните несколько полей- оболочек.
- Назначьте ProductOption этому новому продукту. <== X
- Сохраните продукт.
- Вернуть ответ (для ответа REST).
Сама конечная точка выглядит так:
@RequestMapping(value = "/my_product", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
public ProductWrapper addCSDLProduct(HttpServletRequest request, @RequestBody ProductWrapper wrapper,
@RequestParam(value = "categoryName", required = true) String categoryName,
@RequestParam(value = "price", required = true) double price) {
Category category = null;
List<Category> categories = catalogService.findCategoriesByName( categoryName );
if ( categories != null && categories.size() > 0 ) {
category = categories.get(0);
}
Sku defaultSku = catalogService.createSku();
defaultSku.setRetailPrice(new Money( price ));
defaultSku.setInventoryType( InventoryType.ALWAYS_AVAILABLE );
defaultSku.setName( wrapper.getName() );
defaultSku.setLongDescription( wrapper.getLongDescription() );
defaultSku.setDescription( wrapper.getDescription() );
defaultSku.setUrlKey( wrapper.getUrl() );
defaultSku.setActiveStartDate( new Date() );
Product product = catalogService.createProduct(ProductType.PRODUCT);
product.setDefaultSku(defaultSku);
product.setUrl( wrapper.getUrl() );
product.setCategory(category);
List<ProductOptionXref> productOptionXrefs = new ArrayList<ProductOptionXref>();
List<ProductOption> allProductOptions = catalogService.readAllProductOptions();
if ( null != allProductOptions && allProductOptions.size() > 0 ) {
for ( ProductOption po : allProductOptions ) {
String current = po.getName();
if ( current.equalsIgnoreCase("Shirt Color") ) {
ProductOptionXref productOptionXref = new ProductOptionXrefImpl();
productOptionXref.setProductOption(po);
productOptionXrefs.add(productOptionXref);
}
}
}
product.setProductOptionXrefs(productOptionXrefs);
Product finalProduct = catalogService.saveProduct(product);
Long newId = finalProduct.getId();
ProductWrapper response;
response = (ProductWrapper) context.getBean(ProductWrapper.class.getName());
response.wrapDetails(product, request);
response.setId(newId);
return response;
}
Объект ввода (пример), который я использую:
{
"name": "This is the name of the product.",
"description": "This is the description of the product.",
"longDescription": "This is a long description of the product. Really long.",
"url": "/this/is/the/url/of/the/product",
"defaultSku": {
"name": "This is the name of the product.",
"active": true,
"available": true,
"inventoryType": "ALWAYS_AVAILABLE",
"retailPrice": {
"amount": 19.0,
"currency": "USD"
}
}
}
С категорией "Товар" и ценой 19.00.
Этот код выше в настоящее время возвращает ошибку "Not-null":
Свойство Not-null ссылается на временное значение - временный экземпляр должен быть сохранен перед текущей операцией: org.broadleafcommerce.core.catalog.domain.ProductOptionXrefImpl.product -> org.broadleafcommerce.core.catalog.domain.ProductImpl; вложенным исключением является java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: свойство Not-null ссылается на временное значение - временный экземпляр должен быть сохранен перед текущей операцией: org.broadleafcommerce.core.catalog.domain.ProductOptionXrefImpl.product ->.> broadleafcommerce.core.catalog.domain.ProductImpl
что, скорее всего, связано с моим
if ( current.equalsIgnoreCase("Shirt Color") ) {
ProductOptionXref productOptionXref = new ProductOptionXrefImpl();
productOptionXref.setProductOption(po);
productOptionXrefs.add(productOptionXref);
}
и / или
Product finalProduct = catalogService.saveProduct(product);
линии чуть выше.
Я мог бы (в конце концов) выяснить ошибку "Не пусто", но я задаю вопрос: есть ли у кого-нибудь пример добавления ProductOption или ProductOptionXref во вновь созданный продукт?
Спасибо
Джон
[ОБНОВИТЬ]
Я хотел обновить мой вопрос решением, большое спасибо @phillipuniverse за пример / объяснения.
@RequestMapping(value = "/my_product", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
public ProductWrapper addCSDLProduct(HttpServletRequest request, @RequestBody ProductWrapper wrapper,
@RequestParam(value = "categoryName", required = true) String categoryName,
@RequestParam(value = "price", required = true) double price) {
Category category = null;
List<Category> categories = catalogService.findCategoriesByName( categoryName );
if ( categories != null && categories.size() > 0 ) {
category = categories.get(0);
}
Sku defaultSku = catalogService.createSku();
defaultSku.setRetailPrice(new Money( price ));
defaultSku.setInventoryType( InventoryType.ALWAYS_AVAILABLE );
defaultSku.setName( wrapper.getName() );
defaultSku.setLongDescription( wrapper.getLongDescription() );
defaultSku.setDescription( wrapper.getDescription() );
defaultSku.setUrlKey( wrapper.getUrl() );
defaultSku.setActiveStartDate( new Date() );
Product product = catalogService.createProduct(ProductType.PRODUCT);
product.setDefaultSku(defaultSku);
product.setUrl( wrapper.getUrl() );
product.setCategory(category);
List<ProductOptionXref> productOptionXrefs = new ArrayList<ProductOptionXref>();
List<ProductOption> allProductOptions = catalogService.readAllProductOptions();
if ( null != allProductOptions && allProductOptions.size() > 0 ) {
for ( ProductOption po : allProductOptions ) {
String current = po.getName();
if ( current.equalsIgnoreCase("Shirt Color") ) {
ProductOptionXref productOptionXref = new ProductOptionXrefImpl();
productOptionXref.setProductOption(po);
productOptionXref.setProduct(product);
productOptionXrefs.add(productOptionXref);
}
}
}
product.setProductOptionXrefs(productOptionXrefs);
Product finalProduct = catalogService.saveProduct(product);
finalProduct.getDefaultSku().setDefaultProduct(finalProduct);
catalogService.saveSku(finalProduct.getDefaultSku());
Long newId = finalProduct.getId();
ProductWrapper response;
response = (ProductWrapper) context.getBean(ProductWrapper.class.getName());
response.wrapDetails(product, request);
response.setId(newId);
return response;
}
Джон
1 ответ
Похоже, большинство из того, что у вас там, правильно. Вам не хватает обратной ссылки с Sku по умолчанию; по общему признанию это немного странно. Вы правильно поняли эту часть:
Product product = catalogService.createProduct(ProductType.PRODUCT);
product.setDefaultSku(defaultSku);
Но тогда вам также нужно убедиться, что по умолчанию sku ссылается на продукт; сначала сохраните продукт, а затем установите его:
...
Product finalProduct = catalogService.saveProduct(product);
finalProduct.getDefaultSku().setDefaultProduct(finalProduct);
catalogService.saveSku(finalProduct.getDefaultSku());
Этот код выше в настоящее время возвращает ошибку "Not-null":
Вы правы, проблема в этом коде, и это потому, что вы не устанавливаете product
собственность на ProductOptionXrefImpl
:
if ( current.equalsIgnoreCase("Shirt Color") ) {
ProductOptionXref productOptionXref = new ProductOptionXrefImpl();
productOptionXref.setProductOption(po);
productOptionXrefs.add(productOptionXref);
}
Если вы посмотрите на product
недвижимость в ProductOptionXrefImpl
вы найдете это:
@ManyToOne(targetEntity = ProductImpl.class, optional=false, cascade = CascadeType.REFRESH)
@JoinColumn(name = "PRODUCT_ID")
protected Product product = new ProductImpl();
Вы проходите мимо optional=false
часть, но new ProductImpl()
part делает его всегда "временным" экземпляром в Hibernate; у него нет свойства ID, и Hibernate ничего об этом не знает. Так как cascade
установлено только REFRESH
Hibernate также не пытается сохранить это или что-то (что не должно).
Исправление должно установить product
Свойство по опции xref:
if ( current.equalsIgnoreCase("Shirt Color") ) {
ProductOptionXref productOptionXref = new ProductOptionXrefImpl();
productOptionXref.setProductOption(po);
productOptionXref.setProduct(product);
productOptionXrefs.add(productOptionXref);
}
Я думаю, что это будет работать, но вам, возможно, придется переместить создание варианта продукта ниже уровня первого сохранения продукта и установить его на finalProduct
, Но я думаю, что, как написано, все каскады это поймут.