mirror of https://github.com/jeecgboot/jeecg-boot
Merge pull request #167 from LQYBill/feat/Reconstruct_Sku_price
Feat/reconstruct SKU pricepull/8523/head
commit
39cdc592e6
|
@ -4,9 +4,10 @@ SELECT id AS price_id,
|
|||
price AS price,
|
||||
threshold AS threshold,
|
||||
discounted_price AS discounted_price,
|
||||
price_rmb AS price_rmb,
|
||||
discounted_price_rmb AS discounted_price_rmb,
|
||||
currency_id AS currency_id,
|
||||
date AS date
|
||||
FROM sku_price sp
|
||||
INNER JOIN (SELECT sku_id, MAX(date) max_date FROM sku_price GROUP BY sku_id) sp2
|
||||
INNER JOIN (SELECT sku_id, MAX(date) max_date FROM sku_price
|
||||
where DATE(date) <= CURRENT_DATE
|
||||
GROUP BY sku_id) sp2
|
||||
ON sp.sku_id = sp2.sku_id AND sp.date = sp2.max_date
|
|
@ -12,8 +12,7 @@ SELECT s.id AS sku_id,
|
|||
scp.price AS price,
|
||||
scp.threshold AS threshold,
|
||||
scp.discounted_price AS discounted_price,
|
||||
scp.price_rmb AS price_rmb,
|
||||
scp.discounted_price_rmb AS discounted_price_rmb
|
||||
scp.currency_id AS currency_id
|
||||
FROM sku s
|
||||
LEFT JOIN sku_promotion_relation spr ON s.id = spr.sku_id
|
||||
LEFT JOIN sku_current_price scp ON s.id = scp.sku_id
|
||||
|
|
|
@ -195,16 +195,6 @@ public class MybatisInterceptor implements Interceptor {
|
|||
eventPublisher.publishEvent(new SkuModifiedEvent(this, id, "UPDATE"));
|
||||
}
|
||||
}
|
||||
if(table.equals("sku_price")) {
|
||||
if(operationStatus.equals(INSERT_SUCCESS_MSG)) {
|
||||
String id = extractIdFromRequestParam(requestParam);
|
||||
eventPublisher.publishEvent(new SkuPriceModifiedEvent(this, id, "INSERT"));
|
||||
}
|
||||
if(operationStatus.equals(UPDATE_SUCCESS_MSG)) {
|
||||
String id = extractIdFromRequestParam(requestParam);
|
||||
eventPublisher.publishEvent(new SkuPriceModifiedEvent(this, id, "UPDATE"));
|
||||
}
|
||||
}
|
||||
if(table.equals("sku_declared_value")) {
|
||||
if(operationStatus.equals(INSERT_SUCCESS_MSG)) {
|
||||
String id = extractIdFromRequestParam(requestParam);
|
||||
|
|
|
@ -0,0 +1,380 @@
|
|||
package org.jeecg.modules.business.controller.admin;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||
import org.jeecg.common.system.base.controller.JeecgController;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
import org.jeecg.common.system.vo.LoginUser;
|
||||
import org.jeecg.modules.business.entity.Sku;
|
||||
import org.jeecg.modules.business.entity.SkuPrice;
|
||||
import org.jeecg.modules.business.model.SkuDocument;
|
||||
import org.jeecg.modules.business.mongoService.SkuMongoService;
|
||||
import org.jeecg.modules.business.service.ICurrencyService;
|
||||
import org.jeecg.modules.business.service.ISecurityService;
|
||||
import org.jeecg.modules.business.service.ISkuPriceService;
|
||||
import org.jeecg.modules.business.service.ISkuService;
|
||||
import org.jeecg.modules.business.util.DateUtils;
|
||||
import org.jeecg.modules.business.vo.ResponsesWithMsg;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* @Description: sku_price
|
||||
* @Author: jeecg-boot
|
||||
* @Date: 2025-05-12
|
||||
* @Version: V1.0
|
||||
*/
|
||||
@Api(tags="sku_price")
|
||||
@RestController
|
||||
@RequestMapping("/skuprice")
|
||||
@Slf4j
|
||||
public class SkuPriceController extends JeecgController<SkuPrice, ISkuPriceService> {
|
||||
@Autowired
|
||||
private ISkuPriceService skuPriceService;
|
||||
@Autowired
|
||||
private ISecurityService securityService;
|
||||
@Autowired
|
||||
private ISkuService skuService;
|
||||
@Autowired
|
||||
private ICurrencyService currencyService;
|
||||
@Autowired
|
||||
private SkuMongoService skuMongoService;
|
||||
@Autowired
|
||||
private MongoTemplate mongoTemplate;
|
||||
|
||||
/**
|
||||
* 分页列表查询
|
||||
*
|
||||
* @param skuPrice
|
||||
* @param pageNo
|
||||
* @param pageSize
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
//@AutoLog(value = "SKU售价-分页列表查询")
|
||||
@ApiOperation(value="SKU售价-分页列表查询", notes="SKU售价-分页列表查询")
|
||||
@GetMapping(value = "/list")
|
||||
public Result<IPage<SkuPrice>> queryPageList(SkuPrice skuPrice,
|
||||
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
|
||||
@RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
|
||||
HttpServletRequest req) {
|
||||
QueryWrapper<SkuPrice> queryWrapper = QueryGenerator.initQueryWrapper(skuPrice, req.getParameterMap());
|
||||
Page<SkuPrice> page = new Page<>(pageNo, pageSize);
|
||||
IPage<SkuPrice> pageList = skuPriceService.page(page, queryWrapper);
|
||||
return Result.OK(pageList);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加
|
||||
*
|
||||
* @param skuPrice
|
||||
* @return
|
||||
*/
|
||||
// @AutoLog(value = "SKU售价-添加")
|
||||
@ApiOperation(value="SKU售价-添加", notes="SKU售价-添加")
|
||||
// @RequiresPermissions("skuprice:sku_price:add")
|
||||
@PostMapping(value = "/add")
|
||||
public Result<String> add(@RequestBody SkuPrice skuPrice) {
|
||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
boolean isEmployee = securityService.checkIsEmployee();
|
||||
if (!isEmployee) {
|
||||
log.warn("Unauthorized add attempt by user: {}", sysUser.getUsername());
|
||||
return Result.error(403, "无权限添加 SKU 售价数据");
|
||||
}
|
||||
//unique index on sku_id and date
|
||||
skuPrice.setDate(DateUtils.setToEuropeMorning8(skuPrice.getDate()));
|
||||
QueryWrapper<SkuPrice> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("sku_id", skuPrice.getSkuId());
|
||||
wrapper.eq("date", skuPrice.getDate());
|
||||
boolean exists = skuPriceService.count(wrapper) > 0;
|
||||
if (exists) {
|
||||
return Result.error("已存在相同 SKU 和日期的记录,不能重复添加。");
|
||||
}
|
||||
//duplicate content check(except date)
|
||||
List<SkuPrice> existingList = skuPriceService.list(new QueryWrapper<SkuPrice>()
|
||||
.eq("sku_id", skuPrice.getSkuId()));
|
||||
|
||||
boolean sameContentExists = existingList.stream().anyMatch(existing ->
|
||||
existing.getPrice().compareTo(skuPrice.getPrice()) == 0 &&
|
||||
existing.getDiscountedPrice().compareTo(skuPrice.getDiscountedPrice()) == 0 &&
|
||||
existing.getThreshold().equals(skuPrice.getThreshold()) &&
|
||||
existing.getCurrencyId().equals(skuPrice.getCurrencyId())
|
||||
);
|
||||
if (sameContentExists) {
|
||||
return Result.error("相同内容的售价记录已存在,仅日期不同,请勿重复添加。");
|
||||
}
|
||||
|
||||
skuPrice.setCreateBy(sysUser.getUsername());
|
||||
skuPrice.setCreateTime(new Date());
|
||||
skuPriceService.save(skuPrice);
|
||||
skuMongoService.upsertSkuPrice(skuPrice);
|
||||
return Result.OK("添加成功!");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量删除
|
||||
*
|
||||
* @param ids
|
||||
* @return
|
||||
*/
|
||||
@AutoLog(value = "SKU售价-批量删除")
|
||||
@ApiOperation(value="SKU售价-批量删除", notes="SKU售价-批量删除")
|
||||
// @RequiresPermissions("skuprice:sku_price:deleteBatch")
|
||||
@DeleteMapping(value = "/deleteBatch")
|
||||
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
|
||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
boolean isEmployee = securityService.checkIsEmployee();
|
||||
if (!isEmployee) {
|
||||
log.warn("Unauthorized import attempt by user: {}", sysUser.getUsername());
|
||||
return Result.error(403, "无权限执行导入操作");
|
||||
}
|
||||
List<String> idList = Arrays.asList(ids.split(","));
|
||||
List<SkuPrice> pricesToDelete = skuPriceService.listByIds(idList);
|
||||
// delete from MySQL
|
||||
skuPriceService.removeByIds(idList);
|
||||
// check if the deleted prices are the latest ones in MongoDB
|
||||
for (SkuPrice deleted : pricesToDelete) {
|
||||
String skuId = deleted.getSkuId();
|
||||
Date deletedDate = deleted.getDate();
|
||||
Query query = new Query(Criteria.where("skuId").is(skuId));
|
||||
SkuDocument doc = mongoTemplate.findOne(query, SkuDocument.class);
|
||||
boolean isLatestDeleted = doc != null
|
||||
&& doc.getLatestSkuPrice() != null
|
||||
&& deletedDate.equals(doc.getLatestSkuPrice().getDate());
|
||||
if (isLatestDeleted) {
|
||||
skuMongoService.deleteSkuPriceBySkuId(skuId);
|
||||
List<SkuPrice> remainingPrices = skuPriceService.list(
|
||||
new QueryWrapper<SkuPrice>()
|
||||
.eq("sku_id", skuId)
|
||||
.orderByDesc("date")
|
||||
);
|
||||
// if there are remaining prices, update the latest price in MongoDB
|
||||
if (!remainingPrices.isEmpty()) {
|
||||
log.info("Updating latest SKU price for SKU {} to {}", skuId, remainingPrices.get(0));
|
||||
skuMongoService.upsertSkuPrice(remainingPrices.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
log.info("Deleted SKU prices: {}", pricesToDelete);
|
||||
return Result.OK("批量删除成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过id查询
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
//@AutoLog(value = "SKU售价-通过id查询")
|
||||
@ApiOperation(value="SKU售价-通过id查询", notes="SKU售价-通过id查询")
|
||||
@GetMapping(value = "/queryById")
|
||||
public Result<SkuPrice> queryById(@RequestParam(name="id",required=true) String id) {
|
||||
SkuPrice skuPrice = skuPriceService.getById(id);
|
||||
if(skuPrice==null) {
|
||||
return Result.error("未找到对应数据");
|
||||
}
|
||||
return Result.OK(skuPrice);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出excel
|
||||
*
|
||||
* @param request
|
||||
* @param skuPrice
|
||||
*/
|
||||
// @RequiresPermissions("skuprice:sku_price:exportXls")
|
||||
@RequestMapping(value = "/exportXls")
|
||||
public ModelAndView exportXls(HttpServletRequest request, SkuPrice skuPrice) {
|
||||
return super.exportXls(request, skuPrice, SkuPrice.class, "SKU售价");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 通过excel导入数据
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
|
||||
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
boolean isEmployee = securityService.checkIsEmployee();
|
||||
if (!isEmployee) {
|
||||
log.warn("Unauthorized import attempt by user: {}", sysUser.getUsername());
|
||||
return Result.error(403, "无权限执行导入操作");
|
||||
}
|
||||
log.info("Importing Sku Prices from Excel...");
|
||||
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
|
||||
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
|
||||
ResponsesWithMsg<String> responses = new ResponsesWithMsg<>();
|
||||
List<SkuPrice> skuPrices = new ArrayList<>();
|
||||
//support multiple files
|
||||
for (Map.Entry<String, MultipartFile> entry : fileMap.entrySet()) {
|
||||
MultipartFile file = entry.getValue();
|
||||
try (InputStream inputStream = file.getInputStream()) {
|
||||
Workbook workbook = file.getOriginalFilename().endsWith(".xlsx")
|
||||
? new XSSFWorkbook(inputStream)
|
||||
: new HSSFWorkbook(inputStream);
|
||||
Sheet sheet = workbook.getSheetAt(0);
|
||||
int startRow = sheet.getFirstRowNum();
|
||||
int lastRow = sheet.getLastRowNum();
|
||||
|
||||
// find the first row with valid SKU
|
||||
for (; startRow <= lastRow; startRow++) {
|
||||
Row testRow = sheet.getRow(startRow);
|
||||
if (testRow == null) continue;
|
||||
Cell skuCell = testRow.getCell(0, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
|
||||
String skuCode = skuCell.getStringCellValue().trim();
|
||||
if (!skuCode.isEmpty() && skuService.getByErpCode(skuCode) != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int rowIndex = startRow; rowIndex <= lastRow; rowIndex++) {
|
||||
Row row = sheet.getRow(rowIndex);
|
||||
if (row == null) continue;
|
||||
SkuPrice skuPrice = new SkuPrice();
|
||||
boolean hasError = false;
|
||||
String erpCode = null;
|
||||
|
||||
for (int cellIndex = 0; cellIndex <= 5; cellIndex++) {
|
||||
Cell cell = row.getCell(cellIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
|
||||
|
||||
try {
|
||||
switch (cellIndex) {
|
||||
case 0: // SKU
|
||||
erpCode = cell.getStringCellValue().trim();
|
||||
Sku sku = skuService.getByErpCode(erpCode);
|
||||
if (sku == null) {
|
||||
responses.addFailure("Row " + rowIndex + ": Invalid SKU: " + erpCode);
|
||||
hasError = true;
|
||||
} else {
|
||||
skuPrice.setSkuId(sku.getId());
|
||||
}
|
||||
break;
|
||||
case 1: // Price
|
||||
BigDecimal price;
|
||||
if (cell.getCellType() == CellType.NUMERIC) {
|
||||
price = BigDecimal.valueOf(cell.getNumericCellValue());
|
||||
} else {
|
||||
price = new BigDecimal(cell.getStringCellValue().trim());
|
||||
}
|
||||
skuPrice.setPrice(price);
|
||||
break;
|
||||
case 2: // Threshold
|
||||
int threshold;
|
||||
if (cell.getCellType() == CellType.NUMERIC) {
|
||||
threshold = (int) cell.getNumericCellValue();
|
||||
} else {
|
||||
threshold = Integer.parseInt(cell.getStringCellValue().trim());
|
||||
}
|
||||
skuPrice.setThreshold(threshold);
|
||||
break;
|
||||
case 3: // Discounted Price
|
||||
BigDecimal discountedPrice;
|
||||
if (cell.getCellType() == CellType.NUMERIC) {
|
||||
discountedPrice = BigDecimal.valueOf(cell.getNumericCellValue());
|
||||
} else {
|
||||
discountedPrice = new BigDecimal(cell.getStringCellValue().trim());
|
||||
}
|
||||
skuPrice.setDiscountedPrice(discountedPrice);
|
||||
break;
|
||||
case 4: // Date
|
||||
Date effectiveDate;
|
||||
if (cell.getCellType() == CellType.NUMERIC) {
|
||||
effectiveDate = cell.getDateCellValue();
|
||||
effectiveDate = DateUtils.setToEuropeMorning8(effectiveDate);
|
||||
log.info("Effective date: {}", effectiveDate);
|
||||
} else {
|
||||
effectiveDate = new SimpleDateFormat("yyyy-MM-dd").parse(cell.getStringCellValue().trim());
|
||||
}
|
||||
skuPrice.setDate(effectiveDate);
|
||||
break;
|
||||
case 5: // Currency
|
||||
String currencyCode = cell.getStringCellValue().trim();
|
||||
String currencyId = currencyService.getIdByCode(currencyCode);
|
||||
if (currencyId == null) {
|
||||
responses.addFailure("Row " + (rowIndex+1), ": 无效币种代码: " + currencyCode);
|
||||
hasError = true;
|
||||
} else {
|
||||
skuPrice.setCurrencyId(currencyId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
responses.addFailure("Row " + (rowIndex+1), " Failure at column " + cellIndex + ": " + ex.getMessage());
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasError) {
|
||||
QueryWrapper<SkuPrice> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("sku_id", skuPrice.getSkuId());
|
||||
List<SkuPrice> existingPrices = skuPriceService.list(wrapper);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
String newDateStr = sdf.format(skuPrice.getDate());
|
||||
boolean sameSkuAndDateExists = existingPrices.stream()
|
||||
.anyMatch(existing -> sdf.format(existing.getDate()).equals(newDateStr));
|
||||
if (sameSkuAndDateExists) {
|
||||
responses.addSuccess("Row " + (rowIndex+1), ": 已存在相同 SKU + 日期,跳过导入");
|
||||
continue;
|
||||
}
|
||||
boolean sameContentExists = existingPrices.stream().anyMatch(existing ->
|
||||
existing.getPrice().compareTo(skuPrice.getPrice()) == 0 &&
|
||||
existing.getDiscountedPrice().compareTo(skuPrice.getDiscountedPrice()) == 0 &&
|
||||
existing.getThreshold().equals(skuPrice.getThreshold()) &&
|
||||
existing.getCurrencyId().equals(skuPrice.getCurrencyId())
|
||||
);
|
||||
if (sameContentExists) {
|
||||
responses.addSuccess("Row " + (rowIndex+1), ": 与已有记录内容相同,仅日期不同,跳过导入");
|
||||
continue;
|
||||
}
|
||||
skuPrices.add(skuPrice);
|
||||
skuMongoService.upsertSkuPrice(skuPrice);
|
||||
responses.addSuccess("Row " + (rowIndex+1), ": 导入成功。ERP: " + erpCode);
|
||||
}
|
||||
}
|
||||
if (skuPrices.isEmpty()) {
|
||||
Result<Object> result = Result.error("导入失败:未找到任何有效数据行。");
|
||||
result.setResult(responses);
|
||||
return result;
|
||||
}
|
||||
skuPriceService.saveBatch(skuPrices);
|
||||
} catch (Exception e) {
|
||||
log.error("导入失败", e);
|
||||
return Result.error("导入失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
return Result.OK(responses);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -48,6 +48,7 @@ import java.net.URISyntaxException;
|
|||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -103,6 +104,8 @@ public class InvoiceController {
|
|||
@Autowired
|
||||
private ISkuService skuService;
|
||||
@Autowired
|
||||
private ISkuPriceService skuPriceService;
|
||||
@Autowired
|
||||
private IExchangeRatesService iExchangeRatesService;
|
||||
@Autowired
|
||||
private IQuartzJobService quartzJobService;
|
||||
|
@ -152,7 +155,7 @@ public class InvoiceController {
|
|||
Set<String> skuIds = orderContents.stream().map(PlatformOrderContent::getSkuId).collect(Collectors.toSet());
|
||||
List<String> skusWithoutPrice = platformOrderContentMap.searchSkuDetail(new ArrayList<>(skuIds))
|
||||
.stream()
|
||||
.filter(skuDetail -> skuDetail.getPrice().getPrice() == null && skuDetail.getPrice().getPriceRmb() == null)
|
||||
.filter(skuDetail -> skuDetail.getPrice() == null || skuDetail.getPrice().getPrice()== null)
|
||||
.map(SkuDetail::getErpCode)
|
||||
.collect(Collectors.toList());
|
||||
if (skusWithoutPrice.isEmpty()) {
|
||||
|
@ -948,14 +951,23 @@ public class InvoiceController {
|
|||
break;
|
||||
}
|
||||
}
|
||||
Date today = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
for(PlatformOrderContent content : orderContents){
|
||||
for (SkuPrice skuPrice : skuPrices) {
|
||||
if(content.getSkuId().equals(skuPrice.getSkuId())) {
|
||||
BigDecimal price = skuPrice.getPrice(content.getQuantity(), exchangeRateEurToRmb);
|
||||
price = price.multiply(new BigDecimal(content.getQuantity()));
|
||||
purchaseEstimation = purchaseEstimation.add(price);
|
||||
break;
|
||||
}
|
||||
Optional<SkuPrice> matched = skuPrices.stream()
|
||||
.filter(p -> content.getSkuId().equals(p.getSkuId()))
|
||||
.filter(p -> p.getDate() != null && !p.getDate().after(today))
|
||||
.max(Comparator.comparing(SkuPrice::getDate));
|
||||
log.info("Can't be after today: {} - {}", content.getSkuId(), matched.isPresent() ? matched.get().getDate() : "null");
|
||||
if (matched.isPresent()) {
|
||||
SkuPrice skuPrice = matched.get();
|
||||
BigDecimal price = skuPriceService.getPrice(skuPrice, content.getQuantity(), exchangeRateEurToRmb);
|
||||
price = price.multiply(BigDecimal.valueOf(content.getQuantity()));
|
||||
purchaseEstimation = purchaseEstimation.add(price);
|
||||
log.info("Matched SKU: {}, Qty: {}, Final Price: {}", content.getSkuId(), content.getQuantity(), price);
|
||||
} else {
|
||||
isCompleteInvoiceReady = false;
|
||||
errorMessages.add("No valid price for SKU: " + content.getSkuId());
|
||||
log.warn("No valid price for SKU: {}", content.getSkuId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ public class TransactionController {
|
|||
@Autowired
|
||||
private IShopService shopService;
|
||||
@Autowired
|
||||
private ISkuPriceService skuPriceService;
|
||||
@Autowired
|
||||
PlatformOrderContentMapper platformOrderContentMapper;
|
||||
@Autowired
|
||||
ExchangeRatesMapper exchangeRatesMapper;
|
||||
|
@ -118,7 +120,7 @@ public class TransactionController {
|
|||
for (PlatformOrderContent content : orderContents) {
|
||||
for (SkuPrice skuPrice : skuPrices) {
|
||||
if (content.getSkuId().equals(skuPrice.getSkuId())) {
|
||||
purchaseEstimation = purchaseEstimation.add(skuPrice.getPrice(content.getQuantity(), exchangeRateEurToRmb));
|
||||
purchaseEstimation = purchaseEstimation.add(skuPriceService.getPrice(skuPrice, content.getQuantity(), exchangeRateEurToRmb));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.jeecg.modules.business.entity;
|
|||
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jeecg.modules.business.service.ISkuPriceService;
|
||||
import org.jeecg.modules.business.vo.SkuDetail;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
@ -21,6 +22,8 @@ public class OrderContentDetail {
|
|||
|
||||
private final BigDecimal exchangeRate;
|
||||
|
||||
private final ISkuPriceService skuPriceService;
|
||||
|
||||
/**
|
||||
* Calculate the reduced amount by applying the promotion to the sku.
|
||||
*
|
||||
|
@ -37,7 +40,7 @@ public class OrderContentDetail {
|
|||
* @return the total price (price * quantity)
|
||||
*/
|
||||
public BigDecimal totalPrice() {
|
||||
BigDecimal unit = skuDetail.getPrice().getPrice(quantity, exchangeRate);
|
||||
BigDecimal unit = skuPriceService.getPrice(skuDetail.getPrice(), quantity, exchangeRate);
|
||||
BigDecimal total = unit.multiply(new BigDecimal(quantity));
|
||||
log.info("unit: {}", unit);
|
||||
log.info("total: {}", total);
|
||||
|
@ -45,7 +48,7 @@ public class OrderContentDetail {
|
|||
}
|
||||
|
||||
public BigDecimal unitPrice(){
|
||||
return skuDetail.getPrice().getPrice(quantity, exchangeRate);
|
||||
return skuPriceService.getPrice(skuDetail.getPrice(), quantity, exchangeRate);
|
||||
}
|
||||
|
||||
public int promotionCount() {
|
||||
|
|
|
@ -63,9 +63,10 @@ public class SkuPrice implements Serializable {
|
|||
/**
|
||||
* SKU ID
|
||||
*/
|
||||
@Excel(name = "SKU ID", width = 15, dictTable = "sku", dicText = "erp_code", dicCode = "id")
|
||||
@Dict(dictTable = "sku", dicText = "erp_code", dicCode = "id")
|
||||
@ApiModelProperty(value = "SKU ID")
|
||||
private String skuId;
|
||||
private java.lang.String skuId;
|
||||
/**
|
||||
* 价格
|
||||
*/
|
||||
|
@ -93,40 +94,13 @@ public class SkuPrice implements Serializable {
|
|||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
@ApiModelProperty(value = "生效日期")
|
||||
private Date date;
|
||||
/**
|
||||
* 人民币价格
|
||||
*/
|
||||
@Excel(name = "人民币价格", width = 15)
|
||||
@ApiModelProperty(value = "人民币价格")
|
||||
private java.math.BigDecimal priceRmb;
|
||||
/**
|
||||
* 人民币优惠价
|
||||
*/
|
||||
@Excel(name = "人民币优惠价", width = 15)
|
||||
@ApiModelProperty(value = "人民币优惠价")
|
||||
private java.math.BigDecimal discountedPriceRmb;
|
||||
|
||||
/**
|
||||
* The price of a sku depends on its quantity, Given a quantity here, return the correspondent price.
|
||||
*
|
||||
* @param quantity a quantity
|
||||
* @param eurToRmb Exchange rate from EUR to RMB
|
||||
* @return the price correspondent to the quantity
|
||||
*/
|
||||
public BigDecimal getPrice(int quantity, BigDecimal eurToRmb) {
|
||||
BigDecimal priceCandidate = price;
|
||||
BigDecimal discountedPriceCandidate = discountedPrice == null ? price : discountedPrice;
|
||||
if (priceRmb != null) {
|
||||
priceCandidate = priceRmb.divide(eurToRmb, RoundingMode.HALF_UP);
|
||||
discountedPriceCandidate = discountedPriceRmb == null ? priceCandidate : discountedPriceRmb.divide(eurToRmb, RoundingMode.HALF_UP);
|
||||
}
|
||||
if (threshold != null && quantity >= threshold) {
|
||||
return discountedPriceCandidate;
|
||||
}
|
||||
return priceCandidate;
|
||||
}
|
||||
/**币种ID*/
|
||||
@Excel(name = "币种ID", width = 15, dictTable = "currency", dicText = "code", dicCode = "id")
|
||||
@Dict(dictTable = "currency", dicText = "code", dicCode = "id")
|
||||
@ApiModelProperty(value = "币种ID")
|
||||
private java.lang.String currencyId;
|
||||
|
||||
public String toString() {
|
||||
return String.format("%s, %s[%d], %s(RMB), %s[%d](RMB)", price, discountedPrice, threshold, priceRmb, discountedPriceRmb, threshold);
|
||||
return String.format("%s, %s[%d]", price, discountedPrice, threshold);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
WHERE sku_id = #{mainId}
|
||||
</select>
|
||||
<select id="getLatestBySkuId" resultType="org.jeecg.modules.business.entity.SkuPrice">
|
||||
SELECT date, price, threshold, discounted_price, price_rmb, discounted_price_rmb
|
||||
SELECT date, price, threshold, discounted_price, currency_id
|
||||
FROM sku_price
|
||||
WHERE sku_id = #{skuId}
|
||||
ORDER BY date DESC
|
||||
|
|
|
@ -97,8 +97,9 @@ public class SkuDocument {
|
|||
* effective date
|
||||
*/
|
||||
private Date date;
|
||||
private BigDecimal priceRmb;
|
||||
private BigDecimal discountedPriceRmb;
|
||||
|
||||
private String currencyCode;
|
||||
|
||||
}
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
|
|
|
@ -96,33 +96,6 @@ public class SkuMongoSyncService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens to an event fired by MyBatisInterceptor in jeecg-boot-base-core
|
||||
* /!\ the id in event SHOULD be a sku_price ID.
|
||||
* The condition being if no mapper method uses other criteria to delete a sku_price
|
||||
* @param event contains the sku_price ID and the operation type (INSERT, UPDATE, DELETE)
|
||||
*/
|
||||
@EventListener
|
||||
public void handleSkuPriceModifiedEvent(SkuPriceModifiedEvent event) {
|
||||
log.info("Received a SkuPriceModifiedEvent: {}", event);
|
||||
String id = event.getId();
|
||||
String operation = event.getOperation();
|
||||
|
||||
SkuPrice skuPrice = skuPriceService.getById(id);
|
||||
|
||||
switch (operation) {
|
||||
case "INSERT":
|
||||
case "UPDATE":
|
||||
skuMongoService.upsertSkuPrice(skuPrice);
|
||||
break;
|
||||
case "DELETE":
|
||||
skuMongoService.deleteSkuPriceBySkuId(skuPrice.getSkuId());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@EventListener
|
||||
public void handeSkuWeightModifiedEvent(SkuWeightModifiedEvent event) {
|
||||
log.info("Received a SkuWeightModifiedEvent: {}", event);
|
||||
|
|
|
@ -36,6 +36,8 @@ public class SkuMongoServiceImpl implements SkuMongoService {
|
|||
@Autowired
|
||||
private ISkuPriceService skuPriceService;
|
||||
@Autowired
|
||||
private ICurrencyService currencyService;
|
||||
@Autowired
|
||||
private ISensitiveAttributeService sensitiveAttributeService;
|
||||
|
||||
@Override
|
||||
|
@ -72,13 +74,14 @@ public class SkuMongoServiceImpl implements SkuMongoService {
|
|||
log.error("Cannot insert or update SkuPrice of Sku Mongo Document, SkuDocument with skuId was {} not found.", price.getSkuId());
|
||||
throw new RuntimeException("SkuDocument with skuId: " + price.getSkuId() + " not found");
|
||||
}
|
||||
Currency currency = currencyService.getById(price.getCurrencyId());
|
||||
String currencyCode = currency != null ? currency.getCode() : "UNKNOWN";
|
||||
SkuDocument.LatestSkuPrice skuPrice = SkuDocument.LatestSkuPrice.builder()
|
||||
.date(price.getDate())
|
||||
.price(price.getPrice())
|
||||
.discountedPrice(price.getDiscountedPrice())
|
||||
.threshold(price.getThreshold())
|
||||
.priceRmb(price.getPriceRmb())
|
||||
.discountedPriceRmb(price.getDiscountedPriceRmb())
|
||||
.currencyCode(currencyCode)
|
||||
.build();
|
||||
|
||||
mongoTemplate.update(SkuDocument.class)
|
||||
|
@ -376,13 +379,14 @@ public class SkuMongoServiceImpl implements SkuMongoService {
|
|||
);
|
||||
}
|
||||
if(latestPrice != null) {
|
||||
Currency currency = currencyService.getById(latestPrice.getCurrencyId());
|
||||
String currencyCode = currency != null ? currency.getCode() : "UNKNOWN";
|
||||
skuDocument.setLatestSkuPrice(SkuDocument.LatestSkuPrice.builder()
|
||||
.date(latestPrice.getDate())
|
||||
.price(latestPrice.getPrice())
|
||||
.discountedPrice(latestPrice.getDiscountedPrice())
|
||||
.threshold(latestPrice.getThreshold())
|
||||
.priceRmb(latestPrice.getPriceRmb())
|
||||
.discountedPriceRmb(latestPrice.getDiscountedPriceRmb())
|
||||
.currencyCode(currencyCode)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.jeecg.modules.business.service;
|
|||
|
||||
import org.jeecg.modules.business.entity.SkuPrice;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
@ -15,4 +16,6 @@ public interface ISkuPriceService extends IService<SkuPrice> {
|
|||
List<SkuPrice> selectByMainId(String mainId);
|
||||
|
||||
SkuPrice getLatestBySkuId(String sku_id);
|
||||
|
||||
BigDecimal getPrice(SkuPrice skuPrice, int quantity, BigDecimal eurToRmb);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.jeecg.modules.business.mapper.PlatformOrderMapper;
|
|||
import org.jeecg.modules.business.service.IClientService;
|
||||
import org.jeecg.modules.business.service.IPlatformOrderService;
|
||||
import org.jeecg.modules.business.service.IShippingFeesWaiverProductService;
|
||||
import org.jeecg.modules.business.service.ISkuPriceService;
|
||||
import org.jeecg.modules.business.vo.*;
|
||||
import org.jeecg.modules.business.vo.clientPlatformOrder.ClientPlatformOrderPage;
|
||||
import org.jeecg.modules.business.vo.clientPlatformOrder.PurchaseConfirmation;
|
||||
|
@ -58,6 +59,8 @@ public class PlatformOrderServiceImpl extends ServiceImpl<PlatformOrderMapper, P
|
|||
private IClientService clientService;
|
||||
@Autowired
|
||||
private ExchangeRatesMapper exchangeRatesMapper;
|
||||
@Autowired
|
||||
private ISkuPriceService skuPriceService;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
|
@ -246,7 +249,8 @@ public class PlatformOrderServiceImpl extends ServiceImpl<PlatformOrderMapper, P
|
|||
skuDetail -> new OrderContentDetail(
|
||||
skuDetail,
|
||||
skuQuantity.get(skuDetail.getSkuId()),
|
||||
eurToRmb
|
||||
eurToRmb,
|
||||
skuPriceService
|
||||
)
|
||||
)
|
||||
.collect(toList());
|
||||
|
|
|
@ -2,8 +2,12 @@ package org.jeecg.modules.business.service.impl;
|
|||
|
||||
import org.jeecg.modules.business.entity.SkuPrice;
|
||||
import org.jeecg.modules.business.mapper.SkuPriceMapper;
|
||||
import org.jeecg.modules.business.service.ICurrencyService;
|
||||
import org.jeecg.modules.business.service.ISkuPriceService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -19,8 +23,11 @@ public class SkuPriceServiceImpl extends ServiceImpl<SkuPriceMapper, SkuPrice> i
|
|||
|
||||
@Autowired
|
||||
private SkuPriceMapper skuPriceMapper;
|
||||
|
||||
@Override
|
||||
|
||||
@Autowired
|
||||
private ICurrencyService currencyService;
|
||||
|
||||
@Override
|
||||
public List<SkuPrice> selectByMainId(String mainId) {
|
||||
return skuPriceMapper.selectByMainId(mainId);
|
||||
}
|
||||
|
@ -29,4 +36,32 @@ public class SkuPriceServiceImpl extends ServiceImpl<SkuPriceMapper, SkuPrice> i
|
|||
public SkuPrice getLatestBySkuId(String sku_id) {
|
||||
return skuPriceMapper.getLatestBySkuId(sku_id);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The price of a sku depends on its quantity, Given a quantity here, return the correspondent price.
|
||||
* @param skuPrice SKU price object
|
||||
* @param quantity Quantity of the SKU
|
||||
* @param eurToRmb Exchange rate from EUR to RMB
|
||||
* @return The price based on the quantity
|
||||
*/
|
||||
@Override
|
||||
public BigDecimal getPrice(SkuPrice skuPrice, int quantity, BigDecimal eurToRmb) {
|
||||
String RMB_CURRENCY_CODE = "RMB";
|
||||
String rmbId = currencyService.getIdByCode(RMB_CURRENCY_CODE);
|
||||
BigDecimal priceCandidate = skuPrice.getPrice();
|
||||
BigDecimal discountPriceCandidate = skuPrice.getDiscountedPrice() == null ? priceCandidate : skuPrice.getDiscountedPrice();
|
||||
// Convert the price to EURO if the currency is RMB
|
||||
boolean isRmb = rmbId.equals(skuPrice.getCurrencyId());
|
||||
if (isRmb) {
|
||||
priceCandidate = priceCandidate.divide(eurToRmb, 2, RoundingMode.HALF_UP);
|
||||
discountPriceCandidate = discountPriceCandidate.divide(eurToRmb, 2, RoundingMode.HALF_UP);
|
||||
}
|
||||
// Get the price based on the quantity
|
||||
if (skuPrice.getThreshold() != null && quantity >= skuPrice.getThreshold()) {
|
||||
return discountPriceCandidate;
|
||||
} else {
|
||||
return priceCandidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package org.jeecg.modules.business.util;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class DateUtils {
|
||||
|
||||
public static Date setToEuropeMorning8(Date original) {
|
||||
if (original == null) return null;
|
||||
|
||||
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Paris"));
|
||||
cal.setTime(original);
|
||||
cal.set(Calendar.HOUR_OF_DAY, 8);
|
||||
cal.set(Calendar.MINUTE, 0);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
cal.set(Calendar.MILLISECOND, 0);
|
||||
return cal.getTime();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue