feat: client invoicing page optimization with filters etc..

pull/8040/head
Gauthier LO 2024-12-20 11:27:26 +01:00
parent aab90a0e2c
commit b8124a880f
6 changed files with 132 additions and 154 deletions

View File

@ -529,10 +529,15 @@ public class InvoiceController {
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "50") Integer pageSize,
@RequestParam(name = "column", defaultValue = "order_time") String column,
@RequestParam(name = "order", defaultValue = "ASC") String order) {
@RequestParam(name = "order", defaultValue = "ASC") String order,
@RequestParam(name ="shippingAvailable[]", required = false) List<Integer> shippingAvailable,
@RequestParam(name ="purchaseAvailable[]", required = false) List<Integer> purchaseAvailable,
@RequestParam(name = "productAvailable[]", required = false) List<Integer> productAvailable
) {
log.info("User : {} is requesting uninvoiced orders for shops : [{}]",
((LoginUser) SecurityUtils.getSubject().getPrincipal()).getUsername(),
shopIds);
List<Integer> productStatuses = productAvailable == null || productAvailable.isEmpty() ? Arrays.asList(Integer.valueOf(PlatformOrderFront.productStatus.Unavailable.code), Integer.valueOf(PlatformOrderFront.productStatus.Available.code), Integer.valueOf(PlatformOrderFront.productStatus.Ordered.code)) : productAvailable;
String parsedColumn = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, column.replace("_dictText",""));
String parsedOrder = order.toUpperCase();
if(!parsedOrder.equals("ASC") && !parsedOrder.equals("DESC")) {
@ -545,158 +550,15 @@ public class InvoiceController {
e.printStackTrace();
return Result.error("Error 400 : Bad Request");
}
// checking shipping data availability
// // checking shipping data availability
List<String> shopIdList = Arrays.asList(shopIds.split(","));
// fetch order that can be invoiced either by shipping or purchase or both
List<PlatformOrder> allOrders = platformOrderService.findUninvoicedOrdersByShopForClient(shopIdList, Collections.singletonList(1), parsedColumn, parsedOrder, 1, -1);
int total = allOrders.size();
List<PlatformOrder> orders = platformOrderService.findUninvoicedOrdersByShopForClient(shopIdList, Collections.singletonList(1), parsedColumn, parsedOrder, pageNo, pageSize);
// LinkedList<PlatformOrder> sortedOrders = orders.stream().sorted(Comparator.comparing(PlatformOrder::getOrderTime)).collect(Collectors.toCollection(LinkedList::new));
if(orders.isEmpty())
return Result.OK("No order to invoice.");
Map<String, String> shops = shopService.listByIds(shopIdList).stream().collect(Collectors.toMap(Shop::getId, Shop::getName));
List<String> orderIds = orders.stream().map(PlatformOrder::getId).collect(Collectors.toList());
Map<PlatformOrder, List<PlatformOrderContent>> orderContentMap = platformOrderService.fetchOrderData(orderIds);
// some orders may not have content, so we have to re-add them
if(orderIds.size() != orderContentMap.size()) {
List<String> orderIdsInMap = orderContentMap.keySet().stream().map(PlatformOrder::getId).collect(Collectors.toList());
List<String> orderIdsWithoutContent = orderIds.stream().filter(id -> !orderIdsInMap.contains(id)).collect(Collectors.toList());
List<PlatformOrder> ordersWithoutContent = platformOrderService.listByIds(orderIdsWithoutContent);
Map<PlatformOrder, List<PlatformOrderContent>> orderContentMapWithoutContent = new HashMap<>();
for(PlatformOrder po : ordersWithoutContent) {
orderContentMapWithoutContent.put(po, new ArrayList<>());
}
orderContentMap.putAll(orderContentMapWithoutContent);
}
Map<String, String> errorMapToOrderId = new HashMap<>();
List<PlatformOrderFront> orderFronts = new ArrayList<>();
for(Map.Entry<PlatformOrder, List<PlatformOrderContent>> entry : orderContentMap.entrySet()) {
PlatformOrderFront orderFront = new PlatformOrderFront();
BeanUtils.copyProperties(entry.getKey(), orderFront);
//rename shop id by shop name to prevent it to leak in front
orderFront.setShopId(shops.get(orderFront.getShopId()));
// set default value of shipping and purchase availability
orderFront.setShippingAvailable(Available.code);
orderFront.setPurchaseAvailable(Available.code);
if(entry.getValue().isEmpty()) {
if(!errorMapToOrderId.containsKey(entry.getKey().getPlatformOrderId()))
errorMapToOrderId.put(entry.getKey().getPlatformOrderId(), "Error : order has no content : " + entry.getKey().getPlatformOrderId());
else
errorMapToOrderId.put(entry.getKey().getPlatformOrderId(), errorMapToOrderId.get(entry.getKey().getPlatformOrderId()) + " and has no content");
orderFront.setShippingAvailable(Unavailable.code);
orderFront.setPurchaseAvailable(Unavailable.code);
orderFronts.add(orderFront);
continue;
}
List<String> skuIds = entry.getValue().stream().map(PlatformOrderContent::getSkuId).distinct().collect(Collectors.toList());
// finds the first sku that isn't in db
List<Sku> skuIdsFound = skuService.listByIds(skuIds);
if(skuIdsFound.size() != skuIds.size()) {
if(!errorMapToOrderId.containsKey(entry.getKey().getPlatformOrderId()))
errorMapToOrderId.put(entry.getKey().getPlatformOrderId(), "Error : Missing one or more sku in db for order : " + entry.getKey().getPlatformOrderId());
else
errorMapToOrderId.put(entry.getKey().getPlatformOrderId(), errorMapToOrderId.get(entry.getKey().getPlatformOrderId()) + " and missing one or more sku in db");
orderFront.setShippingAvailable(Unavailable.code);
orderFront.setPurchaseAvailable(Unavailable.code);
continue;
}
if(entry.getKey().getShippingInvoiceNumber() == null) {
// checks if logistic channel is missing
if(entry.getKey().getLogisticChannelName().isEmpty() && entry.getKey().getInvoiceLogisticChannelName() == null) {
if(!errorMapToOrderId.containsKey(entry.getKey().getPlatformOrderId()))
errorMapToOrderId.put(entry.getKey().getPlatformOrderId(), "Error : Missing logistic channel for order : " + entry.getKey().getPlatformOrderId());
else
errorMapToOrderId.put(entry.getKey().getPlatformOrderId(), errorMapToOrderId.get(entry.getKey().getPlatformOrderId()) + " and missing logistic channel");
orderFront.setShippingAvailable(Unavailable.code);
}
// finds the first product with missing weight
String missingWeightSkuId = skuWeightService.searchFirstEmptyWeightSku(skuIds);
if(missingWeightSkuId != null) {
if(!errorMapToOrderId.containsKey(entry.getKey().getPlatformOrderId()))
errorMapToOrderId.put(entry.getKey().getPlatformOrderId(), "Error : Missing one or more weight for order : " + entry.getKey().getPlatformOrderId());
else
errorMapToOrderId.put(entry.getKey().getPlatformOrderId(), errorMapToOrderId.get(entry.getKey().getPlatformOrderId()) + " and missing weight");
orderFront.setShippingAvailable(Unavailable.code);
}
}
if(entry.getKey().getPurchaseInvoiceNumber() == null) {
// finds the first sku with missing price
String missingPriceSkuId = skuService.searchFirstMissingPriceSku(skuIds);
if(missingPriceSkuId != null) {
if(!errorMapToOrderId.containsKey(entry.getKey().getPlatformOrderId()))
errorMapToOrderId.put(entry.getKey().getPlatformOrderId(), "Error : Missing one or more sku price for order : " + entry.getKey().getPlatformOrderId());
else
errorMapToOrderId.put(entry.getKey().getPlatformOrderId(), errorMapToOrderId.get(entry.getKey().getPlatformOrderId()) + " and missing one or more sku price");
orderFront.setPurchaseAvailable(Unavailable.code);
}
}
// set purchase order status (-1 = unavailable, 0 = available, 1 = invoiced, 2 = paid)
if(entry.getKey().getProductAvailable() == null) {
orderFront.setProductAvailable(PlatformOrderFront.productStatus.Unavailable.code);
entry.getKey().setProductAvailable(PlatformOrderFront.productStatus.Unavailable.code);
}
if(entry.getKey().getProductAvailable().equals(PlatformOrderFront.productStatus.Unavailable.code)
&& entry.getKey().getVirtualProductAvailable().equals(PlatformOrderFront.productStatus.Available.code)
&& entry.getKey().getPurchaseInvoiceNumber() == null
)
orderFront.setProductAvailable(PlatformOrderFront.productStatus.Ordered.code);
if(entry.getKey().getPurchaseInvoiceNumber() != null) {
PurchaseOrder purchase = purchaseOrderService.getPurchaseByInvoiceNumber(entry.getKey().getPurchaseInvoiceNumber());
if(purchase.getPaidAmount().compareTo(BigDecimal.ZERO) == 0)
orderFront.setPurchaseAvailable(Invoiced.code);// invoiced
else
orderFront.setPurchaseAvailable(Paid.code);// paid
}
// set shipping order status (-1 = unavailable, 0 = available, 1 = invoiced, 2 = paid)
if(entry.getKey().getShippingInvoiceNumber() != null) {
ShippingInvoice shippingInvoice = iShippingInvoiceService.getShippingInvoice(entry.getKey().getShippingInvoiceNumber());
if(shippingInvoice.getPaidAmount().compareTo(BigDecimal.ZERO) == 0) {
orderFront.setShippingAvailable(Invoiced.code); // invoiced
}
else {
orderFront.setShippingAvailable(Paid.code); // paid
}
}
orderFronts.add(orderFront);
}
List<String> errorMessages = new ArrayList<>(errorMapToOrderId.values());
// sorting by order time ascending
orderFronts = orderFronts.stream().sorted(Comparator.comparing(PlatformOrderFront::getOrderTime)).collect(Collectors.toList());
// system notification
String errors = SECTION_START;
int max_entries = 100;
int current_page = 0;
int total_page = (int) Math.ceil((double) errorMessages.size() /max_entries);
for(int i = 1; i <= errorMessages.size(); i++) {
if(i%max_entries == 1) {
errors = SECTION_START;
current_page++;
}
errors = errors.concat("<li>" + i + " : " + errorMessages.get(i-1) +"</li>");
if(i%max_entries==0 || i == errorMessages.size()) {
errors = errors.concat(SECTION_END);
Map<String, String> templateParam = new HashMap<>();
templateParam.put("nb_entries", String.valueOf(errorMessages.size()));
templateParam.put("errors", errors);
templateParam.put("current_page", String.valueOf(current_page));
templateParam.put("total_page", String.valueOf(total_page));
TemplateMessageDTO message = new TemplateMessageDTO("admin", "admin", "Self Service invoicing estimation Errors", templateParam, "expenses_overview_errors");
ISysBaseApi.sendTemplateAnnouncement(message);
}
}
List<PlatformOrderFront> orders = platformOrderService.fetchUninvoicedOrdersByShopForClientFullSQL(shopIdList, Collections.singletonList(1), parsedColumn, parsedOrder, pageNo, pageSize,
productStatuses, shippingAvailable, purchaseAvailable);
int total = orders.get(0).getTotalCount();
IPage<PlatformOrderFront> page = new Page<>();
page.setRecords(orderFronts);
page.setRecords(orders);
page.setSize(pageSize);
page.setCurrent(pageNo);
page.setTotal(total);

View File

@ -6,10 +6,7 @@ import org.jeecg.modules.business.domain.api.mabang.getorderlist.Order;
import org.jeecg.modules.business.domain.api.yd.YDTrackingNumberData;
import org.jeecg.modules.business.entity.PlatformOrder;
import org.jeecg.modules.business.entity.PlatformOrderShopSync;
import org.jeecg.modules.business.vo.OrderKpi;
import org.jeecg.modules.business.vo.PlatformOrderOption;
import org.jeecg.modules.business.vo.PlatformOrderPage;
import org.jeecg.modules.business.vo.ShippingFeeBillableOrders;
import org.jeecg.modules.business.vo.*;
import org.jeecg.modules.business.vo.clientPlatformOrder.ClientPlatformOrderPage;
import org.jeecg.modules.business.vo.clientPlatformOrder.section.OrderQuantity;
import org.springframework.stereotype.Repository;
@ -193,7 +190,10 @@ public interface PlatformOrderMapper extends BaseMapper<PlatformOrder> {
List<PlatformOrder> findUninvoicedShippingOrdersByShopForClient(@Param("shopIds") List<String> shopIds, @Param("erpStatuses") List<Integer> erpStatuses);
List<PlatformOrder> fetchUninvoicedPurchaseOrdersByShopForClient(@Param("shopIds") List<String> shopIds, @Param("erpStatuses") List<Integer> erpStatuses);
List<PlatformOrder> findUninvoicedOrdersByShopForClient(@Param("shopIds") List<String> shopIds, @Param("erpStatuses") List<Integer> erpStatuses,
@Param("column") String column, @Param("order") String order, @Param("offset") Integer offset, @Param("size") Integer pageSize);
@Param("column") String column, @Param("order") String order, @Param("offset") Integer offset, @Param("size") Integer pageSize);
List<PlatformOrderFront> fetchUninvoicedOrdersByShopForClientFullSQL(@Param("shopIds") List<String> shopIds, @Param("erpStatuses") List<Integer> erpStatuses,
@Param("column") String column, @Param("order") String order, @Param("offset") Integer offset, @Param("size") Integer pageSize,
@Param("productStatuses") List<Integer> productStatuses, @Param("shippingStatuses") List<Integer> shippingStatuses, @Param("purchaseStatuses") List<Integer> purchaseStatuses);
List<String> findUninvoicedOrderIdsByShopForClient(@Param("shopIds") List<String> shopIds, @Param("erpStatuses") List<Integer> erpStatuses);
List<PlatformOrder> fetchEmptyLogisticChannelOrders(@Param("startDate") String startDate,@Param("endDate") String endDate);

View File

@ -682,6 +682,110 @@
</if>
;
</select>
<select id="fetchUninvoicedOrdersByShopForClientFullSQL" resultType="org.jeecg.modules.business.vo.PlatformOrderFront">
WITH sku_stats AS (
SELECT
sku.id AS sku_id,
COUNT(sw.sku_id) AS weight_count,
COUNT(sp.sku_id) AS price_count
FROM sku
LEFT JOIN sku_weight sw ON sku.id = sw.sku_id
LEFT JOIN sku_price sp ON sku.id = sp.sku_id
GROUP BY sku.id
),
uninvoiced_orders AS (
SELECT
po.id AS id,
s.name AS shop_id,
po.platform_order_number AS platform_order_number,
po.order_time AS order_time,
po.country AS country,
MIN(
CASE
WHEN poc.id IS NULL OR sku.id IS NULL THEN -1
WHEN po.shipping_invoice_number IS NULL
AND (po.logistic_channel_name IS NULL OR po.logistic_channel_name = '')
AND (po.invoice_logistic_channel_name IS NULL OR po.invoice_logistic_channel_name = '') THEN -1
WHEN po.shipping_invoice_number IS NULL AND stats.weight_count = 0 THEN -1
WHEN po.shipping_invoice_number IS NOT NULL AND si.paid_amount > 0.00 THEN 2
WHEN po.shipping_invoice_number IS NOT NULL AND si.paid_amount = 0.00 THEN 1
ELSE 0
END
) AS shipping_available,
MIN(
CASE
WHEN po.purchase_invoice_number IS NULL AND stats.price_count = 0 THEN -1
WHEN po.purchase_invoice_number IS NOT NULL AND pur.paid_amount > 0.00 THEN 2
WHEN po.purchase_invoice_number IS NOT NULL AND pur.paid_amount = 0.00 THEN 1
ELSE 0
END
) AS purchase_available,
CASE
WHEN po.product_available = 0
AND po.virtual_product_available = 1
AND po.purchase_invoice_number IS NULL THEN 2
ELSE COALESCE(po.product_available, 0)
END AS product_available
FROM platform_order po
JOIN shop s ON po.shop_id = s.id
LEFT JOIN platform_order_content poc ON po.id = poc.platform_order_id
LEFT JOIN sku ON poc.sku_id = sku.id
LEFT JOIN sku_stats stats ON sku.id = stats.sku_id
LEFT JOIN purchase_order pur ON pur.invoice_number = po.purchase_invoice_number
LEFT JOIN shipping_invoice si ON po.shipping_invoice_number = si.invoice_number
WHERE po.erp_status IN
<foreach
collection="erpStatuses"
separator=","
open="("
close=")"
index="index"
item="erpStatus"
>
#{erpStatus}
</foreach>
AND poc.erp_status &lt;&gt; 5
AND (po.shipping_invoice_number IS NULL
OR (po.shipping_invoice_number LIKE '%%%%-%%-2%%%'
AND po.purchase_invoice_number IS NULL
)
)
AND shop_id IN
<foreach
collection="shopIds"
separator=","
open="("
close=")"
index="index"
item="shopId"
>
#{shopId}
</foreach>
GROUP BY po.id, po.platform_order_number, po.product_available, po.virtual_product_available, po.purchase_invoice_number
)
SELECT *, COUNT(*) OVER() AS total_count
FROM uninvoiced_orders
WHERE
product_available IN
<foreach collection="productStatuses" separator="," open="(" close=")" index="index" item="productStatus">
#{productStatus}
</foreach>
<if test="shippingStatuses != null">
AND shipping_available IN
<foreach collection="shippingStatuses" separator="," open="(" close=")" index="index" item="shippingStatus">
#{shippingStatus}
</foreach>
</if>
<if test="purchaseStatuses != null">
AND purchase_available IN
<foreach collection="purchaseStatuses" separator="," open="(" close=")" index="index" item="purchaseStatus">
#{purchaseStatus}
</foreach>
</if>
ORDER BY ${column} ${order}
LIMIT #{offset}, #{size};
</select>
<insert id="insertPlatformOrdersArchives" parameterType="list">
INSERT INTO platform_order_delete(id, create_by,
create_time, update_by,

View File

@ -219,6 +219,10 @@ public interface IPlatformOrderService extends IService<PlatformOrder> {
* @return
*/
List<PlatformOrder> findUninvoicedOrdersByShopForClient(List<String> shopIds, List<Integer> erpStatuses, String column, String order, Integer pageNo, Integer pageSize);
List<PlatformOrderFront> fetchUninvoicedOrdersByShopForClientFullSQL(List<String> shopIds, List<Integer> erpStatuses, String column, String order, Integer pageNo, Integer pageSize,
List<Integer> productAvailable, List<Integer> shippingAvailable, List<Integer> purchaseAvailable);
/**
* Get ids of all order that can be invoiced by small clients (type 2) themselves.
*

View File

@ -434,6 +434,12 @@ public class PlatformOrderServiceImpl extends ServiceImpl<PlatformOrderMapper, P
int offset = (pageNo - 1) * pageSize;
return platformOrderMap.findUninvoicedOrdersByShopForClient(shopIds, erpStatuses, column, order, offset, pageSize);
}
@Override
public List<PlatformOrderFront> fetchUninvoicedOrdersByShopForClientFullSQL(List<String> shopIds, List<Integer> erpStatuses, String column, String order, Integer pageNo, Integer pageSize,
List<Integer> productAvailable, List<Integer> shippingAvailable, List<Integer> purchaseAvailable) {
int offset = (pageNo - 1) * pageSize;
return platformOrderMap.fetchUninvoicedOrdersByShopForClientFullSQL(shopIds, erpStatuses, column, order, offset, pageSize, productAvailable, shippingAvailable, purchaseAvailable);
}
@Override
public List<String> findUninvoicedOrderIdsByShopForClient(List<String> shopIds, List<Integer> erpStatuses) {

View File

@ -106,6 +106,8 @@ public class PlatformOrderFront {
@ApiModelProperty(value = "可开采购票0=不可1=可)")
private String purchaseAvailable;
private Integer totalCount;
public enum invoiceStatus {
Unavailable("-1"),
Available("0"),