谷粒商城实战笔记-97~98-仓储服务-API-仓库管理-采购完整流程

当前笔记包含以下内容:

  • 97-仓储服务-API-仓库管理-合并采购需求
  • 98-仓储服务-API-仓库管理-领取采购单
  • 99-仓储服务-API-仓库管理-完成采购

一,简化的采购流程概述

在这里插入图片描述

图片展示了一个简化的采购流程。从左到右,流程可以分为以下几个步骤:

  1. 人工创建采购需求:这个阶段通常由内部用户或部门提出购买某种商品或服务的需求。

  2. 库存预警创建采购需求:如果库存量低于预定的阈值,系统会自动触发一个采购需求。

  3. 人工合并:在这一环节中,所有的采购需求被汇总在一起,可能通过手动的方式进行整合。

  4. 系统定时合并:此外,系统也会定期地将采购需求合并成一张采购单。

  5. 分配给采购人员:一旦生成了采购单,它会被分配给专门负责采购的人员。

  6. 通知供应商或自主采购:接下来,采购人员要么联系供应商并下单,要么自行完成采购任务。

  7. 采购单入库:当物品到达后,它们需要被记录和录入到库存管理系统中。

  8. 添加库存:最后一步是更新库存数量,准确反映当前的库存。

二,采购流程

1,新建采购单

在这里插入图片描述

点击按钮,新建采购单,这步操作非常简单。

2,给采购单分配负责人

点击采购单右侧分配按钮,给采购单分配负责人。

注意,负责人来自管理员列表,可以在这个功能模块新增一个管理员。

在这里插入图片描述

然后点击分配按钮,给采购单分配采购负责人。

在这里插入图片描述

3,合并采购需求到采购单

在采购需求中,可以选择讲采购需求合并到未完成采购的采购单中。

在这里插入图片描述

点击合并整单后,会调用一个接口查询unreceive状态的采购单。

选中要合并的需求后,点击合并整单,在下拉列表中选择一个采购单,点击确定。

在这里插入图片描述

4,采购负责人领取采购单

领取采购单在谷粒商城系统仅仅提供了接口,未有前端实现。从业务上来说,采购负责人可以在移动端操作,领取分配给自己的采购单。

这里用postman调用接口,模拟前端操作领取采购单。

在这里插入图片描述
领取完成后,采购单状态变更,如下。

在这里插入图片描述

5,完成采购

采购负责人在完成采购任务后,会在采购管理系统中确认完成,特别说明,谷粒商城中不包含采购管理系统,我们需要用Postman模拟请求。

完成采购有2种可能情况:

  • 所有采购需求都完成的情况下,采购单的状态为已完成,采购需求的状态为已完成
  • 部分采购需求完成,采购单的状态为有异常,成功的采购需求状态为已完成,不成功的采购需求状态为采购失败

完成采购的后台业务逻辑:

  • 更新采购需求状态,可能是完成,可能是采购失败
  • 完成采购需求需要更新库存
  • 根据所有采购需求的状态更新采购单状态,可能是完成,可能是有异常

在这里插入图片描述

localhost:88/api/ware/purchase/done
{

    "id":1,
    "items":[
        {
            "itemId":1,
            "status":3,
            "reason":""
        },
        {
            "itemId":2,
            "status":4,
            "reason":"无货"
        }
    ]
}

三,代码总结

1,查询unreceive状态的采购单接口

Controller:

	@RequestMapping("/unreceive/list")
    public R unreceivelist(@RequestParam Map<String, Object> params){
        PageUtils page = purchaseService.queryPageUnreceivePurchase(params);
        return R.ok().put("page", page);
    }

Service:

	public PageUtils queryPageUnreceivePurchase(Map<String, Object> params) {
        IPage<PurchaseEntity> page = this.page(
                new Query<PurchaseEntity>().getPage(params),
                new QueryWrapper<PurchaseEntity>().eq("status",0).or().eq("status",1)
        );

        return new PageUtils(page);
    }

2 新增将采购需求合并到采购单的接口

Controller:

	@PostMapping("/merge")
    public R merge(@RequestBody MergeVo mergeVo){
        purchaseService.mergePurchase(mergeVo);
        return R.ok();
    }

Service:

	@Transactional
    @Override
    public void mergePurchase(MergeVo mergeVo) {
        Long purchaseId = mergeVo.getPurchaseId();
        if(purchaseId == null){
            //1、新建一个
            PurchaseEntity purchaseEntity = new PurchaseEntity();

            purchaseEntity.setStatus(WareConstant.PurchaseStatusEnum.CREATED.getCode());
            purchaseEntity.setCreateTime(new Date());
            purchaseEntity.setUpdateTime(new Date());
            this.save(purchaseEntity);
            purchaseId = purchaseEntity.getId();
        }

        //TODO 确认采购单状态是0,1才可以合并

        List<Long> items = mergeVo.getItems();
        Long finalPurchaseId = purchaseId;
        List<PurchaseDetailEntity> collect = items.stream().map(i -> {
            PurchaseDetailEntity detailEntity = new PurchaseDetailEntity();

            detailEntity.setId(i);
            detailEntity.setPurchaseId(finalPurchaseId);
            detailEntity.setStatus(WareConstant.PurchaseDetailStatusEnum.ASSIGNED.getCode());
            return detailEntity;
        }).collect(Collectors.toList());


        detailService.updateBatchById(collect);

        PurchaseEntity purchaseEntity = new PurchaseEntity();
        purchaseEntity.setId(purchaseId);
        purchaseEntity.setUpdateTime(new Date());
        this.updateById(purchaseEntity);
    }

3,领取采购单

Controller:

/**
     * 领取采购单
     * @return
     */
    @PostMapping("/received")
    public R received(@RequestBody List<Long> ids){
        purchaseService.received(ids);
        return R.ok();
    }

Service:

@Override
    public void received(List<Long> ids) {
        //1、确认当前采购单是新建或者已分配状态
        List<PurchaseEntity> collect = ids.stream().map(id -> {
            PurchaseEntity byId = this.getById(id);
            return byId;
        }).filter(item -> {
            if (item.getStatus() == WareConstant.PurchaseStatusEnum.CREATED.getCode() ||
                    item.getStatus() == WareConstant.PurchaseStatusEnum.ASSIGNED.getCode()) {
                return true;
            }
            return false;
        }).map(item->{
            item.setStatus(WareConstant.PurchaseStatusEnum.RECEIVE.getCode());
            item.setUpdateTime(new Date());
            return item;
        }).collect(Collectors.toList());

        //2、改变采购单的状态
        this.updateBatchById(collect);


        //3、改变采购项的状态
        collect.forEach((item)->{
            List<PurchaseDetailEntity> entities = detailService.listDetailByPurchaseId(item.getId());
            List<PurchaseDetailEntity> detailEntities = entities.stream().map(entity -> {
                PurchaseDetailEntity entity1 = new PurchaseDetailEntity();
                entity1.setId(entity.getId());
                entity1.setStatus(WareConstant.PurchaseDetailStatusEnum.BUYING.getCode());
                return entity1;
            }).collect(Collectors.toList());
            detailService.updateBatchById(detailEntities);
        });
    }

5, 完成采购

5.1 分页插件配置

增加MybatisPlus分页配置,以便前端的分页功能能正常使用。

在这里插入图片描述

5.2 服务间接口调用的不同方式

在微服务架构中,Feign 是一个声明式的 HTTP 客户端,它简化了 HTTP 请求的发送。当使用 Feign 进行服务间通信时,有两种常见的配置方式:一种是直接与目标服务通信(绕过网关),另一种是通过 API 网关进行通信。

直接访问服务

配置步骤:

  1. 定义 Feign Client:

    @FeignClient(name = "gulimall-product")
    public interface SkuInfoFeignService {
        @GetMapping("/skuinfo/info/{skuId}")
        SkuInfoEntity getSkuInfo(@PathVariable("skuId") Long skuId);
    }
    
  2. 服务发现:

    • 确保 gulimall-product 服务已经在 Eureka 注册中心注册。
    • 在 Feign 客户端所在的服务中配置 Eureka 和 Ribbon 以支持服务发现和服务实例选择。
  3. 负载均衡:

    • Ribbon 自动为 Feign 提供客户端负载均衡能力,无需额外配置。

优劣分析:

  • 优点:

    • 性能更高: 减少了网关转发的延迟。
    • 简单直接: 服务间的调用更加直接,减少了中间环节。
  • 缺点:

    • 服务地址变更困难: 如果服务地址发生变化,需要修改 Feign 客户端的配置。
    • 安全性较低: 缺少统一的安全认证机制。
    • 管理不便: 每个服务都需要单独维护路由信息。
通过网关访问服务

配置步骤:

  1. 定义 Feign Client:

    @FeignClient(name = "gulimall-gateway")
    public interface SkuInfoFeignService {
        @GetMapping("/api/product/skuinfo/info/{skuId}")
        SkuInfoEntity getSkuInfo(@PathVariable("skuId") Long skuId);
    }
    
  2. 网关配置:

    • 配置网关路由规则将请求转发到相应的服务。
    • 需要在网关服务中添加 /api/product/skuinfo/info/{skuId} 路由规则,指向 gulimall-product 服务。
  3. 服务发现:

    • 确保 gulimall-gatewaygulimall-product 都已在 Eureka 注册中心注册。
    • 在 Feign 客户端所在的服务中配置 Eureka 和 Ribbon 以支持服务发现和服务实例选择。

优劣分析:

  • 优点:

    • 统一入口: 所有外部请求都通过网关进入,便于统一管理。
    • 增强安全性: 可以在网关层实现认证授权等安全措施。
    • 易于扩展: 网关可以提供缓存、监控等功能,方便扩展。
  • 缺点:

    • 性能影响: 增加了网关转发的延迟。
    • 复杂度增加: 需要维护网关路由规则,增加了系统的复杂度。
小小结

选择哪种方式取决于您的具体需求和场景。如果追求高性能和简单性,可以选择直接访问服务;如果希望有更好的可管理性和安全性,则应考虑通过网关访问服务。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
根据引用中提供的信息,谷粒商城是一个B2C模式的电商平台,主要销售自营商品给客户。B2C模式指的是商对客的模式,即商家直接向消费者销售商品和服务谷粒商城使用微服务架构,这是一种将应用程序拆分成独立且可独立开发、部署和扩展的小型服务的架构。引用还提到谷粒商城的技术涵盖微服务架构、分布式、全栈、集群、部署和自动化运维等方面。 因此,从前慢-谷粒商城篇章6主要讨论的可能是谷粒商城的技术方面,包括微服务架构、分布式、全栈、集群、部署和自动化运维等内容。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [从前慢-谷粒商城篇章1](https://blog.csdn.net/m0_67391121/article/details/125383572)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [2020年谷粒商城md笔记](https://download.csdn.net/download/ZHUXIUQINGIT/12543161)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小手追梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值