feat:add SKU order workflow with export and place order by Excel

pull/8523/head
Xue YANG 2025-06-30 10:36:17 +02:00
parent 2bb112f952
commit 29dd6316da
7 changed files with 281 additions and 27 deletions

View File

@ -1,5 +1,6 @@
package org.jeecg.modules.business.controller.admin; package org.jeecg.modules.business.controller.admin;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -9,6 +10,9 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result; import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog; import org.jeecg.common.aspect.annotation.AutoLog;
@ -19,10 +23,13 @@ import org.jeecg.modules.business.entity.*;
import org.jeecg.modules.business.mongoService.SkuMongoService; import org.jeecg.modules.business.mongoService.SkuMongoService;
import org.jeecg.modules.business.service.*; import org.jeecg.modules.business.service.*;
import org.jeecg.modules.business.vo.*; import org.jeecg.modules.business.vo.*;
import org.jeecgframework.poi.excel.ExcelExportUtil;
import org.jeecgframework.poi.excel.ExcelImportUtil; import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants; import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams; import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams; import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.entity.params.ExcelExportEntity;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView; import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -37,12 +44,15 @@ import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import javax.mail.Authenticator; import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication; import javax.mail.PasswordAuthentication;
import javax.mail.Session; import javax.mail.Session;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -385,22 +395,22 @@ public class SkuController {
@RequestParam(name = "zhNames", required = false) String zhNames, @RequestParam(name = "zhNames", required = false) String zhNames,
@RequestParam(name = "enNames", required = false) String enNames, @RequestParam(name = "enNames", required = false) String enNames,
ServletRequest servletRequest) { ServletRequest servletRequest) {
if(!securityService.checkIsEmployee()) { if (!securityService.checkIsEmployee()) {
Client client = clientService.getCurrentClient(); Client client = clientService.getCurrentClient();
// Here we don't explicitly tell the user that they are not allowed to access this endpoint for security measure. // Here we don't explicitly tell the user that they are not allowed to access this endpoint for security measure.
if (client == null) { if (client == null) {
return Result.error(HttpStatus.SC_NOT_FOUND, "Profile not found"); return Result.error(HttpStatus.SC_NOT_FOUND, "Profile not found");
} }
if( clientId == null) { if (clientId == null) {
return Result.error(HttpStatus.SC_BAD_REQUEST, "Bad request"); return Result.error(HttpStatus.SC_BAD_REQUEST, "Bad request");
} }
if(!client.getId().equals(clientId)) { if (!client.getId().equals(clientId)) {
return Result.error(HttpStatus.SC_NOT_FOUND, "Client not found"); return Result.error(HttpStatus.SC_NOT_FOUND, "Client not found");
} }
} }
String parsedColumn = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, column.replace("_dictText", "")); String parsedColumn = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, column.replace("_dictText", ""));
String parsedOrder = order.toUpperCase(); String parsedOrder = order.toUpperCase();
if(!parsedOrder.equals("ASC") && !parsedOrder.equals("DESC")) { if (!parsedOrder.equals("ASC") && !parsedOrder.equals("DESC")) {
return Result.error("Error 400 Bad Request"); return Result.error("Error 400 Bad Request");
} }
try { try {
@ -410,20 +420,19 @@ public class SkuController {
} }
List<SkuOrderPage> skuOrdersPage; List<SkuOrderPage> skuOrdersPage;
int total; int total;
if(erpCodes != null || zhNames != null || enNames != null) { if (erpCodes != null || zhNames != null || enNames != null) {
List<String> erpCodeList = erpCodes == null ? null : Arrays.asList(erpCodes.split(",")); List<String> erpCodeList = erpCodes == null ? null : Arrays.asList(erpCodes.split(","));
List<String> zhNameList = zhNames == null ? null : Arrays.asList(zhNames.split(",")); List<String> zhNameList = zhNames == null ? null : Arrays.asList(zhNames.split(","));
List<String> enNameList = enNames == null ? null : Arrays.asList(enNames.split(",")); List<String> enNameList = enNames == null ? null : Arrays.asList(enNames.split(","));
if(clientId != null) { if (clientId != null) {
total = skuService.countAllClientSkusWithFilters(clientId, erpCodeList, zhNameList, enNameList); total = skuService.countAllClientSkusWithFilters(clientId, erpCodeList, zhNameList, enNameList);
skuOrdersPage = skuService.fetchSkusByClientWithFilters(clientId, pageNo, pageSize, parsedColumn, parsedOrder, erpCodeList, zhNameList, enNameList); skuOrdersPage = skuService.fetchSkusByClientWithFilters(clientId, pageNo, pageSize, parsedColumn, parsedOrder, erpCodeList, zhNameList, enNameList);
} else { } else {
total = skuService.countAllSkuWeightsWithFilters(erpCodeList, zhNameList, enNameList); total = skuService.countAllSkuWeightsWithFilters(erpCodeList, zhNameList, enNameList);
skuOrdersPage = skuService.fetchSkuWeightsWithFilters(pageNo, pageSize, parsedColumn, parsedOrder, erpCodeList, zhNameList, enNameList); skuOrdersPage = skuService.fetchSkuWeightsWithFilters(pageNo, pageSize, parsedColumn, parsedOrder, erpCodeList, zhNameList, enNameList);
} }
} } else {
else { if (clientId != null) {
if(clientId != null) {
total = skuService.countAllClientSkus(clientId); total = skuService.countAllClientSkus(clientId);
skuOrdersPage = skuService.fetchSkusByClient(clientId, pageNo, pageSize, parsedColumn, parsedOrder); skuOrdersPage = skuService.fetchSkusByClient(clientId, pageNo, pageSize, parsedColumn, parsedOrder);
} else { } else {
@ -480,6 +489,7 @@ public class SkuController {
page.setTotal(total); page.setTotal(total);
return Result.OK(page); return Result.OK(page);
} }
@GetMapping("/listAllSelectableSkuIds") @GetMapping("/listAllSelectableSkuIds")
public Result<?> listAllSelectableSkuIds(@RequestParam(name = "clientId") String clientId, public Result<?> listAllSelectableSkuIds(@RequestParam(name = "clientId") String clientId,
@RequestParam(name = "erpCodes", required = false) String erpCodes, @RequestParam(name = "erpCodes", required = false) String erpCodes,
@ -487,7 +497,7 @@ public class SkuController {
@RequestParam(name = "enNames", required = false) String enNames @RequestParam(name = "enNames", required = false) String enNames
) { ) {
List<SkuOrderPage> selectableSkuIds; List<SkuOrderPage> selectableSkuIds;
if(erpCodes != null || zhNames != null || enNames != null) { if (erpCodes != null || zhNames != null || enNames != null) {
List<String> erpCodeList = erpCodes == null ? null : Arrays.asList(erpCodes.split(",")); List<String> erpCodeList = erpCodes == null ? null : Arrays.asList(erpCodes.split(","));
List<String> zhNameList = zhNames == null ? null : Arrays.asList(zhNames.split(",")); List<String> zhNameList = zhNames == null ? null : Arrays.asList(zhNames.split(","));
List<String> enNameList = enNames == null ? null : Arrays.asList(enNames.split(",")); List<String> enNameList = enNames == null ? null : Arrays.asList(enNames.split(","));
@ -497,10 +507,11 @@ public class SkuController {
} }
return Result.OK(selectableSkuIds); return Result.OK(selectableSkuIds);
} }
@GetMapping("/searchExistingSkuByKeywords") @GetMapping("/searchExistingSkuByKeywords")
public Result<?> searchExistingSkuByKeywords(@RequestParam("keywords") String keywords) { public Result<?> searchExistingSkuByKeywords(@RequestParam("keywords") String keywords) {
String parsedKeywords = keywords.trim().replaceAll("[{}=$]", ""); String parsedKeywords = keywords.trim().replaceAll("[{}=$]", "");
if(parsedKeywords.isEmpty()) { if (parsedKeywords.isEmpty()) {
return Result.OK(new ArrayList<>()); return Result.OK(new ArrayList<>());
} }
return Result.OK(skuMongoService.textSearch(parsedKeywords)); return Result.OK(skuMongoService.textSearch(parsedKeywords));
@ -510,7 +521,7 @@ public class SkuController {
public Result<?> createMabangSku(@RequestBody List<SkuOrderPage> skuList) { public Result<?> createMabangSku(@RequestBody List<SkuOrderPage> skuList) {
log.info("Request to create {} new skus in Mabang", skuList.size()); log.info("Request to create {} new skus in Mabang", skuList.size());
skuList.forEach(sku -> { skuList.forEach(sku -> {
if(sku.getShippingDiscount() == null) { if (sku.getShippingDiscount() == null) {
sku.setShippingDiscount(BigDecimal.ZERO); sku.setShippingDiscount(BigDecimal.ZERO);
} else { } else {
BigDecimal oldValue = sku.getShippingDiscount().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); BigDecimal oldValue = sku.getShippingDiscount().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
@ -526,7 +537,7 @@ public class SkuController {
List<NewSkuPage> skuList = parseSkuList(params); List<NewSkuPage> skuList = parseSkuList(params);
log.info("Exporting new skus to excel ..."); log.info("Exporting new skus to excel ...");
skuList.forEach(sku -> { skuList.forEach(sku -> {
if(sku.getShippingDiscount() == null) { if (sku.getShippingDiscount() == null) {
sku.setShippingDiscount(BigDecimal.ONE); sku.setShippingDiscount(BigDecimal.ONE);
} else { } else {
BigDecimal oldValue = sku.getShippingDiscount().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); BigDecimal oldValue = sku.getShippingDiscount().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
@ -641,7 +652,7 @@ public class SkuController {
@RequestParam(name = "pageSize", defaultValue = "50") Integer pageSize, @RequestParam(name = "pageSize", defaultValue = "50") Integer pageSize,
@RequestParam(name = "skus[]", required = false) List<String> skuNames @RequestParam(name = "skus[]", required = false) List<String> skuNames
) { ) {
if(skuNames == null) if (skuNames == null)
skuNames = new ArrayList<>(); skuNames = new ArrayList<>();
String shopId = shopService.getIdByCode(shopCode); String shopId = shopService.getIdByCode(shopCode);
if (shopId == null) return Result.error(404, "Shop not found"); if (shopId == null) return Result.error(404, "Shop not found");
@ -651,17 +662,17 @@ public class SkuController {
} }
@GetMapping(value = "/latestSkuCounter") @GetMapping(value = "/latestSkuCounter")
public Result<?> latestSkuCounter(@RequestParam(name= "userCode") String userCode, public Result<?> latestSkuCounter(@RequestParam(name = "userCode") String userCode,
@RequestParam(name= "clientCode") String clientCode, @RequestParam(name = "clientCode") String clientCode,
@RequestParam(name= "date") String date) { @RequestParam(name = "date") String date) {
return Result.OK(skuService.latestSkuCounter(userCode, clientCode, date)); return Result.OK(skuService.latestSkuCounter(userCode, clientCode, date));
} }
@GetMapping(value = "/compare") @GetMapping(value = "/compare")
public Result<?> compareClientSkuWithMabang(@RequestParam(name="clientId") String clientId, public Result<?> compareClientSkuWithMabang(@RequestParam(name = "clientId") String clientId,
@RequestParam(name="erpStatuses[]") List<String> erpStatuses) { @RequestParam(name = "erpStatuses[]") List<String> erpStatuses) {
Map<String, Sku> clientSkus = skuService.listInUninvoicedOrders(clientId, erpStatuses); Map<String, Sku> clientSkus = skuService.listInUninvoicedOrders(clientId, erpStatuses);
if(clientSkus.isEmpty()) { if (clientSkus.isEmpty()) {
log.info("No skus to compare"); log.info("No skus to compare");
return Result.OK(); return Result.OK();
} }
@ -669,4 +680,64 @@ public class SkuController {
return Result.OK(); return Result.OK();
} }
@GetMapping("/skuOrderExport")
public void SkuOrderExport(HttpServletResponse response,
@RequestParam String clientId) throws IOException {
List<SkuOrderPage> skuList = skuService.listSkuOrdersByClient(clientId);
String clientCode = clientService.getById(clientId).getInternalCode();
String exportDate = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
ExportParams exportParams = new ExportParams("SKU Orders" + " - " + clientCode + " - " + exportDate, "SKU Orders");
exportParams.setType(ExcelType.XSSF);
List<ExcelExportEntity> entityList = new ArrayList<>();
entityList.add(new ExcelExportEntity("SKU", "erpCode"));
entityList.add(new ExcelExportEntity("Nom Anglais", "enName"));
entityList.add(new ExcelExportEntity("Nom Chinois", "zhName"));
entityList.add(new ExcelExportEntity("Stock Dispo", "availableAmount"));
entityList.add(new ExcelExportEntity("Achat WIA en cours", "purchasingAmount"));
entityList.add(new ExcelExportEntity("Cde shopify en cours", "qtyInOrdersNotShipped"));
entityList.add(new ExcelExportEntity("Stock " + (new SimpleDateFormat("dd/MM").format(new Date())), "stock"));
entityList.add(new ExcelExportEntity("Quantité à acheter", "qtyToBuy"));
entityList.add(new ExcelExportEntity("Ventes 7j", "salesLastWeek"));
entityList.add(new ExcelExportEntity("Ventes 28j", "salesFourWeeks"));
entityList.add(new ExcelExportEntity("Ventes 42j", "salesSixWeeks"));
entityList.add(new ExcelExportEntity("SKU Price", "skuPrice"));
List<Map<String, Object>> dataList = new ArrayList<>();
for (SkuOrderPage sku : skuList) {
Map<String, Object> map = new HashMap<>();
map.put("erpCode", sku.getErpCode());
map.put("enName", sku.getEnName());
map.put("zhName", sku.getZhName());
map.put("availableAmount", sku.getAvailableAmount());
map.put("purchasingAmount", sku.getPurchasingAmount());
map.put("qtyInOrdersNotShipped", sku.getQtyInOrdersNotShipped());
map.put("stock", sku.getStock());
map.put("qtyToBuy", sku.getQtyToBuy());
map.put("salesLastWeek", sku.getSalesLastWeek());
map.put("salesFourWeeks", sku.getSalesFourWeeks());
map.put("salesSixWeeks", sku.getSalesSixWeeks());
map.put("skuPrice", sku.getSkuPrice());
dataList.add(map);
}
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, dataList);
Sheet sheet = workbook.getSheetAt(0);
if (sheet.getPhysicalNumberOfRows() > 0) {
Row headerRow = sheet.getRow(0);
if (headerRow != null) {
int cellCount = headerRow.getPhysicalNumberOfCells();
for (int i = 0; i < cellCount; i++) {
sheet.autoSizeColumn(i);
}
}
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("SKU Orders_" + clientCode + "_" + exportDate + ".xlsx", "UTF-8"));
try (ServletOutputStream out = response.getOutputStream()) {
workbook.write(out);
out.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}
} }

View File

@ -35,6 +35,7 @@ import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils; import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import javax.mail.Authenticator; import javax.mail.Authenticator;
@ -462,6 +463,43 @@ public class InvoiceController {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@PostMapping("/createOrderByExcel")
public Result<?> createOrderByExcel(@RequestParam("file") MultipartFile file) {
boolean isEmployee = securityService.checkIsEmployee();
Client client = null;
if (!isEmployee) {
client = clientService.getCurrentClient();
if (client == null) {
return Result.error(HttpStatus.SC_NOT_FOUND, "Client not found");
}
}
//get the excel data
List<Map<String, Object>> skuList = skuService.parseExcelToSkuList(file);
// if not employee, filter out skus that are not from the client
if (!isEmployee) {
Iterator<Map<String, Object>> iterator = skuList.iterator();
while (iterator.hasNext()) {
Map<String, Object> sku = iterator.next();
String erpCode = (String) sku.get("erpCode");
if (erpCode == null || erpCode.isEmpty()) {
iterator.remove();
continue;
}
String skuId = skuService.getIdFromErpCode(erpCode);
if (skuId == null) {
iterator.remove();
continue;
}
String skuClientId = clientSkuService.getClientIdFromSkuId(skuId);
if (!client.getId().equals(skuClientId)) {
iterator.remove();
}
}
}
log.info("SKU list after filtering: {}", skuList);
return Result.OK(skuList);
}
@GetMapping(value = "/preShipping/orderTime") @GetMapping(value = "/preShipping/orderTime")
public Result<?> getValidOrderTimePeriod(@RequestParam("shopIds[]") List<String> shopIDs, @RequestParam("erpStatuses[]") List<Integer> erpStatuses) { public Result<?> getValidOrderTimePeriod(@RequestParam("shopIds[]") List<String> shopIDs, @RequestParam("erpStatuses[]") List<Integer> erpStatuses) {
log.info("Request for valid order time period for shops: {} and erpStatuses : {}", shopIDs.toString(), erpStatuses.toString()); log.info("Request for valid order time period for shops: {} and erpStatuses : {}", shopIDs.toString(), erpStatuses.toString());

View File

@ -62,6 +62,7 @@ public interface SkuMapper extends BaseMapper<Sku> {
List<SkuOrderPage> fetchSkuWeightsWithFilters(@Param("offset") Integer offset, @Param("size") Integer pageSize, @Param("column") String column, @Param("order") String order, @Param("erpCodes") String erpCodesRegex, @Param("zhNames") String zhNamesRegex, @Param("enNames") String enNamesRegex); List<SkuOrderPage> fetchSkuWeightsWithFilters(@Param("offset") Integer offset, @Param("size") Integer pageSize, @Param("column") String column, @Param("order") String order, @Param("erpCodes") String erpCodesRegex, @Param("zhNames") String zhNamesRegex, @Param("enNames") String enNamesRegex);
List<SkuOrderPage> fetchAllSkuWeightsWithFilters(@Param("offset") Integer offset, @Param("size") Integer pageSize, @Param("column") String column, @Param("order") String order, @Param("erpCodes") String erpCodesRegex, @Param("zhNames") String zhNamesRegex, @Param("enNames") String enNamesRegex); List<SkuOrderPage> fetchAllSkuWeightsWithFilters(@Param("offset") Integer offset, @Param("size") Integer pageSize, @Param("column") String column, @Param("order") String order, @Param("erpCodes") String erpCodesRegex, @Param("zhNames") String zhNamesRegex, @Param("enNames") String enNamesRegex);
List<SkuOrderPage> fetchSkusByClientWithFilters(@Param("clientId") String clientId, @Param("offset") Integer offset, @Param("size") Integer pageSize, @Param("column") String column, @Param("order") String order, @Param("erpCodes") String erpCodesRegex, @Param("zhNames") String zhNamesRegex, @Param("enNames") String enNamesRegex); List<SkuOrderPage> fetchSkusByClientWithFilters(@Param("clientId") String clientId, @Param("offset") Integer offset, @Param("size") Integer pageSize, @Param("column") String column, @Param("order") String order, @Param("erpCodes") String erpCodesRegex, @Param("zhNames") String zhNamesRegex, @Param("enNames") String enNamesRegex);
List<SkuOrderPage> listSkuOrdersByClient(@Param("clientId") String clientId);
List<SkuOrderPage> listSelectableSkuIdsWithFilters(@Param("clientId") String clientId, @Param("erpCodes") String erpCodeList, @Param("zhNames") String zhNameList, @Param("enNames") String enNameList); List<SkuOrderPage> listSelectableSkuIdsWithFilters(@Param("clientId") String clientId, @Param("erpCodes") String erpCodeList, @Param("zhNames") String zhNameList, @Param("enNames") String enNameList);
List<SkuOrderPage> listSelectableSkuIds(@Param("clientId") String clientId); List<SkuOrderPage> listSelectableSkuIds(@Param("clientId") String clientId);

View File

@ -450,6 +450,58 @@
</if> </if>
; ;
</select> </select>
<select id="listSkuOrdersByClient" resultType="org.jeecg.modules.business.vo.SkuOrderPage">
WITH qtyInOrdersNotShippedCTE AS (
SELECT sku_id AS ID, SUM(quantity) AS quantity
FROM platform_order_content poc
JOIN platform_order po ON poc.platform_order_id = po.id
JOIN shop s ON po.shop_id = s.id
JOIN client c ON s.owner_id = c.id
WHERE c.id = #{clientId}
AND po.erp_status IN ('1','2')
AND po.can_send = 1
AND poc.erp_status IN ('1','2')
GROUP BY sku_id
), latest_exchange_rate AS (
SELECT rate
FROM exchange_rates
WHERE original_currency = 'EUR' AND target_currency = 'RMB'
ORDER BY create_time DESC LIMIT 1
), rmb_id AS (
SELECT id FROM currency WHERE code = 'RMB'
)
SELECT s.id,
s.erp_code,
s.en_name,
s.zh_name,
s.purchasing_amount,
s.available_amount,
qtyInOrdersNotShippedCTE.quantity AS qtyInOrdersNotShipped,
s.available_amount + s.purchasing_amount - COALESCE(qtyInOrdersNotShippedCTE.quantity, 0) AS stock,
s.image_source,
s.service_fee,
IF(sp.currency_id = (SELECT id FROM rmb_id),
ROUND(sp.price / (SELECT rate FROM latest_exchange_rate), 2),
sp.price) AS sku_price,
sp.threshold AS discount_moq,
IF(sp.currency_id = (SELECT id FROM rmb_id),
ROUND(sp.discounted_price / (SELECT rate FROM latest_exchange_rate), 2),
sp.discounted_price) AS discounted_price,
s7.quantity AS sales_last_week,
s28.quantity AS sales_four_weeks,
s42.quantity AS sales_six_weeks
FROM sku s
JOIN client_sku ON s.id = client_sku.sku_id
LEFT JOIN sku_current_price sp ON s.id = sp.sku_id
LEFT JOIN sales_28 s28 ON s.id = s28.sku_id
LEFT JOIN sales_42 s42 ON s.id = s42.sku_id
LEFT JOIN sales_7 s7 ON s.id = s7.sku_id
LEFT JOIN qtyInOrdersNotShippedCTE ON s.id = qtyInOrdersNotShippedCTE.ID
WHERE client_sku.client_id = #{clientId}
AND s.status = 3
ORDER BY stock ASC
</select>
<select id="listSelectableSkuIds" resultType="org.jeecg.modules.business.vo.SkuOrderPage"> <select id="listSelectableSkuIds" resultType="org.jeecg.modules.business.vo.SkuOrderPage">
WITH qtyInOrdersNotShippedCTE AS ( WITH qtyInOrdersNotShippedCTE AS (
SELECT sku_id as ID, SUM(quantity) AS quantity SELECT sku_id as ID, SUM(quantity) AS quantity

View File

@ -6,6 +6,7 @@ import org.jeecg.modules.business.controller.UserException;
import org.jeecg.modules.business.entity.*; import org.jeecg.modules.business.entity.*;
import org.jeecg.modules.business.vo.*; import org.jeecg.modules.business.vo.*;
import org.jeecg.modules.business.vo.inventory.InventoryRecord; import org.jeecg.modules.business.vo.inventory.InventoryRecord;
import org.springframework.web.multipart.MultipartFile;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -98,6 +99,7 @@ public interface ISkuService extends IService<Sku> {
Integer countAllClientSkus(String clientId); Integer countAllClientSkus(String clientId);
List<SkuOrderPage> fetchSkusByClient(String clientId, Integer pageNo, Integer pageSize, String column, String order); List<SkuOrderPage> fetchSkusByClient(String clientId, Integer pageNo, Integer pageSize, String column, String order);
List<SkuOrderPage> listSkuOrdersByClient(String clientId);
Integer countAllSkuWeightsWithFilters(List<String> erpCodeList, List<String> zhNameList, List<String> enNameList); Integer countAllSkuWeightsWithFilters(List<String> erpCodeList, List<String> zhNameList, List<String> enNameList);
@ -134,4 +136,6 @@ public interface ISkuService extends IService<Sku> {
int latestSkuCounter(String userCode, String clientCode, String date); int latestSkuCounter(String userCode, String clientCode, String date);
void setIsSynced(List<String> erpCodes, boolean isSynced); void setIsSynced(List<String> erpCodes, boolean isSynced);
List<Map<String, Object>> parseExcelToSkuList(MultipartFile file);
} }

View File

@ -3,6 +3,7 @@ package org.jeecg.modules.business.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.modules.business.controller.UserException; import org.jeecg.modules.business.controller.UserException;
@ -19,6 +20,7 @@ import org.jeecg.modules.business.vo.inventory.InventoryRecord;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -427,6 +429,10 @@ public class SkuServiceImpl extends ServiceImpl<SkuMapper, Sku> implements ISkuS
return skuMapper.fetchSkusByClient(clientId, offset, pageSize, column, order); return skuMapper.fetchSkusByClient(clientId, offset, pageSize, column, order);
} }
@Override @Override
public List<SkuOrderPage> listSkuOrdersByClient(String clientID){
return skuMapper.listSkuOrdersByClient(clientID);
}
@Override
public Integer countAllSkuWeightsWithFilters(List<String> erpCodes, List<String> zhNames, List<String> enNames) { public Integer countAllSkuWeightsWithFilters(List<String> erpCodes, List<String> zhNames, List<String> enNames) {
StringBuilder erpCodesRegex= new StringBuilder(), zhNamesRegex = new StringBuilder(), enNamesRegex = new StringBuilder(); StringBuilder erpCodesRegex= new StringBuilder(), zhNamesRegex = new StringBuilder(), enNamesRegex = new StringBuilder();
if(erpCodes != null){ if(erpCodes != null){
@ -710,4 +716,80 @@ public class SkuServiceImpl extends ServiceImpl<SkuMapper, Sku> implements ISkuS
public void setIsSynced(List<String> erpCodes, boolean isSynced) { public void setIsSynced(List<String> erpCodes, boolean isSynced) {
skuMapper.setIsSynced(erpCodes, isSynced); skuMapper.setIsSynced(erpCodes, isSynced);
} }
public List<Map<String, Object>> parseExcelToSkuList(MultipartFile file) {
List<Map<String, Object>> result = new ArrayList<>();
try (Workbook workbook = WorkbookFactory.create(file.getInputStream())) {
Sheet sheet = workbook.getSheetAt(0);
int headerRowIndex = -1;
Map<String, Integer> colMap = new HashMap<>();
// find header row with required columns
for (int i = 0; i <= 5; i++) {
Row row = sheet.getRow(i);
if (row == null) continue;
for (int j = 0; j < row.getLastCellNum(); j++) {
Cell cell = row.getCell(j);
if (cell == null || cell.getCellType() != CellType.STRING) continue;
String val = cell.getStringCellValue().trim().toLowerCase();
if (val.equals("sku")) colMap.put("erpCode", j);
else if (val.contains("anglais")) colMap.put("enName", j);
else if (val.contains("chinois")) colMap.put("zhName", j);
else if (val.contains("stock dispo")) colMap.put("stock", j);
else if (val.contains("wia")) colMap.put("purchaseWIA", j);
else if (val.contains("shopify")) colMap.put("shopifyOrder", j);
else if (val.contains("stock") && val.matches(".*\\d{2}/\\d{2}.*")) colMap.put("stockDate", j);
else if (val.contains("quantité") || val.contains("quantity")) colMap.put("quantity", j);
else if (val.contains("ventes 7")) colMap.put("sales7d", j);
else if (val.contains("ventes 28")) colMap.put("sales28d", j);
else if (val.contains("ventes 42")) colMap.put("sales42d", j);
else if (val.contains("price")) colMap.put("skuPrice", j);
}
if (!colMap.isEmpty()) {
headerRowIndex = i;
break;
}
}
if (headerRowIndex == -1 || !colMap.containsKey("erpCode") || !colMap.containsKey("quantity")) {
throw new RuntimeException("Missing required columns: SKU and Quantity");
}
// parse data rows
for (int i = headerRowIndex + 1; i <= sheet.getLastRowNum(); i++) {
Row row = sheet.getRow(i);
if (row == null) continue;
Map<String, Object> sku = new HashMap<>();
for (Map.Entry<String, Integer> entry : colMap.entrySet()) {
String key = entry.getKey();
int col = entry.getValue();
Cell cell = row.getCell(col);
if (cell == null) continue;
Object value = null;
if (cell.getCellType() == CellType.NUMERIC) {
value = key.equals("erpCode")
? new BigDecimal(cell.getNumericCellValue()).toPlainString().trim()
: cell.getNumericCellValue();
} else {
String str = cell.toString().trim();
if (Arrays.asList("quantity", "sales7d", "sales28d", "sales42d", "skuPrice", "stock", "purchaseWIA", "shopifyOrder", "stockDate").contains(key)) {
try {
value = Double.parseDouble(str);
} catch (NumberFormatException ignored) {}
} else {
value = str;
}
}
sku.put(key, value);
}
// Only add SKUs with positive quantity and positive price
Object qtyObj = sku.get("quantity");
if (qtyObj instanceof Number && ((Number) qtyObj).doubleValue() > 0) {
result.add(sku);
}
}
log.info("Parsed Excel SKU list: {}", result);
} catch (Exception e) {
log.error("Excel parsing failed", e);
throw new RuntimeException("Excel parsing error: " + e.getMessage(), e);
}
return result;
}
} }

View File

@ -85,6 +85,12 @@ public class SkuOrderPage {
@Excel(name = "stock", width = 15) @Excel(name = "stock", width = 15)
@ApiModelProperty(value = "stock") @ApiModelProperty(value = "stock")
private Integer stock; private Integer stock;
/**
*
*/
@Excel(name = "qty à acheter", width = 15)
@ApiModelProperty("用户要采购的数量")
private Integer qtyToBuy = 0;
/** /**
* *
*/ */