Browse Source

功能优化。

cangku
wangfukang 2 years ago
parent
commit
f13315cecf
  1. 3
      hiver-admin/src/main/resources/application.yml
  2. 16
      hiver-admin/test-output/test-report.html
  3. 26
      hiver-core/src/main/java/cc/hiver/core/common/utils/CommonUtil.java
  4. 2
      hiver-core/src/main/java/cc/hiver/core/serviceimpl/LogiticsCompanyServiceImpl.java
  5. 33
      hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/AuthController.java
  6. 7
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/config/thread/AiPurchaseThread.java
  7. 9
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/SaleController.java
  8. 1
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/ProductCategoryMapper.java
  9. 5
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/PurchaseDetail.java
  10. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Sale.java
  11. 6
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/SaleCopyVO.java
  12. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/SaleVO.java
  13. 28
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/ShopVo.java
  14. 23
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/purchaseocr/controller/PurchaseOcrPictureController.java
  15. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/purchaseocr/service/PurchaseOcrPictureService.java
  16. 321
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/purchaseocr/service/impl/PurchaseOcrPictureServiceImpl.java
  17. 25
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/ProductCategoryService.java
  18. 16
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/SalesCalculateServiceImpl.java
  19. 87
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/ProductCategoryServiceImpl.java
  20. 21
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/PurchaseServiceImpl.java
  21. 5
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/SaleServiceImpl.java
  22. 1
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/StockServiceImpl.java
  23. 262
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/AliOcrUtil.java
  24. 2
      hiver-modules/hiver-mall/src/main/resources/mapper/OperatingAreaMapper.xml
  25. 21
      hiver-modules/hiver-mall/src/main/resources/mapper/SaleMapper.xml

3
hiver-admin/src/main/resources/application.yml

@ -314,12 +314,11 @@ ignored:
- /hiver/app/sale/savePresale
- /hiver/app/productShare/getShareList
- /hiver/app/productAttribute/selectAttributeAndValueByCategoryId
- /hiver/app/stock/productCount
# 选择物流公司
- /hiver/app/logitics/chooseCompany
# # 临时增加
- /hiver/purchaseOcrPicture/batchSave
- /hiver/app/purchase/getPurchaseAllDataOfAi
# 限流及黑名单不拦截的路径
limitUrls:

16
hiver-admin/test-output/test-report.html

@ -35,7 +35,7 @@
<a href="#"><span class="badge badge-primary">Hiver</span></a>
</li>
<li class="m-r-10">
<a href="#"><span class="badge badge-primary">十二月 18, 2023 11:51:47</span></a>
<a href="#"><span class="badge badge-primary">五月 29, 2024 14:41:12</span></a>
</li>
</ul>
</div>
@ -84,7 +84,7 @@
<div class="test-detail">
<span class="meta text-white badge badge-sm"></span>
<p class="name">passTest</p>
<p class="text-sm"><span>11:51:48 上</span> / <span>0.016 secs</span></p>
<p class="text-sm"><span>14:41:13 下</span> / <span>0.019 secs</span></p>
</div>
<div class="test-contents d-none">
<div class="detail-head">
@ -92,9 +92,9 @@
<div class="info">
<div class='float-right'><span class='badge badge-default'>#test-id=1</span></div>
<h5 class="test-status text-pass">passTest</h5>
<span class='badge badge-success'>12.18.2023 11:51:48</span>
<span class='badge badge-danger'>12.18.2023 11:51:48</span>
<span class='badge badge-default'>0.016 secs</span>
<span class='badge badge-success'>05.29.2024 14:41:13</span>
<span class='badge badge-danger'>05.29.2024 14:41:13</span>
<span class='badge badge-default'>0.019 secs</span>
</div>
<div class="m-t-10 m-l-5"></div>
</div>
@ -104,7 +104,7 @@
<tbody>
<tr class="event-row">
<td><span class="badge log pass-bg">Pass</span></td>
<td>11:51:48</td>
<td>14:41:13</td>
<td>
Test passed
</td>
@ -128,13 +128,13 @@
<div class="col-md-3">
<div class="card"><div class="card-body">
<p class="m-b-0">Started</p>
<h3>十二月 18, 2023 11:51:47</h3>
<h3>五月 29, 2024 14:41:12</h3>
</div></div>
</div>
<div class="col-md-3">
<div class="card"><div class="card-body">
<p class="m-b-0">Ended</p>
<h3>十二月 18, 2023 11:51:48</h3>
<h3>五月 29, 2024 14:41:13</h3>
</div></div>
</div>
<div class="col-md-3">

26
hiver-core/src/main/java/cc/hiver/core/common/utils/CommonUtil.java

@ -1,20 +1,24 @@
package cc.hiver.core.common.utils;
import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;
import java.security.SecureRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 常用工具
*
* @author Yazhi Li
*/
@Slf4j
public class CommonUtil {
private CommonUtil() {
throw new IllegalStateException("Utility class");
}
private static SecureRandom random = new SecureRandom();
private static final SecureRandom random = new SecureRandom();
/**
* 以UUID重命名
@ -25,7 +29,7 @@ public class CommonUtil {
public static String renamePic(String fileName) {
String extName = "";
if (fileName.contains(".")) {
extName = fileName.substring(fileName.lastIndexOf("."));
extName = fileName.substring(fileName.lastIndexOf('.'));
}
return IdUtil.simpleUUID() + extName;
}
@ -34,9 +38,9 @@ public class CommonUtil {
* 随机6位数生成
*/
public static String getRandomNum() {
int num = random.nextInt(999999);
final int num = random.nextInt(999999);
// 不足六位前面补0
String str = String.format("%06d", num);
final String str = String.format("%06d", num);
return str;
}
@ -57,4 +61,18 @@ public class CommonUtil {
}
return flag;
}
public static String getProductSn(String productSn) {
log.info("需要提取的货号为:" + productSn);
// 更精确地假设货号在"商品名称:"之后,且紧跟着的是货号,直到遇到逗号
final Pattern pattern = Pattern.compile("([\\w.-]+)");
final Matcher matcher = pattern.matcher(productSn);
if (matcher.find()) {
productSn = matcher.group();
log.info("提取后的货号为:" + productSn);
} else {
log.info(productSn + "未找到符合格式的货号");
}
return productSn;
}
}

2
hiver-core/src/main/java/cc/hiver/core/serviceimpl/LogiticsCompanyServiceImpl.java

@ -152,7 +152,7 @@ public class LogiticsCompanyServiceImpl implements LogiticsCompanyService {
Predicate[] arr = new Predicate[list.size()];
cq.where(list.toArray(arr));
cq.orderBy(cb.desc(root.<Integer>get("isOnLine")),cb.asc(root.<String>get("companyName")));
cq.orderBy(cb.desc(root.<Integer>get("isOnLine")),cb.desc(root.<Integer>get("createTime")),cb.asc(root.<String>get("companyName")));
return null;
}
});

33
hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/AuthController.java

@ -25,8 +25,10 @@ import cc.hiver.mall.entity.ShopUser;
import cc.hiver.mall.invitelog.constant.InviteLogConstant;
import cc.hiver.mall.invitelog.entity.InviteLog;
import cc.hiver.mall.invitelog.service.InviteLogService;
import cc.hiver.mall.pojo.vo.ShopVo;
import cc.hiver.mall.service.ShopService;
import cc.hiver.mall.service.ShopUserService;
import cc.hiver.mall.service.mybatis.ProductCategoryService;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.IdUtil;
import io.swagger.annotations.Api;
@ -95,6 +97,8 @@ public class AuthController {
@Autowired
private ShopUserService shopUserService;
@Autowired
private ProductCategoryService productCategoryService;
@PersistenceContext
private EntityManager entityManager;
@ -328,10 +332,10 @@ public class AuthController {
public Result register(@Valid RegisterShopVo registerShopVo) {
// 新增用户表信息
User user = new User();
if(StringUtils.isEmpty(registerShopVo.getMobile())){
if (StringUtils.isEmpty(registerShopVo.getMobile())) {
return ResultUtil.error("手机号不能为空!");
}
if(StringUtils.isEmpty(registerShopVo.getPassword())){
if (StringUtils.isEmpty(registerShopVo.getPassword())) {
return ResultUtil.error("密码不能为空!");
}
// 一个用户可存在多个店铺
@ -397,8 +401,8 @@ public class AuthController {
shopUser.setType(UserConstant.SHOP_USER_ADMIN);
shopUserService.save(shopUser);
// 判断是否传递了邀请人及邀请店铺,设置了的话,新增邀请返佣信息
if(StringUtils.isNotEmpty(registerShopVo.getInviteUserId()) && StringUtils.isNotEmpty(registerShopVo.getInviteShopId())){
InviteLog inviteLog = new InviteLog();
if (StringUtils.isNotEmpty(registerShopVo.getInviteUserId()) && StringUtils.isNotEmpty(registerShopVo.getInviteShopId())) {
final InviteLog inviteLog = new InviteLog();
inviteLog.setInviteUserId(registerShopVo.getInviteUserId());
inviteLog.setInviteShopId(registerShopVo.getInviteShopId());
inviteLog.setRegisterShopId(shop.getId());
@ -407,6 +411,8 @@ public class AuthController {
inviteLog.setIsOpen(InviteLogConstant.IS_OPEN[0]);
inviteLogService.saveInviteLog(inviteLog);
}
// 20240525 新增店铺,默认新增默认分类,颜色-均色;尺码-均码
productCategoryService.addShopDefaultCategory(shop.getId());
return ResultUtil.data(user);
}
@ -425,7 +431,11 @@ public class AuthController {
// 获取店铺的商圈
final Shop shop = shopService.get(shopId);
securityUtil.chooseShop(shopId, shop.getRegionId(), token);
return ResultUtil.success("成功选择商铺");
final ShopVo shopVo = new ShopVo();
shopVo.setShopIcon(shop.getShopIcon());
shopVo.setShopAddress(shop.getShopAddress());
shopVo.setRemark(shop.getRemark());
return new ResultUtil<ShopVo>().setData(shopVo);
}
/*
@ -453,20 +463,21 @@ public class AuthController {
/**
* 物流公司注销登录
* @author 王富康
* @date 2024/2/25
*
* @param companyId
* @param companyName
* @param response
* @return Result
* @author 王富康
* @date 2024/2/25
*/
@RequestMapping(value = "/loginOutOfCompany", method = RequestMethod.POST)
@RequestMapping(value = "/loginOutOfCompany", method = RequestMethod.POST)
@ApiOperation("物流公司注销登录")
public Result loginOutOfCompany(String companyId,String companyName, HttpServletResponse response){
if(StringUtils.isEmpty(companyId)){
public Result loginOutOfCompany(String companyId, String companyName, HttpServletResponse response) {
if (StringUtils.isEmpty(companyId)) {
return ResultUtil.error("配送公司id不能为空!");
}
if(StringUtils.isEmpty(companyName)){
if (StringUtils.isEmpty(companyName)) {
return ResultUtil.error("配送公司名称不能为空!");
}
final String key = SecurityConstant.COMPANY_TOKEN + companyId + ':' + companyName;

7
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/config/thread/AiPurchaseThread.java

@ -4,6 +4,7 @@ import cc.hiver.mall.common.constant.PurchaseConstant;
import cc.hiver.mall.purchaseocr.entity.PurchaseOcrPicture;
import cc.hiver.mall.purchaseocr.service.PurchaseOcrPictureService;
import cc.hiver.mall.purchaseocr.vo.PurchaseOcrExample;
import cc.hiver.mall.service.mybatis.ProductCategoryService;
import cc.hiver.mall.service.mybatis.ProductService;
import cc.hiver.mall.service.mybatis.PurchaseDetailService;
import cc.hiver.mall.service.mybatis.PurchaseService;
@ -31,11 +32,12 @@ public class AiPurchaseThread implements Runnable {
private PurchaseDetailService purchaseDetailService;
private PurchaseOcrPicture purchaseOcrPicture;
private PurchaseOcrExample purchaseOcrExample;
private ProductCategoryService productCategoryService;
public AiPurchaseThread() {
}
public AiPurchaseThread(String purchaseId, PurchaseOcrPicture purchaseOcrPicture,PurchaseOcrExample purchaseOcrExample, PurchaseOcrPictureService purchaseOcrPictureService, ProductService productService, PurchaseDetailService purchaseDetailService, PurchaseService purchaseService) {
public AiPurchaseThread(String purchaseId, PurchaseOcrPicture purchaseOcrPicture,PurchaseOcrExample purchaseOcrExample, PurchaseOcrPictureService purchaseOcrPictureService, ProductService productService, PurchaseDetailService purchaseDetailService, PurchaseService purchaseService,ProductCategoryService productCategoryService) {
this.purchaseId = purchaseId;
this.purchaseOcrPicture = purchaseOcrPicture;
this.purchaseOcrExample = purchaseOcrExample;
@ -43,6 +45,7 @@ public class AiPurchaseThread implements Runnable {
this.productService = productService;
this.purchaseDetailService = purchaseDetailService;
this.purchaseService = purchaseService;
this.productCategoryService = productCategoryService;
}
public static class Result {
@ -69,7 +72,7 @@ public class AiPurchaseThread implements Runnable {
log.info("当前线程名称:------------>>>>>" + Thread.currentThread().getName());
try {
log.info("正在ocr识别:" + purchaseOcrPicture.getOcrPicture() + "<br/>线程池名称:" + Thread.currentThread().getName());
jsonObject = AliOcrUtil.multiRoundConversationCall(purchaseOcrPicture,purchaseOcrExample, productService, purchaseDetailService);
jsonObject = AliOcrUtil.multiRoundConversationCall(purchaseOcrPicture,purchaseOcrExample, productService, purchaseDetailService, productCategoryService);
// 得到处理结果之后,开始新增库存的详细信息
purchaseOcrPicture.setOcrMsg(jsonObject.getString("resultContent"));
purchaseOcrPicture.setOcrStatus(PurchaseConstant.OCR_STATUS[1]);

9
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/SaleController.java

@ -31,7 +31,6 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
@ -493,8 +492,10 @@ public class SaleController {
if (saleVO == null) {
saleVO = new SaleVO();
}
startTime = saleVO.getStartTime() == null ? DateUtils.formatDate(new Date(), "yyyy-MM-dd") : saleVO.getStartTime();
endTime = saleVO.getEndTime() == null ? DateUtils.formatDate(new Date(), "yyyy-MM-dd") : saleVO.getEndTime();
final String dateText = DateUtil.COMMON.getDateText(new Date());
startTime = saleVO.getStartTime() == null ? dateText : saleVO.getStartTime();
final String tommorwText = DateUtil.getAfterDayTime(dateText, 1);
endTime = saleVO.getEndTime() == null ? tommorwText : saleVO.getEndTime();
saleAllVO = salesCalculateService.calculateService(startTime, endTime);
// 获取本周营收统计
@ -809,7 +810,7 @@ public class SaleController {
orderService.update(orderXd);
// 库存退回去
// 封装退货的信息
List<ReturnSaleDetailDTO> returnDetails = new ArrayList<>();
final List<ReturnSaleDetailDTO> returnDetails = new ArrayList<>();
final QueryWrapper<SaleDetail> queryWrapper = new QueryWrapper<>();
queryWrapper.select("product_id")
.eq("sale_id", orderId)

1
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/dao/mapper/ProductCategoryMapper.java

@ -35,4 +35,5 @@ public interface ProductCategoryMapper extends BaseMapper<ProductCategory> {
List<ProductCategoryVo> selectByShopId(String shopId);
List<ProductCategoryVo> selectByCategoryIdList(@Param("categoryIdList") List<String> categoryIdList);
}

5
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/PurchaseDetail.java

@ -36,6 +36,11 @@ public class PurchaseDetail extends HiverBaseEntity {
@ApiModelProperty(value = "商品分类")
private String categoryId;
@Transient
@TableField(exist = false)
@ApiModelProperty(value = "分类名称")
private String categoryName;
@ApiModelProperty(value = "商品属性列表")
private String attributeList;

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Sale.java

@ -77,6 +77,9 @@ public class Sale implements Serializable {
@ApiModelProperty(value = "收款状态 0-未收款 1-已收款 2-部分收款")
private String payStatus;
@ApiModelProperty(value = " 收款方式:0 现金 1微信 2支付宝 3银行卡转账 4收款码")
private String payType;
/**
* 订单状态开单
* 0待抢单

6
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/SaleCopyVO.java

@ -1,12 +1,9 @@
package cc.hiver.mall.pojo.vo;
import cc.hiver.core.common.utils.SnowFlakeUtil;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
@ -57,6 +54,9 @@ public class SaleCopyVO implements Serializable {
@ApiModelProperty(value = "收款状态 0-未收款 1-已收款 2-部分收款")
private String payStatus;
@ApiModelProperty(value = " 收款方式:0 现金 1微信 2支付宝 3银行卡转账 4收款码")
private String payType;
@ApiModelProperty(value = "订单状态 1-拣货中 2-已预定 3-已作废 4-已取货 5-已送达")
private String status;

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/SaleVO.java

@ -17,6 +17,9 @@ public class SaleVO implements Serializable {
@ApiModelProperty(value = "收款状态 0-未收款 1-已收款 2-部分收款")
private String payStatus;
@ApiModelProperty(value = " 收款方式:0 现金 1微信 2支付宝 3银行卡转账 4收款码")
private String payType;
@ApiModelProperty(value = "订单状态 1-未预定 2-已预定 3-待自提 4-已取货 5-已送达")
private String status;

28
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/ShopVo.java

@ -0,0 +1,28 @@
package cc.hiver.mall.pojo.vo;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 选择店铺之后返回一些店铺信息
* @author 王富康
* @date 2024/5/23
*/
@Data
@Accessors(chain = true)
public class ShopVo implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "店铺图标")
private String shopIcon;
@ApiModelProperty(value = "地址")
private String shopAddress;
@ApiModelProperty(value = "备注")
private String remark;
}

23
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/purchaseocr/controller/PurchaseOcrPictureController.java

@ -34,21 +34,36 @@ public class PurchaseOcrPictureController {
@RequestMapping(value = "/batchSave", method = RequestMethod.POST)
@ApiOperation("新增或编辑OCR识别信息")
public Result batchSave(@RequestBody PurchaseOciPictureAddVo purchaseOciPictureAddVo) {
JSONObject jsonObject = purchaseOcrPictureService.batchSave(purchaseOciPictureAddVo);
final JSONObject jsonObject = purchaseOcrPictureService.batchSave(purchaseOciPictureAddVo);
return new ResultUtil<JSONObject>().setData(jsonObject);
}
/**
* Ai语音入库获取商品信息
*
* @param questionMsg
* @return Result
* @author 王富康
* @date 2024/5/23
*/
@RequestMapping(value = "/callWithMessageOfPurchase", method = RequestMethod.POST)
@ApiOperation("AI语音入库")
public Result callWithMessageOfPurchase(String questionMsg) throws NoApiKeyException, InputRequiredException {
final JSONObject jsonObject = purchaseOcrPictureService.callWithMessageOfPurchase(questionMsg);
return new ResultUtil<JSONObject>().setData(jsonObject);
}
@RequestMapping(value = "/invoicingAi", method = RequestMethod.POST)
@ApiOperation("AI开单")
public Result invoicingAi(String questionMsg) throws NoApiKeyException, InputRequiredException {
JSONObject jsonObject = purchaseOcrPictureService.invoicingAi(questionMsg);
final JSONObject jsonObject = purchaseOcrPictureService.invoicingAi(questionMsg);
return new ResultUtil<JSONObject>().setData(jsonObject);
}
@RequestMapping(value = "/multiRoundConversationCall", method = RequestMethod.POST)
@ApiOperation("图片识别-多轮对话")
public List<MultiModalConversationResult> multiRoundConversationCall(String picturePath,Integer count) throws NoApiKeyException, InputRequiredException, UploadFileException {
List<MultiModalConversationResult> multiModalConversationResults = purchaseOcrPictureService.multiRoundConversationCall(picturePath,count);
public List<MultiModalConversationResult> multiRoundConversationCall(String picturePath, Integer count) throws NoApiKeyException, InputRequiredException, UploadFileException {
final List<MultiModalConversationResult> multiModalConversationResults = purchaseOcrPictureService.multiRoundConversationCall(picturePath, count);
return multiModalConversationResults;
}
}

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/purchaseocr/service/PurchaseOcrPictureService.java

@ -23,4 +23,6 @@ public interface PurchaseOcrPictureService {
List<PurchaseOcrPicture> queryAllPictureStatus(String purchaseId);
List<PurchaseOcrCountVo> getOcrCount();
JSONObject callWithMessageOfPurchase(String questionMsg) throws NoApiKeyException, InputRequiredException;
}

321
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/purchaseocr/service/impl/PurchaseOcrPictureServiceImpl.java

@ -1,41 +1,55 @@
package cc.hiver.mall.purchaseocr.service.impl;
import cc.hiver.core.common.utils.CommonUtil;
import cc.hiver.core.common.utils.SecurityUtil;
import cc.hiver.core.entity.User;
import cc.hiver.mall.common.constant.PurchaseConstant;
import cc.hiver.mall.config.thread.AiPurchaseThread;
import cc.hiver.mall.config.thread.ThreadPoolConfiguration;
import cc.hiver.mall.entity.Purchase;
import cc.hiver.mall.entity.Shop;
import cc.hiver.mall.entity.*;
import cc.hiver.mall.pojo.vo.ProductAttributeOfAddVo;
import cc.hiver.mall.pojo.vo.ProductAttributeValueVo;
import cc.hiver.mall.pojo.vo.ProductCategoryVo;
import cc.hiver.mall.pojo.vo.PurchaseVo;
import cc.hiver.mall.purchaseocr.entity.PurchaseOcrPicture;
import cc.hiver.mall.purchaseocr.mapper.PurchaseOcrPictureMapper;
import cc.hiver.mall.purchaseocr.service.PurchaseOcrPictureService;
import cc.hiver.mall.purchaseocr.vo.PurchaseOciPictureAddVo;
import cc.hiver.mall.purchaseocr.vo.PurchaseOcrCountVo;
import cc.hiver.mall.purchaseocr.vo.PurchaseOcrExample;
import cc.hiver.mall.saleaimsg.entity.SaleAiMsg;
import cc.hiver.mall.service.ShopService;
import cc.hiver.mall.service.mybatis.ProductService;
import cc.hiver.mall.service.mybatis.PurchaseDetailService;
import cc.hiver.mall.service.mybatis.PurchaseService;
import cc.hiver.mall.service.mybatis.*;
import cc.hiver.mall.utils.AliOcrUtil;
import cn.hutool.core.date.StopWatch;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.exception.UploadFileException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
@Service
public class PurchaseOcrPictureServiceImpl implements PurchaseOcrPictureService {
private static final Pattern productSn = Pattern.compile("货号");
private static final Pattern COMPILE = Pattern.compile("\\D+");
private static final Pattern SYYS = Pattern.compile("所有颜色", Pattern.LITERAL);
private static final Pattern SYCM = Pattern.compile("所有尺码", Pattern.LITERAL);
@Autowired
private PurchaseOcrPictureMapper purchaseOcrPictureMapper;
@ -60,6 +74,12 @@ public class PurchaseOcrPictureServiceImpl implements PurchaseOcrPictureService
@Autowired
private ThreadPoolConfiguration threadPoolConfiguration;
@Autowired
private StockService stockService;
@Autowired
private ProductCategoryService productCategoryService;
@Override
public JSONObject batchSave(PurchaseOciPictureAddVo purchaseOciPictureAddVo) {
final JSONObject jsonObject = new JSONObject();
@ -116,10 +136,10 @@ public class PurchaseOcrPictureServiceImpl implements PurchaseOcrPictureService
// 异步处理ocr识别
try {
// 获取参数示例
PurchaseOcrExample purchaseOcrExample = purchaseOciPictureAddVo.getPurchaseOcrExample();
final PurchaseOcrExample purchaseOcrExample = purchaseOciPictureAddVo.getPurchaseOcrExample();
AiPurchaseThread timerThread;
for (PurchaseOcrPicture purchaseOcrPicture : purchaseOcrPictureAddList) {
timerThread = new AiPurchaseThread(purchaseId, purchaseOcrPicture,purchaseOcrExample, purchaseOcrPictureService, productService, purchaseDetailService, purchaseService);
timerThread = new AiPurchaseThread(purchaseId, purchaseOcrPicture, purchaseOcrExample, purchaseOcrPictureService, productService, purchaseDetailService, purchaseService, productCategoryService);
// 这里可以使用线程池,也可以使用CompletionService处理,运行任务需要是callable的,需要最终结果。
threadPoolConfiguration.threadPoolTaskExecutor().execute(timerThread);
}
@ -160,4 +180,287 @@ public class PurchaseOcrPictureServiceImpl implements PurchaseOcrPictureService
final String shopId = securityUtil.getShopId();
return purchaseOcrPictureMapper.getOcrCount(shopId);
}
@Override
public JSONObject callWithMessageOfPurchase(String questionMsg) throws NoApiKeyException, InputRequiredException {
final JSONObject returnJsonObject = new JSONObject();
final StopWatch stopWatch = new StopWatch("Ai入库计时:");
// 叉转X 文本纠错 使用正则表达式替换单个或多个连续的“叉”字符
questionMsg = replaceAllX(questionMsg);
// 解析语句,根据“货号”分割换行一下,一个一个执行
final String[] split = productSn.split(questionMsg);
final List<SaleAiMsg> saleAiMsgs = new ArrayList<>();
for (String s : split) {
if (cc.hiver.core.common.utils.StringUtils.isNotEmpty(s)) {
final String oneAiMsg = "货号:" + s;
// 封装需要新增的ai开单记录表
final SaleAiMsg saleAiMsg = new SaleAiMsg();
saleAiMsg.setAiMsg(oneAiMsg);
saleAiMsgs.add(saleAiMsg);
}
}
final PurchaseVo purchaseVo = new PurchaseVo();
// 定义一个map,货号为key,purchaseDetail 为value
final Map<String, PurchaseDetail> purchaseDetailMap = new HashMap<>();
// shopId从缓存中设置
final String shopId = securityUtil.getShopId();
// 进行识别
for (SaleAiMsg saleAiMsg : saleAiMsgs) {
stopWatch.start("Ai入库计时:" + saleAiMsg);
try {
final JSONObject jsonObject = AliOcrUtil.callWithMessageOfPurchase(saleAiMsg.getAiMsg());
final String resultContent = jsonObject.get("resultContent").toString();
final JSONArray json = JSON.parseArray(resultContent);
for (int i = 0; i < json.size(); i++) {
final JSONObject object = json.getJSONObject(i);
String productSn = object.getString("productSn");
// 尝试从货号中提取正确的货号,因为货号可能包含颜色等信息
productSn = CommonUtil.getProductSn(productSn);
final String productName = object.getString("productName");
final String priceStr = object.getString("price");
BigDecimal price = BigDecimal.valueOf(0);
// 使用正则表达式提取数字部分
final Pattern pattern = Pattern.compile("-?\\d+(\\.\\d+)?");
final Matcher matcher = pattern.matcher(priceStr);
if (matcher.find()) {
// 获取匹配到的数字字符串并转换为BigDecimal
final String numericPart = matcher.group();
price = new BigDecimal(numericPart);
}
final String attributeList = object.getString("attributeList");
final JSONArray attributeListJsonArray = JSON.parseArray(attributeList);
// 根据货号去查询商品,如果
final List<Product> byProductSn = productService.getByProductSn(productSn, shopId);
if (byProductSn != null && !byProductSn.isEmpty()) {
// 原则上一个店铺一个货号对应一个商品,这里如果查到了,直接拿第一个。
final Product product = byProductSn.get(0);
final String productId = product.getId();
// 查询商品所有的库存
final List<Stock> stockList = stockService.getProductStock(productId);
final Map<String, Integer> stockMap = new HashMap<>();
for (Stock stock : stockList) {
stockMap.put(stock.getAttributeList(), stock.getStockCount());
}
final String categoryId = product.getCategoryId();
final PurchaseDetail purchaseDetail = new PurchaseDetail();
purchaseDetail.setProductId(productId);
purchaseDetail.setProductName(product.getProductName());
purchaseDetail.setShopId(product.getShopId());
purchaseDetail.setCategoryId(categoryId);
purchaseDetail.setPrice(product.getPrice());
purchaseDetail.setPurchasePrice(price);
purchaseDetail.setWholesalePrice(product.getWholesalePrice());
purchaseDetail.setProductPicture(product.getProductPicture());
purchaseDetail.setProductSn(product.getProductSn());
purchaseDetail.setProductCount(0);
purchaseDetail.setSupplierName(product.getSupplierName());
final List<StockLog> stockLogList = new ArrayList<>();
// 获取商品分类及规格信息
final List<String> categoryIdList = new ArrayList<>();
categoryIdList.add(categoryId);
final List<ProductCategoryVo> shopCategory = productCategoryService.getShopCategory(categoryIdList);
final ProductCategoryVo productCategoryVo = shopCategory.get(0);
final List<ProductAttributeOfAddVo> productAttributeOfAddVos = productCategoryVo.getProductAttributeOfAddVos();
final Map<String, ProductAttributeOfAddVo> productAttributeOfAddVoMap = new HashMap<>();
for (ProductAttributeOfAddVo productAttributeOfAddVo : productAttributeOfAddVos) {
productAttributeOfAddVoMap.put(productAttributeOfAddVo.getAttributeName(), productAttributeOfAddVo);
}
//获取颜色及规格进行拼接
List<ProductAttributeValueVo> colorProductAttributeValueVoList = new ArrayList<>();
List<ProductAttributeValueVo> sizeProductAttributeValueVoList = new ArrayList<>();
if (productAttributeOfAddVoMap.containsKey("颜色")) {
colorProductAttributeValueVoList = productAttributeOfAddVoMap.get("颜色").getProductAttributeValueVoList();
}
// 将所有颜色放到一个集合中
final CopyOnWriteArrayList<String> colorList = new CopyOnWriteArrayList<>();
for (ProductAttributeValueVo productAttributeValueVo : colorProductAttributeValueVoList) {
colorList.add(productAttributeValueVo.getValue());
}
if (productAttributeOfAddVoMap.containsKey("尺码")) {
sizeProductAttributeValueVoList = productAttributeOfAddVoMap.get("尺码").getProductAttributeValueVoList();
}
// 将所有尺码放到一个集合中
final CopyOnWriteArrayList<String> sizeList = new CopyOnWriteArrayList<>();
for (ProductAttributeValueVo productAttributeValueVo : sizeProductAttributeValueVoList) {
sizeList.add(productAttributeValueVo.getValue());
}
for (int j = 0; j < attributeListJsonArray.size(); j++) {
final JSONObject attributeListObject = attributeListJsonArray.getJSONObject(j);
String color = attributeListObject.getString("color").toUpperCase();
String size = attributeListObject.getString("size").toUpperCase();
final String productCount1 = attributeListObject.getString("productCount");
final int productCount = Integer.parseInt(COMPILE.matcher(productCount1).replaceAll(""));
// 20240330 只能新增颜色和尺码,颜色统一改为*色、尺码统一转大写,加‘码’;
// 根据规格id规格是颜色、还是尺码。
if (!color.contains("色")) {
color += '色';
}
if (!size.contains("码")) {
size += '码';
}
size = size.toUpperCase();
if ("SYYS色".equals(color) && "SYCM码".equals(size)) {
for (ProductAttributeValueVo productAttributeValueVo : colorProductAttributeValueVoList) {
for (ProductAttributeValueVo attributeValueVo : sizeProductAttributeValueVoList) {
final StockLog stockLog = new StockLog();
final String attribute = "{\"颜色\":\"" + productAttributeValueVo.getValue() + "\",\"尺码\":\"" + attributeValueVo.getValue() + "\"}";
stockLog.setAttributeList(attribute);
stockLog.setProductCount(productCount);
purchaseDetail.setProductCount(purchaseDetail.getProductCount() + productCount);
stockLogList.add(stockLog);
}
}
continue;
// 所有颜色,所有尺码
}
if ("SYYS色".equals(color)) {
// 所有颜色,固定尺码
for (ProductAttributeValueVo productAttributeValueVo : colorProductAttributeValueVoList) {
final StockLog stockLog = new StockLog();
final String attribute = "{\"颜色\":\"" + productAttributeValueVo.getValue() + "\",\"尺码\":\"" + size + "\"}";
stockLog.setAttributeList(attribute);
stockLog.setProductCount(productCount);
purchaseDetail.setProductCount(purchaseDetail.getProductCount() + productCount);
stockLogList.add(stockLog);
}
continue;
}
if ("SYCM码".equals(size)) {
// 所有尺码,固定颜色
for (ProductAttributeValueVo attributeValueVo : sizeProductAttributeValueVoList) {
final StockLog stockLog = new StockLog();
final String attribute = "{\"颜色\":\"" + color + "\",\"尺码\":\"" + attributeValueVo.getValue() + "\"}";
stockLog.setAttributeList(attribute);
stockLog.setProductCount(productCount);
purchaseDetail.setProductCount(purchaseDetail.getProductCount() + productCount);
stockLogList.add(stockLog);
}
continue;
}
// 不包含所有按照获取的拼接
final StockLog stockLog = new StockLog();
final String attribute = "{\"颜色\":\"" + color + "\",\"尺码\":\"" + size + "\"}";
stockLog.setAttributeList(attribute);
stockLog.setProductCount(productCount);
purchaseDetail.setProductCount(purchaseDetail.getProductCount() + productCount);
stockLogList.add(stockLog);
}
// 判断是否存在改货号,如果不存在,新增,存在,则追加stockLogList
if (purchaseDetailMap.containsKey(productSn)) {
final PurchaseDetail addPurchaseDetail = purchaseDetailMap.get(productSn);
addPurchaseDetail.getStockLogList1().addAll(stockLogList);
} else {
purchaseDetail.setStockLogList1(stockLogList);
purchaseDetailMap.put(productSn, purchaseDetail);
}
} else {
// 没查到,封装数据,货号为id
final PurchaseDetail purchaseDetail = new PurchaseDetail();
purchaseDetail.setId(StringUtils.isEmpty(productSn) ? productName : productSn);
purchaseDetail.setProductName(productName);
purchaseDetail.setProductSn(productSn);
purchaseDetail.setPurchasePrice(price);
purchaseDetail.setProductCount(0);
// 获取默认分类
final ProductCategoryVo defaultCategory = productCategoryService.getDefaultCategory(shopId);
if (defaultCategory != null) {
purchaseDetail.setCategoryId(defaultCategory.getCategoryId());
purchaseDetail.setCategoryName(defaultCategory.getCategoryName());
}
final List<StockLog> stockLogList = new ArrayList<>();
for (int j = 0; j < attributeListJsonArray.size(); j++) {
final JSONObject attributeListObject = attributeListJsonArray.getJSONObject(j);
String color = attributeListObject.getString("color").toUpperCase();
String size = attributeListObject.getString("size").toUpperCase();
final String productCount1 = attributeListObject.getString("productCount");
final int productCount = Integer.parseInt(COMPILE.matcher(productCount1).replaceAll(""));
// 20240330 只能新增颜色和尺码,颜色统一改为*色、尺码统一转大写,加‘码’;
// 根据规格id规格是颜色、还是尺码。
if (!color.contains("色")) {
color += '色';
}
if (!size.contains("码")) {
size += '码';
}
size = size.toUpperCase();
// 不包含所有按照获取的拼接
final StockLog stockLog = new StockLog();
final String attribute = "{\"颜色\":\"" + color + "\",\"尺码\":\"" + size + "\"}";
stockLog.setAttributeList(attribute);
stockLog.setProductCount(productCount);
purchaseDetail.setProductCount(purchaseDetail.getProductCount() + productCount);
stockLogList.add(stockLog);
}
// 判断是否存在改货号,如果不存在,新增,存在,则追加stockLogList
if (purchaseDetailMap.containsKey(productSn)) {
final PurchaseDetail addPurchaseDetail = purchaseDetailMap.get(productSn);
addPurchaseDetail.getStockLogList1().addAll(stockLogList);
} else {
purchaseDetail.setStockLogList1(stockLogList);
purchaseDetailMap.put(productSn, purchaseDetail);
}
}
}
} catch (NoApiKeyException e) {
throw new RuntimeException(e);
} catch (InputRequiredException e) {
throw new RuntimeException(e);
}
stopWatch.stop();
}
log.info(stopWatch.prettyPrint());
final List<PurchaseDetail> purchaseDetails = new ArrayList<>();
for (Map.Entry<String, PurchaseDetail> stringPurchaseDetailEntry : purchaseDetailMap.entrySet()) {
purchaseDetails.add(stringPurchaseDetailEntry.getValue());
}
purchaseVo.setPurchaseDetails(purchaseDetails);
returnJsonObject.put("data", purchaseVo);
return returnJsonObject;
}
/**
* 使用正则表达式替换输入字符串中连续的字符为相应数量的X字符
*
* @param input 待替换的字符串
* @return 替换后的字符串
*/
private static String replaceAllX(String input) {
// 定义正则表达式
final Pattern pattern = Pattern.compile("(叉+)");
// 创建匹配器
final Matcher matcher = pattern.matcher(input);
// 用于构建替换后的结果字符串
final StringBuffer sb = new StringBuffer();
while (matcher.find()) {
// 获取匹配到的“叉”字符数
final int count = matcher.group(1).length();
// 创建一个字符数组,用于存放“X”字符
final char[] xs = new char[count];
// 填充数组
Arrays.fill(xs, 'X');
// 将字符数组转换为字符串
final String replacement = new String(xs);
// 将替换后的字符串添加到结果缓冲区
matcher.appendReplacement(sb, replacement);
}
// 添加剩余未匹配部分到结果缓冲区
matcher.appendTail(sb);
// 对【所有】进行特殊处理
String returnStr = sb.toString();
returnStr = SYYS.matcher(returnStr).replaceAll(",SYYS色");
returnStr = SYCM.matcher(returnStr).replaceAll(",SYCM码");
// 返回最终替换后的字符串
return returnStr;
}
}

25
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/service/mybatis/ProductCategoryService.java

@ -13,12 +13,33 @@ public interface ProductCategoryService extends IService<ProductCategory> {
/**
* AI入库的时候新增的分类信息分类Id肯定是有的
* @author 王富康
* @date 2024/3/31
*
* @param productCategoryVoList
* @return boolean
* @author 王富康
* @date 2024/3/31
*/
boolean batchSaveCategoryAndAttributeOfAi(List<ProductCategoryAiVo> productCategoryVoList);
CopyOnWriteArrayList<ProductCategoryVo> getShopCategory(List<String> categoryIdList);
/**
* 注册店铺是新增默认分类
*
* @param shopId
* @author 王富康
* @date 2024/5/25
*/
void addShopDefaultCategory(String shopId);
/**
* 获取该店铺的默认分类如果只有一个分类就返回如果多个就返回空
*
* @return ProductCategory
* @author 王富康
* @date 2024/5/25
*/
ProductCategoryVo getDefaultCategory(String shopId);
List<ProductCategoryVo> getCategoryByCategoryIdList(List<String> categoryIdList);
}

16
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/SalesCalculateServiceImpl.java

@ -2,7 +2,6 @@ package cc.hiver.mall.serviceimpl;
import cc.hiver.core.common.constant.SaleConstant;
import cc.hiver.core.common.utils.SecurityUtil;
import cc.hiver.core.common.utils.StringUtils;
import cc.hiver.mall.dao.mapper.ReturnSaleMapper;
import cc.hiver.mall.dao.mapper.SaleMapper;
import cc.hiver.mall.entity.ReturnSaleExample;
@ -58,22 +57,13 @@ public class SalesCalculateServiceImpl implements SalesCalculateService {
// 店铺id从缓存中获取,并放到数据中去
final String shopId = securityUtil.getShopId();
// 日期类型
Date startDate = new Date();
Date endDate = new Date();
// 查询日期范围内数据
try{
if (StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime)) {
startTime = DateUtils.formatDate(new Date(), "yyyy-MM-dd") + " 00:00:00";
endTime = DateUtils.formatDate(new Date(), "yyyy-MM-dd") + " 23:59:59";
startDate = DateUtil.COMMON_FULL.getTextDate(startTime);
endDate = DateUtil.COMMON_FULL.getTextDate(endTime);
} else {
startDate = DateUtil.COMMON_FULL.getTextDate(startTime + " 00:00:00");
endDate = DateUtil.COMMON_FULL.getTextDate(endTime + " 23:59:59");
// 如果根据时间查询,那么结束时间加1天,
endTime = DateUtil.addDay(endTime, 1);
}
startDate = DateUtil.COMMON.getTextDate(startTime);
endDate = DateUtil.COMMON.getTextDate(endTime);
}catch (Exception e){
log.error("日期转换出错!");
}

87
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/ProductCategoryServiceImpl.java

@ -14,6 +14,8 @@ import cc.hiver.mall.service.mybatis.ProductAttributeValueService;
import cc.hiver.mall.service.mybatis.ProductCategoryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -44,8 +46,14 @@ public class ProductCategoryServiceImpl extends ServiceImpl<ProductCategoryMappe
try {
// 新增类别信息
final ProductCategory productCategory = new ProductCategory();
final String shopId = securityUtil.getShopId();
productCategory.setShopId(shopId);
// 20240525 注册店铺的时候需要增加默认分类,shopId从注册店铺的那边传过来
if (StringUtils.isEmpty(productCategoryVo.getShopId())) {
final String shopId = securityUtil.getShopId();
productCategory.setShopId(shopId);
} else {
productCategory.setShopId(productCategoryVo.getShopId());
}
productCategory.setCategoryName(productCategoryVo.getCategoryName());
productCategoryMapper.insert(productCategory);
@ -114,7 +122,7 @@ public class ProductCategoryServiceImpl extends ServiceImpl<ProductCategoryMappe
final List<ProductAttributeValue> addProductAttributeValues = new ArrayList<>();
// 获取这些分类下都有哪些规格
final List<ProductCategoryVo> shopCategory = getShopCategory(categoryIdList);
final Map<String, List<ProductAttributeOfAddVo>> productAttributes =new HashMap<>();
final Map<String, List<ProductAttributeOfAddVo>> productAttributes = new HashMap<>();
for (ProductCategoryVo productCategoryVo : shopCategory) {
productAttributes.put(productCategoryVo.getCategoryId(), productCategoryVo.getProductAttributeOfAddVos());
}
@ -132,7 +140,7 @@ public class ProductCategoryServiceImpl extends ServiceImpl<ProductCategoryMappe
final String attributeName = entry.getKey();
final List<String> attributeValueList = entry.getValue();
// 首先判断是否需要新增规格
if(!stockAttributeNameList.contains(attributeName)){
if (!stockAttributeNameList.contains(attributeName)) {
final ProductAttribute productAttribute = new ProductAttribute();
productAttribute.setCreateTime(new Date());
productAttribute.setCategoryId(categoryId);
@ -147,12 +155,12 @@ public class ProductCategoryServiceImpl extends ServiceImpl<ProductCategoryMappe
productAttributeValue.setValue(s);
addProductAttributeValues.add(productAttributeValue);
}
}else{
} else {
// 包含规格,那么就只需要新增属性即可
// 拿到旧的规格
ProductAttributeOfAddVo oldProductAttributeOfAddVo = new ProductAttributeOfAddVo();
for (ProductAttributeOfAddVo productAttributeOfAddVo : productAttributeOfAddVos) {
if(productAttributeOfAddVo.getAttributeName().equals(attributeName)){
if (productAttributeOfAddVo.getAttributeName().equals(attributeName)) {
oldProductAttributeOfAddVo = productAttributeOfAddVo;
}
}
@ -163,7 +171,7 @@ public class ProductCategoryServiceImpl extends ServiceImpl<ProductCategoryMappe
}
// 判断旧的值中是否包含新的值,如果不包含就新增
for (String s : attributeValueList) {
if(!stockAttributeValueList.contains(s)){
if (!stockAttributeValueList.contains(s)) {
final ProductAttributeValue productAttributeValue = new ProductAttributeValue();
productAttributeValue.setCreateTime(new Date());
productAttributeValue.setAttributeId(oldProductAttributeOfAddVo.getAttributeId());
@ -248,4 +256,69 @@ public class ProductCategoryServiceImpl extends ServiceImpl<ProductCategoryMappe
}
return new CopyOnWriteArrayList<>(productCategoryMap.values());
}
@Override
public void addShopDefaultCategory(String shopId) {
final ProductCategoryVo productCategoryVo = new ProductCategoryVo();
productCategoryVo.setShopId(shopId);
productCategoryVo.setCategoryName("默认分类");
final CopyOnWriteArrayList<ProductAttributeOfAddVo> productAttributeOfAddVos = new CopyOnWriteArrayList<>();
// 新增颜色
final ProductAttributeOfAddVo productAttributeOfAddVo = new ProductAttributeOfAddVo();
productAttributeOfAddVo.setAttributeName("颜色");
final CopyOnWriteArrayList<ProductAttributeValueVo> productAttributeValueVoList = new CopyOnWriteArrayList<>();
final ProductAttributeValueVo productAttributeValueVo = new ProductAttributeValueVo();
productAttributeValueVo.setValue("均色");
productAttributeValueVoList.add(productAttributeValueVo);
// 回填到均色到颜色中
productAttributeOfAddVo.setProductAttributeValueVoList(productAttributeValueVoList);
// 回填到颜色到分类中
productAttributeOfAddVos.add(productAttributeOfAddVo);
// 新增尺码
final ProductAttributeOfAddVo sizeProductAttributeOfAddVo = new ProductAttributeOfAddVo();
sizeProductAttributeOfAddVo.setAttributeName("尺码");
final CopyOnWriteArrayList<ProductAttributeValueVo> sizeProductAttributeValueVoList = new CopyOnWriteArrayList<>();
final ProductAttributeValueVo sizeProductAttributeValueVo = new ProductAttributeValueVo();
sizeProductAttributeValueVo.setValue("均码");
sizeProductAttributeValueVoList.add(sizeProductAttributeValueVo);
// 回填均码到尺码中
sizeProductAttributeOfAddVo.setProductAttributeValueVoList(sizeProductAttributeValueVoList);
// 回填尺码到分类中
productAttributeOfAddVos.add(sizeProductAttributeOfAddVo);
productCategoryVo.setProductAttributeOfAddVos(productAttributeOfAddVos);
// 批量去新增
batchSaveCategoryAndAttribute(productCategoryVo);
}
/**
* 获取该店铺的默认分类如果只有一个分类就返回如果多个或者本来就没分类就返回空
*
* @return ProductCategory
* @author 王富康
* @date 2024/5/25
*/
@Nullable
@Override
public ProductCategoryVo getDefaultCategory(String shopId) {
final List<ProductCategoryVo> productCategoryVoList = productCategoryMapper.selectByShopId(shopId);
if(productCategoryVoList.isEmpty()){
return null;
}else{
if(productCategoryVoList.size() == 1){
return productCategoryVoList.get(0);
}else{
return null;
}
}
}
@Override
public List<ProductCategoryVo> getCategoryByCategoryIdList(List<String> categoryIdList) {
return productCategoryMapper.selectByCategoryIdList(categoryIdList);
}
}

21
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/PurchaseServiceImpl.java

@ -8,15 +8,13 @@ import cc.hiver.mall.dao.mapper.PurchaseMapper;
import cc.hiver.mall.entity.*;
import cc.hiver.mall.pojo.dto.DebtSupplier;
import cc.hiver.mall.pojo.query.PurchasePageQuery;
import cc.hiver.mall.pojo.vo.ProductCategoryVo;
import cc.hiver.mall.pojo.vo.PurchaseVo;
import cc.hiver.mall.purchaseocr.entity.PurchaseOcrPicture;
import cc.hiver.mall.purchaseocr.service.PurchaseOcrPictureService;
import cc.hiver.mall.purchaseocr.vo.PurchaseOcrCountVo;
import cc.hiver.mall.service.SupplierService;
import cc.hiver.mall.service.mybatis.DealingsRecordService;
import cc.hiver.mall.service.mybatis.PurchaseDetailService;
import cc.hiver.mall.service.mybatis.PurchaseService;
import cc.hiver.mall.service.mybatis.StockLogService;
import cc.hiver.mall.service.mybatis.*;
import cc.hiver.mall.utils.DateUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -25,6 +23,7 @@ import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class PurchaseServiceImpl extends ServiceImpl<PurchaseMapper, Purchase> implements PurchaseService {
@ -53,6 +52,9 @@ public class PurchaseServiceImpl extends ServiceImpl<PurchaseMapper, Purchase> i
@Autowired
private PurchaseOcrPictureService purchaseOcrPictureService;
@Autowired
private ProductCategoryService productCategoryService;
@Override
public Page<DebtSupplier> getDebtByShopId(PurchasePageQuery purchasePageQuery) {
@ -317,6 +319,17 @@ public class PurchaseServiceImpl extends ServiceImpl<PurchaseMapper, Purchase> i
}
// 获取商品信息
final List<PurchaseDetail> purchaseDetails = purchaseDetailService.getByPurchaseId(id);
// 20240525 需要返回分类名称
final List<String> categoryIds = purchaseDetails.stream().map(PurchaseDetail::getCategoryId).collect(Collectors.toList());
// 根据分类id获取分类名称
final List<ProductCategoryVo> categoryByCategoryIdList = productCategoryService.getCategoryByCategoryIdList(categoryIds);
final Map<String,String> categoryMap = categoryByCategoryIdList.stream().collect(Collectors.toMap(ProductCategoryVo::getCategoryId, ProductCategoryVo::getCategoryName));
// 将分类名称封装到采购单明细中
purchaseDetails.forEach(purchaseDetail -> {
final String categoryId = purchaseDetail.getCategoryId();
purchaseDetail.setCategoryName(categoryMap.get(categoryId));
});
final List<PurchaseDetail> removePurchaseDetails = new ArrayList<>();
// 处理数据

5
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/SaleServiceImpl.java

@ -2,6 +2,7 @@ package cc.hiver.mall.serviceimpl.mybatis;
import cc.hiver.core.common.constant.DealingsRecordConstant;
import cc.hiver.core.common.constant.SaleConstant;
import cc.hiver.core.common.utils.CommonUtil;
import cc.hiver.core.common.utils.SecurityUtil;
import cc.hiver.core.common.utils.StringUtils;
import cc.hiver.core.common.utils.ThreadPoolUtil;
@ -583,7 +584,9 @@ public class SaleServiceImpl extends ServiceImpl<SaleMapper, Sale> implements Sa
final JSONArray json = JSON.parseArray(resultContent);
for (int i = 0; i < json.size(); i++) {
final JSONObject object = json.getJSONObject(i);
final String productSn = object.getString("productSn");
String productSn = object.getString("productSn");
// 尝试从货号中提取正确的货号,因为货号可能包含颜色等信息
productSn = CommonUtil.getProductSn(productSn);
// 根据货号去查询商品,如果
final List<Product> byProductSn = productService.getByProductSn(productSn, shopId);
if (byProductSn != null && !byProductSn.isEmpty()) {

1
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/StockServiceImpl.java

@ -659,6 +659,7 @@ public class StockServiceImpl extends ServiceImpl<StockMapper, Stock> implements
// Ai已经生成了入库单主表信息
final Purchase purchase = purchaseVo.getPurchase();
purchase.setShopId(shopId);
final String purchaseId = purchase.getId();
// 先根据入库单id 删除详情及库存履历表信息
purchaseDetailService.deleteByPurchaseId(purchaseId);

262
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/AliOcrUtil.java

@ -1,6 +1,7 @@
package cc.hiver.mall.utils;// Copyright (c) Alibaba, Inc. and its affiliates.
import cc.hiver.core.common.constant.CommonConstant;
import cc.hiver.core.common.utils.CommonUtil;
import cc.hiver.mall.config.aliocr.AliOcrConfig;
import cc.hiver.mall.entity.*;
import cc.hiver.mall.pojo.vo.*;
@ -59,7 +60,7 @@ public class AliOcrUtil {
* @author 王富康
* @date 2024/3/31
*/
public static JSONObject multiRoundConversationCall(PurchaseOcrPicture purchaseOcrPicture, PurchaseOcrExample purchaseOcrExample, ProductService productService, PurchaseDetailService purchaseDetailService) throws ApiException, NoApiKeyException, UploadFileException {
public static JSONObject multiRoundConversationCall(PurchaseOcrPicture purchaseOcrPicture, PurchaseOcrExample purchaseOcrExample, ProductService productService, PurchaseDetailService purchaseDetailService, ProductCategoryService productCategoryService) throws ApiException, NoApiKeyException, UploadFileException {
final JSONObject jsonObject = new JSONObject();
final String ocrPictureId = purchaseOcrPicture.getId();
final String picturePath = purchaseOcrPicture.getOcrPicture();
@ -71,13 +72,13 @@ public class AliOcrUtil {
// 拼接的示例结果
String productSnExample = purchaseOcrExample.getProductSn();
String productNameExample = purchaseOcrExample.getProductName();
if(StringUtils.isNotEmpty(ocrPictureOrder)){
if (StringUtils.isNotEmpty(ocrPictureOrder)) {
final String[] strings = ocrPictureOrder.split("-");
final String indexStr = strings[0];
productSnExample += indexStr;
productNameExample += indexStr;
}
final StopWatch stopWatch = new StopWatch(ocrPictureId+"Ai回答计时");
final StopWatch stopWatch = new StopWatch(ocrPictureId + "Ai回答计时");
Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682";
final CopyOnWriteArrayList<MultiModalConversationResult> multiModalConversationResults = new CopyOnWriteArrayList<>();
final MultiModalConversation conv = new MultiModalConversation();
@ -96,7 +97,7 @@ public class AliOcrUtil {
"5.如果按照你的理解在图中找到了productSn和productName字段对应的信息,则productSn和productName字段的值以图中内容为准。如果按照你的理解在图中没有找到productSn和productName字段对应的信息,则productSn和productName字段的值使用JSON示例中productSn和productName的值填充。 " +
"6.请注意返回JSON符号解析格式正确 ,确保java程序能够正确解析。" +
"7.严格返回" + count + "条JSON数据,如果数量有偏差按照实际条数返回,不能自动省略!";
log.info("AI提问内容:"+firstQuestionMsg);
log.info("AI提问内容:" + firstQuestionMsg);
MultiModalMessageItemText userText = new MultiModalMessageItemText(firstQuestionMsg);
final MultiModalConversationMessage userMessage =
MultiModalConversationMessage.builder().role(Role.USER.getValue())
@ -114,7 +115,7 @@ public class AliOcrUtil {
multiModalConversationResults.add(result);
// 解析结果
String text = result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text").toString();
log.info("一轮对话-的json======"+ text);
log.info("一轮对话-的json======" + text);
// 根据{}截取数据
final int startIndex = text.indexOf('{');
final int endIndex = text.lastIndexOf('}');
@ -127,45 +128,45 @@ public class AliOcrUtil {
// 有时候返回的是productCounts,改为productCount
jsonStr = fixJsonStr(jsonStr);
JSONArray endJson = new JSONArray();
try{
try {
endJson = JSON.parseArray(jsonStr);
}catch (Exception e){
log.error(Thread.currentThread().getName()+"-一轮对话--->json识别报错喽,没关系,我把错误信息输出出来:"+e.getMessage(), e);
} catch (Exception e) {
log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,没关系,我把错误信息输出出来:" + e.getMessage(), e);
// 如果格式化报错,特殊处理下,再次进行转义。
final String message = e.getMessage();
boolean needAgain = true;
// 以下是对目前可能出现的问题进行过滤处理
// attributeList格式不对
if(message.contains("attributeList")){
if (message.contains("attributeList")) {
needAgain = false;
log.error(Thread.currentThread().getName()+"-一轮对话--->json识别报错喽,没关系,attributeList格式有问题,我来替换一下!");
log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,没关系,attributeList格式有问题,我来替换一下!");
// 如果是attributeList出现问题,那么尝试修复。
jsonStr = fixAttributeList(jsonStr);
try{
try {
endJson = JSON.parseArray(jsonStr);
}catch (Exception replaceOneException){
log.error(Thread.currentThread().getName()+"-一轮对话--->json识别报错喽,没关系,attributeList替换了也没好使!");
} catch (Exception replaceOneException) {
log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,没关系,attributeList替换了也没好使!");
needAgain = true;
}
}
// 识别多了个“}”
if(message.contains("not close endJson text")){
if (message.contains("not close endJson text")) {
needAgain = false;
log.error(Thread.currentThread().getName()+"-一轮对话--->json识别报错喽,没关系,可能是多了“}”,我来去掉试一下一下!");
log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,没关系,可能是多了“}”,我来去掉试一下一下!");
//
jsonStr = jsonStr.substring(0, jsonStr.length()-1);
try{
jsonStr = jsonStr.substring(0, jsonStr.length() - 1);
try {
endJson = JSON.parseArray(jsonStr);
}catch (Exception replaceOneException){
log.error(Thread.currentThread().getName()+"-一轮对话--->json识别报错喽,没关系,可能是多了“}”,去掉了也没好使!");
} catch (Exception replaceOneException) {
log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,没关系,可能是多了“}”,去掉了也没好使!");
needAgain = true;
}
}
if(needAgain){
log.error(Thread.currentThread().getName()+"-一轮对话--->json识别报错喽,没关系,我来重新识别一下!");
if (needAgain) {
log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,没关系,我来重新识别一下!");
//尝试重新识别一次
final String errorJsonQuestionMsg = "返回的json格式有误,请重新返回。";
final MultiModalMessageItemText assistentText = new MultiModalMessageItemText(
@ -183,7 +184,7 @@ public class AliOcrUtil {
stopWatch.stop();
// 解析结果
text = result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text").toString();
log.info("一轮对话--json格式错误,重新识别的结果======"+ text);
log.info("一轮对话--json格式错误,重新识别的结果======" + text);
// 根据{}截取数据
final int secondStartIndex = text.indexOf('{');
final int secondEndIndex = text.lastIndexOf('}');
@ -192,43 +193,43 @@ public class AliOcrUtil {
// 有时候返回的是productCounts,改为productCount
errorJsonJsonStr = fixJsonStr(errorJsonJsonStr);
try{
try {
//
endJson = JSON.parseArray(errorJsonJsonStr);
}catch (Exception errorJsonException){
log.error(Thread.currentThread().getName()+"-一轮对话--->json识别报错喽,重新识别又报错了,没关系,我把错误信息输出出来:"+errorJsonException.getMessage(), errorJsonException);
} catch (Exception errorJsonException) {
log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,重新识别又报错了,没关系,我把错误信息输出出来:" + errorJsonException.getMessage(), errorJsonException);
// 如果格式化报错,特殊处理下,再次进行转义。
final String errorJsonExceptionMessage = errorJsonException.getMessage();
boolean firstCheckResult = true;
if(errorJsonExceptionMessage.contains("attributeList")){
if (errorJsonExceptionMessage.contains("attributeList")) {
firstCheckResult = false;
log.error(Thread.currentThread().getName()+"-一轮对话--->json识别报错喽,重新识别又报错了,没关系,attributeList格式有问题,我来替换一下!");
log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,重新识别又报错了,没关系,attributeList格式有问题,我来替换一下!");
// 如果是attributeList出现问题,那么尝试修复。
errorJsonJsonStr = fixAttributeList(errorJsonJsonStr);
try{
try {
endJson = JSON.parseArray(errorJsonJsonStr);
}catch (Exception errorJsonJsonException){
log.error(Thread.currentThread().getName()+"-一轮对话--->json识别报错喽,重新识别又报错了,attributeList替换了也没好使!");
} catch (Exception errorJsonJsonException) {
log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,重新识别又报错了,attributeList替换了也没好使!");
firstCheckResult = true;
}
}
// 识别多了个“}”
if(errorJsonExceptionMessage.contains("not close endJson text")){
if (errorJsonExceptionMessage.contains("not close endJson text")) {
firstCheckResult = false;
log.error(Thread.currentThread().getName()+"-一轮对话--->json识别报错喽,重新识别又报错了,没关系,可能是多了“}”,我来去掉试一下一下!");
log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,重新识别又报错了,没关系,可能是多了“}”,我来去掉试一下一下!");
//
errorJsonJsonStr = errorJsonJsonStr.substring(0, errorJsonJsonStr.length()-1);
try{
errorJsonJsonStr = errorJsonJsonStr.substring(0, errorJsonJsonStr.length() - 1);
try {
endJson = JSON.parseArray(errorJsonJsonStr);
}catch (Exception replaceOneException){
log.error(Thread.currentThread().getName()+"-一轮对话--->json识别报错喽,重新识别又报错了,可能是多了“}”,去掉了也没好使!");
} catch (Exception replaceOneException) {
log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,重新识别又报错了,可能是多了“}”,去掉了也没好使!");
firstCheckResult = true;
}
}
if(firstCheckResult){
log.error(Thread.currentThread().getName()+"-一轮对话--->json识别报错喽,,重新识别又报错了,不识别了,直接毁灭吧!");
if (firstCheckResult) {
log.error(Thread.currentThread().getName() + "-一轮对话--->json识别报错喽,,重新识别又报错了,不识别了,直接毁灭吧!");
throw errorJsonException;
}
}
@ -255,69 +256,69 @@ public class AliOcrUtil {
stopWatch.stop();
// 解析结果
String secondText = result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text").toString();
log.info("二轮对话识别结果:"+secondText);
log.info("二轮对话识别结果:" + secondText);
// 根据{}截取数据
final int secondStartIndex = secondText.indexOf('{');
final int secondEndIndex = secondText.lastIndexOf('}');
if (secondStartIndex == -1 || secondEndIndex == -1) {
// 二轮对话,没有查询到想要的数据,那么就使用一轮的结果
log.info(Thread.currentThread().getName()+"-二轮对话--->识别数据失败,使用第一次的识别结果未找到指定标识符:识别结果为:" + text);
}else{
log.info(Thread.currentThread().getName() + "-二轮对话--->识别数据失败,使用第一次的识别结果未找到指定标识符:识别结果为:" + text);
} else {
String secondJsonStr = '[' + secondText.substring(secondStartIndex, secondEndIndex + 1) + ']';
// 有时候返回的是productCounts,改为productCount
secondJsonStr = fixJsonStr(secondJsonStr);
try{
try {
final JSONArray secondJson = JSON.parseArray(secondJsonStr);
final int secondResultCount = secondJson.size();
// 20240515 跟第一次的数据对比,哪个数量多,用哪个。
if(secondResultCount > fristResultCount){
if (secondResultCount > fristResultCount) {
endJson = secondJson;
}
}catch (Exception e){
} catch (Exception e) {
boolean needAgain = true;
log.error(Thread.currentThread().getName()+"-二轮对话--->json识别报错喽,没关系,我把错误信息输出出来:"+e.getMessage(),e);
log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,没关系,我把错误信息输出出来:" + e.getMessage(), e);
// 如果格式化报错,特殊处理下,再次进行转义。
final String message = e.getMessage();
if(message.contains("attributeList")){
if (message.contains("attributeList")) {
needAgain = false;
log.error(Thread.currentThread().getName()+"-二轮对话--->json识别报错喽,没关系,attributeList格式有问题,我来替换一下!");
log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,没关系,attributeList格式有问题,我来替换一下!");
// 如果是attributeList出现问题,那么尝试修复。
secondJsonStr = fixAttributeList(secondJsonStr);
try{
try {
// endJson = JSON.parseArray(secondJsonStr);
final JSONArray secondJson = JSON.parseArray(secondJsonStr);
final int secondResultCount = secondJson.size();
// 20240515 跟第一次的数据对比,哪个数量多,用哪个。
if(secondResultCount > fristResultCount){
if (secondResultCount > fristResultCount) {
endJson = secondJson;
}
}catch (Exception exception){
log.error(Thread.currentThread().getName()+"-二轮对话--->json识别报错喽,attributeList替换了也没好使!");
} catch (Exception exception) {
log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,attributeList替换了也没好使!");
needAgain = true;
}
}
// 识别多了个“}”
if(message.contains("not close endJson text")){
if (message.contains("not close endJson text")) {
needAgain = false;
log.error(Thread.currentThread().getName()+"-二轮对话--->json识别报错喽,没关系,可能是多了“}”,我来去掉试一下一下!");
log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,没关系,可能是多了“}”,我来去掉试一下一下!");
//
secondJsonStr = secondJsonStr.substring(0, secondJsonStr.length()-1);
try{
secondJsonStr = secondJsonStr.substring(0, secondJsonStr.length() - 1);
try {
// endJson = JSON.parseArray(secondJsonStr);
final JSONArray secondJson = JSON.parseArray(secondJsonStr);
final int secondResultCount = secondJson.size();
// 20240515 跟第一次的数据对比,哪个数量多,用哪个。
if(secondResultCount > fristResultCount){
if (secondResultCount > fristResultCount) {
endJson = secondJson;
}
}catch (Exception replaceOneException){
log.error(Thread.currentThread().getName()+"-二轮对话--->json识别报错喽,可能是多了“}”,去掉了也没好使!");
} catch (Exception replaceOneException) {
log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,可能是多了“}”,去掉了也没好使!");
needAgain = true;
}
}
if(needAgain){
log.error(Thread.currentThread().getName()+"-二轮对话--->json识别报错喽,没关系,我来重新识别一下!");
if (needAgain) {
log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,没关系,我来重新识别一下!");
//尝试重新识别一次
final String errorJsonQuestionMsg = "返回的json格式有误,请重新返回。";
final MultiModalMessageItemText secondJsonErrorAssistentText = new MultiModalMessageItemText(
@ -335,7 +336,7 @@ public class AliOcrUtil {
stopWatch.stop();
// 解析结果
secondText = result.getOutput().getChoices().get(0).getMessage().getContent().get(0).get("text").toString();
log.info("二轮对话-json格式错误,重新识别的结果======"+ secondText);
log.info("二轮对话-json格式错误,重新识别的结果======" + secondText);
// 根据{}截取数据
final int errorSsecondStartIndex = secondText.indexOf('{');
final int errorSecondEndIndex = secondText.lastIndexOf('}');
@ -343,58 +344,58 @@ public class AliOcrUtil {
String errorJsonJsonStr = '[' + secondText.substring(errorSsecondStartIndex, errorSecondEndIndex + 1) + ']';
// 有时候返回的是productCounts,改为productCount
errorJsonJsonStr = fixJsonStr(errorJsonJsonStr);
try{
try {
//
// endJson = JSON.parseArray(errorJsonJsonStr);
final JSONArray secondJson = JSON.parseArray(errorJsonJsonStr);
final int secondResultCount = secondJson.size();
// 20240515 跟第一次的数据对比,哪个数量多,用哪个。
if(secondResultCount > fristResultCount){
if (secondResultCount > fristResultCount) {
endJson = secondJson;
}
}catch (Exception errorJsonException){
} catch (Exception errorJsonException) {
boolean secondCheckResult = true;
final String errorJsonExceptionMessage = errorJsonException.getMessage();
log.error(Thread.currentThread().getName()+"-二轮对话--->json识别报错喽,重新识别又报错了,没关系,我把错误信息输出出来:"+ errorJsonExceptionMessage, errorJsonException);
if(errorJsonExceptionMessage.contains("attributeList")){
log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,重新识别又报错了,没关系,我把错误信息输出出来:" + errorJsonExceptionMessage, errorJsonException);
if (errorJsonExceptionMessage.contains("attributeList")) {
secondCheckResult = false;
log.error(Thread.currentThread().getName()+"-二轮对话--->json识别报错喽,,重新识别又报错了,没关系,,attributeList格式有问题,我来替换一下!");
log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,,重新识别又报错了,没关系,,attributeList格式有问题,我来替换一下!");
// 如果是attributeList出现问题,那么尝试修复。
errorJsonJsonStr = fixAttributeList(errorJsonJsonStr);
try{
try {
// endJson = JSON.parseArray(errorJsonJsonStr);
final JSONArray secondJson = JSON.parseArray(errorJsonJsonStr);
final int secondResultCount = secondJson.size();
// 20240515 跟第一次的数据对比,哪个数量多,用哪个。
if(secondResultCount > fristResultCount){
if (secondResultCount > fristResultCount) {
endJson = secondJson;
}
}catch (Exception secondCheckException){
log.error(Thread.currentThread().getName()+"-二轮对话--->json识别报错喽,,重新识别又报错了,attributeList替换了也没好使!");
} catch (Exception secondCheckException) {
log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,,重新识别又报错了,attributeList替换了也没好使!");
secondCheckResult = true;
}
}
if(errorJsonExceptionMessage.contains("not close endJson text")){
if (errorJsonExceptionMessage.contains("not close endJson text")) {
secondCheckResult = false;
log.error(Thread.currentThread().getName()+"-二轮对话--->json识别报错喽,重新识别又报错了,没关系,可能是多了“}”,我来去掉试一下一下!");
log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,重新识别又报错了,没关系,可能是多了“}”,我来去掉试一下一下!");
// 如果是attributeList出现问题,那么尝试修复。
errorJsonJsonStr = errorJsonJsonStr.substring(0, errorJsonJsonStr.length()-1);
try{
errorJsonJsonStr = errorJsonJsonStr.substring(0, errorJsonJsonStr.length() - 1);
try {
// endJson = JSON.parseArray(errorJsonJsonStr);
final JSONArray secondJson = JSON.parseArray(errorJsonJsonStr);
final int secondResultCount = secondJson.size();
// 20240515 跟第一次的数据对比,哪个数量多,用哪个。
if(secondResultCount > fristResultCount){
if (secondResultCount > fristResultCount) {
endJson = secondJson;
}
}catch (Exception secondCheckException){
log.error(Thread.currentThread().getName()+"-二轮对话--->json识别报错喽,重新识别又报错了,可能是多了“}”,去掉了也没好使!");
} catch (Exception secondCheckException) {
log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,重新识别又报错了,可能是多了“}”,去掉了也没好使!");
secondCheckResult = true;
}
}
if(secondCheckResult){
log.error(Thread.currentThread().getName()+"-二轮对话--->json识别报错喽,,重新识别又报错了,不识别了,直接用第一次识别的结果吧!");
if (secondCheckResult) {
log.error(Thread.currentThread().getName() + "-二轮对话--->json识别报错喽,,重新识别又报错了,不识别了,直接用第一次识别的结果吧!");
}
}
}
@ -408,7 +409,7 @@ public class AliOcrUtil {
/*if (StringUtils.isNotEmpty(parentPicturePath)) {
picturePath = parentPicturePath;
}*/
getPurchaseDetailMap(purchaseDetailService, productService, orderId, shopId, picturePath, endJson);
getPurchaseDetailMap(purchaseDetailService, productService, orderId, shopId, picturePath, endJson, productCategoryService);
stopWatch.stop();
// 将map 转为list 进行落库操作
/*stopWatch.start("批量插入==");
@ -446,7 +447,7 @@ public class AliOcrUtil {
attributeList = attributeList.replace("productCounts", "productCount");
return attributeList;
}
/**
* 1.有时候返回的是productCounts改为productCount
* 2. 有的时候中间会有...,需要特殊处理一下
@ -458,16 +459,16 @@ public class AliOcrUtil {
*/
public static String fixJsonStr(String str) {
// 如果包含"...",那么就截取掉,在商品中不会出现,并且在json应该只会出现一次,如果会出现多次的话,那这里需要再次优化
if(str.contains("...")){
if (str.contains("...")) {
final String[] newStr = COMPILED.split(str);
final int newStrLength = newStr.length;
if(newStrLength ==2){
if (newStrLength == 2) {
// 第一个字符串从开头截取到第一个}
newStr[0] = newStr[0].substring(0, newStr[0].lastIndexOf('}'));
// 第二个字符串从第一个{截取到最后
newStr[1] = newStr[1].substring(newStr[1].indexOf('{'));
// 重新拼接,并且中间加上逗号
str = newStr[0]+ ',' +newStr[1];
str = newStr[0] + ',' + newStr[1];
}
}
str = str.replace("productCounts", "productCount");
@ -487,7 +488,7 @@ public class AliOcrUtil {
* @author 王富康
* @date 2024/5/10
*/
public static JSONObject streamCall(PurchaseOcrPicture purchaseOcrPicture, PurchaseOcrExample purchaseOcrExample, ProductService productService, PurchaseDetailService purchaseDetailService)
public static JSONObject streamCall(PurchaseOcrPicture purchaseOcrPicture, PurchaseOcrExample purchaseOcrExample, ProductService productService, PurchaseDetailService purchaseDetailService, ProductCategoryService productCategoryService)
throws ApiException, NoApiKeyException, UploadFileException {
final JSONObject jsonObject = new JSONObject();
final String picturePath = purchaseOcrPicture.getOcrPicture();
@ -574,7 +575,7 @@ public class AliOcrUtil {
/*if (StringUtils.isNotEmpty(parentPicturePath)) {
picturePath = parentPicturePath;
}*/
getPurchaseDetailMap(purchaseDetailService, productService, orderId, shopId, picturePath, json);
getPurchaseDetailMap(purchaseDetailService, productService, orderId, shopId, picturePath, json, productCategoryService);
stopWatch.stop();
log.info(stopWatch.prettyPrint());
@ -597,7 +598,7 @@ public class AliOcrUtil {
* @author 王富康
* @date 2024/3/31
*/
private static void getPurchaseDetailMap(PurchaseDetailService purchaseDetailService, ProductService productService, String orderId, String shopId, String ocrPicturePath, JSONArray json) {
private static void getPurchaseDetailMap(PurchaseDetailService purchaseDetailService, ProductService productService, String orderId, String shopId, String ocrPicturePath, JSONArray json, ProductCategoryService productCategoryService) {
// 开始解析图片识别的数据,进行入库操作。
// 解析未实体对象
final CopyOnWriteArrayList<PurchaseOcrVo> purchaseOcrVos = new CopyOnWriteArrayList<>();
@ -608,7 +609,10 @@ public class AliOcrUtil {
for (int i = 0; i < json.size(); i++) {
final JSONObject jsonObject = json.getJSONObject(i);
final PurchaseOcrVo purchaseOcrVo = new PurchaseOcrVo();
purchaseOcrVo.setProductSn(jsonObject.getString("productSn"));
String productSnOfJson = jsonObject.getString("productSn");
// 尝试从货号中提取正确的货号,因为货号可能包含颜色等信息
productSnOfJson = CommonUtil.getProductSn(productSnOfJson);
purchaseOcrVo.setProductSn(productSnOfJson);
purchaseOcrVo.setProductName(jsonObject.getString("productName"));
purchaseOcrVo.setPrice(jsonObject.getBigDecimal("price"));
final String productCount = jsonObject.getString("productCount");
@ -626,7 +630,7 @@ public class AliOcrUtil {
final CopyOnWriteArrayList<PurchaseOcrDetailVo> attributeList = new CopyOnWriteArrayList<>();
final String size = attributeListJson.getString("size");
if(size.contains(",")){
if (size.contains(",")) {
final String[] sizeArray = size.split(",");
for (String s : sizeArray) {
final PurchaseOcrDetailVo purchaseOcrDetailVo = new PurchaseOcrDetailVo();
@ -634,7 +638,7 @@ public class AliOcrUtil {
purchaseOcrDetailVo.setSize(s);
attributeList.add(purchaseOcrDetailVo);
}
}else if(size.contains("-")){
} else if (size.contains("-")) {
final String[] sizeArray = size.split("-");
for (String s : sizeArray) {
final PurchaseOcrDetailVo purchaseOcrDetailVo = new PurchaseOcrDetailVo();
@ -642,7 +646,7 @@ public class AliOcrUtil {
purchaseOcrDetailVo.setSize(s);
attributeList.add(purchaseOcrDetailVo);
}
}else{
} else {
final PurchaseOcrDetailVo purchaseOcrDetailVo = new PurchaseOcrDetailVo();
purchaseOcrDetailVo.setColor(attributeListJson.getString("color"));
purchaseOcrDetailVo.setSize(size);
@ -794,6 +798,12 @@ public class AliOcrUtil {
purchaseDetail.setWholesalePrice(product.getWholesalePrice());
purchaseDetail.setProductName(product.getProductName());
stockLog.setProductId(product.getId());
}else{
// 新商品,获取默认分类
final ProductCategoryVo defaultCategory = productCategoryService.getDefaultCategory(shopId);
if (defaultCategory != null) {
purchaseDetail.setCategoryId(defaultCategory.getCategoryId());
}
}
stockLogList.add(stockLog);
purchaseDetail.setStockLogList1(stockLogList);
@ -822,7 +832,11 @@ public class AliOcrUtil {
final MessageManager msgManager = new MessageManager(10);
final Message systemMsg =
Message.builder().role(Role.SYSTEM.getValue()).content("You are a helpful assistant.").build();
questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }],只输出JSON数据即可,不用返回字段描述";
//questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }]。以下是几点要求: 1.“货号”两个字和颜色中间的内容代表productSn,productSn可能包含\"新\"、\"退\"、\"旧\"、\"换\"、\"补\"。 2.\"SYYS色\"代表“所有颜色”,\"color\"字段返回“SYYS色”。 3.\"SYCM码\"代表“所有尺码”,\"size\"字段返回“SYCM码”。 4.只输出JSON数据即可,不用返回字段描述和解析过程。";
questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }]," +
"productSn的返回值中去掉颜色,尺码等信息,\n" +
"如果没有识别到\"color\"的内容,则\"color\"赋值“均色”。如果没有识别到\"size\"的内容,则\"size\"赋值“均码”,\n" +
"只输出JSON数据即可,不用返回字段描述。";
final Message userMsg = Message.builder().role(Role.USER.getValue()).content(questionMsg).build();
msgManager.add(systemMsg);
msgManager.add(userMsg);
@ -830,10 +844,6 @@ public class AliOcrUtil {
final QwenParam param =
QwenParam.builder().model(Generation.Models.QWEN_PLUS).messages(msgManager.get())
.resultFormat(QwenParam.ResultFormat.MESSAGE)
.temperature(1F)
.topP(0.1)
.topK(1)
.seed(500)
.build();
final GenerationResult result = gen.call(param);
log.info(result.toString());
@ -850,6 +860,48 @@ public class AliOcrUtil {
return jsonObject;
}
/**
* ai语音入库
*
* @param questionMsg
* @return JSONObject
* @author 王富康
* @date 2024/5/23
*/
public static JSONObject callWithMessageOfPurchase(String questionMsg)
throws NoApiKeyException, ApiException, InputRequiredException {
final JSONObject jsonObject = new JSONObject();
Constants.apiKey = "sk-bcfa4865b89548acb8225f910f13d682";
final Generation gen = new Generation();
final MessageManager msgManager = new MessageManager(10);
final Message systemMsg =
Message.builder().role(Role.SYSTEM.getValue()).content("You are a helpful assistant.").build();
// questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"productName\": \"名称\" , \"price\":\"单价\",\"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }]。以下是几点要求: 1.“货号”两个字和\"名称\"两个字中间的内容代表productSn的值,如果没有名称则“货号”两个字和颜色中间的内容代表productSn的值,productSn可能包含\"新\"、\"退\"、\"旧\"、\"换\"、\"补\"。2.\"SYYS色\"代表“所有颜色”,\"color\"字段返回“SYYS色”。 3.\"SYCM码\"代表“所有尺码”,\"size\"字段返回“SYCM码”。4.如果没有名称,productName字段返回\"\"。5.只输出JSON数据即可,不用返回字段描述和解析过程。";
questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"productName\": \"名称\" , \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}], \"price\":\"单价\" }]," +
"如果没有识别到\"price\"的内容,则\"price\"赋值\"0\"," +
"如果没有识别到\"color\"的内容,则\"color\"赋值“均色”," +
"如果没有识别到\"size\"的内容,则\"size\"赋值“均码”,\n" +
"如果没有识别到\"productName\"的内容,则\"productName\"使用\"productSn\"的值填充。只输出JSON数据即可,不用返回字段描述。";
final Message userMsg = Message.builder().role(Role.USER.getValue()).content(questionMsg).build();
msgManager.add(systemMsg);
msgManager.add(userMsg);
final QwenParam param =
QwenParam.builder().model(Generation.Models.QWEN_PLUS).messages(msgManager.get())
.resultFormat(QwenParam.ResultFormat.MESSAGE)
.build();
final GenerationResult result = gen.call(param);
log.info(result.toString());
// 解析结果
final String text = result.getOutput().getChoices().get(0).getMessage().getContent();
// 根据{}截取数据
final int startIndex = text.indexOf('{');
final int endIndex = text.lastIndexOf('}');
final String jsonStr = '[' + text.substring(startIndex, endIndex + 1) + ']';
jsonObject.put("resultContent", jsonStr);
jsonObject.put("msg", result.getOutput().getChoices().get(0).getMessage().getContent());
return jsonObject;
}
public static JSONObject callWithMessageSync(String questionMsg, String saleId, String shopId, String createBy, ProductService productService, ProductCategoryService productCategoryService, SaleService saleService, SaleDetailService saleDetailService)
throws NoApiKeyException, ApiException, InputRequiredException {
final JSONObject jsonObject = new JSONObject();
@ -859,7 +911,11 @@ public class AliOcrUtil {
final MessageManager msgManager = new MessageManager(10);
final Message systemMsg =
Message.builder().role(Role.SYSTEM.getValue()).content("You are a helpful assistant.").build();
questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }],只输出JSON数据即可,不用返回字段描述";
// questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }],只输出JSON数据即可,不用返回字段描述";
questionMsg += "请帮我把所有内容封装为JSON,json格式为:[{ \"productSn\": \"货号\", \"attributeList\": [{\"color\":\"颜色\",\"size\":\"尺码\",\"productCount\": \"数量\"}] }]," +
"productSn的返回值中去掉颜色,尺码等信息,\n" +
"如果没有识别到\"color\"的内容,则\"color\"赋值“均色”。如果没有识别到\"size\"的内容,则\"size\"赋值“均码”,\n" +
"只输出JSON数据即可,不用返回字段描述。";
final Message userMsg = Message.builder().role(Role.USER.getValue()).content(questionMsg).build();
msgManager.add(systemMsg);
msgManager.add(userMsg);
@ -867,10 +923,6 @@ public class AliOcrUtil {
final QwenParam param =
QwenParam.builder().model(Generation.Models.QWEN_PLUS).messages(msgManager.get())
.resultFormat(QwenParam.ResultFormat.MESSAGE)
.temperature(1F)
.topP(0.1)
.topK(1)
.seed(500)
.build();
final GenerationResult result = gen.call(param);
log.info(result.toString());
@ -911,8 +963,10 @@ public class AliOcrUtil {
final CopyOnWriteArrayList<SaleDetail> saleDetailList = new CopyOnWriteArrayList<>();
for (int i = 0; i < json.size(); i++) {
final JSONObject object = json.getJSONObject(i);
final String productSn = object.getString("productSn");
// 根据货号去查询商品,如果
String productSn = object.getString("productSn");
// 尝试从货号中提取正确的货号,因为货号可能包含颜色等信息
productSn = CommonUtil.getProductSn(productSn);
// 根据货号去查询商品
final CopyOnWriteArrayList<Product> byProductSn = productService.getByProductSn(productSn, shopId);
if (byProductSn != null && !byProductSn.isEmpty()) {
// 原则上一个店铺一个货号对应一个商品,这里如果查到了,直接拿第一个。

2
hiver-modules/hiver-mall/src/main/resources/mapper/OperatingAreaMapper.xml

@ -220,7 +220,7 @@
)
</if>
group by t.shipping_method_id, t.shipping_method
order by s.is_on_line desc,t.shipping_method
order by s.is_on_line desc,s.create_time desc, t.shipping_method
</select>
<!--管理商品分页列表-->
<select id="getOperatingAreaList" resultType="cc.hiver.mall.operatingarea.vo.OperatingAreaPageVO">

21
hiver-modules/hiver-mall/src/main/resources/mapper/SaleMapper.xml

@ -21,6 +21,7 @@
<result column="already_earn" jdbcType="DECIMAL" property="alreadyEarn" />
<result column="no_earn" jdbcType="DECIMAL" property="noEarn" />
<result column="pay_status" jdbcType="VARCHAR" property="payStatus" />
<result column="pay_type" jdbcType="VARCHAR" property="payType" />
<result column="status" jdbcType="VARCHAR" property="status" />
<result column="transport_type" jdbcType="VARCHAR" property="transportType" />
<result column="share_address" jdbcType="VARCHAR" property="shareAddress" />
@ -102,7 +103,7 @@
</sql>
<sql id="Base_Column_List">
id, create_by, create_by_name, create_time, del_flag, update_by, update_by_name, update_time, user_id, user_name, shop_id, shop_name, total_amount, discount,
discount_amount, real_amount, already_earn, no_earn, pay_status, status, other_expense, transport_type, share_address, receive_address, province, city, area,
discount_amount, real_amount, already_earn, no_earn, pay_status,pay_type, status, other_expense, transport_type, share_address, receive_address, province, city, area,
trans_company, company_name, product_count, remark, sale_name, company_phone, create_by_phone,mode_of_service,ai_flag,ai_result,ai_not_recognition
</sql>
@ -141,7 +142,7 @@ trans_company, company_name, product_count, remark, sale_name, company_phone, cr
del_flag, update_by,update_by_name, update_time,
user_id,user_name, shop_id,shop_name, total_amount,
discount, discount_amount, real_amount,
already_earn, no_earn, pay_status,
already_earn, no_earn, pay_status,pay_type,
status, transport_type, share_address,
receive_address, province, city,
area,sale_name,remark,other_expense,trans_company,company_name,company_phone,product_count,create_by_phone,mode_of_service,ai_flag,ai_result,ai_not_recognition)
@ -149,7 +150,7 @@ trans_company, company_name, product_count, remark, sale_name, company_phone, cr
#{delFlag,jdbcType=INTEGER}, #{updateBy,jdbcType=VARCHAR},#{updateByName,jdbcType=VARCHAR}, #{updateTime,jdbcType=TIMESTAMP},
#{userId,jdbcType=VARCHAR},#{userName,jdbcType=VARCHAR}, #{shopId,jdbcType=VARCHAR},#{shopName,jdbcType=VARCHAR}, #{totalAmount,jdbcType=DECIMAL},
#{discount,jdbcType=DECIMAL}, #{discountAmount,jdbcType=DECIMAL}, #{realAmount,jdbcType=DECIMAL},
#{alreadyEarn,jdbcType=DECIMAL}, #{noEarn,jdbcType=DECIMAL}, #{payStatus,jdbcType=VARCHAR},
#{alreadyEarn,jdbcType=DECIMAL}, #{noEarn,jdbcType=DECIMAL}, #{payStatus,jdbcType=VARCHAR}, #{payType,jdbcType=VARCHAR},
#{status,jdbcType=VARCHAR}, #{transportType,jdbcType=VARCHAR}, #{shareAddress,jdbcType=VARCHAR},
#{receiveAddress,jdbcType=VARCHAR}, #{province,jdbcType=VARCHAR}, #{city,jdbcType=VARCHAR},
#{area,jdbcType=VARCHAR}, #{saleName,jdbcType=VARCHAR}, #{remark,jdbcType=VARCHAR},
@ -208,6 +209,9 @@ trans_company, company_name, product_count, remark, sale_name, company_phone, cr
<if test="payStatus != null">
pay_status,
</if>
<if test="payType != null">
pay_type,
</if>
<if test="status != null">
status,
</if>
@ -420,6 +424,9 @@ trans_company, company_name, product_count, remark, sale_name, company_phone, cr
<if test="record.payStatus != null">
pay_status = #{record.payStatus,jdbcType=VARCHAR},
</if>
<if test="record.payType != null">
pay_type = #{record.payType,jdbcType=VARCHAR},
</if>
<if test="record.status != null">
status = #{record.status,jdbcType=VARCHAR},
</if>
@ -494,6 +501,7 @@ trans_company, company_name, product_count, remark, sale_name, company_phone, cr
already_earn = #{record.alreadyEarn,jdbcType=DECIMAL},
no_earn = #{record.noEarn,jdbcType=DECIMAL},
pay_status = #{record.payStatus,jdbcType=VARCHAR},
pay_type = #{record.payType,jdbcType=VARCHAR},
status = #{record.status,jdbcType=VARCHAR},
transport_type = #{record.transportType,jdbcType=VARCHAR},
share_address = #{record.shareAddress,jdbcType=VARCHAR},
@ -562,6 +570,9 @@ trans_company, company_name, product_count, remark, sale_name, company_phone, cr
</if>
<if test="payStatus != null">
pay_status = #{payStatus,jdbcType=VARCHAR},
</if>
<if test="payType != null">
pay_type = #{payType,jdbcType=VARCHAR},
</if>
<if test="status != null">
status = #{status,jdbcType=VARCHAR},
@ -634,6 +645,7 @@ trans_company, company_name, product_count, remark, sale_name, company_phone, cr
already_earn = #{alreadyEarn,jdbcType=DECIMAL},
no_earn = #{noEarn,jdbcType=DECIMAL},
pay_status = #{payStatus,jdbcType=VARCHAR},
pay_type = #{payType,jdbcType=VARCHAR},
status = #{status,jdbcType=VARCHAR},
transport_type = #{transportType,jdbcType=VARCHAR},
share_address = #{shareAddress,jdbcType=VARCHAR},
@ -747,6 +759,9 @@ trans_company, company_name, product_count, remark, sale_name, company_phone, cr
<if test='saleVO.payStatus!=null'>
and pay_status = #{saleVO.payStatus}
</if>
<if test='saleVO.payType!=null'>
and pay_type = #{saleVO.payType}
</if>
<if test='saleVO.status!=null'>
and status = #{saleVO.status}
</if>

Loading…
Cancel
Save