商城体系之产商品系统

news2024/11/25 20:16:12

本文主要讲解商城体系下产商品系统的设计。商城系统可以拆分成多个业务中台和多个应用服务。

1、产商品系统业务架构

产商品系统作为商城重要的基础信息组成部分,主要划分为产品信息和商品信息,产品信息保持最原始的产品基础属性和内容,商品信息则根据不同的售卖策略、营销价格属性或SKU进行组装而成。

因此商品源于产品而不同于产品。简单概括来说,商品是营销属性的产品。

2、产商品关键内容信息

产商品中心关键内容包括:产品信息、商品信息、目录管理、标签信息、产品字典库、产品分类、产品属性、价格版本管理、商品SKU组合。

产品信息应该包括产品基本信息,产品价格(与报价系统产品价格统一库),产品工艺术属性信息。

3、产商品系统边界

产商品系统与其他系统关系

订单系统与产商品系统调用关系

4、产商品结构模型设计

5、关键代码片断

@RestController
@RequestMapping("/customer-api/v1/collect")
public class GoodsCollectController {

    /**
     * 分页获取当前会员的收藏列表
     *
     * @return 收藏列表
     */
    @RestApi(module = "商品收藏-C端", name = "分页获取当前会员的收藏列表", logabled = true)
    @PostMapping("/page")
    public DataResponse<CustomizePage<GoodsCollectVO>> pageCurrentMemberGoodsCollect(@RequestBody @Valid GoodsCollectQry qry) {
        CustomizePage<MallGoodsCollectE> goodsCollectE = MallGoodsCollectE.queryInstance().pageCurrentMemberGoodsCollect(qry);
        return DataResponse.of(GoodsCollectVOConverter.convert(goodsCollectE));
    }

    /**
     * 加入收藏
     *
     * @param cmd 商品id
     * @return 收藏列表
     */
    @RestApi(module = "商品收藏-C端", name = "加入收藏", logabled = true)
    @PostMapping("/add")
    public DataResponse<Boolean> addGoodsCollect(@RequestBody @Valid AddGoodsCollectCmd cmd) {
        return DataResponse.of(MallGoodsCollectE.queryInstance().addGoodsCollect(cmd));
    }

    /**
     * 取消收藏
     *
     * @param id 收藏id
     * @return 操作结果
     */
    @RestApi(module = "商品收藏-C端", name = "取消收藏", logabled = true)
    @DeleteMapping("/{id}")
    public DataResponse<Boolean> deleteGoodsCollect(@PathVariable Long id) {
        return DataResponse.of(MallGoodsCollectE.queryInstance().deleteGoodsCollect(id));
    }

    /**
     * 根据 商品id 查询当前商品收藏情况
     *
     * @param cmd 商品id
     * @return 当前商品收藏情况
     */
    @RestApi(module = "商品收藏-C端", name = "根据 商品id 查询当前商品收藏情况", logabled = true)
    @PostMapping("/getGoodsCollect")
    public DataResponse<GetGoodsCollectVO> getGoodsCollect(@RequestBody GetGoodsCollectCmd cmd) {
        MallGoodsCollectE mallGoodsCollectE = MallGoodsCollectE.queryInstance().getGoodsCollect(cmd);
        return DataResponse.of(BeanToolkit.instance().copy(mallGoodsCollectE, GetGoodsCollectVO.class));
    }
}
@Slf4j
@Service
public class GoodsService {
    @Autowired
    private GoodsSkuRpcService goodsSkuRpcService;
    @Autowired
    private GoodsGateway goodsGateway;

    /**
     * 查询商品详情
     */
    public Map<String, SpuApiCO> mapSkuCO(List<String> skuIds) {
        if (CollUtil.isEmpty(skuIds)) {
            return Collections.emptyMap();
        }
        DataResponse<Map<String, SpuApiCO>> dataResponse = goodsSkuRpcService.mapByIds(skuIds);
        return ResponseUtil.resultValidate(dataResponse);
    }

    /**
     * 批量更新商品库存
     */
    public void updateInventory(List<UpdateInventoryDTO> dtoList) {
        goodsGateway.updateInventory(dtoList);
    }

    /**
     * 获取商品供应商集合
     */
    public Map<String, SupplierDTO> mapSupplierCO() {
        return goodsGateway.mapSupplierCO();
    }

    /**
     * 计算商品购买价格
     *
     * @param skuCO       商品信息
     * @param count       购买数量
     * @param memberLevel 会员等级
     * @param region      购买区域
     * @return 购买价格
     */
    public CalcPayPriceDTO calcPayPrice(SkuCO skuCO, Integer count, Integer memberLevel, String region) {
        //万
        BigDecimal tenThousand = BigDecimal.valueOf(10000);
        //该方法的中的价格单位为分
        //商品原价,原积分
        Long price = BigDecimalUtils.yuan2Penny(skuCO.getPrice());
        Long integral = skuCO.getIntegral();

        //需支付价格,积分,运费
        Long goodsTotalPrice = price;
        Long goodsTotalIntegral = integral;
        Long freight = 0L;

        // 1、计算会员等级差异化
        DiffPriceOption levelDifference = skuCO.getLevelDifference();
        if (levelDifference.enabled()) {
            DiffPriceTmpl.DiffPriceForLevel diffPriceForLevel = levelDifference.getTmpl().getDiffs().stream()
                    .filter(tmpl -> tmpl.getLevel().equals(memberLevel))
                    .findFirst()
                    .get();

            if (DiffPriceMode.PERCENTAGE_DISCOUNT.getValue().equals(levelDifference.getTmpl().getMode())) {
                // 1.1、结算比例调整
                Long percent = diffPriceForLevel.getPercent().multiply(BigDecimal.valueOf(100)).longValue();
                goodsTotalPrice = BigDecimal.valueOf(price * percent).divide(tenThousand, RoundingMode.HALF_UP).longValue();
                // 积分不足1取1
                BigDecimal integralDecimal = BigDecimal.valueOf(integral * percent);
                goodsTotalIntegral = integralDecimal.compareTo(tenThousand) > 0 ?
                        integralDecimal.divide(tenThousand, RoundingMode.HALF_UP).longValue()
                        : integralDecimal.divide(tenThousand, RoundingMode.UP).longValue();
            } else if (DiffPriceMode.EXTRA_PAYMENT.getValue().equals(levelDifference.getTmpl().getMode())) {
                // 1.2、需额外支付
                if (diffPriceForLevel.getExtraPrice() != null) {
                    Long extraPrice = BigDecimalUtils.yuan2Penny(diffPriceForLevel.getExtraPrice());
                    goodsTotalPrice = (price + extraPrice);
                }
                if (diffPriceForLevel.getExtraIntegral() != null) {
                    goodsTotalIntegral = (integral + diffPriceForLevel.getExtraIntegral());
                }
            } else {
                throw new ServiceException("价格结算失败");
            }
        }
        // 购物车结算时,收货地址还没选,选了再计算
        if (StringUtil.isNotEmpty(region)) {
            // 2、计算运费
            ShippingCostOption freeShippingRange = skuCO.getFreeShippingRange();
            if (freeShippingRange.enabled()) {
                UCRegionCacheCO customerRegion = MtdsBaseUCRegionCacheUtils.getUCRegionCacheCOById(region);
                Optional<ShippingCostTmpl.RegionalCost> regionalCostOptional = freeShippingRange.getTmpl().getRegionalCosts().stream()
                        .filter(tmpl -> customerRegion.getPids().contains(tmpl.getRegionId()))
                        .findFirst();

                if (regionalCostOptional.isPresent()) {
                    ShippingCostTmpl.RegionalCost regionalCost = regionalCostOptional.get();
                    // 2.1 满足包邮条件
                    if (regionalCost.getFreeEnabled() == 1 && count >= regionalCost.getFreeQty()) {
                        freight = 0L;
                    } else {
                        // 2.2 计算运费
                        if (count <= regionalCost.getBaseQty()) {
                            freight = freight + BigDecimalUtils.yuan2Penny(regionalCost.getBasePrice());
                        } else {
                            freight = freight + BigDecimalUtils.yuan2Penny(regionalCost.getBasePrice());

                            int increaseCount = (count - regionalCost.getBaseQty());
                            long extraFreight = BigDecimalUtils.yuan2Penny(regionalCost.getIncreasePrice())
                                    * increaseCount;
                            freight = freight + (extraFreight);
                        }
                    }
                }
            }
        }

        //支付金额
        Long payPrice = (goodsTotalPrice * count) + freight;
        return CalcPayPriceDTO.builder()
                .skuId(Long.valueOf(skuCO.getId()))
                .oldGoodsTotalPrice(price * count)
                .goodsTotalPrice(goodsTotalPrice * count)
                .payPrice(payPrice)
                .freight(freight)
                .oldGoodsTotalIntegral(integral * count)
                .goodsTotalIntegral(goodsTotalIntegral * count)
                .build();
    }
}
@Slf4j
@Component
public class GoodsGatewayImpl implements GoodsGateway {
    @Autowired
    private GoodsSkuRpcService goodsSkuRpcService;
    @Autowired
    private GoodsSupplierRpcService supplierRpcService;

    @Override
    public void updateInventory(List<UpdateInventoryDTO> dtoList) {
        List<SkuIncrementCmd> skuIncrementCmds = BeanToolkit.instance().copyList(dtoList, SkuIncrementCmd.class);
        Response response = goodsSkuRpcService.increment(skuIncrementCmds);
        if (!response.getStatus()) {
            throw new RpcErrorException(response.getMessage(), "商品");
        }
    }

    @Override
    public Map<String, SupplierDTO> mapSupplierCO() {
        DataResponse<List<SupplierCO>> response = supplierRpcService.listAll();
        List<SupplierCO> supplierCOS = ResponseUtil.resultValidate(response);
        if (CollUtil.isEmpty(supplierCOS)) {
            return Collections.emptyMap();
        }

        List<SupplierDTO> supplierDTOS = BeanToolkit.instance().copyList(supplierCOS, SupplierDTO.class);
        return supplierDTOS.stream().collect(Collectors.toMap(SupplierDTO::getId, Function.identity()));
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/785099.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

下拉框可筛选可树状多选组件

实际效果图片 父页面 <el-form-item label"转发&#xff1a;" :label-width"formLabelWidth" class"formflex_item"><el-select ref"select" :clearable"true" clear"clearSelect" remove-tag"r…

day2 驱动开发 c语言

通过驱动开发给pcb板子点灯。 u-boot已经提前移植到了emmc中。 灯也是一种字符型设备。 编程流程需要先注册设备&#xff0c;然后创建结点&#xff0c;然后操作电灯相关寄存器 应用层直接调用read write来打开字符设备进行操作。 这样写会造成无法处理内核页面请求的虚拟地址…

SpringBoot中java操作excel【EasyExcel】

EasyExcel 处理Excel&#xff1b;简单记录&#xff0c;方便日后查询&#xff01; 官方文档&#xff1a; Easy Excel (alibaba.com) 一、EasyExcel概述 Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存&#xff0c;poi有一套…

前端食堂技术周刊第 91 期:2023 npm 状态、TC39 会议回顾、浏览器中的 Sass、React 18 如何提高应用程序性能

美味值&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f; 口味&#xff1a;茶椰生花 食堂技术周刊仓库地址&#xff1a;https://github.com/Geekhyt/weekly 大家好&#xff0c;我是童欧巴。欢迎来到前端食堂技术周刊&#xff0c;我们先来看下…

js基础-练习三

九九乘法表&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthsc, initial-scale1.0"><title>九九乘法表</title><style&g…

5.9 Bootstrap 警告框(Alert)插件

文章目录 Bootstrap 警告框&#xff08;Alert&#xff09;插件用法选项方法事件 Bootstrap 警告框&#xff08;Alert&#xff09;插件 警告框&#xff08;Alert&#xff09;消息大多是用来向终端用户显示诸如警告或确认消息的信息。使用警告框&#xff08;Alert&#xff09;插件…

基于 Flink SQL CDC 数据处理的终极武器

文章目录 一、传统的数据同步方案与 Flink SQL CDC 解决方案1.1 Flink SQL CDC 数据同步与原理解析1.2 基于日志的 CDC 方案介绍1.3 选择 Flink 作为 ETL 工具 二、 基于 Flink SQL CDC 的数据同步方案实践2.1 CDC Streaming ETL2.2 Flink-CDC实践之mysql案例 来源互联网多篇文…

Redis—分布式系统

Redis—分布式系统 &#x1f50e;理解分布式&#x1f50e;分布式—应用服务与数据库服务分离引入更多的应用服务节点理解负载均衡 引入更多的数据库服务节点缓存分库分表 微服务 &#x1f50e;常见概念应用(Application) / 系统(System)模块(Module) / 组件(Component)分布式(D…

nvm 安装 Node 报错:panic: runtime error: index out of range [3] with length 3

最近在搞 TypeScript&#xff0c;然后想着品尝一下 pnpm&#xff0c;但是 pnmp 8.x 最低需要 Node 16.x&#xff0c;但是电脑上暂时还没有该版本&#xff0c;通过 nvm list available 命令查看可用的 Node 版本&#xff1a; nvm list available# 显示如下 | CURRENT | …

【C++进阶】:继承

继承 一.继承的概念和定义1.概念2.定义 二.基类和派生类对象赋值转换三.继承中的作用域四.派生类的默认成员函数五.继承与友元六.继承与静态成员七.复杂的菱形继承及菱形虚拟继承1.二义性2.原理 八.总结 一.继承的概念和定义 1.概念 继承(inheritance)机制是面向对象程序设计使…

虚拟文件描述符VFD

瀚高数据库 目录 环境 文档用途 详细信息 环境 系统平台&#xff1a;Linux x86-64 Red Hat Enterprise Linux 7 版本&#xff1a;14 文档用途 了解VFD 详细信息 1.相关数据类型 typedef struct vfd{int fd; /* current FD, or VFD_CLOSED if non…

23 自定义控件

案例&#xff1a;组合Spin Box和Horizontal Slider实现联动 新建Qt设计师界面&#xff1a; 选择Widget&#xff1a; 选择类名&#xff08;生成.h、.cpp、.ui文件&#xff09; 在smallWidget.ui中使用Spin Box和Horizontal Slider控件 可以自定义数字区间&#xff1a; 在主窗口w…

第17章 常见函数

创建函数 第一种格式采用关键字function&#xff0c;后跟分配给该代码块的函数名。 function name {commands }第二种 name() { commands }你也必须注意函数名。记住&#xff0c;函数名必须是唯一的&#xff0c;否则也会有问题。如果你重定义了函数&#xff0c;新定义会覆…

【时间复杂度】

旋转数组 题目 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 /* 解题思路&#xff1a;使用三次逆转法&#xff0c;让数组旋转k次 1. 先整体逆转 // 1,2,3,4,5,6,7 // 7 6 5 4 3 2 1 2. 逆转子数组[0, k - 1] // 5 6 7 4 3…

C语言基本结构:顺序、选择和循环

文章目录 前言顺序结构代码讲解 选择结构代码讲解 循环结构总结 前言 在计算机编程中&#xff0c;掌握基本的编程结构是非常重要的。C语言作为一种广泛应用的编程语言&#xff0c;具有丰富的基本结构&#xff0c;包括顺序结构、选择结构和循环结构。这些基本结构为开发人员提供…

RocketMQ主从集群broker无法启动,日志报错

使用vmWare安装的centOS7.9虚拟机&#xff0c;RocketMQ5.1.3 在rocketMQ的bin目录里使用相对路径的方式启动broker&#xff0c;jps查询显示没有启动&#xff0c;日志报错如下 排查配置文件没有问题&#xff0c;nameServer也已经正常启动 更换绝对路径&#xff0c;启动broker&…

flutter:animate_do(flutter中的Animate.css)

简介 做过web开发的应该大部分人都知道Animate.css&#xff0c;它为开发者提供了一系列预定义的动画效果&#xff0c;可以通过简单的CSS类来实现各种动画效果。而animate_do 相当于flutter中的Animate.css,它提供了很多定义好的动画效果 基本使用 官方地址 https://pub-web.…

一文学会redis在springBoot中的使用

“收藏从未停止&#xff0c;练习从未开始”&#xff0c;或许有那么一些好题好方法&#xff0c;在被你选中收藏后却遗忘在收藏夹里积起了灰&#xff1f;今天请务必打开你沉甸甸的收藏重新回顾&#xff0c;分享一下那些曾让你拍案叫绝的好东西吧&#xff01; 一、什么是redis缓存…

【深度学习】【三维重建】windows10环境配置PyTorch3d详细教程

【深度学习】【三维重建】windows10环境配置PyTorch3d详细教程 文章目录 【深度学习】【三维重建】windows10环境配置PyTorch3d详细教程Anaconda31.安装Anaconda32.卸载Anaconda33.修改Anaconda3安装虚拟环境的默认位置 安装PyTorch3d确定版本对应关系源码编译安装Pytorch3d 总…

Day 65: 集成学习之 AdaBoosting (3. 集成器)

代码&#xff1a; package dl;import java.io.FileReader; import weka.core.Instance; import weka.core.Instances;/*** The booster which ensembles base classifiers.*/ public class Booster {/*** Classifiers.*/SimpleClassifier[] classifiers;/*** Number of classi…