|
|
|
|
@@ -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<ConsStockFlowMapper, ConsStockFlow> implements ConsStockFlowService {
|
|
|
|
|
/**
|
|
|
|
|
* 耗材库存变动记录
|
|
|
|
|
*
|
|
|
|
|
* @author Tankaikai tankaikai@aliyun.com
|
|
|
|
|
* @since 1.0 2025-02-21
|
|
|
|
|
*/
|
|
|
|
|
@AllArgsConstructor
|
|
|
|
|
@Service
|
|
|
|
|
@Slf4j
|
|
|
|
|
public class ConsStockFlowServiceImpl extends ServiceImpl<ConsStockFlowMapper, ConsStockFlow> 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<ConsStockFlow> entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class);
|
|
|
|
|
List<ConsStockFlow> insertList = new ArrayList<>();
|
|
|
|
|
List<ConsInfo> 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<ConsStockFlow> entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class);
|
|
|
|
|
List<ConsStockFlow> insertList = new ArrayList<>();
|
|
|
|
|
List<ConsInfo> 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<ConsStockFlow> entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class);
|
|
|
|
|
List<ConsStockFlow> insertList = new ArrayList<>();
|
|
|
|
|
List<ConsInfo> 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<ConsStockFlow> entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class);
|
|
|
|
|
List<ConsStockFlow> insertList = new ArrayList<>();
|
|
|
|
|
List<ConsInfo> 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<ConsCheckStockRecordVo> 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<ConsCheckStockRecordVo> 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<ConsStockFlowDTO> 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<ConsCheckStockRecordVo> 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<ConsCheckStockRecordVo> 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<ConsStockFlowDTO> 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<String> 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<ConsInOutStockBodyParam> bodyList = new ArrayList<>();
|
|
|
|
|
Set<String> nameList = saleOrderDTO.getItems().stream().map(SaleOrderDTO.Item::getConName).collect(Collectors.toSet());
|
|
|
|
|
Map<String, ConsInfo> 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<SaleOrderDTO.Item> 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<String> 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<ConsInOutStockBodyParam> bodyList = new ArrayList<>();
|
|
|
|
|
Set<String> nameList = saleOrderDTO.getItems().stream().map(SaleOrderDTO.Item::getConName).collect(Collectors.toSet());
|
|
|
|
|
Map<String, ConsInfo> 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<SaleOrderDTO.Item> 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|