3.02 Create order operation details – order creation and rollback (create order operation details)

Step 1:

 Create orders order table, sub-order table and order status table corresponding pojo and mappper
 Orders and OrderItemsMapper
 OrderItems and OrderItemsMapper
 OrderStatus and OrderStatusMapper

Step 2: Create OrderService and corresponding implementation class

public interface OrderService {<!-- -->
    /**
     * Used to create order related information
     * @param submitOrderBO
     */
    public OrderVO createOrder(SubmitOrderBO submitOrderBO);
}

package com.one.service.order.impl;
import com.one.bo.SubmitOrderBO;
import com.one.enums.OrderStatusEnum;
import com.one.enums.YesOrNo;
import com.one.mapper.OrderItemsMapper;
import com.one.mapper.OrderStatusMapper;
import com.one.mapper.OrdersMapper;
import com.one.pojo.*;
import com.one.service.address.AddressService;
import com.one.service.item.ItemService;
import com.one.service.order.OrderService;
import com.one.vo.MerchantOrdersVO;
import com.one.vo.OrderVO;
import org.n3r.idworker.Sid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;

@Service
public class OrderServiceImpl implements OrderService {<!-- -->
    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private OrderItemsMapper orderItemsMapper;
    @Autowired
    private OrderStatusMapper orderStatusMapper;
    @Autowired
    private AddressService addressService;
    @Autowired
    private ItemService itemService;
    @Autowired
    private Sid sid;

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public OrderVO createOrder(SubmitOrderBO submitOrderBO) {<!-- -->
        String userId = submitOrderBO.getUserId();
        String addressId = submitOrderBO.getAddressId();
        String itemSpecIds = submitOrderBO.getItemSpecIds();
        Integer payMethod = submitOrderBO.getPayMethod();
        String leftMsg = submitOrderBO.getLeftMsg();
        // Set the free shipping fee to 0
        Integer postAmount = 0;
        String orderId = sid.nextShort();
        UserAddress address = addressService.queryUserAddres(userId, addressId);

        // 1. Save new order data
        Orders newOrder = new Orders();
        newOrder.setId(orderId);
        newOrder.setUserId(userId);
        newOrder.setReceiverName(address.getReceiver());
        newOrder.setReceiverMobile(address.getMobile());
        newOrder.setReceiverAddress(address.getProvince() + " " + address.getCity() + " " + address.getDistrict() + " " + address.getDetail());
        newOrder.setPostAmount(postAmount);
        newOrder.setPayMethod(payMethod);
        newOrder.setLeftMsg(leftMsg);
        newOrder.setIsComment(YesOrNo.NO.type);
        newOrder.setIsDelete(YesOrNo.NO.type);
        newOrder.setCreatedTime(new Date());
        newOrder.setUpdatedTime(new Date());


        // 2. Loop to save the order product information table based on itemSpecIds
        String itemSpecIdArr[] = itemSpecIds.split(",");
        Integer totalAmount = 0; // Accumulated original price of the product
        Integer realPayAmount = 0; // Accumulated actual payment price after discount
        for (String itemSpecId : itemSpecIdArr) {<!-- -->
            // TODO After integrating redis, the quantity of product purchased will be obtained from the redis shopping cart again.
            int buyCounts = 1;

            // 2.1 According to the specification id, query the specific information of the specification, mainly to obtain the price
            ItemsSpec itemSpec = itemService.queryItemSpecById(itemSpecId);
            totalAmount + = itemSpec.getPriceNormal() * buyCounts;
            realPayAmount + = itemSpec.getPriceDiscount() * buyCounts;

            // 2.2 Obtain product information and product pictures based on the product ID
            String itemId = itemSpec.getItemId();
            Items item = itemService.queryItemById(itemId);
            String imgUrl = itemService.queryItemMainImgById(itemId);

            // 2.3 Loop to save sub-order data to the database
            String subOrderId = sid.nextShort();
            OrderItems subOrderItem = new OrderItems();
            subOrderItem.setId(subOrderId);
            subOrderItem.setOrderId(orderId);
            subOrderItem.setItemId(itemId);
            subOrderItem.setItemName(item.getItemName());
            subOrderItem.setItemImg(imgUrl);
            subOrderItem.setBuyCounts(buyCounts);
            subOrderItem.setItemSpecId(itemSpecId);
            subOrderItem.setItemSpecName(itemSpec.getName());
            subOrderItem.setPrice(itemSpec.getPriceDiscount());
            orderItemsMapper.insert(subOrderItem);

            // 2.4 After the user submits the order, the inventory needs to be deducted from the specification table
            itemService.decreaseItemSpecStock(itemSpecId, buyCounts);
        }

        newOrder.setTotalAmount(totalAmount);
        newOrder.setRealPayAmount(realPayAmount);
        ordersMapper.insert(newOrder);

        // 3. Save the order status table
        OrderStatus waitPayOrderStatus = new OrderStatus();
        waitPayOrderStatus.setOrderId(orderId);
        waitPayOrderStatus.setOrderStatus(OrderStatusEnum.WAIT_PAY.type);
        waitPayOrderStatus.setCreatedTime(new Date());
        orderStatusMapper.insert(waitPayOrderStatus);

        // 4. Construct merchant orders for transmission to the payment center
        MerchantOrdersVO merchantOrdersVO = new MerchantOrdersVO();
        merchantOrdersVO.setMerchantOrderId(orderId);
        merchantOrdersVO.setMerchantUserId(userId);
        merchantOrdersVO.setAmount(realPayAmount + postAmount);
        merchantOrdersVO.setPayMethod(payMethod);

        // 5. Build custom order vo
        OrderVO orderVO = new OrderVO();
        orderVO.setOrderId(orderId);
        orderVO.setMerchantOrdersVO(merchantOrdersVO);

        return orderVO;
    }
}

Step 3: How to create an order
3.1 Interface ItemService:

 /**
     * Obtain the specific information of the specification object based on the product specification id
     * @param specId
     * @return
     */
    public ItemsSpec queryItemSpecById(String specId);
    /**
     * Obtain the product image main image url based on the product ID
     * @param itemId
     * @return
     */
    public String queryItemMainImgById(String itemId);

    /**
     * decrease stock
     * @param specId
     * @param buyCounts
     */
    public void decreaseItemSpecStock(String specId, int buyCounts);
3.2 Interface ItemService implementation class
 @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public ItemsSpec queryItemSpecById(String specId) {<!-- -->
        return itemsSpecMapper.selectByPrimaryKey(specId);
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public String queryItemMainImgById(String itemId) {<!-- -->
        ItemsImg itemsImg = new ItemsImg();
        itemsImg.setItemId(itemId);
        itemsImg.setIsMain(YesOrNo.YES.type);
        ItemsImg result = itemsImgMapper.selectOne(itemsImg);
        return result != null ? result.getUrl() : "";
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void decreaseItemSpecStock(String specId, int buyCounts) {<!-- -->
        int result = itemsMapperCustom.decreaseItemSpecStock(specId, buyCounts);
        if (result != 1) {<!-- -->
            throw new RuntimeException("Order creation failed, reason: Insufficient inventory!");
        }
    }
3.3 ItemsMapperCustom class in mapper interface:
 public int decreaseItemSpecStock(@Param("specId") String specId, @Param("pendingCounts") int pendingCounts);
    <update id="decreaseItemSpecStock">
        update
            items_spec
        set
            stock = stock - #{<!-- -->pendingCounts}
        where
            id = #{<!-- -->specId}
        and
            stock >= #{<!-- -->pendingCounts}
    </update>

Step 4: Create the corresponding bo class and enumeration

public enum PayMethod {<!-- -->
WEIXIN(1, "WeChat"),
ALIPAY(2, "Alipay");
public final Integer type;
public final String value;
PayMethod(Integer type, String value){<!-- -->
this.type = type;
this.value = value;
}
}
public enum OrderStatusEnum {<!-- -->
WAIT_PAY(10, "Pending payment"),
WAIT_DELIVER(20, "Paid, waiting for shipment"),
WAIT_RECEIVE(30, "Delivered, waiting to be received"),
SUCCESS(40, "Transaction successful"),
CLOSE(50, "Transaction Closed");
public final Integer type;
public final String value;
OrderStatusEnum(Integer type, String value){<!-- -->
this.type = type;
this.value = value;
}
}
public class SubmitOrderBO {<!-- -->
    private String userId;
    private String itemSpecIds;
    private String addressId;
    private Integer payMethod;
    private String leftMsg;
}

Step 5: Create controller class

package com.one.controller.order;
import com.one.bo.SubmitOrderBO;
import com.one.controller.BaseController;
import com.one.enums.PayMethod;
import com.one.service.order.OrderService;
import com.one.utils.JSONResult;
import com.one.vo.OrderVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Api(value = "Order-related", tags = {<!-- -->"Order-related api interface"})
@RequestMapping("orders")
@RestController
public class OrdersController extends BaseController {<!-- -->
    final static Logger logger = LoggerFactory.getLogger(OrdersController.class);
    
    @Autowired
    private OrderService orderService;
    
    @ApiOperation(value = "User Places Order", notes = "User Places Order", httpMethod = "POST")
    @PostMapping("/create")
    public JSONResult create(@RequestBody SubmitOrderBO submitOrderBO, HttpServletRequest request, HttpServletResponse response) {<!-- -->
        if (submitOrderBO.getPayMethod() != PayMethod.WEIXIN.type & amp; & amp; submitOrderBO.getPayMethod() != PayMethod.ALIPAY.type ) {<!-- -->
            return JSONResult.errorMsg("Payment method not supported!");
        }
        // 1. Create an order
        OrderVO orderVO = orderService.createOrder(submitOrderBO);
        String orderId = orderVO.getOrderId();
        // 2. After creating the order, remove the settled (submitted) items in the shopping cart
        // 3. Send the current order to the payment center to save the order data of the payment center
        return JSONResult.ok(orderId);
    }
}