diff --git a/cash-common/cash-common-service/src/main/java/com/czg/order/dto/OrderInfoAddDTO.java b/cash-common/cash-common-service/src/main/java/com/czg/order/dto/OrderInfoAddDTO.java index 56db70d30..e40f33d1f 100644 --- a/cash-common/cash-common-service/src/main/java/com/czg/order/dto/OrderInfoAddDTO.java +++ b/cash-common/cash-common-service/src/main/java/com/czg/order/dto/OrderInfoAddDTO.java @@ -21,6 +21,15 @@ import java.math.BigDecimal; @NoArgsConstructor @AllArgsConstructor public class OrderInfoAddDTO implements Serializable { + /** + * 上菜方式 + * 待起菜 PENDING_PREP + * 待出菜 READY_TO_SERVE + * 已出菜 SENT_OUT + * 已上菜 DELIVERED + * 已超时 EXPIRED + */ + private String subStatus; //限时折扣部分 private LimitRateDTO limitRate; diff --git a/cash-common/cash-common-tools/src/main/java/com/czg/utils/AliOcrUtil.java b/cash-common/cash-common-tools/src/main/java/com/czg/utils/AliOcrUtil.java index 799ae4d5c..831f872cd 100644 --- a/cash-common/cash-common-tools/src/main/java/com/czg/utils/AliOcrUtil.java +++ b/cash-common/cash-common-tools/src/main/java/com/czg/utils/AliOcrUtil.java @@ -8,13 +8,17 @@ import com.alibaba.dashscope.app.ApplicationParam; import com.alibaba.dashscope.app.ApplicationResult; import com.alibaba.dashscope.app.RagOptions; import com.aliyun.bailian20231229.Client; +import com.aliyun.bailian20231229.models.AddFileResponse; import com.aliyun.bailian20231229.models.ApplyFileUploadLeaseResponse; import com.aliyun.bailian20231229.models.ApplyFileUploadLeaseResponseBody; +import com.aliyun.bailian20231229.models.DescribeFileResponse; import com.czg.exception.CzgException; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import java.io.InputStream; +import java.io.DataOutputStream; +import java.net.HttpURLConnection; +import java.net.URL; import java.util.List; import java.util.Map; @@ -53,13 +57,14 @@ public class AliOcrUtil { - public static ApplyFileUploadLeaseResponseBody.ApplyFileUploadLeaseResponseBodyData applyFileUpload(InputStream stream, String fileName) { - String md5 = DigestUtil.md5Hex(stream); + public static ApplyFileUploadLeaseResponseBody.ApplyFileUploadLeaseResponseBodyData applyFileUpload(byte[] bytes, String fileName) { + + String md5 = DigestUtil.md5Hex(bytes); com.aliyun.bailian20231229.Client client = createClient(); com.aliyun.bailian20231229.models.ApplyFileUploadLeaseRequest applyFileUploadLeaseRequest = new com.aliyun.bailian20231229.models.ApplyFileUploadLeaseRequest() .setFileName(fileName) .setMd5(md5) - .setSizeInBytes("100000") + .setSizeInBytes(String.valueOf(bytes.length)) .setCategoryType("SESSION_FILE") .setUseInternalEndpoint(false); com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions(); @@ -76,40 +81,94 @@ public class AliOcrUtil { } } - public static String uploadFile(InputStream stream, String fileName) throws Exception { + public static String getSessionId(byte[] bytes, String fileName) { + String leaseId = null; + try { + leaseId = uploadFile(bytes, fileName); + } catch (Exception e) { + throw new RuntimeException(e); + } + com.aliyun.bailian20231229.Client client = createClient(); + com.aliyun.bailian20231229.models.AddFileRequest addFileRequest = new com.aliyun.bailian20231229.models.AddFileRequest() + .setLeaseId(leaseId) + .setParser("DASHSCOPE_DOCMIND") + .setCategoryId("default") + .setCategoryType("SESSION_FILE"); + com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions(); + java.util.Map headers = new java.util.HashMap<>(); + try { + // 复制代码运行请自行打印 API 的返回值 + AddFileResponse addFileResponse = client.addFileWithOptions("llm-9zg04s7wlbvi32tq", addFileRequest, headers, runtime); + String fileId = addFileResponse.getBody().getData().getFileId(); + while (!getFileStatus(fileId)) { + Thread.sleep(100); + } + return fileId; + } catch (Exception error) { + throw new RuntimeException(error); + } + } - ApplyFileUploadLeaseResponseBody.ApplyFileUploadLeaseResponseBodyData applyInfo = applyFileUpload(stream, fileName); + public static boolean getFileStatus(String fileId) { + com.aliyun.bailian20231229.Client client = createClient(); + com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions(); + java.util.Map headers = new java.util.HashMap<>(); + try { + // 复制代码运行请自行打印 API 的返回值 + DescribeFileResponse describeFileResponse = client.describeFileWithOptions("llm-9zg04s7wlbvi32tq", fileId, headers, runtime); + + log.info("file status: {}", describeFileResponse.getBody()); + return describeFileResponse.getBody().getData() != null && "FILE_IS_READY".equals(describeFileResponse.getBody().getData().getStatus()); + } catch (Exception error) { + throw new RuntimeException(error); + } + } + + + public static String uploadFile(byte[] bytes, String fileName) throws Exception { + + ApplyFileUploadLeaseResponseBody.ApplyFileUploadLeaseResponseBodyData applyInfo = applyFileUpload(bytes, fileName); - // 获取预签名要求的所有头 Map headers = (Map) applyInfo.getParam().getHeaders(); + // 补充必须的 Content-Type + if (!headers.containsKey("Content-Type")) { + headers.put("Content-Type", "application/octet-stream"); + } + HttpRequest request = HttpRequest.put(applyInfo.getParam().getUrl()); - // 必须一模一样地设置所有 headers(否则签名失效) + // 设置所有 header for (Map.Entry entry : headers.entrySet()) { request.header(entry.getKey(), entry.getValue()); } // 设置文件内容 - request.body(stream.readAllBytes()); + request.body(bytes); HttpResponse resp = request.execute(); - log.info(resp.body()); + + log.info("upload status: {}", resp.getStatus()); + if (resp.getStatus() != 200) { + throw new CzgException("OSS 上传失败: " + resp.body()); + } + return applyInfo.getFileUploadLeaseId(); } - public static String appCall(InputStream stream, String fileName) { + + public static String appCall(byte[] bytes, String fileName) { String id = null; try { - id = uploadFile(stream, fileName); + id = getSessionId(bytes, fileName); } catch (Exception e) { throw new RuntimeException(e); } - ApplicationParam param = ApplicationParam.builder() + ApplicationParam param = ApplicationParam.builder() .apiKey("sk-2343af4413834ad1ab43b036e3a903de") - .appId("3493340ef5e146c487364395fbca7bf3") - .prompt("开始处理") + .appId("cd612ac509a4499f8ac68a656532d4ae") + .prompt("你是一名票据OCR结构化专家,请从我提供的票据图片中智能提取信息并只输出JSON,不得添加解释、不补充不存在内容、不得返回空字符串、字段缺失填null、字段不可省略、数字一律用字符串,使用以下固定JSON结构:{\"documentType\":\"\",\"orderNumber\":\"\",\"date\":\"\",\"customerName\":\"\",\"operator\":\"\",\"items\":[{\"conName\":\"\",\"spec\":\"\",\"unitName\":\"\",\"inOutNumber\":\"\",\"purchasePrice\":\"\",\"subTotal\":\"\"}],\"totalAmount\":\"\",\"remark\":\"\"}。字段映射规则:documentType对应单据类型/销售单/采购单/出货单;orderNumber对应单号/编号/No;date对应日期/开单日期;customerName对应客户名称/收货单位/供应商;operator对应业务员/经办人/制单人/操作员;items.conName对应品名/名称;items.spec对应规格/型号;items.unitName对应单位;items.inOutNumber对应数量;items.purchasePrice对应单价;items.subTotal对应金额/小计;totalAmount对应总金额/合计金额;remark对应备注。严禁生成图片中不存在的字段内容,看不清或未出现的字段必须为null,不允许推测或补全,不得生成多余字段;items只能根据识别到的行生成,不得虚构。必须能识别旋转、倾斜、模糊、撕裂、光照差异、列顺序混乱、无表格线等情况并尽量恢复信息。最终输出必须是纯JSON,不得包含任何非JSON字符。") .ragOptions(RagOptions.builder() .sessionFileIds(List.of(id)) .build()) diff --git a/cash-service/order-service/src/main/java/com/czg/service/order/service/impl/OrderInfoServiceImpl.java b/cash-service/order-service/src/main/java/com/czg/service/order/service/impl/OrderInfoServiceImpl.java index 102bc59ba..509a13583 100644 --- a/cash-service/order-service/src/main/java/com/czg/service/order/service/impl/OrderInfoServiceImpl.java +++ b/cash-service/order-service/src/main/java/com/czg/service/order/service/impl/OrderInfoServiceImpl.java @@ -293,6 +293,7 @@ public class OrderInfoServiceImpl extends ServiceImpl orderDetails = cartService.getCartByTableCode(shopInfo.getId(), param.getTableCode(), param.getPlaceNum()); +// if (param.) AssertUtil.isListEmpty(orderDetails, "下单失败 购物车为空"); processOrderDetails(orderDetails, param.getLimitRate()); //生成订单 diff --git a/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ConsStockFlowServiceImpl.java b/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ConsStockFlowServiceImpl.java index 6aa8e3609..879ac1c36 100644 --- a/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ConsStockFlowServiceImpl.java +++ b/cash-service/product-service/src/main/java/com/czg/service/product/service/impl/ConsStockFlowServiceImpl.java @@ -1,340 +1,349 @@ -package com.czg.service.product.service.impl; + package com.czg.service.product.service.impl; -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.bean.copier.CopyOptions; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.thread.ThreadUtil; -import cn.hutool.core.util.NumberUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.crypto.digest.DigestUtil; -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONObject; -import com.czg.exception.CzgException; -import com.czg.market.entity.MkOcr; -import com.czg.product.entity.MkOcrService; -import com.czg.product.dto.ConsStockFlowDTO; -import com.czg.product.dto.SaleOrderDTO; -import com.czg.product.entity.ConsInfo; -import com.czg.product.entity.ConsStockFlow; -import com.czg.product.enums.InOutItemEnum; -import com.czg.product.enums.InOutTypeEnum; -import com.czg.product.param.*; -import com.czg.product.service.ConsStockFlowService; -import com.czg.product.vo.ConsCheckStockRecordVo; -import com.czg.sa.StpKit; -import com.czg.service.product.mapper.ConsInfoMapper; -import com.czg.service.product.mapper.ConsStockFlowMapper; -import com.czg.service.product.mapper.ProductMapper; -import com.czg.service.product.util.WxAccountUtil; -import com.czg.utils.AliOcrUtil; -import com.czg.utils.PageUtil; -import com.github.pagehelper.PageHelper; -import com.github.pagehelper.PageInfo; -import com.mybatisflex.core.paginate.Page; -import com.mybatisflex.core.query.QueryWrapper; -import com.mybatisflex.spring.service.impl.ServiceImpl; -import jakarta.annotation.Resource; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; + import cn.hutool.core.bean.BeanUtil; + import cn.hutool.core.bean.copier.CopyOptions; + import cn.hutool.core.collection.CollUtil; + import cn.hutool.core.thread.ThreadUtil; + import cn.hutool.core.util.NumberUtil; + import cn.hutool.core.util.StrUtil; + import cn.hutool.crypto.digest.DigestUtil; + import com.alibaba.fastjson2.JSON; + import com.alibaba.fastjson2.JSONObject; + import com.czg.exception.CzgException; + import com.czg.market.entity.MkOcr; + import com.czg.product.entity.MkOcrService; + import com.czg.product.dto.ConsStockFlowDTO; + import com.czg.product.dto.SaleOrderDTO; + import com.czg.product.entity.ConsInfo; + import com.czg.product.entity.ConsStockFlow; + import com.czg.product.enums.InOutItemEnum; + import com.czg.product.enums.InOutTypeEnum; + import com.czg.product.param.*; + import com.czg.product.service.ConsStockFlowService; + import com.czg.product.vo.ConsCheckStockRecordVo; + import com.czg.sa.StpKit; + import com.czg.service.product.mapper.ConsInfoMapper; + import com.czg.service.product.mapper.ConsStockFlowMapper; + import com.czg.service.product.mapper.ProductMapper; + import com.czg.service.product.util.WxAccountUtil; + import com.czg.utils.AliOcrUtil; + import com.czg.utils.PageUtil; + import com.github.pagehelper.PageHelper; + import com.github.pagehelper.PageInfo; + import com.mybatisflex.core.paginate.Page; + import com.mybatisflex.core.query.QueryWrapper; + import com.mybatisflex.spring.service.impl.ServiceImpl; + import jakarta.annotation.Resource; + import lombok.AllArgsConstructor; + import lombok.extern.slf4j.Slf4j; + import org.springframework.stereotype.Service; + import org.springframework.transaction.annotation.Transactional; -import java.io.InputStream; -import java.math.BigDecimal; -import java.time.LocalDate; -import java.util.*; -import java.util.stream.Collectors; + import java.io.ByteArrayInputStream; + import java.io.IOException; + import java.io.InputStream; + import java.math.BigDecimal; + import java.time.LocalDate; + import java.util.*; + import java.util.stream.Collectors; -/** - * 耗材库存变动记录 - * - * @author Tankaikai tankaikai@aliyun.com - * @since 1.0 2025-02-21 - */ -@AllArgsConstructor -@Service -@Slf4j -public class ConsStockFlowServiceImpl extends ServiceImpl implements ConsStockFlowService { + /** + * 耗材库存变动记录 + * + * @author Tankaikai tankaikai@aliyun.com + * @since 1.0 2025-02-21 + */ + @AllArgsConstructor + @Service + @Slf4j + public class ConsStockFlowServiceImpl extends ServiceImpl implements ConsStockFlowService { - private final ConsInfoMapper consInfoMapper; - private final ProductMapper productMapper; - @Resource - private WxAccountUtil wxAccountUtil; - @Resource - private MkOcrService ocrService; + private final ConsInfoMapper consInfoMapper; + private final ProductMapper productMapper; + @Resource + private WxAccountUtil wxAccountUtil; + @Resource + private MkOcrService ocrService; - private QueryWrapper buildQueryWrapper(ConsStockFlowDTO param) { - QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper(); - /*if (StrUtil.isNotEmpty(param.getName())) { - queryWrapper.like(ConsStockFlow::getName, param.getName()); - }*/ - Long shopId = StpKit.USER.getShopId(0L); - queryWrapper.eq(ConsStockFlow::getShopId, shopId); - queryWrapper.orderBy(ConsStockFlow::getId, false); - return queryWrapper; - } + private QueryWrapper buildQueryWrapper(ConsStockFlowDTO param) { + QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper(); + /*if (StrUtil.isNotEmpty(param.getName())) { + queryWrapper.like(ConsStockFlow::getName, param.getName()); + }*/ + Long shopId = StpKit.USER.getShopId(0L); + queryWrapper.eq(ConsStockFlow::getShopId, shopId); + queryWrapper.orderBy(ConsStockFlow::getId, false); + return queryWrapper; + } - @Override - @Transactional(rollbackFor = Exception.class) - public void inStock(ConsInOutStockHeadParam param) { - Long shopId = StpKit.USER.getShopId(0L); - Long createUserId = StpKit.USER.getLoginIdAsLong(); - String createUserName = StpKit.USER.getAccount(); - ConsStockFlow head = BeanUtil.copyProperties(param, ConsStockFlow.class); - List entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class); - List insertList = new ArrayList<>(); - List updateStockList = new ArrayList<>(); - for (ConsStockFlow entity : entityList) { - BeanUtil.copyProperties(head, entity, CopyOptions.create().ignoreNullValue()); - entity.setShopId(shopId); - entity.setInOutType(InOutTypeEnum.IN.value()); - entity.setInOutItem(InOutItemEnum.MANUAL_IN.value()); + @Override + @Transactional(rollbackFor = Exception.class) + public void inStock(ConsInOutStockHeadParam param) { + Long shopId = StpKit.USER.getShopId(0L); + Long createUserId = StpKit.USER.getLoginIdAsLong(); + String createUserName = StpKit.USER.getAccount(); + ConsStockFlow head = BeanUtil.copyProperties(param, ConsStockFlow.class); + List entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class); + List insertList = new ArrayList<>(); + List updateStockList = new ArrayList<>(); + for (ConsStockFlow entity : entityList) { + BeanUtil.copyProperties(head, entity, CopyOptions.create().ignoreNullValue()); + entity.setShopId(shopId); + entity.setInOutType(InOutTypeEnum.IN.value()); + entity.setInOutItem(InOutItemEnum.MANUAL_IN.value()); + entity.setCreateUserId(createUserId); + entity.setCreateUserName(createUserName); + Long conId = entity.getConId(); + ConsInfo consInfo = consInfoMapper.selectOneById(conId); + if (consInfo == null) { + throw new CzgException(StrUtil.format("耗材{}不存在", entity.getConName())); + } + entity.setBeforeNumber(consInfo.getStockNumber()); + entity.setAfterNumber(NumberUtil.add(entity.getBeforeNumber(), entity.getInOutNumber())); + insertList.add(entity); + consInfo.setStockNumber(entity.getAfterNumber()); + updateStockList.add(consInfo); + } + super.saveBatch(insertList); + for (ConsInfo consInfo : updateStockList) { + consInfoMapper.update(consInfo); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void outStock(ConsInOutStockHeadParam param) { + Long shopId = StpKit.USER.getShopId(0L); + Long createUserId = StpKit.USER.getLoginIdAsLong(); + String createUserName = StpKit.USER.getAccount(); + ConsStockFlow head = BeanUtil.copyProperties(param, ConsStockFlow.class); + List entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class); + List insertList = new ArrayList<>(); + List updateStockList = new ArrayList<>(); + for (ConsStockFlow entity : entityList) { + BeanUtil.copyProperties(head, entity, CopyOptions.create().ignoreNullValue()); + entity.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, entity.getInOutNumber())); + entity.setShopId(shopId); + entity.setInOutType(InOutTypeEnum.OUT.value()); + entity.setInOutItem(InOutItemEnum.MANUAL_OUT.value()); + entity.setCreateUserId(createUserId); + entity.setCreateUserName(createUserName); + Long conId = entity.getConId(); + ConsInfo consInfo = consInfoMapper.selectOneById(conId); + if (consInfo == null) { + throw new CzgException(StrUtil.format("耗材{}不存在", entity.getConName())); + } + entity.setBeforeNumber(consInfo.getStockNumber()); + entity.setAfterNumber(NumberUtil.add(entity.getBeforeNumber(), entity.getInOutNumber())); + insertList.add(entity); + consInfo.setStockNumber(entity.getAfterNumber()); + updateStockList.add(consInfo); + } + super.saveBatch(insertList); + for (ConsInfo consInfo : updateStockList) { + consInfoMapper.update(consInfo); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void checkStock(ConsCheckStockParam param) { + Long shopId = StpKit.USER.getShopId(0L); + Long createUserId = StpKit.USER.getLoginIdAsLong(); + String createUserName = StpKit.USER.getAccount(); + ConsStockFlow entity = new ConsStockFlow(); entity.setCreateUserId(createUserId); entity.setCreateUserName(createUserName); - Long conId = entity.getConId(); - ConsInfo consInfo = consInfoMapper.selectOneById(conId); + entity.setShopId(shopId); + entity.setConId(param.getConId()); + entity.setConName(param.getConName()); + entity.setPurchasePrice(param.getPrice()); + ConsInfo consInfo = consInfoMapper.selectOneById(param.getConId()); if (consInfo == null) { throw new CzgException(StrUtil.format("耗材{}不存在", entity.getConName())); } + BigDecimal winLossNumber = NumberUtil.sub(param.getActualNumber(), param.getStockNumber()); + if (!NumberUtil.equals(winLossNumber, param.getWinLossNumber())) { + throw new CzgException(StrUtil.format("耗材{}库存在发生变动,请刷新后重试", entity.getConName())); + } entity.setBeforeNumber(consInfo.getStockNumber()); + entity.setInOutNumber(winLossNumber); entity.setAfterNumber(NumberUtil.add(entity.getBeforeNumber(), entity.getInOutNumber())); - insertList.add(entity); + if (NumberUtil.isLess(winLossNumber, BigDecimal.ZERO)) { + entity.setInOutType(InOutTypeEnum.OUT.value()); + entity.setInOutItem(InOutItemEnum.LOSS_OUT.value()); + } else { + entity.setInOutType(InOutTypeEnum.IN.value()); + entity.setInOutItem(InOutItemEnum.WIN_IN.value()); + } + entity.setSubTotal(NumberUtil.mul(winLossNumber, param.getPrice())); + entity.setRemark(param.getRemark()); + saveFlow(entity); consInfo.setStockNumber(entity.getAfterNumber()); - updateStockList.add(consInfo); - } - super.saveBatch(insertList); - for (ConsInfo consInfo : updateStockList) { consInfoMapper.update(consInfo); } - } - @Override - @Transactional(rollbackFor = Exception.class) - public void outStock(ConsInOutStockHeadParam param) { - Long shopId = StpKit.USER.getShopId(0L); - Long createUserId = StpKit.USER.getLoginIdAsLong(); - String createUserName = StpKit.USER.getAccount(); - ConsStockFlow head = BeanUtil.copyProperties(param, ConsStockFlow.class); - List entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class); - List insertList = new ArrayList<>(); - List updateStockList = new ArrayList<>(); - for (ConsStockFlow entity : entityList) { - BeanUtil.copyProperties(head, entity, CopyOptions.create().ignoreNullValue()); - entity.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, entity.getInOutNumber())); - entity.setShopId(shopId); - entity.setInOutType(InOutTypeEnum.OUT.value()); - entity.setInOutItem(InOutItemEnum.MANUAL_OUT.value()); + @Override + public Page getCheckStockRecordPage(Long conId) { + Long shopId = StpKit.USER.getShopId(0L); + return super.pageAs(PageUtil.buildPage(), query().eq(ConsStockFlow::getShopId, shopId).eq(ConsStockFlow::getConId, conId).orderBy(ConsStockFlow::getId, false), ConsCheckStockRecordVo.class); + } + + @Override + public List getCheckStockRecordList(Long conId) { + Long shopId = StpKit.USER.getShopId(0L); + return super.mapper.selectListByQueryAs(query().eq(ConsStockFlow::getShopId, shopId).eq(ConsStockFlow::getConId, conId).orderBy(ConsStockFlow::getId, false), ConsCheckStockRecordVo.class); + } + + @Override + public void reportDamage(ConsReportDamageParam param) { + Long shopId = StpKit.USER.getShopId(0L); + Long createUserId = StpKit.USER.getLoginIdAsLong(); + String createUserName = StpKit.USER.getAccount(); + ConsInfo consInfo = consInfoMapper.selectOneById(param.getConId()); + if (consInfo == null) { + throw new CzgException("耗材不存在"); + } + ConsStockFlow entity = new ConsStockFlow(); entity.setCreateUserId(createUserId); entity.setCreateUserName(createUserName); - Long conId = entity.getConId(); - ConsInfo consInfo = consInfoMapper.selectOneById(conId); - if (consInfo == null) { - throw new CzgException(StrUtil.format("耗材{}不存在", entity.getConName())); + entity.setShopId(shopId); + entity.setConId(param.getConId()); + entity.setConName(consInfo.getConName()); + entity.setPurchasePrice(consInfo.getPrice()); + BigDecimal balance = NumberUtil.sub(consInfo.getStockNumber(), param.getNumber()); + if (NumberUtil.isLess(balance, BigDecimal.ZERO)) { + throw new CzgException(StrUtil.format("耗材{}报损数量不能大于当前库存{}", entity.getConName(), consInfo.getStockNumber())); } entity.setBeforeNumber(consInfo.getStockNumber()); - entity.setAfterNumber(NumberUtil.add(entity.getBeforeNumber(), entity.getInOutNumber())); - insertList.add(entity); + entity.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, param.getNumber())); + entity.setAfterNumber(balance); + entity.setInOutType(InOutTypeEnum.OUT.value()); + entity.setInOutItem(InOutItemEnum.DAMAGE_OUT.value()); + entity.setSubTotal(NumberUtil.mul(param.getNumber(), consInfo.getPrice())); + entity.setImgUrls(JSON.toJSONString(param.getImgUrls())); + saveFlow(entity); consInfo.setStockNumber(entity.getAfterNumber()); - updateStockList.add(consInfo); - } - super.saveBatch(insertList); - for (ConsInfo consInfo : updateStockList) { consInfoMapper.update(consInfo); } - } - @Override - @Transactional(rollbackFor = Exception.class) - public void checkStock(ConsCheckStockParam param) { - Long shopId = StpKit.USER.getShopId(0L); - Long createUserId = StpKit.USER.getLoginIdAsLong(); - String createUserName = StpKit.USER.getAccount(); - ConsStockFlow entity = new ConsStockFlow(); - entity.setCreateUserId(createUserId); - entity.setCreateUserName(createUserName); - entity.setShopId(shopId); - entity.setConId(param.getConId()); - entity.setConName(param.getConName()); - entity.setPurchasePrice(param.getPrice()); - ConsInfo consInfo = consInfoMapper.selectOneById(param.getConId()); - if (consInfo == null) { - throw new CzgException(StrUtil.format("耗材{}不存在", entity.getConName())); + @Override + public Page findConsStockFlowPage(ConsStockFlowParam param) { + Long shopId = StpKit.USER.getShopId(0L); + PageHelper.startPage(PageUtil.buildPageHelp()); + return PageUtil.convert(new PageInfo<>(mapper.findConsStockFlowPage(shopId, param.getInOutType(), param.getInOutItem(), param.getConId()))); } - BigDecimal winLossNumber = NumberUtil.sub(param.getActualNumber(), param.getStockNumber()); - if (!NumberUtil.equals(winLossNumber, param.getWinLossNumber())) { - throw new CzgException(StrUtil.format("耗材{}库存在发生变动,请刷新后重试", entity.getConName())); - } - entity.setBeforeNumber(consInfo.getStockNumber()); - entity.setInOutNumber(winLossNumber); - entity.setAfterNumber(NumberUtil.add(entity.getBeforeNumber(), entity.getInOutNumber())); - if (NumberUtil.isLess(winLossNumber, BigDecimal.ZERO)) { - entity.setInOutType(InOutTypeEnum.OUT.value()); - entity.setInOutItem(InOutItemEnum.LOSS_OUT.value()); - } else { - entity.setInOutType(InOutTypeEnum.IN.value()); - entity.setInOutItem(InOutItemEnum.WIN_IN.value()); - } - entity.setSubTotal(NumberUtil.mul(winLossNumber, param.getPrice())); - entity.setRemark(param.getRemark()); - saveFlow(entity); - consInfo.setStockNumber(entity.getAfterNumber()); - consInfoMapper.update(consInfo); - } - @Override - public Page getCheckStockRecordPage(Long conId) { - Long shopId = StpKit.USER.getShopId(0L); - return super.pageAs(PageUtil.buildPage(), query().eq(ConsStockFlow::getShopId, shopId).eq(ConsStockFlow::getConId, conId).orderBy(ConsStockFlow::getId, false), ConsCheckStockRecordVo.class); - } - - @Override - public List getCheckStockRecordList(Long conId) { - Long shopId = StpKit.USER.getShopId(0L); - return super.mapper.selectListByQueryAs(query().eq(ConsStockFlow::getShopId, shopId).eq(ConsStockFlow::getConId, conId).orderBy(ConsStockFlow::getId, false), ConsCheckStockRecordVo.class); - } - - @Override - public void reportDamage(ConsReportDamageParam param) { - Long shopId = StpKit.USER.getShopId(0L); - Long createUserId = StpKit.USER.getLoginIdAsLong(); - String createUserName = StpKit.USER.getAccount(); - ConsInfo consInfo = consInfoMapper.selectOneById(param.getConId()); - if (consInfo == null) { - throw new CzgException("耗材不存在"); - } - ConsStockFlow entity = new ConsStockFlow(); - entity.setCreateUserId(createUserId); - entity.setCreateUserName(createUserName); - entity.setShopId(shopId); - entity.setConId(param.getConId()); - entity.setConName(consInfo.getConName()); - entity.setPurchasePrice(consInfo.getPrice()); - BigDecimal balance = NumberUtil.sub(consInfo.getStockNumber(), param.getNumber()); - if (NumberUtil.isLess(balance, BigDecimal.ZERO)) { - throw new CzgException(StrUtil.format("耗材{}报损数量不能大于当前库存{}", entity.getConName(), consInfo.getStockNumber())); - } - entity.setBeforeNumber(consInfo.getStockNumber()); - entity.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, param.getNumber())); - entity.setAfterNumber(balance); - entity.setInOutType(InOutTypeEnum.OUT.value()); - entity.setInOutItem(InOutItemEnum.DAMAGE_OUT.value()); - entity.setSubTotal(NumberUtil.mul(param.getNumber(), consInfo.getPrice())); - entity.setImgUrls(JSON.toJSONString(param.getImgUrls())); - saveFlow(entity); - consInfo.setStockNumber(entity.getAfterNumber()); - consInfoMapper.update(consInfo); - } - - @Override - public Page findConsStockFlowPage(ConsStockFlowParam param) { - Long shopId = StpKit.USER.getShopId(0L); - PageHelper.startPage(PageUtil.buildPageHelp()); - return PageUtil.convert(new PageInfo<>(mapper.findConsStockFlowPage(shopId, param.getInOutType(), param.getInOutItem(), param.getConId()))); - } - - @Override - public void saveFlow(ConsStockFlow entity) { - super.save(entity); - Long shopId = entity.getShopId(); - BigDecimal afterNumber = entity.getAfterNumber(); - ConsInfo consInfo = consInfoMapper.selectOneById(entity.getConId()); - String shopName = ""; - try { - shopName = StpKit.USER.getShopName(); - } catch (Exception e) { - log.error("获取店铺名称失败"); - } - if (StrUtil.isEmpty(shopName)) { - shopName = productMapper.getShopName(shopId); - } - BigDecimal conWarning = consInfo.getConWarning(); - // 库存小于警告值,发送消息提醒 - if (NumberUtil.isLess(afterNumber, conWarning)) { - List openIdList = consInfoMapper.findOpenIdList(shopId, "con"); - if (CollUtil.isEmpty(openIdList)) { - return; - } - String conName = StrUtil.format("{}数量<预警值{}", consInfo.getConName(), conWarning); - String finalShopName = shopName; - ThreadUtil.execAsync(() -> { - openIdList.parallelStream().forEach(openId -> { - wxAccountUtil.sendStockMsg(finalShopName, conName, afterNumber, openId); - }); - }); - } - } - - @Override - public Integer ocr(String originalFilename, InputStream inputStream) { - Long shopId = StpKit.USER.getShopId(); - String md5 = DigestUtil.md5Hex(inputStream); - MkOcr ocr = ocrService.getOne(new QueryWrapper().eq(MkOcr::getShopId, shopId).eq(MkOcr::getMd5, md5)); - if (ocr != null) { - return ocr.getId(); - } - MkOcr mkOcr = new MkOcr(); - mkOcr.setShopId(shopId); - mkOcr.setMd5(md5); - ocrService.save(mkOcr); - ThreadUtil.execAsync(() -> { + @Override + public void saveFlow(ConsStockFlow entity) { + super.save(entity); + Long shopId = entity.getShopId(); + BigDecimal afterNumber = entity.getAfterNumber(); + ConsInfo consInfo = consInfoMapper.selectOneById(entity.getConId()); + String shopName = ""; try { - String infoStr = AliOcrUtil.appCall(inputStream, originalFilename); - SaleOrderDTO saleOrderDTO = JSONObject.parseObject(infoStr, SaleOrderDTO.class); - - ArrayList bodyList = new ArrayList<>(); - Set nameList = saleOrderDTO.getItems().stream().map(SaleOrderDTO.Item::getConName).collect(Collectors.toSet()); - Map consInfoMap = new HashMap<>(); - if (!nameList.isEmpty()) { - consInfoMap = consInfoMapper.selectListByQuery(new QueryWrapper().in(ConsInfo::getConName, nameList).eq(ConsInfo::getShopId, shopId)) - .stream().collect(Collectors.toMap(ConsInfo::getConName, consInfo -> consInfo)); - } - ArrayList unInCons = new ArrayList<>(); - for (SaleOrderDTO.Item item : saleOrderDTO.getItems()) { - ConsInfo consInfo = consInfoMap.get(item.getConName()); - if (consInfo == null) { - unInCons.add(item); - continue; - } - bodyList.add(new ConsInOutStockBodyParam() - .setConId(consInfo.getId().toString()) - .setConName(consInfo.getConName()) - .setPurchasePrice(new BigDecimal(item.getPurchasePrice())) - .setUnitName(item.getUnitName()) - .setSubTotal(new BigDecimal(item.getSubTotal())) - .setInOutNumber(new BigDecimal(item.getInOutNumber()))); - } - - ConsInOutStockHeadParam headParam = new ConsInOutStockHeadParam(); - headParam.setBatchNo(saleOrderDTO.getOrderNumber()) - .setInOutDate(LocalDate.parse(saleOrderDTO.getDate())) - .setAmountPayable(new BigDecimal(saleOrderDTO.getTotalAmount())) - .setBodyList(bodyList) - .setUnInCons(unInCons) - .setOcrSaleOrder(saleOrderDTO); - - - mkOcr.setStatus("SUCCESS"); - mkOcr.setResp(JSON.toJSONString(headParam)); - }catch (Exception e) { - mkOcr.setErr(e.getMessage()); - mkOcr.setStatus("FAILED"); - log.warn("ocr失败: {}", e.getMessage()); - }finally { - ocrService.updateById(mkOcr); + shopName = StpKit.USER.getShopName(); + } catch (Exception e) { + log.error("获取店铺名称失败"); + } + if (StrUtil.isEmpty(shopName)) { + shopName = productMapper.getShopName(shopId); + } + BigDecimal conWarning = consInfo.getConWarning(); + // 库存小于警告值,发送消息提醒 + if (NumberUtil.isLess(afterNumber, conWarning)) { + List openIdList = consInfoMapper.findOpenIdList(shopId, "con"); + if (CollUtil.isEmpty(openIdList)) { + return; + } + String conName = StrUtil.format("{}数量<预警值{}", consInfo.getConName(), conWarning); + String finalShopName = shopName; + ThreadUtil.execAsync(() -> { + openIdList.parallelStream().forEach(openId -> { + wxAccountUtil.sendStockMsg(finalShopName, conName, afterNumber, openId); + }); + }); } - - }); - - return mkOcr.getId(); - } - - @Override - public ConsInOutStockHeadParam ocrDetail(Long id) { - MkOcr mkOcr = ocrService.getOne(new QueryWrapper().eq(MkOcr::getShopId, StpKit.USER.getShopId()).eq(MkOcr::getId, id)); - if (StrUtil.isNotBlank(mkOcr.getResp())) { - return JSONObject.parseObject(mkOcr.getResp(), ConsInOutStockHeadParam.class); } - return null; + + @Override + public Integer ocr(String originalFilename, InputStream inputStream) { + Long shopId = StpKit.USER.getShopId(); + byte[] readAllBytes = null; + try { + readAllBytes = inputStream.readAllBytes(); + } catch (IOException e) { + throw new RuntimeException(e); + } + String md5 = DigestUtil.md5Hex(readAllBytes); + MkOcr ocr = ocrService.getOne(new QueryWrapper().eq(MkOcr::getShopId, shopId).eq(MkOcr::getMd5, md5)); + if (ocr != null) { + // return ocr.getId(); + } + MkOcr mkOcr = new MkOcr(); + mkOcr.setShopId(shopId); + mkOcr.setMd5(md5); + ocrService.save(mkOcr); + byte[] finalReadAllBytes1 = readAllBytes; + ThreadUtil.execAsync(() -> { + try { + String infoStr = AliOcrUtil.appCall(finalReadAllBytes1, originalFilename); + SaleOrderDTO saleOrderDTO = JSONObject.parseObject(infoStr, SaleOrderDTO.class); + + ArrayList bodyList = new ArrayList<>(); + Set nameList = saleOrderDTO.getItems().stream().map(SaleOrderDTO.Item::getConName).collect(Collectors.toSet()); + Map consInfoMap = new HashMap<>(); + if (!nameList.isEmpty()) { + consInfoMap = consInfoMapper.selectListByQuery(new QueryWrapper().in(ConsInfo::getConName, nameList).eq(ConsInfo::getShopId, shopId)) + .stream().collect(Collectors.toMap(ConsInfo::getConName, consInfo -> consInfo)); + } + ArrayList unInCons = new ArrayList<>(); + for (SaleOrderDTO.Item item : saleOrderDTO.getItems()) { + ConsInfo consInfo = consInfoMap.get(item.getConName()); + if (consInfo == null) { + unInCons.add(item); + continue; + } + bodyList.add(new ConsInOutStockBodyParam() + .setConId(consInfo.getId().toString()) + .setConName(consInfo.getConName()) + .setPurchasePrice(new BigDecimal(item.getPurchasePrice())) + .setUnitName(item.getUnitName()) + .setSubTotal(new BigDecimal(item.getSubTotal())) + .setInOutNumber(new BigDecimal(item.getInOutNumber()))); + } + + ConsInOutStockHeadParam headParam = new ConsInOutStockHeadParam(); + headParam.setBatchNo(saleOrderDTO.getOrderNumber()) + .setInOutDate(LocalDate.parse(saleOrderDTO.getDate())) + .setAmountPayable(new BigDecimal(saleOrderDTO.getTotalAmount())) + .setBodyList(bodyList) + .setUnInCons(unInCons) + .setOcrSaleOrder(saleOrderDTO); + + + mkOcr.setStatus("SUCCESS"); + mkOcr.setResp(JSON.toJSONString(headParam)); + }catch (Exception e) { + mkOcr.setErr(e.getMessage()); + mkOcr.setStatus("FAILED"); + log.error("ocr失败:", e); + }finally { + ocrService.updateById(mkOcr); + } + + }); + + return mkOcr.getId(); + } + + @Override + public ConsInOutStockHeadParam ocrDetail(Long id) { + MkOcr mkOcr = ocrService.getOne(new QueryWrapper().eq(MkOcr::getShopId, StpKit.USER.getShopId()).eq(MkOcr::getId, id)); + if (StrUtil.isNotBlank(mkOcr.getResp())) { + return JSONObject.parseObject(mkOcr.getResp(), ConsInOutStockHeadParam.class); + } + return null; + } } -}