如何从 Hybris 店面的购物车生成多个订单?

Posted

技术标签:

【中文标题】如何从 Hybris 店面的购物车生成多个订单?【英文标题】:How to generate multiple orders from cart in Hybris storefront? 【发布时间】:2018-04-24 04:59:41 【问题描述】:

我正在使用 Hybris 6.3,我们为 B2B 实施生成了一个模块,我需要根据购物车中的产品、账单地址、付款、交货等必须共享的情况将购物车内容分成不同的订单相同的参数。

根据我们从客户那里收集到的要求,我们得出结论,应用寄售策略不是我们在这里所需要的,因为它处理一个订单并将其拆分用于运输和交付目的,相反,我们客户的需求是不同的产品在购物车中按一组共享属性进行分组,并为每组产品生成一个订单。

到目前为止,我已经确定了店面扩展中负责下订单的类,DefaultCheckoutFacade,其中包含以下方法:

 @Override
 public OrderData placeOrder() throws InvalidCartException
 
     final CartModel cartModel = getCart();
     if (cartModel != null)
     
         if (cartModel.getUser().equals(getCurrentUserForCheckout()) || getCheckoutCustomerStrategy().isAnonymousCheckout())
         
             beforePlaceOrder(cartModel);
             final OrderModel orderModel = placeOrder(cartModel);
             afterPlaceOrder(cartModel, orderModel);
             if (orderModel != null)
             
                 return getOrderConverter().convert(orderModel);
             
         
     
     return null;
 

据我了解,我应该重写此方法以根据我的要求中设置的标准生成不同的 CartModel,并为每个 CartModel 下订单。我修改了CartModel类,它是超类AbstractOrderModel,我猜在上面方法中调用getCart()之后,我只需要修改 CartModel 中的条目并为我需要下的每个订单调用方法 placeOrder(),但是否允许修改 CartModel 对象以这种方式?

或者,如果我需要将我的购物车分成不同的订单,我应该以不同的方式处理吗?是否像拥有多个购物车但将它们显示为一个应该做的事情?这种修改应该在 OOTB commercefacades 扩展上进行吗?有没有办法在我们模块的某个地方扩展它?

编辑

我开始阅读有关Multiple Carts 的信息,这似乎是我需要的,但我还没有找到如何将条目保存到已保存的购物车中。在this link 我可以看到如何保存购物车,方法 saveCart 返回一个 CommerceSaveCartResultData 对象,saveCart 和方法 getCartForCodeAndCurrentUser 收到一个必须包含 CartModel 的 CommerceSaveCartParameter,如何生成该对象的实例以在 CommerceSaveCartParameter 中设置?

【问题讨论】:

【参考方案1】:

此功能的常用方法是使用 OOTB Order Splitting 功能 (DefaultOrderSplittingService) 将您的订单拆分为 OrderEntryGroup。 Hybris 文档中的示例:

<bean id="orderSplittingService" class="de.hybris.platform.ordersplitting.impl.DefaultOrderSplittingService">
<property name="modelService" ref="modelService"/>
<property name="consignmentService" ref="consignmentService"/>
<property name="strategiesList">
    <list>
        <ref bean="splitByDeliveryMode"/>
    </list>
</property>

战略实施:

    public class SplitByDeliveryMode extends AbstractSplittingStrategy


    @Override
    public Object getGroupingObject(final AbstractOrderEntryModel orderEntry)
    
        return orderEntry.getDeliveryMode();
    

    @Override
    public void afterSplitting(final Object groupingObject, final ConsignmentModel createdOne)
    
        createdOne.setDeliveryMode((DeliveryModeModel) groupingObject);

    


如果您确实需要克隆订单,可以自定义SubmitOrderStrategyDefaultOrderService 并使用CloneAbstractOrderStrategy

【讨论】:

寄售不是我们这里需要的,购物车中的商品需要按照我们业务逻辑中定义的标准进行分组,并为每组具有相同标准的商品生成订单,我需要将购物车中的商品拆分为不同的订单,而不是将订单拆分为寄售。 你为什么如此执着于克隆订单?拆分成货物正是你应该在这里做的。您可以非常灵活地定义如何拆分订单的标准。它不仅仅用于交付模式或仓库目的。 购物车中的每组商品都需要生成一个订单,而不是克隆它 @UrielArvizu :您应该只使用寄售拆分。它将帮助您使事情变得更容易。您可以编写自定义策略,根据购物车中的产品、帐单地址、付款、交货等将您的订单拆分为寄售。 问题是,寄售和订单不是一回事,订单从我们的客户发送到 ECC,寄售直接从 ItemModel 继承,并且缺少订单所做的信息,加上 ECC 然后发送iDocs with Orders,所以这是不使用寄售的主要原因。【参考方案2】:

我认为您需要使用多个购物车。当用户点击结帐按钮时,您可以创建列表中的新购物车,然后将其从购物车中删除并进行处理。因为购物车的计算量很大,如果你不分成两个购物车,优惠券和规则可能会因为整个产品而给客户额外的费用。

【讨论】:

我没有使用过多个购物车,每个购物车会生成一个单独的订单吗?你有文档的链接吗? 找到 this link 并且我想我可以从显示给用户的主购物车创建购物车,每个购物车都填充了按共享标准分组的条目,但还没有找到如何将条目添加到这个购物车的实例,有什么建议吗? @UrielArvizu 有 cartService 用于将商品添加到购物车。您需要开发在购物车之间移动物品。 但是我需要生成一个 CartModel 来传递给 saveCart 的 CommerceSaveCartParameter,对吧?知道如何创建一个实例吗? 我检查了DefaultCartService,确实有你提到的方法但是它接收到一个CartModel,我怎样才能生成新的CartModel实例?【参考方案3】:

我们有一个非常相似的要求。我们的策略是使用之前建议的 SplittingService,并覆盖 CloneAbstractOrderStrategy 以将寄售转换为 OrderModel(或 SubOrderModel)。这可能很复杂,因为您必须正确管理订单的计算等,但可以使用这种方法来实现。

【讨论】:

【参考方案4】:

最后我发现我的方法从一开始就完全错误,不应该做订单拆分,既不生成多个购物车也不使用寄售,这两个都是错误的选择。

由于要求将多个订单发送到 ERP,而在我的客户案例中,DataHub 是负责执行此操作的,因此需要扩展的两个扩展是:saporderexchangesaporderexchangeb2bysaporderfullfillment

首先我从 ysaporderfullfillment 模板创建了一个 customsaporderfullfillment 扩展,然后我必须更改 SendOrderToDataHubAction 中的 executeAction 方法来拆分生成的订单来自 Hybris,根据设定的标准:

@Override
public Transition executeAction(final OrderProcessModel process) throws RetryLaterException

    LOG.info("Executing Send Order To DataHub Action");
    final OrderModel order = process.getOrder();
    List<SendToDataHubResult> results = new ArrayList<>();
    List<AbstractOrderEntryModel> entries = order.getEntries();
    Map<String, List<AbstractOrderEntryModel>> sortedEntries = sortEntries(entries);
    final Object[] keyArray = sortedEntries.keySet().toArray();
    LOG.info("Number of Orders to generate: " + keyArray.length);

    for (int i = 0; i < keyArray.length; i++)
    
        // Clone the order
        String newOrderCode = generateOrderCode();
        LOG.info("Generated Order Code " + newOrderCode);
        OrderModel clonedOrder = getOrderService().clone(null, null, order,
                newOrderCode);
        LOG.info("Cloned order.");
        String key = keyArray[i].toString();
        LOG.info("Setting entries for Key: " + key);
        final List<AbstractOrderEntryModel> entriesForCart = sortedEntries.get(key);
        clonedOrder.setEntries(entriesForCart);
        LOG.info("Sending Order to DataHub");
        sendOrder(clonedOrder, results);
    

    if (!results.isEmpty() && results.stream().allMatch(result -> result.isSuccess())) 
        LOG.info("All Orders were sent successfully.");
        setOrderStatus(order, ExportStatus.EXPORTED);
        resetEndMessage(process);

        return Transition.OK;

     else 
        LOG.info("Not all Orders were sent successfully.");
        setOrderStatus(order, ExportStatus.NOTEXPORTED);
        handleRetry(process);

        return Transition.NOK;
    


然后我必须用我自己的 customaporderexchangeb2b 扩展扩展 saporderexchangeb2b 扩展,我必须创建一个 CustomB2BOrderContributor 来映射到我需要的 RawHybrisOrder 属性:

@Override
public Set<String> getColumns()

    final Set<String> columns = super.getColumns();
    columns.addAll(Arrays.asList(CustomOrderCsvColumns.SALES_ORGANIZATION, CustomOrderCsvColumns.DISTRIBUTION_CHANNEL,
            CustomOrderCsvColumns.DIVISION, CustomOrderCsvColumns.DOCUMENT_TYPE));
    LOG.info("Columns present " + columns.size() + " : " + columns.toString());
    return columns;


@Override
public List<Map<String, Object>> createRows(final OrderModel model)

    final List<Map<String, Object>> rows = super.createRows(model);
    return enhanceRowsByCustomB2BFields(model, rows);


protected List<Map<String, Object>> enhanceRowsByCustomB2BFields(final OrderModel model, final List<Map<String, Object>> rows)

    // There is only one row on order level
    final Map<String, Object> row = rows.get(0);
    final String salesArea = ((HelvexProductModel) model.getEntries().get(0).getProduct()).getSalesArea();
    final String[] valuesArray = salesArea.split("_");
    final String salesOrganization = valuesArray[0];
    final String distributionChannel = valuesArray[1];
    final String division = valuesArray[2];
    LOG.info("Enhancing columns of Order " + model.getCode() + " with Sales Organization : " + salesOrganization
            + ", Distribution Channel : " + distributionChannel + ", Division : " + division);
    row.put(CustomOrderCsvColumns.SALES_ORGANIZATION, salesOrganization);
    row.put(CustomOrderCsvColumns.DISTRIBUTION_CHANNEL, distributionChannel);
    row.put(CustomOrderCsvColumns.DIVISION, division);
    row.put(CustomOrderCsvColumns.DOCUMENT_TYPE, Config.getParameter("helvex.org.sales." + salesOrganization));
    row.put(CustomOrderCsvColumns.MOTIVE, sessionService.getAttribute(CustomOrderCsvColumns.MOTIVE));
    LOG.info("Enhanced rows " + row.toString());
    return rows;

由于 RawHybrisOrder 缺少 saporder-raw、saporder-canonical 和 saporder-target 中的映射,我不得不将添加的属性添加到 raw 和 canonical 的行中,最后我覆盖了要发送的 iDoc 的目标定义所以我在规范中映射的属性被用来代替标准映射。

现在你会说,生成的 Hybris 订单怎么样?由于我们显示的订单是从 ERP 而非 Hybris 数据库中检索的,因此该订单不会显示在店面中。

【讨论】:

以上是关于如何从 Hybris 店面的购物车生成多个订单?的主要内容,如果未能解决你的问题,请参考以下文章

Hybris 使用 Employee 登录店面

SAP CX (HYBRIS) : 如何从保存的购物车中删除已删除的产品

[项目构建 十二]babasport 订单的处理原理及代码实现.

自定义hybris生成订单的ID格式

PHP购物车怎么生成订单号

text 从店面移动粘性页脚中删除购物车