恒合仓库 - 商品管理模块、上传照片、添加采购单、添加出库单、商品分类

2023-11-19

商品管理模块

文章目录

一、分页查询商品

image-20230815124434879

1.1 实体类

1.1.1 Store 仓库

/**
 * 仓库表store表对应的实体类:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Store implements Serializable {

    private static final long serialVersionUID = 4011912702717598523L;
   
    private Integer storeId;//仓库id

    private String storeName;//仓库名称

    private String storeNum;//仓库编码

    private String storeAddress;//仓库地址

    private String concat;//仓库联系人

    private String phone;//仓库联系电话
}

image-20230815124752533

1.1.2 Brand 品牌

/**
 * 品牌表brand表对应的实体类:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Brand implements Serializable {

    private Integer brandId;//品牌id

    private String brandName;//品牌名称

    private String brandLeter;//品牌首字母

    private String brandDesc;//品牌描述
}

image-20230815125543769

1.1.3 ProductType 商品分类

/**
 * 商品分类表product_type表对应的实体类:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class ProductType implements Serializable {

    private Integer typeId;//分类id

    private Integer parentId;//上级分类id

    private String typeCode;//分类代码

    private String typeName;//分类名称

    private String typeDesc;//分类描述

    //自定义List<ProductType>集合属性,用于存储当前分类的所有子级分类
    private List<ProductType> childProductCategory;
}

image-20230815125754166

1.1.4 Supply 供应商

/**
 * 供应商表supply表对应的实体类:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Supply implements Serializable {

    private Integer supplyId;//供应商id

    private String supplyNum;//供应商代码

    private String supplyName;//供应商名称

    private String supplyIntroduce;//供应商介绍

    private String concat;//供应商联系人

    private String phone;//供应商联系电话

    private String address;//供应商地址

    private String isDelete;//是否删除状态,0未删除,1删除
}

image-20230815130227455

1.1.5 Place 产地

image-20230815130208570

/**
 * 产地表place表对应的实体类:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Place implements Serializable {

    private Integer placeId;//产地id

    private String placeName;//产地名称

    private String placeNum;//产地代码

    private String introduce;//产地介绍

    private String isDelete;//是否删除状态,0未删除,1删除
}

1.1.6 Unit 单位

/**
 * 单位表unit表对应的实体类:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Unit implements Serializable {

    private Integer unitId;//单位id

    private String unitName;//单位

    private String unitDesc;//单位描述
}

image-20230815130421129

1.1.7 Product 商品

/**
 * 商品表product表对应的实体类:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Product {

    private Integer productId;//商品id

    private Integer storeId;//商品所在仓库id
    private String storeName;//非表中字段 --商品所在仓库名称

    private Integer brandId;//商品所属品牌id
    private String brandName;//非表中字段 -- 商品所属品牌名称

    private String productName;//商品名称

    private String productNum;//商品编码

    private Integer productInvent;//商品库存

    private Integer typeId;//商品所属分类id
    private String typeName;//非表中字段 -- 商品所属分类名称

    private Integer supplyId;//商品供应商id
    private String supplyName;//非表中字段 -- 商品供应商名称

    private Integer placeId;//商品产地id
    private String placeName;//非表中字段 -- 商品产地名称

    private Integer unitId;//商品单位id
    private String unitName;//非表中字段 -- 商品单位名称

    private String introduce;//商品介绍

    private String upDownState;//商品上下架状态,1.上架,0.下架

    private Double inPrice;//商品进价

    private Double salePrice;//商品售价

    private Double memPrice;//商品会员价

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;//商品的创建时间

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;//商品的修改时间

    private Integer createBy;//创建商品的用户id

    private Integer updateBy;//修改商品的用户id

    private String imgs;//商品的图片地址

    @JsonFormat(pattern="yyyy-MM-dd")
    private Date productDate;//商品的生产日期

    @JsonFormat(pattern="yyyy-MM-dd")
    private Date suppDate;//商品的保质期

    private String isOverDate;//非表中字段 -- 商品是否过期,0未过期,1已过期
}

image-20230815134005095

1.2 查询所有仓库

为搜索商品仓库下拉框组装数据

1.2.1 Mapper

//  查询所有仓库的方法
    public List<Store> findAllStore();
<select id="findAllStore" resultType="com.pn.entity.Store">
    select *
    from store
</select>

1.2.2 Service

@CacheConfig(cacheNames = "com.pn.service.impl.StoreServiceImpl")
@Service
public class StoreServiceImpl implements StoreService {
    @Autowired
    private StoreMapper storeMapper;


    @Cacheable(key = "'all:store'")
    @Override
    public List<Store> queryAllStore() {
        return storeMapper.findAllStore();
    }
}

1.2.3 Controller

@Slf4j
@RestController
@RequestMapping("/product")
public class ProductController {

//  注入StoreService
    @Autowired
    private StoreService storeService;

    @RequestMapping("/store-list")
    public Result storeList(){
       return Result.ok(storeService.queryAllStore()) ;
    }
}

1.2.4 效果图

image-20230815132234669

1.3 查询所有品牌

1.3.1 Mapper

//  查询所有品牌的方法
    public List<Brand> findAllBrand();
<select id="findAllBrand" resultType="com.pn.entity.Brand">
    select *
    from brand
</select>

1.3.2 Service

@CacheConfig(cacheNames = "'com.pn.service.impl.BrandServiceImpl'")
@Service
public class BrandServiceImpl implements BrandService {

    @Autowired
    private BrandMapper brandMapper;


    @Cacheable(key = "'all:brand'")
    @Override
    public List<Brand> queryAllBrand() {
        return brandMapper.findAllBrand();
    }
}

1.3.3 Controller

@CacheConfig(cacheNames = "com.pn.service.impl.BrandServiceImpl")
@Service
public class BrandServiceImpl implements BrandService {

    @Autowired
    private BrandMapper brandMapper;


    @Cacheable(key = "'all:brand'")
    @Override
    public List<Brand> queryAllBrand() {
        return brandMapper.findAllBrand();
    }
}

1.3.4 效果图

image-20230815133312021

1.4 分页查询商品

根据仓库 商品名称 品牌 类型 供应商 产地 上下架状态 过期与查询商品并分页

image-20230815140448462

1.4.1 Mapper

//  查询商品行数的方法
    public Integer findProductRowCount(Product product);

//  分页查询商品的方法
    public List<Product> findProductPage(@Param("page") Page page, @Param("product") Product product);
<select id="findProductRowCount" resultType="java.lang.Integer">
    select count(*) from
    product t1, store t2, brand t3, product_type t4, supply t5,
    place t6, unit t7
    where t1.store_id = t2.store_id and t1.brand_id = t3.brand_id
    and t1.type_id = t4.type_id and t1.supply_id = t5.supply_id
    and t1.place_id = t6.place_id and t1.unit_id = t7.unit_id
    <if test="storeId != null">
        and t1.store_id = #{storeId}
    </if>
    <if test="productName != null and productName != ''">
        and t1.product_name like concat('%',#{productName},'%')
    </if>
    <if test="brandName != null and brandName != ''">
        and t3.brand_name like concat('%', #{brandName}, '%')
    </if>
    <if test="typeName != null and typeName != ''">
        and t4.type_name like concat('%', #{typeName}, '%')
    </if>
    <if test="supplyName != null and supplyName != ''">
        and t5.supply_name like concat('%', #{supplyName}, '%')
    </if>
    <if test="placeName != null and placeName != ''">
        and t6.place_name like concat('%', #{placeName}, '%')
    </if>
    <if test="upDownState != null and upDownState != ''">
        and t1.up_down_state = #{upDownState}
    </if>
    <!--
      如果方法参数Product对象的isOverDate属性值为1(查询已过期商品),则查询
      当前时间大于product表中supp_date列的时间的商品;
      反之如果方法参数Product对象的isOverDate属性值为0(查询未过期商品),则
      查询当前时间小于product表中supp_date列的时间的商品;
    -->
    <if test="isOverDate != null and isOverDate != '' and isOverDate==1">
        and date_format(now(), '%y-%m-%d') &gt; t1.supp_date
    </if>
    <if test="isOverDate != null and isOverDate != '' and isOverDate==0">
        and date_format(now(), '%y-%m-%d') &lt; t1.supp_date
    </if>
</select>

<select id="findProductPage" resultType="com.pn.entity.Product">
    select t1.*, t2.store_name, t3.brand_name, t4.type_name,
    t5.supply_name, t6.place_name, t7.unit_name from
    product t1, store t2, brand t3, product_type t4, supply t5,
    place t6, unit t7
    where t1.store_id = t2.store_id and t1.brand_id = t3.brand_id
    and t1.type_id = t4.type_id and t1.supply_id = t5.supply_id
    and t1.place_id = t6.place_id and t1.unit_id = t7.unit_id
    <if test="product.storeId != null">
        and t1.store_id = #{product.storeId}
    </if>
    <if test="product.productName != null and product.productName != ''">
        and t1.product_name like concat('%',#{product.productName},'%')
    </if>
    <if test="product.brandName != null and product.brandName != ''">
        and t3.brand_name like concat('%', #{product.brandName}, '%')
    </if>
    <if test="product.typeName != null and product.typeName != ''">
        and t4.type_name like concat('%', #{product.typeName}, '%')
    </if>
    <if test="product.supplyName != null and product.supplyName != ''">
        and t5.supply_name like concat('%', #{product.supplyName}, '%')
    </if>
    <if test="product.placeName != null and product.placeName != ''">
        and t6.place_name like concat('%', #{product.placeName}, '%')
    </if>
    <if test="product.upDownState != null and product.upDownState != ''">
        and t1.up_down_state = #{product.upDownState}
    </if>
    <if test="product.isOverDate != null and product.isOverDate != '' and product.isOverDate==1">
        and date_format(now(), '%y-%m-%d') &gt; t1.supp_date
    </if>
    <if test="product.isOverDate != null and product.isOverDate != '' and product.isOverDate==0">
        and date_format(now(), '%y-%m-%d') &lt; t1.supp_date
    </if>
    order by t1.create_time
    limit #{page.limitIndex}, #{page.pageSize}
</select>

1.4.2 Service

    @Autowired
    private ProductMapper productMapper;

    @Override
    public Page queryProductPage(Page page, Product product) {
//      查询商品行数
        Integer count = productMapper.findProductRowCount(product);
        page.setTotalNum(count);
        page.setLimitIndex(page.getLimitIndex());
        page.setPageCount(page.getPageCount());
//      分页查询商品
        List<Product> productPage = productMapper.findProductPage(page, product);

        page.setResultList(productPage);
        return page;
    }

1.4.3 Controller

    //分页查询商品的url接口
    @RequestMapping("/product-page-list")
    public Result productListPage(Page page, Product product) {
        page = productService.queryProductPage(page, product);
        return Result.ok(page);
    }

1.4.4 效果图

image-20230815145308406

二、添加商品

image-20230815153154763

2.1 查询所有分类树

2.1.1 Mapper

//  查询所有商品分类的方法
    public List<ProductType>  findAllProductType();
<select id="findAllProductType" resultType="com.pn.entity.ProductType">
    select *
    from product_type
</select>

2.1.2 Service

@CacheConfig(cacheNames = "com.pn.service.impl.ProductTypeServiceImpl")
@Service
public class ProductTypeServiceImpl implements ProductTypeService {

    @Autowired
    private ProductMapper productMapper;

    @Cacheable(key = "'all:typeTree'")
    @Override
    public List<ProductType> productTypeTree() {
//      查询出所有的商品分类
        List<ProductType> allProductType = productMapper.findAllProductType();
//      将所有商品分类转换成商品分类树
        return allTypeToTypeTree(allProductType,0);
    }

    private List<ProductType> allTypeToTypeTree(List<ProductType> typeList, Integer pid) {
//      拿到n级分类
        List<ProductType> nTypeList = new ArrayList<>();
        for (ProductType productType : typeList) {
            if (productType.getParentId().equals(pid)) {
                nTypeList.add(productType);
            }
        }

//      遍历n级分类,为其找子
        for (ProductType productType : nTypeList) {
//          找子集
            List<ProductType> productTypes = allTypeToTypeTree(typeList, productType.getTypeId());
            productType.setChildProductCategory(productTypes);
        }
        return nTypeList;
    }
}

2.1.3 Controller

@Autowired
private ProductTypeService productTypeTree;

//查询所有商品分类树的接口
@RequestMapping("/category-tree")
public Result loadTypeTree(){
    return Result.ok(productTypeTree.productTypeTree());
}

2.1.4 效果图

image-20230815223112067

2.2 查询所有供应商

2.2.1 Mapper

//  查询所有供应商的方法
    public List<Supply> findAllSupply();
<select id="findAllSupply" resultType="com.pn.entity.Supply">
    select *
    from supply
    where is_delete = 0
</select>

2.2.2 Service

@CacheConfig(cacheNames = "com.pn.service.impl.SupplyServiceImpl")
@Service
public class SupplyServiceImpl implements SupplyService {
    @Autowired
    private SupplyMapper supplyMapper;

    @Cacheable(key = "'all:supply'")
    @Override
    public List<Supply> supplyMapper() {
        return supplyMapper.findAllSupply();
    }
}

2.2.3 Controller

@Autowired
private SupplyService supplyService;

// 查询所有供应商的接口
@RequestMapping("/supply-list")
public Result supplyList(){
    return Result.ok(supplyService.supplyMapper());
}

2.2.4 效果图

image-20230815223134896

2.3 查询所有产地

2.3.1 Mapper

//查询所有产地
public List<Place> findAllPlace();
<select id="findAllPlace" resultType="com.pn.entity.Place">
    select * from place
</select>

2.3.2 Service

//指定缓存的名称即键的前缀,一般是@CacheConfig标注的类的全类名
@CacheConfig(cacheNames = "com.pn.service.impl.PlaceServiceImpl")
@Service
public class PlaceServiceImpl implements PlaceService {

    //注入PlaceMapper
    @Autowired
    private PlaceMapper placeMapper;

    /*
      查询所有产地的业务方法
     */
    //对查询到的所有产地进行缓存,缓存到redis的键为all:place
    @Cacheable(key = "'all:place'")
    @Override
    public List<Place> queryAllPlace() {
        //查询所有产地
        return placeMapper.findAllPlace();
    }
}

2.3.3 Controller

    @RequestMapping("/place-list")
    public Result placeList(){
//      执行业务
        return Result.ok(placeService.queryAllPlace());
    }

2.3.4 效果图

image-20230815223157406

2.4 查询所有单位

2.4.1 Mapper

//查询所有单位的方法
public List<Unit> findAllUnit();
<select id="findAllUnit" resultType="com.pn.entity.Unit">
    select * from unit
</select>

2.4.2 Service

//指定缓存的名称即键的前缀,一般是@CacheConfig标注的类的全类名
@CacheConfig(cacheNames = "com.pn.service.impl.UnitServiceImpl")
@Service
public class UnitServiceImpl implements UnitService {

    //注入UnitMapper
    @Autowired
    private UnitMapper unitMapper;

    /*
      查询所有单位的业务方法
     */
    //对查询到的所有单位进行缓存,缓存到redis的键为all:unit
    @Cacheable(key = "'all:unit'")
    @Override
    public List<Unit> queryAllUnit() {
        //查询所有单位
        return unitMapper.findAllUnit();
    }
}

2.4.3 Controller

    @RequestMapping("/unit-list")
    public Result unitList(){
//      执行业务
        return Result.ok(unitService.queryAllUnit());
    }

2.4.4 效果图

image-20230815223220207

2.5 上传图片

我们尝试一下上传图片,发现请求负载是一个上传的图片的二进制

image-20230818212224025

之后我们把图片上传到下图所示位置,但是这是未编译的资源

image-20230818214451024

我们真正上传到服务器上的项目是编译后的项目

image-20230818214838013

简单来说我们图片的上传位置并不是未编译之前的位置,而是编译之后且部署到服务器的classes/static/img/upload位置

所以我们在配置文件中就可以配置

#自定义属性 - 图片上传到的位置
file:
  upload-path: "classpath:static/img/upload"
  #自定义属性 - 上传的图片保存数据库的访问路径的目录路径
  access-path: "/img/upload/"

这个upload-path可以理解为未编译时,存放到上面的图2,编译后存放到上图的图3

2.5.1 Mapper

2.5.2 Service

2.5.3 Controller

 //   上传图片url接口
    //    file.transferTo(上传的文件保存到的磁盘文件的File对象)); --实现文件的上传
    @RequestMapping("/img-upload")
    @CrossOrigin//表示此接口允许被跨域请求
    public Result uploadImage(MultipartFile file) throws IOException {
        log.info("uploadAddress - "+uploadAddress);
//      实现文件的上传
//      拿到图片上传到的目录路径的file对象 - classpath:static/img/upload 图片要上传到的路径
        File uploadDirFile = ResourceUtils.getFile(uploadAddress);

//        String file1 = Objects.requireNonNull(this.getClass().getClassLoader().getResource("static/image/upload/")).getFile();
//        System.out.println(file1);

//      我们之前封装目录路径的方式如下所示
//      File f = new File(uploadAddress);
//      现在我们并不能这么封装,因为这个路径是特殊的类路径的路径,我们需要一个特定的工具类进行解析

//      拿到图片上传到的目录路径的磁盘路径
        String uploadDirPath = uploadDirFile.getAbsolutePath();
        log.info("uploadDirPath - "+uploadDirPath);

//      拿到我们上传的图片的名称
        String originalFilename = file.getOriginalFilename();
//      拿到上传的文件要保存到的磁盘文件的路径
        String uploadFilePath = uploadDirPath + "/" + originalFilename;
//      File对象表示文件保存到的那个位置
        file.transferTo(new File(uploadFilePath));


        return Result.ok("图片上传成功!");

    }

2.5.4 效果图

图片上传到下面的位置

image-20230819130929944

image-20230819130958050

2.6 添加商品

/product/product-add 真正添加商品的请求

image-20230819131404740

2.6.1 Mapper

备注:商品名可以重复,但是型号不能重复

//  添加商品的方法
    public int insertProduct(Product product);
<!--添加商品的方法-->
<insert id="insertProduct">
    insert into product
    values (null, #{storeId}, #{brandId}, #{productName}, #{productNum},
            #{productInvent}, #{typeId}, #{supplyId}, #{placeId}, #{unitId},
            #{introduce}, 0, #{inPrice}, #{salePrice}, #{memPrice}, now(),
            null, #{createBy}, null, #{imgs}, #{productDate}, #{suppDate})
</insert>
//  根据型号查询商品的方法
    public Product findProductByNum(@Param("productNum") String productNum);
<select id="findProductByNum" resultType="com.pn.entity.Product">
    select  * from product where product_num=#{productNum}
</select>

2.6.2 Service

//  添加商品的业务方法
    @Override
    public Result addProduct(Product product) {
//      先判断商品的型号是否已存在
        Product prct = productMapper.findProductByNum(product.getProductNum());

        if (prct != null){
            return Result.err(501,"商品型号已经存在");
        }

//      设定图片的访问地址(product.getImgs()前端传输过来的只有图片的名字)
        product.setImgs(imageURL+product.getImgs());
//      添加商品
        int success = productMapper.insertProduct(product);

        if(success>0){
            return Result.ok("添加商品成功");
        }

        return Result.err(501,"添加商品失败");
    }

2.6.3 Controller

    @Autowired
    private TokenUtils tokenUtils;

//   添加商品的URL接口
    @RequestMapping("/product-add")
    public Result addProduct(@RequestBody Product product, @RequestHeader("Token")String token){
//      拿到当前登录的用户id
        CurrentUser currentUser = tokenUtils.getCurrentUser(token);
        
        product.setCreateBy(currentUser.getUserId());
        
        return productService.addProduct(product);
    }

2.6.4 效果图

image-20230819140356002

image-20230819140423667

三、修改商品

3.1 上下架状态

3.1.1 Mapper

//  根据商品id修改商品上下架状态的方法
    public int setStateByPid(@Param("productId")Integer productId,@Param("upDownState")String upDownState);
<update id="setStateByPid">
    update product set up_down_state=#{upDownState} where product_id = #{productId}
</update>

3.1.2 Service

@Override
public Result updateStateByPid(Product product) {
    int success = productMapper.setStateByPid(product.getProductId(), product.getUpDownState());
    return success>0 ? Result.ok("商品上下架状态修改成功"):Result.err(501,"商品上下架状态修改失败");
}

3.1.3 Controller

//  修改商品上下架状态
@RequestMapping("/state-change")
public Result changeProductState(@RequestBody Product product) {
    return productService.updateStateByPid(product);
}

3.2 修改商品

当我们修改商品信息的时候并没有修改图片,如下所示

图片没有被修改的时候还是完整的访问地址

image-20230819151005717

当我们修改商品的信息的时候修改了图片,如下所示

我们imgs的内容变成了图片的名称

image-20230819151207118

3.2.1 Mapper

根据商品的id修改商品信息

//  根据商品的id修改商品的信息
    public int setProductById(Product product);

3.2.2 Service

    @Value("${file.access-path}")
    private String imageURL; //   /img/upload/

    @Override
    public Result setProductById(Product product) {
//      首先看一下型号(根据型号获取product对象)
        Product prod = productMapper.findProductByNum(product.getProductNum());

//      判断型号是否改动
        if (prod != null && !prod.getProductId().equals(product.getProductId())) {
//          表示商品的型号被修改了,并且修改后的型号已经存在
            return Result.err(501, "修改后的型号已经存在");
        }

//      处理突图片,判断图片是否被修改(如果图片被修改了,则这个参数是一个图片的名称,反之是一个完整的文件路径)
        String imgs = product.getImgs();
        if (!imgs.contains(imageURL)){
//          说明图片被修改过了,product.getImgs()的值只是图片的名称
            product.setImgs(imageURL+product.getImgs());
        }

//      修改商品信息
        int success = productMapper.setProductById(product);

        return success > 0 ? Result.ok("商品修改成功") : Result.err(501, "商品修改失败");
    }

3.2.3 Controller

//   修改商品信息
    @RequestMapping("/product-update")
    public Result updateProduct(@RequestBody Product product ,@RequestHeader("Token") String token){
        //拿到当前登录的用户id
        CurrentUser currentUser = tokenUtils.getCurrentUser(token);

        product.setCreateBy(currentUser.getUserId());

        return productService.setProductById(product);
    }

四、删除商品

4.1 Mapper

//  根据商品id删除商品的方法
    public int removeProductByIds(List<Integer> productIdList);
<delete id="removeProductByIds">
    delete from product
    where product_id in
    <foreach collection="list" open="(" close=")" separator="," item="prod">
        #{prod}
    </foreach>
</delete>

4.2 Service

@Override
public Result deleteProductByIds(List<Integer> productIdList) {
    int success = productMapper.removeProductByIds(productIdList);
    return success>0 ? Result.ok("商品删除成功"):Result.err(501,"商品删除失败");
}

4.3 controller

    //  删除单个商品
    @RequestMapping("/product-delete/{productId}")
    public Result deleteProduct(@PathVariable Integer productId) {
        return productService.deleteProductByIds(Arrays.asList(productId));
    }

    //  批量删除商品
    @RequestMapping("/product-delete")
    public Result deleteProductList(@PathVariable List<Integer> productIdList) {
        return productService.deleteProductByIds(productIdList);
    }

五、添加采购单(核心)

5.1 采购流程

类似进货

采购流程

  • 在商品列表针对具体的商品添加采购单

    image-20230819193051386

    向buy_list表中添加一条记录。添加的采购单表示预买的商品(还没有买,is_in字段的值是0)

    image-20230819185218636

  • 当商品采购到之后进行入库

    在采购单列表做入库操作,向in_store表添加记录(状态是0未入库),同时修改采购单表buy_list表由0改为1入库

image-20230819191554350

​ 下面是in_store表

image-20230819191805399

  • 商品真正的入库

    在入库单列表做确认入库操作

    image-20230819191905348

    将入库单表in_store表的入库单状态由0改为1入库

5.2 采购单实体类

/**
 * 采购单表buy_list表的实体类:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Purchase {

    private Integer buyId;//采购单id

    private Integer productId;//采购单采购的商品id

    private Integer storeId;//采购单采购的商品所在仓库id

    private Integer buyNum;//预计采购的商品数量

    private Integer factBuyNum;//实际采购的商品数量

    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date buyTime;//采购时间

    private Integer supplyId;//采购单采购的商品的供应商id

    private Integer placeId;//采购单采购的商品的产地id

    private String buyUser;//采购人

    private String phone;//采购人联系电话

    private String isIn;//是否生成入库单,1.是,0.否

    //---------------追加属性---------------------------

    private String productName;//商品名称

    private String storeName;//仓库名称

    private String startTime;//搜索起始时间

    private String endTime;//搜索结束时间
}

5.3 添加采购单

image-20230819193441082

采购单数据库表buy_list如下所示

image-20230819193636735

image-20230819194050277

5.3.1 Mapper

@Mapper
public interface PurchaseMapper {
//   添加采购单
    public int insertPurchase(Purchase purchase);
    
}
<insert id="insertPurchase">
    insert into buy_list
    values (null, #{productId}, #{storeId}, #{buyNum}, null, now(),
            #{supplyId}, #{placeId}, #{buyUser}, #{phone}, 0)
</insert>

5.3.2 Service

@Service
public class PurchaseServiceImpl implements PurchaseService {

    @Autowired
    private PurchaseMapper purchaseMapper;

    @Override
    public Result savePurchase(Purchase purchase) {
//      初始化时,实际采购数量要和预计采购数量一致
        purchase.setFactBuyNum(purchase.getBuyNum());
        int success = purchaseMapper.insertPurchase(purchase);

        return success>0 ? Result.ok("添加采购单成功") : Result.err(501,"添加采购单失败");
    }

}

5.3.3 Controller

@RestController
@RequestMapping("/purchase")
public class PurchaseController {

    @Autowired
    private PurchaseService purchaseService;

    @RequestMapping("/purchase-add")
    public Result addPurchase(@RequestBody Purchase purchase){

        return purchaseService.savePurchase(purchase);
    }

}

5.3.4 效果图

image-20230819201233500

image-20230819201346600

六、添加出库单(核心)

6.1 出库流程

  • 在商品列表针对具体的商品添加出库单

    向出库单表out_store表添加出库单(状态是0,未出库),准备出库

    image-20230819192927647

    image-20230819192954264

  • 商品真正出库之后,在出库单列表做确认出库操作

    商品真正出库之后,在出库单列表做确认出库操作

    将出库单表out_store表的出库状态由0改为1表示已出库

image-20230819193019679

5.2 出库单实体类

image-20230819205840782

image-20230819210314682

/**
 * 出库单表out_store表的实体类:
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class OutStore {

    private Integer outsId;//出库单id

    private Integer productId;//出库单出库的商品id

    private Integer storeId;//出库单出库的商品所在仓库id

    private Integer tallyId;//理货员id

    private Double outPrice;//商品的出库价格

    private Integer outNum;//出库的商品数量

    private Integer createBy;//创建出库单的用户id

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;//创建出库单的时间

    private String isOut;//是否出库,0.未出库,1.已出库

    //------------------追加的属性-------------------------

    private String productName;//商品名称

    private String startTime;//起始时间

    private String endTime;//结束时间

    private String storeName;//仓库名称

    private String userCode;//创建出库单的用户的名称
}

5.3 添加出库单

需要先上架,才能进行“出库”

image-20230819205527630

5.3.1 Mapper

//添加出库单的方法
public int insertOutStore(OutStore outStore);
<insert id="insertOutStore">
    insert into out_store values(
      null, #{productId}, #{storeId}, null, null,
      #{outNum}, #{createBy}, now(), 0
    )
</insert>

5.3.2 Service

@Service
public class OutStoreServiceImpl implements OutStoreService {

  @Autowired
  private OutStoreMapper outStoreMapper;

    @Override
    public Result saveOutStore(OutStore outStore) {
//      添加
        int success = outStoreMapper.insertOutStore(outStore);

        return success>0? Result.ok("添加出货单成功") :Result.err(501,"添加出货单失败");
    }
}

5.3.3 Controller


@RequestMapping("/outstore")
@RestController
public class OutStoreController {

    //注入OutStoreService
    @Autowired
    private OutStoreService outStoreService;

    //注入TokenUtils
    @Autowired
    private TokenUtils tokenUtils;

    @RequestMapping("/outstore-add")
    public Result addOutStore(@RequestBody OutStore outStore,
                              @RequestHeader("Token") String token){

        //获取当前登录的用户
        CurrentUser currentUser = tokenUtils.getCurrentUser(token);
        //获取当前登录的用户id,即添加出库单的用户id
        int createBy = currentUser.getUserId();
        outStore.setCreateBy(createBy);

        //响应
        return outStoreService.saveOutStore(outStore);
    }


}

5.3.4 效果图

image-20230819212314879

image-20230819212414598

七、商品分类

7.1 查询商品分类树

这个地方在2.1写过,我们重新写一个接口即可

7.1.1 Controller

//  查询商品分类树的url
    @RequestMapping("/product-category-tree")
    public Result productCategoryTree(){
//      执行业务
     return  Result.ok(productTypeService.productTypeTree())  ;
    }

7.1.2 效果图

image-20230820135443546

7.2 添加商品分类

一种是添加一级分类,直接添加即可

image-20230820135701043

一种是添加二级分类,需要先勾选一级分类

image-20230820135732834

分类编码type_code字段不能重复,这个地方的校验时当光标离开“分类编码”文本框的时候便开始校验

分类名type_name字段不能重复

image-20230820140145740

7.2.1 Mapper

校验分类编码、分类名称是否重复的Mapper方法

//  根据分类编码或者分类名称查询商品分类的方法
    public ProductType findTypeByCodeOrName(ProductType productType);
    <select id="findTypeByCodeOrName" resultType="com.pn.entity.ProductType">
        select *
        from product_type
        <where>
            <if test="typeName !=null and typeName != '' ">
                type_name = #{typeName}
            </if>
            <if test="typeCode !=null and typeCode != '' ">
               or type_code = #{typeCode}
            </if>
        </where>
    </select>

添加商品分类的Mapper方法

//  添加商品分类的方法
    public int insertProductType(ProductType productType);
<insert id="insertProductType">
    insert into product_type
    values (null, #{parentId}, #{typeCode}, #{typeName}, #{typeDesc})
</insert>

7.2.2 Service

校验分类编码、校验分类名称的业务方法分开,因为校验分类编码是否重复是在光标离开文本框的时候发送请求进行校验的,但是校验分类名称的时候是在提交表单数据的时候

校验分类编码是否重复的方法

    @Override
    public Result checkTypeCode(String typeCode) {
//      根据分类编码查询分类,并判断是否存在
        ProductType productType  = new ProductType();
        productType.setTypeCode(typeCode);
        ProductType prodType = productMapper.findTypeByCodeOrName(productType);

        return Result.ok(prodType == null);
    }

添加商品分类

    @CacheEvict(key = "'all:typeTree'")
    @Override
    public Result saveProductType(ProductType productType) {
//      首先校验一下分类名称是否存在
        ProductType prodType = new ProductType();
        prodType.setTypeName(productType.getTypeName());
        ProductType prodCategory = productMapper.findTypeByCodeOrName(prodType);
        if (prodCategory!=null){
            return Result.err(501,"分类名称已经存在");
        }

//      分类名称不存在,添加分类
        int success = productMapper.insertProductType(productType);

        return success>0 ? Result.ok("添加分类成功") : Result.err(501,"添加分类失败");
    }

7.2.3 Controller

校验分类编码是否重复的Controller

//  校验分类编码是否已经存在
    @RequestMapping("/verify-type-code")
    public Result checkTypeCode(String typeCode){
//      执行业务
       return productTypeService.checkTypeCode(typeCode);
    }

添加商品分类Controller

//  添加商品分类的url接口
    @RequestMapping("/type-add")
    public Result addProductType(@RequestBody ProductType productType){
        return productTypeService.saveProductType(productType);

7.2.4 效果图

当“分类编码”文本框失去焦点后如下所示

image-20230820143842807

添加商品分类

image-20230820150157665

image-20230820150537985

7.3 删除商品分类

删除商品分类,我们要删除哪个商品分类,就勾选哪个商品分类

如果删除父级分类的话,子级分类也要删除

根据分类id或父级分类id删除分类

7.3.1 Mapper

//  根据分类id或父级分类id删除分类的方法
    public int removeProductType(Integer typeId);
<delete id="removeProductType">
    delete
    from product_type
    where type_id = #{typeId} or parent_id = #{typeId}
</delete>

7.3.2 Service

    @CacheEvict(key = "'all:typeTree'")
    @Override
    public Result deleteProductType(Integer typeId) {
        int success = productMapper.removeProductType(typeId);

        return success>0? Result.ok("删除成功") : Result.err(501,"删除失败");
    }

7.3.3 Controller

//  删除商品分类
    @RequestMapping("/type-delete/{typeId}")
    public Result typeDelete(@PathVariable Integer typeId){
       return productTypeService.deleteProductType(typeId);
    }

7.4 修改商品分类

只能改分类名称和分类描述

image-20230820224152401

image-20230820224224072

7.4.1 Mapper

//  根据分类id修改分类的方法
    public int setProductTypeById(ProductType productType);
<update id="setProductTypeById">
    update product_type
    set type_name=#{typeName},
        type_desc=#{typeDesc}
    where type_id= #{typeId}
</update>

7.4.2 Service

    @CacheEvict(key = "'all:typeTree'")
    @Override
    public Result setProductType(ProductType productType) {
//      修改的分类名称是否已经存在
        ProductType prodType = new ProductType();
        prodType.setTypeName(productType.getTypeName());
        ProductType prodCategory = productMapper.findTypeByCodeOrName(prodType);

        if (prodCategory!=null && !prodCategory.getTypeId().equals((productType.getTypeId()))){
            return Result.err(501,"分类名称已经存在");
        }

        int success = productMapper.setProductTypeById(productType);

        return success>0? Result.ok("修改分类成功") : Result.err(501,"修改分类失败");
    }

7.4.3 Controller

//  修改商品分类的url
    @RequestMapping("/type-update")
    public Result updateProductType(@RequestBody ProductType productType){
        return productTypeService.setProductType(productType);
    }

7.4.4 效果图

image-20230820231056089

image-20230820231114015

image-20230820231129377

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

恒合仓库 - 商品管理模块、上传照片、添加采购单、添加出库单、商品分类 的相关文章

随机推荐

  • main.c(31): warning: #223-D: function “uart_init“ declared implicitly

    Keil5编程之warning 223 D function xxx declared implicitly 1 函数没有头文件中进行声明 在头文件中添加声明 2 定义错误 字母大小可能不一致 仔细看一下出现问题的函数是否在声明和调用时使用
  • C语言入门——适合练手的密码本项目

    一 引言 学C语言有一段时间了 趁着正好做了密码本的小项目 把它分享出来 二 思路与原理 密码本 见名知意 就是存放账号密码 起到备忘录作用的本子 将需要备忘的数据通过加密存放在文本文件中 打开的文本文件为加密文本 需要通过软件查看已经存放
  • 用实际例子理解回调函数(Calback)

    用实际例子理解回调函数 Calback 在我们编码的过程中 调用和回调几乎无处不在 但是我对回调函数到底是怎样一回事并没有一个真正透彻的理解 最近我查找学习了一些资料 学到了很多 我参考了一些知乎上的分享 很不错 https www zhi
  • <数据结构>创建一个单链表

    单链表基本操作的实现 内容 构建线性表的链式存储结构 采用动态分配方式实现单链表的初始化 数据的插入 删除 输出单链表内中各元素 求单链表的长度 实现单链表中数据结点的按值排序 实现单链表的逆置 合并两个有序的单链表 有序的a表和有序的b表
  • node版本管理工具nvm

    1 标题卸载nvm和node js 系统变量中删除nvm添加变量 NVM HOME和NVM SYMLINK 环境变量中 path 删除nvm自动添加的变量 Path NVM HOME NVM SYMLINK 删除自身安装node环境 参考图
  • 《机器人操作系统入门》课程代码示例安装出错解决方法

    问题描述 学习 机器人操作系统入门 课程时 在Ubuntu 16 04 上安装了kinetic 安装ROS Academy for Beginners时依赖总是报错 如下所示 rosdep install from paths src ig
  • endnote插入的不是序号(而是大括号加上作者)的解决

    仅作为记录 大佬请跳过 之前用word通过endnote导入文献 都是可以的 在正文出现 1 的引用 但是博主新的word 需要修改参考文献 因此拟重新导入参考文献来修改 但发现导入的都是 Dou 2017 在正文中 文章目录 解决 参考
  • 50多个开源PDF阅读编辑工具汇总

    PDF Editing Creation 50 open source free alternatives to Adobe Acrobat 文章来源于这里 版权归原作者所有 Adobe Acrobat is expensive but t
  • QT QTableWidget 表格 学习笔记

    首先 了解一下QTableWidget 控件的属性 成员方法 功能 setText const QString text 设置单元格中的文本 setlcon const Qlcon icon 给单元格添加图标 setBackground c
  • unity3d 输入法相关API

    Input inputString 获取输入的文字 正在打的中文是接受不到的 只有在文字写到文本框才能获取 Input imeCompositionMode 是否是激活输入框状态 on 是 Input compositionString 空
  • 软件测试之登录测试详解

    一 功能测试 登录 功能性测试用例包括 1 什么都不输入 点击提交按钮 看提示信息 非空检查 2 输入已注册的用户名和正确的密码 验证是否登录成功 3 输入已注册的用户名和不正确的密码 验证是否登录失败 并且提示信息正确 4 输入未注册的用
  • mysql将执行过的sql放到历史记录里面

    查看是不是开启将历史执行的sql存入文件 show variables like general log 输出结果如下 gt Variable name Value
  • Anaconda安装教程

    文章目录 1 下载链接 2 安装步骤 3 确认已安装Anaconda 4 问题解决 4 1问题一 4 2问题二 1 下载链接 Anaconda百度网盘链接 点击即可进入百度网盘 提取码u5fx 建议不要去官网下载最新版本的 因为后期可能会遇
  • H264视频传输、编解码----RTSP认证

    Rtsp认证主要分为两种 基本认证 basic authentication 和摘要认证 digest authentication 基本认证是http 1 0提出的认证方案 其消息传输不经过加密转换因此存在严重的安全隐患 摘要认证是htt
  • 智能门禁(2)---安检人脸识别人证验证系统解决方案

    安检人脸识别人证验证系统解决方案方案 一 概述及特点 基于可见光下的中远距离人脸识别算法 人脸识别智能监控平台 对多个摄像头监控范围内的多个人脸同时进行检测 跟踪和识别 实时对人员身份进行确认 一旦发现黑名单人员 自动报警 实现24小时的非
  • Python沙雕故事生成器

    Python故事生成器 本文章小编来给大家分享使用Python制作一个故事生成器 仅供娱乐 一 知识归纳 StringVar 控件变量 python中在使用界面编程时 用于跟踪数值不断发生变化的变量 确保数值的变更可以随时在根窗口上面显示出
  • YOLO3 -- 介绍

    YOLO介绍 YOLO官网 YOLO You Only Look Once 是目标检测模型 目标检测是计算机视觉中比较简单的任务 用来在一张图片中找到某些特定的物体 目标检测不仅要求我们识别这些物体的种类 同时要求我们标出这些物体的位置 Y
  • 【深度学习系列】用Tensorflow进行图像分类

    上个月发布了四篇文章 主要讲了深度学习中的 hello world mnist图像识别 以及卷积神经网络的原理详解 包括基本原理 自己手写CNN和paddlepaddle的源码解析 这篇主要跟大家讲讲如何用PaddlePaddle和Tens
  • eaxyx界面学习

    1 easyX的原理 基于Windows图形编程 将Windows下的复杂程序过程进行封装 仅给用户提供一个简单熟悉的接口 用户对于图形库中函数的调用 最终都会由Windows底层的API实现 在官网搜索eaxyx下载点击安装即可 接着引用
  • 恒合仓库 - 商品管理模块、上传照片、添加采购单、添加出库单、商品分类

    商品管理模块 文章目录 商品管理模块 一 分页查询商品 1 1 实体类 1 1 1 Store 仓库 1 1 2 Brand 品牌 1 1 3 ProductType 商品分类 1 1 4 Supply 供应商 1 1 5 Place 产地