新增盘点接口

This commit is contained in:
SongZhang 2024-07-01 18:10:43 +08:00
parent 2af4c4d44e
commit 7bf66ab106
15 changed files with 518 additions and 3 deletions

View File

@ -82,4 +82,5 @@ public class TbProductStockOperateController {
tbProductStockOperateService.deleteAll(ids);
return new ResponseEntity<>(HttpStatus.OK);
}
}

View File

@ -0,0 +1,55 @@
package cn.ysk.cashier.controller.product;
import cn.hutool.core.util.StrUtil;
import cn.ysk.cashier.annotation.AnonymousAccess;
import cn.ysk.cashier.dto.product.TbProductStocktakinDTO;
import cn.ysk.cashier.dto.product.TbProductStocktakinQueryCriteria;
import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.service.product.TbProductStocktakinService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
@RestController
@RequiredArgsConstructor
@Api(tags = "库存盘点操作")
@RequestMapping("/api/tbProductStocktakin")
public class TbProductStocktakinController {
private final TbProductStocktakinService tbProductStocktakinService;
@PostMapping
@AnonymousAccess
@ApiOperation("新增盘点")
public ResponseEntity<Object> addStocktakin(
@RequestBody @Validated TbProductStocktakinDTO productStocktakinDTO
) {
if (productStocktakinDTO.getShopId() == null || productStocktakinDTO.getProductId() == null || productStocktakinDTO.getStocktakinNum() == null) {
throw new BadRequestException("参数缺失");
}
if (productStocktakinDTO.getStocktakinNum() < 0) {
throw new BadRequestException("盘点数量不能为负数");
}
tbProductStocktakinService.addStocktakin(productStocktakinDTO);
return ResponseEntity.ok("成功");
}
@AnonymousAccess
@GetMapping
@ApiOperation("获取盘点数据")
public ResponseEntity<Object> getStocktakinList(TbProductStocktakinQueryCriteria productStocktakinQueryCriteria, Pageable pageable) {
productStocktakinQueryCriteria.setSort("id,desc");
if (productStocktakinQueryCriteria.getShopId() == null) {
throw new BadRequestException("店铺id缺失");
}
return ResponseEntity.ok(tbProductStocktakinService.getPage(productStocktakinQueryCriteria, pageable));
}
}

View File

@ -0,0 +1,23 @@
package cn.ysk.cashier.dto.product;
import lombok.Data;
import org.yaml.snakeyaml.events.Event;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Data
public class TbProductStocktakinDTO {
private Integer skuId;
@NotNull
private Integer shopId;
@NotNull
private Integer productId;
@NotNull
@Min(0)
private Integer stocktakinNum;
private BigDecimal price;
private String note;
}

View File

@ -0,0 +1,9 @@
package cn.ysk.cashier.dto.product;
import lombok.Data;
@Data
public class TbProductStocktakinGetDTO {
private Integer productId;
private Integer skuId;
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.ysk.cashier.dto.product;
import cn.ysk.cashier.annotation.Query;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
/**
* @website https://eladmin.vip
* @author lyf
* @date 2024-01-19
**/
@Data
public class TbProductStocktakinQueryCriteria {
/** 精确 */
@Query
private Integer shopId;
/** 精确 */
@Query
private String skuId;
/** 精确 */
@Query
private String productId;
/** 精确 */
@Query
private String name;
/** BETWEEN */
@Query(type = Query.Type.BETWEEN)
private List<Long> createTime;
private Integer page;
private Integer size;
private String sort = "id,desc";
}

View File

@ -19,6 +19,9 @@ import cn.ysk.cashier.base.BaseMapper;
import cn.ysk.cashier.pojo.product.TbProduct;
import cn.ysk.cashier.dto.product.TbProductDto;
import cn.ysk.cashier.utils.ListUtil;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.mapstruct.Mapper;
import org.mapstruct.ReportingPolicy;
@ -49,4 +52,7 @@ public interface TbProductMapper extends BaseMapper<TbProductDto, TbProduct> {
.map(String::valueOf)
.collect(Collectors.joining(","));
}
@Select("select * from tb_product where id=#{id}")
TbProduct selectById(@Param("id") Integer productId);
}

View File

@ -0,0 +1,9 @@
package cn.ysk.cashier.mapper.product;
import cn.ysk.cashier.pojo.product.TbProductStockDetail;
import cn.ysk.cashier.pojo.product.TbProductStocktakin;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface TbProductStocktakinRepository extends JpaRepository<TbProductStocktakin, Integer>, JpaSpecificationExecutor<TbProductStocktakin> {
}

View File

@ -2,8 +2,16 @@ package cn.ysk.cashier.mybatis.mapper;
import cn.ysk.cashier.pojo.product.TbProductSku;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
public interface TbProducSkutMapper extends BaseMapper<TbProductSku> {
}
@Select("select * from tb_product_sku where id=#{id} and product_id=#{productId}")
TbProductSku selectByProIdAndId(@Param("id") Integer id, @Param("productId") Integer productId);
@Update("update tb_product_sku set stock_number=#{stocktakinNum} where id=#{id} and stock_number=#{stockNumber}")
Integer updateStock(@Param("id") Integer id,@Param("stockNumber") Double stockNumber,@Param("stocktakinNum") Integer stocktakinNum);
}

View File

@ -0,0 +1,93 @@
package cn.ysk.cashier.pojo.product;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 库存盘点表
* @TableName tb_product_stocktakin
*/
@Entity
@Table(name="tb_product_stocktakin")
@Data
@EqualsAndHashCode
public class TbProductStocktakin implements Serializable {
/**
*
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
/**
* 店铺id
*/
@Column(name = "product_id")
private Integer productId;
/**
* skuId
*/
@Column(name = "sku_id")
private Integer skuId;
/**
* 商品名
*/
private String name;
/**
* 商品封面
*/
private String coverImg;
/**
* 库存数量
*/
private Integer stock;
/**
* 盘点数量
*/
@Column(name = "inventory_stock")
private Integer inventoryStock;
/**
* 盈亏金额
*/
@Column(name = "phase_price")
private BigDecimal phasePrice;
/**
* 单价
*/
private BigDecimal price;
/**
* 盈亏数量
*/
@Column(name = "phase_num")
private Integer phaseNum;
/**
* 创建时间
*/
@Column(name = "create_time")
private Date createTime;
/**
* 备注
*/
private String note;
private Integer shopId;
private static final long serialVersionUID = 1L;
}

View File

@ -2,11 +2,13 @@ package cn.ysk.cashier.repository.product;
import cn.ysk.cashier.pojo.product.TbProduct;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import javax.transaction.Transactional;
import java.util.List;
/**
@ -43,4 +45,10 @@ public interface TbProductRepository extends JpaRepository<TbProduct, Integer>,
@Modifying
@Query("update FROM TbProduct pro set pro.stockNumber=pro.stockNumber+:number WHERE pro.id =:productId")
void incrProductStockNumber(Integer productId, Integer number);
@Transactional
@Modifying
@Query("update FROM TbProduct pro set pro.stockNumber=:stocktakinNum where pro.id=:id and pro.stockNumber=:stockNumber")
Integer updateStock(@Param("id") Integer id,@Param("stockNumber") Integer stockNumber,
@Param("stocktakinNum") Integer stocktakinNum);
}

View File

@ -59,7 +59,7 @@ public interface TbProductSkuRepository extends JpaRepository<TbProductSku, Inte
" WHEN pro.isDistribute = 1 THEN IFNULL(pro.stockNumber, 0) " +
" ELSE SUM(sku.stockNumber) " +
" END " +
", pro.isDistribute, pro.isPauseSale, true, sku.warnLine) " +
", pro.isDistribute, pro.isPauseSale, true, sku.warnLine, pro.lowPrice) " +
"from " +
"TbProduct pro " +
"LEFT JOIN TbProductSku sku on pro.id = sku.productId " +
@ -97,7 +97,7 @@ public interface TbProductSkuRepository extends JpaRepository<TbProductSku, Inte
@Query("SELECT new cn.ysk.cashier.vo.StockV2Vo(" +
"sku.id,pro.id,pro.coverImg,pro.name,unit.name,pro.typeEnum,sku.specSnap,pro.isStock,sku.stockNumber, 1, sku.isPauseSale, false " +
"sku.id,pro.id,pro.coverImg,pro.name,unit.name,pro.typeEnum,sku.specSnap,pro.isStock,sku.stockNumber, 1, sku.isPauseSale, false, 0, sku.salePrice" +
") " +
"from " +
"TbProductSku sku " +

View File

@ -351,6 +351,9 @@ public class TbProductStockOperateServiceImpl implements TbProductStockOperateSe
}
}
public static void main(String[] args) {
}
private void setProSpecInfo(TbProduct product, TbProductSku productSku, double num, BigDecimal cost, boolean isShareStock) {
if (product.getSpecInfo() != null) {
JSONArray specInfoArr = JSON.parseArray(product.getSpecInfo());

View File

@ -0,0 +1,204 @@
package cn.ysk.cashier.service.impl.productimpl;
import cn.hutool.core.date.DateUtil;
import cn.ysk.cashier.dto.product.TbProductStocktakinDTO;
import cn.ysk.cashier.dto.product.TbProductStocktakinQueryCriteria;
import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.mapper.product.TbProductMapper;
import cn.ysk.cashier.mapper.product.TbProductStocktakinRepository;
import cn.ysk.cashier.mybatis.mapper.TbProducSkutMapper;
import cn.ysk.cashier.pojo.product.*;
import cn.ysk.cashier.pojo.shop.TbShopInfo;
import cn.ysk.cashier.pojo.shop.TbShopUnit;
import cn.ysk.cashier.repository.product.TbProductRepository;
import cn.ysk.cashier.repository.product.TbProductStockDetailRepository;
import cn.ysk.cashier.repository.product.TbProductStockOperateRepository;
import cn.ysk.cashier.repository.shop.TbShopInfoRepository;
import cn.ysk.cashier.repository.shop.TbShopUnitRepository;
import cn.ysk.cashier.service.product.TbProductStocktakinService;
import cn.ysk.cashier.utils.QueryHelp;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class TbProductStocktakinServiceImpl implements TbProductStocktakinService {
private final TbShopInfoRepository shopInfoRepository;
private final TbProducSkutMapper producSkutMapper;
private final TbProductMapper productMapper;
private final TbProducSkutMapper tbProducSkutMapper;
private final TbProductRepository tbProductRepository;
private final TbProductStocktakinRepository productStocktakinRepository;
private final TbProductStockOperateRepository tbProductStockOperateRepository;
private final TbProductStockDetailRepository tbProductStockDetailRepository;
private final TbShopUnitRepository tbShopUnitRepository;
public TbProductStocktakinServiceImpl(TbShopInfoRepository shopInfoRepository, TbProducSkutMapper producSkutMapper, TbProductMapper productMapper, TbProducSkutMapper tbProducSkutMapper, TbProductRepository tbProductRepository, TbProductStocktakinRepository productStocktakinRepository, TbProductStockOperateRepository tbProductStockOperateRepository, TbProductStockDetailRepository tbProductStockDetailRepository, TbShopUnitRepository tbShopUnitRepository) {
this.shopInfoRepository = shopInfoRepository;
this.producSkutMapper = producSkutMapper;
this.productMapper = productMapper;
this.tbProducSkutMapper = tbProducSkutMapper;
this.tbProductRepository = tbProductRepository;
this.productStocktakinRepository = productStocktakinRepository;
this.tbProductStockOperateRepository = tbProductStockOperateRepository;
this.tbProductStockDetailRepository = tbProductStockDetailRepository;
this.tbShopUnitRepository = tbShopUnitRepository;
}
@Override
public void addStocktakin(TbProductStocktakinDTO productStocktakinDTO) {
TbShopInfo shopInfo = shopInfoRepository.findById(productStocktakinDTO.getShopId()).orElse(null);
if (shopInfo == null) {
throw new BadRequestException("店铺不存在");
}
TbProduct product = tbProductRepository.findById(productStocktakinDTO.getProductId()).orElse(null);
TbProductStocktakin productStocktakin = new TbProductStocktakin();
productStocktakin.setProductId(productStocktakinDTO.getProductId());
productStocktakin.setCreateTime(DateUtil.date());
productStocktakin.setNote(productStocktakinDTO.getNote());
productStocktakin.setStock(product.getStockNumber());
productStocktakin.setInventoryStock(productStocktakinDTO.getStocktakinNum());
productStocktakin.setName(product.getName());
productStocktakin.setCoverImg(product.getCoverImg());
productStocktakin.setShopId(Integer.valueOf(product.getShopId()));
productStocktakinDTO.setPrice(product.getLowPrice());
// 查询单位
TbShopUnit tbShopUnit = tbShopUnitRepository.findById(product.getUnitId()).orElse(null);
int phaseNum = productStocktakinDTO.getStocktakinNum() - product.getStockNumber();
long times = Instant.now().toEpochMilli();
TbProductStockOperate stockOperate = new TbProductStockOperate();
stockOperate.setShopId(product.getShopId());
Map<String, String> operatorSnapMap = new HashMap<>();
operatorSnapMap.put("name", shopInfo.getShopName());
operatorSnapMap.put("account", shopInfo.getAccount());
stockOperate.setOperatorSnap(JSON.toJSONString(operatorSnapMap));
stockOperate.setStockTime(times);
stockOperate.setCreatedAt(times);
stockOperate.setUpdatedAt(times);
stockOperate.setStatus("normal");
// 保存库存详情
TbProductStockDetail productStockDetail = new TbProductStockDetail();
productStockDetail.setCreatedAt(times);
productStockDetail.setUpdatedAt(times);
productStockDetail.setIsStock(1);
int round;
productStockDetail.setProductId(String.valueOf(product.getId()));
productStockDetail.setProductName(product.getName());
productStockDetail.setUnitName(tbShopUnit == null ? null : tbShopUnit.getName());
productStockDetail.setShopId(String.valueOf(shopInfo.getId()));
productStockDetail.setSkuId(String.valueOf(productStocktakinDTO.getSkuId()));
productStockDetail.setSourcePath("NORMAL");
JSONObject snap = new JSONObject();
snap.put("coverImg", product.getCoverImg());
snap.put("productId", product.getId());
snap.put("name", product.getName());
snap.put("number", phaseNum);
snap.put("unitName", tbShopUnit == null ? null : tbShopUnit.getName());
// snap.put("specSnap", tbShopUnit == null ? null : tbShopUnit.getName());
// 共享库存
if (product.getIsDistribute() == 1) {
round = (int) Math.floor( product.getStockNumber());
productStocktakin.setPhasePrice(
productStocktakinDTO.getPrice().multiply(BigDecimal.valueOf(productStocktakinDTO.getStocktakinNum())).subtract(
productStocktakinDTO.getPrice().multiply(BigDecimal.valueOf(product.getStockNumber()))
)
);
productStockDetail.setSubType(productStocktakinDTO.getStocktakinNum() > product.getStockNumber() ? 1 : -1);
stockOperate.setType(productStocktakinDTO.getStocktakinNum() > product.getStockNumber() ? "盘点入库" : "盘点出库");
productStockDetail.setType(productStocktakinDTO.getStocktakinNum() > product.getStockNumber() ? "盘点入库" : "盘点出库");
productStocktakin.setPhaseNum(productStocktakinDTO.getStocktakinNum() - product.getStockNumber());
if (tbProductRepository.updateStock(product.getId(), product.getStockNumber(), productStocktakinDTO.getStocktakinNum()) < 1) {
throw new BadRequestException("修改库存失败,稍后再试");
}
snap.put("stockNumber", product.getStockNumber());
}else {
if (productStocktakinDTO.getSkuId() == null) {
throw new BadRequestException("非共享库存必须传入skuId");
}
TbProductSku productSku = producSkutMapper.selectByProIdAndId(productStocktakinDTO.getSkuId(),
productStocktakinDTO.getProductId());
productStocktakinDTO.setPrice(productSku.getSalePrice());
round = (int) Math.floor( productSku.getStockNumber());
productStockDetail.setSubType(productStocktakinDTO.getStocktakinNum() > productSku.getStockNumber() ? 1 : -1);
stockOperate.setType(productStocktakinDTO.getStocktakinNum() > productSku.getStockNumber() ? "盘点入库" : "盘点出库");
productStockDetail.setType(productStocktakinDTO.getStocktakinNum() > productSku.getStockNumber() ? "盘点入库" : "盘点出库");
productStocktakin.setSkuId(productSku.getId());
productStocktakin.setPhasePrice(
productStocktakinDTO.getPrice().multiply(BigDecimal.valueOf(productStocktakinDTO.getStocktakinNum())).subtract(
productStocktakinDTO.getPrice().multiply(BigDecimal.valueOf(product.getStockNumber()))
)
);
productStocktakin.setPhaseNum((int) (productStocktakinDTO.getStocktakinNum() - productSku.getStockNumber()));
if (producSkutMapper.updateStock(productSku.getId(), productSku.getStockNumber(), productStocktakinDTO.getStocktakinNum()) < 1) {
throw new BadRequestException("修改库存失败,稍后再试");
}
snap.put("stockNumber", productSku.getStockNumber());
}
productStocktakin.setPrice(productStocktakinDTO.getPrice());
productStockDetail.setStockNumber((double) phaseNum);
productStockDetail.setCostAmount(productStocktakinDTO.getPrice().multiply(BigDecimal.valueOf(Math.abs(phaseNum))));
JSONArray array = new JSONArray();
array.add(snap);
stockOperate.setStockSnap(array.toJSONString());
productStockDetail.setStockSnap(array.toJSONString());
productStocktakinRepository.save(productStocktakin);
TbProductStockOperate saveStockOperate = tbProductStockOperateRepository.save(stockOperate);
productStockDetail.setLeftNumber(round);
productStockDetail.setRecordId(saveStockOperate.getId().toString());
tbProductStockDetailRepository.save(productStockDetail);
}
@Override
public Page<TbProductStocktakin> getPage(TbProductStocktakinQueryCriteria productStocktakinQueryCriteria, Pageable pageable) {
Page<TbProductStocktakin> page = productStocktakinRepository.findAll((Specification<TbProductStocktakin>) (root, query, criteriaBuilder) -> {
Predicate predicate = QueryHelp.getPredicate(root, productStocktakinQueryCriteria, criteriaBuilder);
query.orderBy(criteriaBuilder.desc(root.get("id")));
return predicate;
}, pageable);
return page;
}
}

View File

@ -0,0 +1,13 @@
package cn.ysk.cashier.service.product;
import cn.ysk.cashier.dto.product.TbProductStocktakinDTO;
import cn.ysk.cashier.dto.product.TbProductStocktakinQueryCriteria;
import cn.ysk.cashier.pojo.product.TbProductStocktakin;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
public interface TbProductStocktakinService {
void addStocktakin(TbProductStocktakinDTO productStocktakinDTO);
Page<TbProductStocktakin> getPage(TbProductStocktakinQueryCriteria productStocktakinQueryCriteria, Pageable pageable);
}

View File

@ -2,6 +2,7 @@ package cn.ysk.cashier.vo;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
@ -23,6 +24,7 @@ public class StockV2Vo {
private Integer isPauseSale;
private Object number;
private Integer warnLine;
private BigDecimal salePrice;
public StockV2Vo(Integer proId, Integer skuId, String name, String unitName,String specSnap, Object number,Object stockNumber, Integer isDistribute) {
this.proId = proId;
@ -78,6 +80,29 @@ public class StockV2Vo {
this.warnLine = warnLine;
}
public StockV2Vo(Integer id, Integer proId,String img,String name,String unitName, String type, String specSnap,
Object isStock, Object number, Integer isDistribute, Integer isPauseSale, boolean isPro, Integer warnLine, BigDecimal sellPrice) {
this.id = id.toString() + "-" + proId.toString();
if (isPro) {
this.id += proId;
} else {
this.id += id;
}
this.skuId = id;
this.proId = proId;
this.img = img;
this.name = name;
this.unitName = unitName;
setType(type);
this.specSnap = specSnap;
this.isStock = isStock;
this.stockNumber = number;
this.isDistribute = isDistribute;
this.isPauseSale = isPauseSale;
this.warnLine = warnLine;
this.salePrice = sellPrice;
}
public void setType(String type) {
switch (type) {
case "normal":