1.库存新增上下架接口

2.库存记录返回orderNo
3.增加保存库存记录mq处理
This commit is contained in:
SongZhang 2024-07-17 09:55:23 +08:00
parent 279057d54f
commit a16b2925b2
13 changed files with 223 additions and 11 deletions

View File

@ -0,0 +1,30 @@
package cn.ysk.cashier.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfig {
public static final String QUEUE_STOCK_RECORD_SALE = "queue.stock.record.sale";
public static final String EXCHANGE_STOCK_RECORD = "exchange.stock.record";
public static final String ROUTING_STOCK_RECORD_SALE = "routing.stock.record.sale";
@Bean
Queue stockRecordSaleQueue() {
return new Queue(QUEUE_STOCK_RECORD_SALE);
}
@Bean
DirectExchange stockRecordExchange() {
return new DirectExchange(EXCHANGE_STOCK_RECORD);
}
@Bean
Binding binding(Queue stockRecordSaleQueue, DirectExchange stockRecordExchange) {
return BindingBuilder.bind(stockRecordSaleQueue).to(stockRecordExchange).with(ROUTING_STOCK_RECORD_SALE);
}
}

View File

@ -1,6 +1,7 @@
package cn.ysk.cashier.controller.product; package cn.ysk.cashier.controller.product;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.ysk.cashier.annotation.AnonymousAccess;
import cn.ysk.cashier.annotation.Log; import cn.ysk.cashier.annotation.Log;
import cn.ysk.cashier.annotation.rest.AnonymousPostMapping; import cn.ysk.cashier.annotation.rest.AnonymousPostMapping;
import cn.ysk.cashier.dto.product.StockQueryDto; import cn.ysk.cashier.dto.product.StockQueryDto;
@ -112,6 +113,18 @@ public class StockController {
return new ResponseEntity<>(dataMap, HttpStatus.OK); return new ResponseEntity<>(dataMap, HttpStatus.OK);
} }
@AnonymousAccess
@PutMapping("/grounding")
@ApiOperation("上下架商品")
public ResponseEntity<Object> grounding(
@RequestParam Integer shopId,
@RequestParam Integer skuId,
@RequestParam Boolean isGrounding
){
stockService.grounding(shopId,skuId, isGrounding);
return ResponseEntity.ok("success");
}
@GetMapping("/sku") @GetMapping("/sku")
@ApiOperation("查询库存") @ApiOperation("查询库存")
public ResponseEntity<Object> queryProductSku(String productId){ public ResponseEntity<Object> queryProductSku(String productId){

View File

@ -15,6 +15,7 @@
*/ */
package cn.ysk.cashier.controller.product; package cn.ysk.cashier.controller.product;
import cn.ysk.cashier.annotation.AnonymousAccess;
import cn.ysk.cashier.annotation.Log; import cn.ysk.cashier.annotation.Log;
import cn.ysk.cashier.pojo.product.TbProductStockDetail; import cn.ysk.cashier.pojo.product.TbProductStockDetail;
import cn.ysk.cashier.service.product.TbProductStockDetailService; import cn.ysk.cashier.service.product.TbProductStockDetailService;
@ -91,4 +92,4 @@ public class TbProductStockDetailController {
tbProductStockDetailService.deleteAll(ids); tbProductStockDetailService.deleteAll(ids);
return new ResponseEntity<>(HttpStatus.OK); return new ResponseEntity<>(HttpStatus.OK);
} }
} }

View File

@ -127,6 +127,10 @@ public class TbProductSku implements Serializable {
@ApiModelProperty(value = "是否暂停销售") @ApiModelProperty(value = "是否暂停销售")
private Integer isPauseSale = 0; private Integer isPauseSale = 0;
@Column(name = "`is_grounding`")
@ApiModelProperty(value = "是否上架")
private Integer isGrounding = 0;
public void setIsDel(Integer isDel) { public void setIsDel(Integer isDel) {
if(isDel!=null){ if(isDel!=null){
this.isDel = isDel; this.isDel = isDel;

View File

@ -0,0 +1,36 @@
package cn.ysk.cashier.rabbit;
import cn.ysk.cashier.config.RabbitConfig;
import cn.ysk.cashier.pojo.product.TbProductStockDetail;
import cn.ysk.cashier.service.product.TbProductStockDetailService;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class StockListener {
private final TbProductStockDetailService productStockDetailService;
public StockListener(TbProductStockDetailService productStockDetailService) {
this.productStockDetailService = productStockDetailService;
}
@RabbitListener(queues = RabbitConfig.QUEUE_STOCK_RECORD_SALE)
public void recordSaleHandler(String message) {
log.info("接收到下单保存库存信息mq消息消息内容: {}", message);
JSONObject jsonObject = JSONObject.parseObject(message);
if (!jsonObject.containsKey("orderId")) {
log.info("mq消息体有误确实orderId");
return;
}
try {
productStockDetailService.addSaleRecord(jsonObject.getInteger("orderId"));
}catch (Exception e) {
log.error("执行保存库存mq失败", e);
}
}
}

View File

@ -2,6 +2,7 @@ package cn.ysk.cashier.repository.order;
import cn.ysk.cashier.dto.product.StockCountDTO; import cn.ysk.cashier.dto.product.StockCountDTO;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
@ -32,4 +33,20 @@ public interface StockCountRepository extends JpaRepository<StockCountDTO, Integ
"info.product_id ",nativeQuery = true) "info.product_id ",nativeQuery = true)
List<StockCountDTO> countStock( @Param("startTime") String startTime, @Param("endTime") String endTime); List<StockCountDTO> countStock( @Param("startTime") String startTime, @Param("endTime") String endTime);
} @Query(value = "SELECT pro.shop_id as shop_id, pro.id as pro_id, info.product_name as pro_name, pro.is_stock," +
" info.product_sku_name as sku_name, unit.NAME as unit_name ," +
"SUM( CASE WHEN orders.order_type != 'return' THEN info.num ELSE 0 END )- SUM( CASE WHEN orders.order_type = 'return' THEN info.num ELSE 0 END ) as stock_count," +
"CASE WHEN pro.is_distribute = '0' THEN sku.stock_number ELSE pro.stock_number END AS stock_number " +
"FROM " +
"tb_order_info orders " +
"LEFT JOIN tb_order_detail info ON orders.id = info.order_id " +
"LEFT JOIN tb_product pro ON info.product_id = pro.id " +
"LEFT JOIN (SELECT product_id,sum(stock_number) as stock_number from tb_product_sku GROUP BY product_id) sku ON info.product_id = sku.product_id " +
"LEFT JOIN tb_shop_unit unit ON unit.id = pro.unit_id " +
"WHERE " +
"orders.id = :orderId " +
"AND ( info.STATUS = 'closed' OR info.STATUS = 'refund' ) " +
"GROUP BY " +
"info.product_id ",nativeQuery = true)
List<StockCountDTO> countStockById(Integer orderId);
}

View File

@ -55,4 +55,7 @@ public interface TbProductRepository extends JpaRepository<TbProduct, Integer>,
@Modifying @Modifying
@Query("update TbProduct set stockNumber=stockNumber+:num where id=:id") @Query("update TbProduct set stockNumber=stockNumber+:num where id=:id")
void incrStock(@Param("id") Integer id, @Param("num") Integer num); void incrStock(@Param("id") Integer id, @Param("num") Integer num);
@Query("select product from TbProduct product where product.id=:id and product.shopId=:shopId")
TbProduct selectByShopIdAndId(Integer id, String shopId);
} }

View File

@ -3,6 +3,7 @@ package cn.ysk.cashier.repository.product;
import cn.ysk.cashier.pojo.product.TbProductSku; import cn.ysk.cashier.pojo.product.TbProductSku;
import cn.ysk.cashier.vo.StockV2Vo; import cn.ysk.cashier.vo.StockV2Vo;
import cn.ysk.cashier.vo.StockVo; import cn.ysk.cashier.vo.StockVo;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update; import org.apache.ibatis.annotations.Update;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
@ -10,7 +11,6 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query; import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import javax.transaction.Transactional; import javax.transaction.Transactional;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -170,4 +170,14 @@ public interface TbProductSkuRepository extends JpaRepository<TbProductSku, Inte
@Modifying @Modifying
@Query("update TbProductSku set stockNumber=stockNumber+:num where id=:productId") @Query("update TbProductSku set stockNumber=stockNumber+:num where id=:productId")
void incrStock(@Param("productId") Integer productId, @Param("num") Double num); void incrStock(@Param("productId") Integer productId, @Param("num") Double num);
@Transactional
@Modifying
@Query("update TbProductSku set isGrounding=:isGrounding where productId=:productId")
void updateGroundingByProId(@Param("productId") String productId, @Param("isGrounding") Integer isGrounding);
@Transactional
@Modifying
@Query("update TbProductSku set isGrounding=:isGrounding where id=:skuId")
void updateGrounding(Integer skuId,int isGrounding);
} }

View File

@ -4,10 +4,12 @@ import cn.ysk.cashier.dto.product.OutAndOnDto;
import cn.ysk.cashier.dto.product.StockQueryDto; import cn.ysk.cashier.dto.product.StockQueryDto;
import cn.ysk.cashier.dto.product.TbProductDto; import cn.ysk.cashier.dto.product.TbProductDto;
import cn.ysk.cashier.exception.BadRequestException; import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.pojo.product.TbProduct;
import cn.ysk.cashier.pojo.product.TbProductSku; import cn.ysk.cashier.pojo.product.TbProductSku;
import cn.ysk.cashier.pojo.product.TbProductStockDetail; import cn.ysk.cashier.pojo.product.TbProductStockDetail;
import cn.ysk.cashier.pojo.shop.TbShopInfo; import cn.ysk.cashier.pojo.shop.TbShopInfo;
import cn.ysk.cashier.pojo.shop.TbShopUnit; import cn.ysk.cashier.pojo.shop.TbShopUnit;
import cn.ysk.cashier.repository.product.TbProductRepository;
import cn.ysk.cashier.repository.product.TbProductSkuRepository; import cn.ysk.cashier.repository.product.TbProductSkuRepository;
import cn.ysk.cashier.repository.product.TbProductStockDetailRepository; import cn.ysk.cashier.repository.product.TbProductStockDetailRepository;
import cn.ysk.cashier.repository.shop.TbShopInfoRepository; import cn.ysk.cashier.repository.shop.TbShopInfoRepository;
@ -15,7 +17,6 @@ import cn.ysk.cashier.repository.shop.TbShopUnitRepository;
import cn.ysk.cashier.service.TbProductStockOperateService; import cn.ysk.cashier.service.TbProductStockOperateService;
import cn.ysk.cashier.service.product.StockService; import cn.ysk.cashier.service.product.StockService;
import cn.ysk.cashier.service.product.TbProductService; import cn.ysk.cashier.service.product.TbProductService;
import cn.ysk.cashier.service.product.TbProductStockDetailService;
import cn.ysk.cashier.utils.CacheKey; import cn.ysk.cashier.utils.CacheKey;
import cn.ysk.cashier.utils.FileUtil; import cn.ysk.cashier.utils.FileUtil;
import cn.ysk.cashier.utils.RedisUtils; import cn.ysk.cashier.utils.RedisUtils;
@ -60,6 +61,7 @@ public class StockServiceImpl implements StockService {
private final TbShopInfoRepository tbShopInfoRepository; private final TbShopInfoRepository tbShopInfoRepository;
private final TbShopUnitRepository shopUnitRepository; private final TbShopUnitRepository shopUnitRepository;
private final TbProductStockDetailRepository tbProductStockDetailRepository; private final TbProductStockDetailRepository tbProductStockDetailRepository;
private final TbProductRepository tbProductRepository;
@PersistenceContext @PersistenceContext
private EntityManager em; private EntityManager em;
@ -384,4 +386,19 @@ public class StockServiceImpl implements StockService {
} }
tbProductSkuRepository.updateWarnLineByShopId(stockUpdateWarnLineVO.getWarnLine(), stockUpdateWarnLineVO.getShopId()); tbProductSkuRepository.updateWarnLineByShopId(stockUpdateWarnLineVO.getWarnLine(), stockUpdateWarnLineVO.getShopId());
} }
@Override
public void grounding(Integer shopId, Integer skuId, Boolean isGrounding) {
TbProductSku tbProductSku = skuRepository.findById(skuId).orElse(null);
if (tbProductSku == null) {
throw new BadRequestException("商品不存在skuId: " + skuId);
}
TbProduct product = tbProductRepository.selectByShopIdAndId(Integer.parseInt(tbProductSku.getProductId()), String.valueOf(shopId));
// 共享库存下架所有sku
if (product.getIsDistribute().equals(1)) {
tbProductSkuRepository.updateGroundingByProId(product.getId().toString(), isGrounding ? 1 : 0);
}else {
tbProductSkuRepository.updateGrounding(skuId, isGrounding ? 1 : 0);
}
}
} }

View File

@ -15,27 +15,31 @@
*/ */
package cn.ysk.cashier.service.impl.productimpl; package cn.ysk.cashier.service.impl.productimpl;
import cn.hutool.core.util.StrUtil;
import cn.ysk.cashier.dto.product.StockCountDTO;
import cn.ysk.cashier.pojo.order.TbOrderInfo;
import cn.ysk.cashier.pojo.product.TbProductStockDetail; import cn.ysk.cashier.pojo.product.TbProductStockDetail;
import cn.ysk.cashier.utils.ValidationUtil; import cn.ysk.cashier.repository.order.StockCountRepository;
import cn.ysk.cashier.utils.FileUtil; import cn.ysk.cashier.repository.order.TbOrderInfoRepository;
import cn.ysk.cashier.utils.*;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import cn.ysk.cashier.repository.product.TbProductStockDetailRepository; import cn.ysk.cashier.repository.product.TbProductStockDetailRepository;
import cn.ysk.cashier.service.product.TbProductStockDetailService; import cn.ysk.cashier.service.product.TbProductStockDetailService;
import cn.ysk.cashier.dto.product.TbProductStockDetailDto; import cn.ysk.cashier.dto.product.TbProductStockDetailDto;
import cn.ysk.cashier.dto.product.TbProductStockDetailQueryCriteria; import cn.ysk.cashier.dto.product.TbProductStockDetailQueryCriteria;
import cn.ysk.cashier.mapper.product.TbProductStockDetailMapper; import cn.ysk.cashier.mapper.product.TbProductStockDetailMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import cn.ysk.cashier.utils.PageUtil;
import cn.ysk.cashier.utils.QueryHelp;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.*; import java.util.*;
import java.io.IOException; import java.io.IOException;
import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
/** /**
@ -46,11 +50,17 @@ import javax.servlet.http.HttpServletResponse;
**/ **/
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j
public class TbProductStockDetailServiceImpl implements TbProductStockDetailService { public class TbProductStockDetailServiceImpl implements TbProductStockDetailService {
private final TbProductStockDetailRepository tbProductStockDetailRepository; private final TbProductStockDetailRepository tbProductStockDetailRepository;
private final TbProductStockDetailMapper tbProductStockDetailMapper; private final TbProductStockDetailMapper tbProductStockDetailMapper;
private final StockCountRepository stockCountRepository;
private final EntityManager entityManager;
private final TbOrderInfoRepository tbOrderInfoRepository;
@Override @Override
public Map<String,Object> queryAll(TbProductStockDetailQueryCriteria criteria, Pageable pageable){ public Map<String,Object> queryAll(TbProductStockDetailQueryCriteria criteria, Pageable pageable){
Page<TbProductStockDetail> page = tbProductStockDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); Page<TbProductStockDetail> page = tbProductStockDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
@ -66,10 +76,23 @@ public class TbProductStockDetailServiceImpl implements TbProductStockDetailServ
Page<TbProductStockDetail> page = tbProductStockDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) Page<TbProductStockDetail> page = tbProductStockDetailRepository.findAll((root, criteriaQuery, criteriaBuilder)
-> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
Page<TbProductStockDetailDto> map = page.map(tbProductStockDetailMapper::toDto); Page<TbProductStockDetailDto> map = page.map(tbProductStockDetailMapper::toDto);
ArrayList<Map<String, Object>> contents = new ArrayList<>();
for (TbProductStockDetailDto tbProductStockDetailDto : map.getContent()) { for (TbProductStockDetailDto tbProductStockDetailDto : map.getContent()) {
if (StrUtil.isNotBlank(tbProductStockDetailDto.getOrderId())) {
TbOrderInfo tbOrderInfo = tbOrderInfoRepository.findById(Integer.valueOf(tbProductStockDetailDto.getOrderId())).orElse(null);
Map<String, Object> map1 = BeanUtil.transBean2Map(tbProductStockDetailDto);
if (tbOrderInfo != null) {
map1.put("orderNo", tbOrderInfo.getOrderNo());
}
contents.add(map1);
}
tbProductStockDetailDto.setTypes(); tbProductStockDetailDto.setTypes();
} }
return PageUtil.toPage(map); Map<String,Object> info = new LinkedHashMap<>(2);
info.put("content",contents);
info.put("totalElements",page.getTotalElements());
return info;
} }
@ -152,4 +175,33 @@ public class TbProductStockDetailServiceImpl implements TbProductStockDetailServ
} }
FileUtil.downloadExcel(list, response); FileUtil.downloadExcel(list, response);
} }
}
@Override
public void addSaleRecord(Integer orderId) {
List<StockCountDTO> stockCountDTOS = stockCountRepository.countStockById(orderId);
log.info("查询到订单id: {}的所有库存数据: {}", orderId, stockCountDTOS);
stockCountDTOS.forEach(s->{
if (s.getStockCount() > 0) {
TbProductStockDetail productStockDetail = new TbProductStockDetail();
productStockDetail.setCreatedAt(System.currentTimeMillis());
productStockDetail.setUpdatedAt(System.currentTimeMillis());
productStockDetail.setShopId(s.getShopId());
productStockDetail.setProductId(s.getProId().toString());
productStockDetail.setProductName(s.getProName());
productStockDetail.setOrderId(orderId.toString());
// productStockDetail.setSkuId(s.getSkuId().toString());
productStockDetail.setIsStock(s.getIsStock());//是否开启库存
productStockDetail.setLeftNumber(s.getStockNumber()+s.getStockCount());//原库存
// productStockDetail.setSpecSnap(s.getSkuName());
productStockDetail.setUnitName(s.getUnitName());
productStockDetail.setStockNumber(-Double.valueOf(s.getStockCount()));
productStockDetail.setSourcePath("NORMAL");
productStockDetail.setType("售出记录");
productStockDetail.setRemark("售出记录:" + orderId);
productStockDetail.setSubType(-1);
tbProductStockDetailRepository.save(productStockDetail);
}
});
}
}

View File

@ -44,4 +44,13 @@ public interface StockService {
* @param stockUpdateWarnLineVO 警戒线 * @param stockUpdateWarnLineVO 警戒线
*/ */
void updateProductWarnLine(StockUpdateWarnLineVO stockUpdateWarnLineVO); void updateProductWarnLine(StockUpdateWarnLineVO stockUpdateWarnLineVO);
/**
* 上下架商品
*
* @param shopId 店铺id
* @param skuId ski
* @param isGrounding
*/
void grounding(Integer shopId, Integer skuId, Boolean isGrounding);
} }

View File

@ -86,4 +86,6 @@ public interface TbProductStockDetailService {
* @throws IOException / * @throws IOException /
*/ */
void download(List<TbProductStockDetailDto> all, HttpServletResponse response) throws IOException; void download(List<TbProductStockDetailDto> all, HttpServletResponse response) throws IOException;
}
void addSaleRecord(Integer orderId);
}

View File

@ -0,0 +1,18 @@
package cn.ysk.cashier.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.function.Supplier;
public class Utils {
private static final Logger log = LoggerFactory.getLogger(Utils.class);
public static <T> void catchErrNoReturn(Supplier<T> supplier) {
try {
supplier.get();
}catch (Exception e) {
log.error("执行方法出现异常", e);
}
}
}