diff --git a/mall-account/src/main/java/com/suisung/mall/account/controller/mobile/SinglePushController.java b/mall-account/src/main/java/com/suisung/mall/account/controller/mobile/SinglePushController.java index 52b458d9..117f3677 100644 --- a/mall-account/src/main/java/com/suisung/mall/account/controller/mobile/SinglePushController.java +++ b/mall-account/src/main/java/com/suisung/mall/account/controller/mobile/SinglePushController.java @@ -33,8 +33,8 @@ public class SinglePushController { return "success"; } - @PostMapping("/pushTocid") - public CommonResult pushTocid(@RequestParam String userId, @RequestParam String message) { + @PostMapping("/pushTo") + public CommonResult pushTo(@RequestParam String userId, @RequestParam String message) { log.info("pushTocid"); return accountSinglePushService.pushTocid(message, userId); } diff --git a/mall-common/src/main/java/com/suisung/mall/common/api/StateCode.java b/mall-common/src/main/java/com/suisung/mall/common/api/StateCode.java index 0ce63060..eb68092b 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/api/StateCode.java +++ b/mall-common/src/main/java/com/suisung/mall/common/api/StateCode.java @@ -42,6 +42,8 @@ public class StateCode { public static final int PRODUCT_STATE_NORMAL = 1001; //正常 public static final int PRODUCT_STATE_OFF_THE_SHELF = 1002; //下架 + public static final int PRODUCT_STATE_OFF_THE_SHELF_UNCHECK = 1003; //同步数据的状态,下架未分配商品 + public static final int DEMAND_STATE_CONDUCT = 1000; //采购中 public static final int DEMAND_STATE_REJECT = 1030; //被驳回 public static final int DEMAND_STATE_EXAMINE = 1040; //审核中 diff --git a/mall-common/src/main/java/com/suisung/mall/common/enums/DicEnum.java b/mall-common/src/main/java/com/suisung/mall/common/enums/DicEnum.java index 4629dd01..3030fec1 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/enums/DicEnum.java +++ b/mall-common/src/main/java/com/suisung/mall/common/enums/DicEnum.java @@ -26,6 +26,8 @@ public enum DicEnum { YESORNO_0("0", "否","yesOrno","是否","是否"), YESORNO_1("1", "是","yesOrno","是否","是否"), + + GOODS_UN_SYNC_SX("1", "白条猪","unSyncGoodsSX","思迅非同步商品","白条猪"), ; ; private String code; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/base/ShopBaseProductSpec.java b/mall-common/src/main/java/com/suisung/mall/common/modules/base/ShopBaseProductSpec.java index 1d7a887b..c7d0cbe3 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/base/ShopBaseProductSpec.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/base/ShopBaseProductSpec.java @@ -14,6 +14,8 @@ import lombok.experimental.Accessors; import java.io.Serializable; import java.util.List; +import static com.baomidou.mybatisplus.annotation.FieldStrategy.NOT_EMPTY; + /** *

* 商品规格表 @@ -36,24 +38,33 @@ public class ShopBaseProductSpec implements Serializable { private Integer spec_id; @ApiModelProperty(value = "规格类别名称") + @TableField(updateStrategy=NOT_EMPTY) private String spec_name; @ApiModelProperty(value = "规格类别注释") + @TableField(updateStrategy=NOT_EMPTY) private String spec_remark; @ApiModelProperty(value = "显示类型(ENUM): text-文字; image-图片") + @TableField(updateStrategy=NOT_EMPTY) private String spec_format; @ApiModelProperty(value = "排序") + @TableField(updateStrategy=NOT_EMPTY) private Integer spec_order; @ApiModelProperty(value = "规格分类编号:不是商品类型编号,选择分类,可关联到任意级分类。(可以使用一级分类category_id,只在后台快捷定位中起作用) - 不用新建分类表管理。") + @TableField(updateStrategy=NOT_EMPTY) private Integer spec_category_id; @ApiModelProperty(value = "系统内置(ENUM):1-是; 0-否 | 系统内置不可删除 默认安装中会添加一个默认颜色规格") + @TableField(updateStrategy=NOT_EMPTY) private Integer spec_buildin; @ApiModelProperty(value = "规格属性") @TableField(exist = false) private List specItems; + + @ApiModelProperty(value = "所属店铺") + private Integer store_id; } diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/base/ShopBaseProductType.java b/mall-common/src/main/java/com/suisung/mall/common/modules/base/ShopBaseProductType.java index df576401..033c85aa 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/base/ShopBaseProductType.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/base/ShopBaseProductType.java @@ -1,6 +1,7 @@ package com.suisung.mall.common.modules.base; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; @@ -11,6 +12,8 @@ import lombok.experimental.Accessors; import java.io.Serializable; +import static com.baomidou.mybatisplus.annotation.FieldStrategy.NOT_EMPTY; + /** *

* 商品类型表-强调共性,类别cat是强调区别. @@ -33,39 +36,51 @@ public class ShopBaseProductType implements Serializable { private Integer type_id; @ApiModelProperty(value = "类型名称") + @TableField(updateStrategy=NOT_EMPTY) private String type_name; @ApiModelProperty(value = "备注") + @TableField(updateStrategy=NOT_EMPTY) private String type_remark; @ApiModelProperty(value = "是否启用辅助属性(ENUM):1-是; 0-否") + @TableField(updateStrategy=NOT_EMPTY) private Integer type_is_assist; @ApiModelProperty(value = "是否启用参数(ENUM):1-是; 0-否") + @TableField(updateStrategy=NOT_EMPTY) private Integer type_is_param; @ApiModelProperty(value = "是否启用品牌(ENUM):1-是; 0-否") + @TableField(updateStrategy=NOT_EMPTY) private Integer type_is_brand; @ApiModelProperty(value = "是否启用实体商品(ENUM):1-是; 0-否") + @TableField(updateStrategy=NOT_EMPTY) private Integer type_is_entity; @ApiModelProperty(value = "分类编号-可关联到任意级分类。(可以使用一级分类category_id,只在后台快捷定位中起作用) - 要取消快捷定位功能,通过UI交互来更好实现") + @TableField(updateStrategy=NOT_EMPTY) private Integer type_category_id; @ApiModelProperty(value = "是否草稿(ENUM):1-草稿;0-发布") + @TableField(updateStrategy=NOT_EMPTY) private Integer type_is_draft; @ApiModelProperty(value = "规格id(DOT)") + @TableField(updateStrategy=NOT_EMPTY) private String type_spec_ids; @ApiModelProperty(value = "品牌编号") + @TableField(updateStrategy=NOT_EMPTY) private String type_brand_ids; @ApiModelProperty(value = "辅助属性(DOT)") + @TableField(updateStrategy=NOT_EMPTY) private String type_assist_ids; @ApiModelProperty(value = "系统内置(ENUM):1-内置; 0-非内置") + @TableField(updateStrategy=NOT_EMPTY) private Integer type_buildin; } diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductBase.java b/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductBase.java index 6e34ba2a..92ecc307 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductBase.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductBase.java @@ -15,6 +15,8 @@ import java.math.BigDecimal; import java.util.Date; import java.util.List; +import static com.baomidou.mybatisplus.annotation.FieldStrategy.NOT_EMPTY; + /** *

* 商品基础表-SPU表 @@ -28,7 +30,7 @@ import java.util.List; @Accessors(chain = true) @TableName("shop_product_base") @ApiModel(value = "ShopProductBase对象", description = "商品基础表-SPU表") -public class ShopProductBase implements Serializable { +public class ShopProductBase implements Serializable{ private static final long serialVersionUID = 1L; @@ -76,9 +78,11 @@ public class ShopProductBase implements Serializable { private Integer layout_route_id; @ApiModelProperty(value = "商品审核(ENUM):3001-审核通过;3002-审核中;3000-审核未通过") + @TableField(updateStrategy=NOT_EMPTY) private Integer product_verify_id; @ApiModelProperty(value = "商品状态(LIST):1001-正常;1002-下架仓库中;1000-违规禁售") + @TableField(updateStrategy=NOT_EMPTY) private Integer product_state_id; @ApiModelProperty(value = "库存锁定(ENUM):1001-下单锁定;1002-支付锁定;") @@ -130,5 +134,21 @@ public class ShopProductBase implements Serializable { @TableField(exist = false) private List productItems; + //在同步数据的时候,生鲜需要按平台的规格拆分售卖,这些主要记录原始数据,总重量一般为kg,KG,公斤 + @ApiModelProperty(value = "总量单位") + private String unit_name; + + @ApiModelProperty(value = "总重量") + @TableField(updateStrategy=NOT_EMPTY) + private BigDecimal shop_weight; + + @ApiModelProperty(value = "单价") + @TableField(updateStrategy=NOT_EMPTY) + private BigDecimal unit_price; + + @ApiModelProperty(value = "商品分类编号,通过type决定规格,但是分类下的规格值都不同") + @TableField(exist = false) + private Integer categoryId; + } diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductComment.java b/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductComment.java index 7fe36af3..129d9194 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductComment.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductComment.java @@ -30,7 +30,7 @@ import java.util.Date; @Accessors(chain = true) @TableName("shop_product_comment") @ApiModel(value = "ShopProductComment对象", description = "商品评价表") -public class ShopProductComment implements Serializable { +public class ShopProductComment implements Serializable{ private static final long serialVersionUID = 1L; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductInfo.java b/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductInfo.java index 0b67bd3c..051a42f9 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductInfo.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductInfo.java @@ -1,6 +1,7 @@ package com.suisung.mall.common.modules.product; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; @@ -12,6 +13,8 @@ import lombok.experimental.Accessors; import java.io.Serializable; import java.math.BigDecimal; +import static com.baomidou.mybatisplus.annotation.FieldStrategy.NOT_EMPTY; + /** *

* 商品信息表 @@ -34,54 +37,74 @@ public class ShopProductInfo implements Serializable { private Long product_id; @ApiModelProperty(value = "SPU商家编码:货号") + @TableField(updateStrategy=NOT_EMPTY) private String product_number; @ApiModelProperty(value = "商品条形码") + @TableField(updateStrategy=NOT_EMPTY) private String product_barcode; @ApiModelProperty(value = "商品型号") + @TableField(updateStrategy=NOT_EMPTY) private String product_model; @ApiModelProperty(value = "属性(JSON) - 辅助属性及VAL") + @TableField(updateStrategy=NOT_EMPTY) private String product_assist; @ApiModelProperty(value = "规格(JSON)-规格、规格值、goods_id") + @TableField(updateStrategy=NOT_EMPTY) private String product_spec; @ApiModelProperty(value = "规格类别编号") + @TableField(updateStrategy=NOT_EMPTY) private String spec_ids; @ApiModelProperty(value = "商品SKU(JSON):{'uniq_id':[item_id, price, url]}") + @TableField(updateStrategy=NOT_EMPTY) private String product_uniqid; @ApiModelProperty(value = "长度单位") + @TableField(updateStrategy=NOT_EMPTY) private Integer unit_length_id; @ApiModelProperty(value = "重量单位") + @TableField(updateStrategy=NOT_EMPTY) private Integer unit_weight_id; @ApiModelProperty(value = "商品重量") + @TableField(updateStrategy=NOT_EMPTY) private BigDecimal product_weight; @ApiModelProperty(value = "尺寸长 x 宽 x 高(DOT):商品体积") private String product_cubage; @ApiModelProperty(value = "扣减库存") + @TableField(updateStrategy=NOT_EMPTY) private Integer product_subtract; @ApiModelProperty(value = "计量单位") + @TableField(updateStrategy=NOT_EMPTY) private Integer unit_type_id; @ApiModelProperty(value = "商品税别:商品税率可以按照商品分类来设置") + @TableField(updateStrategy=NOT_EMPTY) private Integer tax_class_id; @ApiModelProperty(value = "每人限购") + @TableField(updateStrategy=NOT_EMPTY) private Integer product_buy_limit; @ApiModelProperty(value = "参加会员等级折扣") + @TableField(updateStrategy=NOT_EMPTY) private Integer product_user_level_discount; @ApiModelProperty(value = "参加店铺发放的会员卡折扣") + @TableField(updateStrategy=NOT_EMPTY) private Integer product_shop_card_discount; +// @ApiModelProperty(value = "产品名称") +// @TableField(exist=false) +// private String productName; + } diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductItem.java b/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductItem.java index c05e64c5..8397934c 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductItem.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductItem.java @@ -1,9 +1,6 @@ package com.suisung.mall.common.modules.product; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.annotation.Version; +import com.baomidou.mybatisplus.annotation.*; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -13,6 +10,8 @@ import lombok.experimental.Accessors; import java.io.Serializable; import java.math.BigDecimal; +import static com.baomidou.mybatisplus.annotation.FieldStrategy.NOT_EMPTY; + /** *

* 商品表-SKU表 商品名称(产品名称+颜色规格名称) =shop_product_item @@ -47,27 +46,34 @@ public class ShopProductItem implements Serializable { private Long color_id; @ApiModelProperty(value = "是否为默认展示的商品-列表页展示,必须为item_enable") + @TableField(updateStrategy=NOT_EMPTY) private Integer item_is_default; @ApiModelProperty(value = "SKU商家编码:SKU商家编码为非必填项,若不填写,系统会自动生成一个SKU商家编码。") + @TableField(updateStrategy=NOT_EMPTY) private String item_number; @ApiModelProperty(value = "条形码") + @TableField(updateStrategy=NOT_EMPTY) private String item_barcode; @ApiModelProperty(value = "成本价") + @TableField(updateStrategy=NOT_EMPTY) private BigDecimal item_cost_price; @ApiModelProperty(value = "平台价") + @TableField(updateStrategy=NOT_EMPTY) private BigDecimal item_platform_price; @ApiModelProperty(value = "商品建议零售价") private BigDecimal item_advice_price; @ApiModelProperty(value = "商品价格") + @TableField(updateStrategy=NOT_EMPTY) private BigDecimal item_unit_price; @ApiModelProperty(value = "市场价") + @TableField(updateStrategy=NOT_EMPTY) private BigDecimal item_market_price; @ApiModelProperty(value = "积分价格") @@ -77,24 +83,31 @@ public class ShopProductItem implements Serializable { private BigDecimal item_unit_sp; @ApiModelProperty(value = "商品库存") + @TableField(updateStrategy=NOT_EMPTY) private Integer item_quantity; @ApiModelProperty(value = "商品冻结库存") + @TableField(updateStrategy=NOT_EMPTY) private Integer item_quantity_frozen; @ApiModelProperty(value = "库存预警值") + @TableField(updateStrategy=NOT_EMPTY) private Integer item_warn_quantity; @ApiModelProperty(value = "商品规格序列化(JSON):{spec_id:spec_item_id, spec_id:spec_item_id, spec_id:spec_item_id}") + @TableField(updateStrategy=NOT_EMPTY) private String item_spec; @ApiModelProperty(value = "商品规格值编号") + @TableField(updateStrategy=NOT_EMPTY) private String spec_item_ids; @ApiModelProperty(value = "是否启用(LIST):1001-正常;1002-下架仓库中;1000-违规禁售") + @TableField(updateStrategy=NOT_EMPTY) private Integer item_enable; @ApiModelProperty(value = "被改动(BOOL):0-未改动;1-已改动分销使用") + @TableField(updateStrategy=NOT_EMPTY) private Integer item_is_change; @ApiModelProperty(value = "商品重量") @@ -160,4 +173,14 @@ public class ShopProductItem implements Serializable { @Version @ApiModelProperty(value = "乐观锁") private Integer version; + +// @ApiModelProperty(value = "产品名称") +// @TableField(exist=false) +// private String productName; + +// @ApiModelProperty(value = "商品SKU(JSON):{'uniq_id':[item_id, price, url]}") +// @TableField(exist=false) +// private String product_uniqid; + + } diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductItemSeq.java b/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductItemSeq.java index c3936d1c..1ce79b39 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductItemSeq.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductItemSeq.java @@ -1,6 +1,7 @@ package com.suisung.mall.common.modules.product; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductSpecItem.java b/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductSpecItem.java index a81efcfd..7d5d02d0 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductSpecItem.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/product/ShopProductSpecItem.java @@ -1,6 +1,7 @@ package com.suisung.mall.common.modules.product; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; @@ -10,6 +11,7 @@ import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; import java.io.Serializable; +import java.math.BigDecimal; /** *

@@ -50,5 +52,24 @@ public class ShopProductSpecItem implements Serializable { @ApiModelProperty(value = "是否启用(BOOL):0-不显示;1-显示") private Integer spec_item_enable; + @ApiModelProperty(value = "切割后的价格") + @TableField(exist=false) + private BigDecimal itemPrice; + + @ApiModelProperty(value = "切割后的库存") + @TableField(exist=false) + private BigDecimal itemQuantity; + + @ApiModelProperty(value = "规格值") + @TableField(exist=false) + private String item_spec; + + @ApiModelProperty(value = "规格值") + @TableField(exist=false) + private String product_spec; + + @ApiModelProperty(value = "是否新增,批次使用") + @TableField(exist=false) + private boolean isUpdate; } diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/sync/ProductMapping.java b/mall-common/src/main/java/com/suisung/mall/common/modules/sync/ProductMapping.java new file mode 100644 index 00000000..9786763f --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/sync/ProductMapping.java @@ -0,0 +1,68 @@ +package com.suisung.mall.common.modules.sync; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.List; + +import static com.baomidou.mybatisplus.annotation.FieldStrategy.NOT_EMPTY; + +@Data +@TableName("product_mapping") +@ApiModel("商品映射实体") +public class ProductMapping implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id",type = IdType.AUTO) + @ApiModelProperty("主键ID") + private Long id; + + @TableField(value = "product_name",updateStrategy=NOT_EMPTY) + @NotEmpty(message="商品名称不能为空") + @ApiModelProperty("商品名称") + private String productName; + + @TableField(value ="store_id",updateStrategy=NOT_EMPTY) + @ApiModelProperty(value = "店铺编号") + @NotNull(message="店铺编号不能为空") + private Integer storeId; + + @TableField(value ="spec_value",updateStrategy=NOT_EMPTY) + @ApiModelProperty("规格数据") + @NotNull(message="规格数据不能为空") + private BigDecimal specValue; + + @TableField(value ="spec_unit",updateStrategy=NOT_EMPTY) + @ApiModelProperty("规格单位") + @NotEmpty(message="规格单位不能为空") + private String specUnit; + + @TableField(value ="description",updateStrategy=NOT_EMPTY) + @ApiModelProperty("商品描述") + private String description; + + @TableField(value = "sort_order",updateStrategy=NOT_EMPTY) + @ApiModelProperty("排序值") + private Integer sortOrder; + + + /** + * 生成唯一键:productName + storeId + specValue + specUnit + */ + public String getUniqueKey() { + return String.format("%s|%d|%s|%s", + productName, + storeId, + specValue.stripTrailingZeros().toPlainString(), + specUnit); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/base/controller/admin/ShopBaseProductSpecController.java b/mall-shop/src/main/java/com/suisung/mall/shop/base/controller/admin/ShopBaseProductSpecController.java index 7b0f371f..7a8ef9e0 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/base/controller/admin/ShopBaseProductSpecController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/base/controller/admin/ShopBaseProductSpecController.java @@ -4,10 +4,12 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.domain.UserDto; import com.suisung.mall.common.exception.ApiException; import com.suisung.mall.common.modules.base.ShopBaseProductSpec; import com.suisung.mall.common.modules.product.ShopProductSpecItem; import com.suisung.mall.common.utils.CheckUtil; +import com.suisung.mall.common.utils.ContextUtil; import com.suisung.mall.common.utils.I18nUtil; import com.suisung.mall.shop.base.service.ShopBaseProductSpecService; import com.suisung.mall.shop.product.service.ShopProductSpecItemService; @@ -54,6 +56,9 @@ public class ShopBaseProductSpecController { @RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) { QueryWrapper queryWrapper = new QueryWrapper<>(); + UserDto userDto= ContextUtil.getCurrentUser(); + Integer storeId = Integer.valueOf(userDto.getStore_id()); + queryWrapper.eq("store_id",storeId); queryWrapper.orderByAsc("spec_id"); if (CheckUtil.isNotEmpty(shopBaseProductSpec.getSpec_name())) { queryWrapper.like("spec_name", shopBaseProductSpec.getSpec_name()); @@ -74,7 +79,10 @@ public class ShopBaseProductSpecController { @RequestParam(value = "spec_category_id", required = false) Integer spec_category_id, @RequestParam(value = "spec_order") Integer spec_order, @RequestParam(value = "spec_id", required = false) Integer spec_id) { + UserDto userDto= ContextUtil.getCurrentUser(); + Integer storeId = Integer.valueOf(userDto.getStore_id()); ShopBaseProductSpec shopBaseProductSpec = new ShopBaseProductSpec(); + shopBaseProductSpec.setStore_id(storeId); shopBaseProductSpec.setSpec_id(spec_id); shopBaseProductSpec.setSpec_name(spec_name); shopBaseProductSpec.setSpec_format(spec_format); @@ -92,19 +100,19 @@ public class ShopBaseProductSpecController { @ApiOperation(value = "商品规格表-通过spec_id删除", notes = "商品规格表-通过spec_id删除") @RequestMapping(value = "/delete", method = RequestMethod.POST) public CommonResult delete(@RequestParam(name = "spec_ids") String spec_ids) { - List specIds = Convert.toList(Integer.class, spec_ids); - if (CollUtil.isEmpty(specIds)) { + List spes = Convert.toList(Integer.class, spec_ids); + if (CollUtil.isEmpty(spes)) { throw new ApiException(I18nUtil._("商品规格编号异常!spec_id: ") + spec_ids); } QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.in("spec_id", specIds); + queryWrapper.in("spec_id", spes); List spec_item_ids = shopProductSpecItemService.findKey(queryWrapper); if (CollUtil.isNotEmpty(spec_item_ids)) { throw new ApiException(String.format(I18nUtil._("不能删除正在被商品规格值表使用的规格!商品规格值编号【%s】"), CollUtil.join(spec_item_ids, ","))); } - return CommonResult.success(shopBaseProductSpecService.remove(specIds)); + return CommonResult.success(shopBaseProductSpecService.remove(spes)); } @ApiOperation(value = "商品规格表-获取分类规格参数", notes = "商品规格表-获取分类规格参数") diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/ShopBaseProductSpecService.java b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/ShopBaseProductSpecService.java index 54af80a7..bc8f7007 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/ShopBaseProductSpecService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/ShopBaseProductSpecService.java @@ -19,4 +19,9 @@ public interface ShopBaseProductSpecService extends IBaseService> specMap(); List getSpecsByIds(String type_spec_ids, Integer store_id); + + + Map getShopBaseProductSpecMap(Integer store_id); + + void clearShopBaseProductSpecMap(Integer store_id); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductSpecServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductSpecServiceImpl.java index 74544565..86763d60 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductSpecServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductSpecServiceImpl.java @@ -1,23 +1,25 @@ package com.suisung.mall.shop.base.service.impl; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.suisung.mall.common.domain.UserDto; import com.suisung.mall.common.modules.base.ShopBaseProductCategory; import com.suisung.mall.common.modules.base.ShopBaseProductSpec; import com.suisung.mall.common.modules.product.ShopProductSpecItem; +import com.suisung.mall.common.utils.ContextUtil; import com.suisung.mall.common.utils.I18nUtil; +import com.suisung.mall.core.web.service.RedisService; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.shop.base.mapper.ShopBaseProductSpecMapper; import com.suisung.mall.shop.base.service.ShopBaseProductCategoryService; import com.suisung.mall.shop.base.service.ShopBaseProductSpecService; import com.suisung.mall.shop.product.service.ShopProductSpecItemService; +import com.suisung.mall.shop.sync.keymanage.RedisKey; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** @@ -37,9 +39,16 @@ public class ShopBaseProductSpecServiceImpl extends BaseServiceImpl> specMap() { - List specs = find(new QueryWrapper<>()); + QueryWrapper queryWrapper= new QueryWrapper<>(); + UserDto userDto= ContextUtil.getCurrentUser(); + Integer store_id = Integer.valueOf(userDto.getStore_id()); + queryWrapper.eq("store_id",store_id); + List specs = find(queryWrapper); Map> map = new HashMap<>(); for (ShopBaseProductSpec spec : specs) { if (spec.getSpec_category_id() == 0) { @@ -82,4 +91,30 @@ public class ShopBaseProductSpecServiceImpl extends BaseServiceImpl(); + String redisKey=RedisKey.STOREDATASHOPBASEPRODUCTSPEC+":"+store_id; + if(null!=redisService.get(redisKey)){ + map= (Map) redisService.get(redisKey); + }else { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("store_id",store_id); + List shopBaseProductSpecList=this.list(queryWrapper); + for(ShopBaseProductSpec spec:shopBaseProductSpecList){ + map.put(String.valueOf(spec.getSpec_category_id()),spec); + } + if (CollUtil.isNotEmpty(map)) redisService.set(redisKey, map, 60 * 60); + } + return map; + } + + @Override + public void clearShopBaseProductSpecMap(Integer store_id) { + String redisKey=RedisKey.STOREDATASHOPBASEPRODUCTSPEC+":"+store_id; + if(null!=redisService.get(redisKey)){ + redisService.del(redisKey); + } + } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductTypeServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductTypeServiceImpl.java index 7dfa8ead..58f0ae2e 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductTypeServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/base/service/impl/ShopBaseProductTypeServiceImpl.java @@ -85,8 +85,8 @@ public class ShopBaseProductTypeServiceImpl extends BaseServiceImpl { void clearRelateGoodsId(); void clearKey(); + void batchUpdateSeq(List shopNumberSeqList); + + List getBatchSpecItemId(int batchSize); + + void clearKeyStoreItemSepcId(); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/number/service/impl/ShopNumberSeqServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/number/service/impl/ShopNumberSeqServiceImpl.java index 1146b002..2542b974 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/number/service/impl/ShopNumberSeqServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/number/service/impl/ShopNumberSeqServiceImpl.java @@ -3,22 +3,24 @@ package com.suisung.mall.shop.number.service.impl; import cn.hutool.core.date.DateUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.suisung.mall.common.modules.number.ShopNumberSeq; +import com.suisung.mall.common.modules.product.ShopProductSpecItem; import com.suisung.mall.core.web.service.RedisService; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.shop.number.mapper.ShopNumberSeqMapper; import com.suisung.mall.shop.number.service.ShopNumberSeqService; -import org.apache.ibatis.session.ExecutorType; -import org.apache.ibatis.session.SqlSession; -import org.apache.ibatis.session.SqlSessionFactory; +import com.suisung.mall.shop.product.service.ShopProductSpecItemService; +import com.suisung.mall.shop.sync.keymanage.RedisKey; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.LongStream; @@ -40,6 +42,9 @@ public class ShopNumberSeqServiceImpl extends BaseServiceImpl getBatchSpecItemId(int batchSize) { + int start=0; + if(null!=redisService.get(RedisKey.STOREDATASPECITEMID)){ + start=(Integer) redisService.get(RedisKey.STOREDATASPECITEMID); + redisService.set(RedisKey.STOREDATASPECITEMID,start+batchSize); + } + QueryWrapper queryWrapper= new QueryWrapper<>(); + queryWrapper.select("max(spec_item_id) as spec_item_id"); + ShopProductSpecItem shopProductSpecItem=shopProductSpecItemService.getOne(queryWrapper); + if(null!=shopProductSpecItem){ + start=shopProductSpecItem.getSpec_item_id(); + redisService.set(RedisKey.STOREDATASPECITEMID,start+batchSize); + } + if(start==0){ + redisService.set(RedisKey.STOREDATASPECITEMID,start+batchSize); + return IntStream.rangeClosed(start+1, start+batchSize).boxed().collect(Collectors.toList()); + } + return IntStream.rangeClosed(start+1, start+batchSize).boxed().collect(Collectors.toList()); + } + + public static void main(String[] args) { + System.out.printf(IntStream.rangeClosed(1, 1).boxed().collect(Collectors.toList()).toString()); + } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/product/controller/admin/ShopProductSpecItemController.java b/mall-shop/src/main/java/com/suisung/mall/shop/product/controller/admin/ShopProductSpecItemController.java index eed4e780..60ef30e5 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/product/controller/admin/ShopProductSpecItemController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/product/controller/admin/ShopProductSpecItemController.java @@ -66,7 +66,8 @@ public class ShopProductSpecItemController extends BaseControllerImpl { public CommonResult specItems(ShopProductSpecItem shopProductSpecItem) { UserDto user = getCurrentUser(); - Integer store_id = Convert.toInt(user.getStore_id()); + //Integer store_id = Convert.toInt(user.getStore_id()); + Integer store_id = 1; QueryWrapper queryWrapper = new QueryWrapper<>(); Integer spec_id = shopProductSpecItem.getSpec_id(); @@ -86,7 +87,8 @@ public class ShopProductSpecItemController extends BaseControllerImpl { @RequestMapping(value = "/edit", method = RequestMethod.POST) public CommonResult edit(ShopProductSpecItem shopProductSpecItem) { UserDto user = getCurrentUser(); - shopProductSpecItem.setStore_id(Integer.valueOf(user.getStore_id())); + // shopProductSpecItem.setStore_id(Integer.valueOf(user.getStore_id())); + shopProductSpecItem.setStore_id(1); return CommonResult.success(shopProductSpecItemService.saveOrUpdate(shopProductSpecItem)); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductSpecItemService.java b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductSpecItemService.java index ec6583e1..d8659815 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductSpecItemService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/ShopProductSpecItemService.java @@ -5,6 +5,7 @@ import com.suisung.mall.common.modules.product.ShopProductSpecItem; import com.suisung.mall.core.web.service.IBaseService; import java.util.List; +import java.util.Map; /** *

@@ -17,4 +18,8 @@ import java.util.List; public interface ShopProductSpecItemService extends IBaseService { List getItems(QueryWrapper queryWrapper); + + Map getExistItem(Integer storeId); + + void clearExistItem(Integer storeId); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductBaseServiceImpl.java index 3829658c..71bec3a4 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductBaseServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductBaseServiceImpl.java @@ -38,6 +38,7 @@ import com.suisung.mall.common.modules.sixun.SxSyncGoods; import com.suisung.mall.common.modules.store.ShopStoreActivityBase; import com.suisung.mall.common.modules.store.ShopStoreActivityItem; import com.suisung.mall.common.modules.store.ShopStoreBase; +import com.suisung.mall.common.modules.sync.ProductMapping; import com.suisung.mall.common.modules.user.ShopUserCart; import com.suisung.mall.common.modules.user.ShopUserFavoritesItem; import com.suisung.mall.common.modules.user.ShopUserProductBrowse; @@ -65,13 +66,12 @@ import com.suisung.mall.shop.product.pojo.vo.ProductVo; import com.suisung.mall.shop.product.service.*; import com.suisung.mall.shop.sixun.service.SxSyncGoodsService; import com.suisung.mall.shop.store.service.*; -import com.suisung.mall.shop.sync.Utils.BatchInsertUtils; +import com.suisung.mall.shop.sync.Utils.ProductPriceCalculator; +import com.suisung.mall.shop.sync.Utils.ShopJsonUtils; +import com.suisung.mall.shop.sync.service.ProductMappingService; import com.suisung.mall.shop.user.service.*; import org.apache.commons.lang3.StringUtils; -import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; -import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac; -import org.mybatis.spring.SqlSessionFactoryBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -83,8 +83,6 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionTemplate; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; - -import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.Serializable; @@ -210,8 +208,11 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl udpateItemIds = new ArrayList<>(); List addShopProductItems=new ArrayList<>(); List updateShopProductItems=new ArrayList<>(); - int taskCount = 2; - CountDownLatch latch = new CountDownLatch(taskCount); + + List addShopProductSpecItems=new ArrayList<>(); + List updateShopProductSpecItems=new ArrayList<>(); + // int taskCount = 2; + // CountDownLatch latch = new CountDownLatch(taskCount); // 1. 批量新增 if (CollUtil.isNotEmpty(newProducts)) { // 4. 批量生成新商品的ID @@ -5466,7 +5469,16 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl items = newShopProductItemList.get(i); processProductItems(items, productId, addItemSeqs); @@ -5488,11 +5500,10 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl itemIds = processProductItemsId(addShopProductItems, addItemSeqs); + List itemIds = processProductItemsId(addShopProductItems, addItemSeqs,newShopProductInfoList); addItemIds.addAll(itemIds); // 2. 批量更新 if (CollUtil.isNotEmpty(newProducts)) { - // new Thread(() -> { logger.info("保存任务开始执行"); try { long startTime=System.nanoTime(); @@ -5500,17 +5511,10 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl items = udpateShopProductItemList.get(i); processProductItems(items, productId, updateItemSeqs);// @@ -5548,11 +5561,10 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl itemIds = processProductItemsId(updateShopProductItems, updateItemSeqs); + List itemIds = processProductItemsId(updateShopProductItems, updateItemSeqs,newShopProductInfoList); udpateItemIds.addAll(itemIds); // 2. 批量更新 if (CollUtil.isNotEmpty(updateProducts)) { - // new Thread(() -> { logger.info("更新任务开始执行"); try { long startTime=System.nanoTime(); @@ -5560,25 +5572,25 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl processProductItemsId(List items,List itemSeqs){ + private List processProductItemsId(List items,List itemSeqs, + List newShopProductInfoList){ List itemIds = new ArrayList<>(); if (CollUtil.isEmpty(items)) return itemIds; List generatedIds = shopNumberSeqService.batchCreateNextNo("item_id", items.size()); + // Map cacheMap=new HashMap<>(); for (int i = 0; i < items.size(); i++) { Long itemId = generatedIds.get(i); ShopProductItem item = items.get(i); item.setItem_id(itemId); +// if(StringUtils.isNotEmpty(item.getItem_spec())){ +// String product_uniqid=ShopJsonUtils.generateJsonWithOrgJson(item.getSpec_item_ids(),new Object[]{itemId,item.getItem_unit_price(),"",1002}); +// cacheMap.put(item.getProductName(),product_uniqid); +// } itemIds.add(itemId); ShopProductItemSeq field_row= itemSeqs.get(i); field_row.setItem_id(itemId); - } - +// for(ShopProductInfo shopProductInfo:newShopProductInfoList){ +// if(ObjectUtil.isNotEmpty(cacheMap.get(shopProductInfo.getProductName()))){ +// String product_uniqid=cacheMap.get(shopProductInfo.getProductName()); +// shopProductInfo.setProduct_uniqid(product_uniqid); +// } +// } return itemIds; } +// /** +// * 计算并产生规格 与商品配置表匹配,匹配正确则新增规格商品 +// * @return +// */ +// private ShopProductSpecItem processShopProductSpecItem(ShopProductBase base){ +// Map shopProductSpecItemMap = shopProductSpecItemService.getExistItem(base.getStore_id()); +// Map productMappingMap = productMappingService.getProductMapping(); +// Map ShopBaseProductSpecMap = baseProductSpecService.getShopBaseProductSpecMap(base.getStore_id()); +// String productName=base.getProduct_name(); +// +// if(null!=productMappingMap.get(productName)){ +// Integer specId= (Integer) ShopBaseProductSpecMap.get(base.getProduct_name()+"规格"); +// ProductMapping productMapping= (ProductMapping) productMappingMap.get(productName); +// String Spec_item_name=productMapping.getProductName()+productMapping.getSpecValue()+productMapping.getSpecUnit();//规格名称 +// Integer Spec_item_id= (Integer) shopProductSpecItemMap.get(Spec_item_name); +// ShopProductSpecItem addShopProductSpecItem=new ShopProductSpecItem(); +// addShopProductSpecItem.setUpdate(true); +// if(ObjectUtil.isEmpty(Spec_item_id)){ +// Spec_item_id=shopNumberSeqService.getSpecItemId(); +// addShopProductSpecItem.setUpdate(false); +// } +// addShopProductSpecItem.setStore_id(base.getStore_id()); +// addShopProductSpecItem.setCategory_id(base.getCategoryId()); +// addShopProductSpecItem.setSpec_item_id(Spec_item_id); +// addShopProductSpecItem.setSpec_id(specId);//根据规格获取 +// addShopProductSpecItem.setSpec_item_name(Spec_item_name); +// addShopProductSpecItem.setSpec_item_enable(1);//上架 +// addShopProductSpecItem.setSpec_item_order("10"); +// BigDecimal[] bigDecimals= ProductPriceCalculator.calculatePriceAndQuantity(base.getUnit_price(),base.getShop_weight(),productMapping.getSpecValue(),productMapping.getSpecUnit()); +// addShopProductSpecItem.setItemPrice(bigDecimals[0]); +// addShopProductSpecItem.setItemQuantity(bigDecimals[1]); +// List> items=new ArrayList<>(); +// Map item=new HashMap<>(); +// item.put("name",addShopProductSpecItem.getSpec_item_name());//规格列表 +// item.put("id",Spec_item_id); +// items.add(item); +// List> specItems=new ArrayList<>(); +// Map specItem=new HashMap<>(); +// specItem.put("name",base.getProduct_name()+"规格");//规格名称 +// specItem.put("id",specId); +// specItems.add(specItem); +// String item_spec=ShopJsonUtils.generateJsonWithOrgJson(items,specItems); +// addShopProductSpecItem.setItem_spec(item_spec); +// // addShopProductSpecItem.setProduct_uniqid(product_uniqid); +// return addShopProductSpecItem; +// } +// return null; +// } + + // 处理商品项 private void processProductItems(List items, Long productId, List itemSeqs) { - for (int i = 0; i < items.size(); i++) { ShopProductItem item = items.get(i); + // item.setProductName(productName); item.setProduct_id(productId); + String item_spec = item.getItem_spec(); +// if(null!=shopProductSpecItem){ +// item_spec=shopProductSpecItem.getItem_spec(); +// if(isUpdate){ +// item.setItem_unit_price(shopProductSpecItem.getItemPrice()); +// }else { +// item.setItem_unit_price(shopProductSpecItem.getItemPrice()); +// item.setItem_market_price(shopProductSpecItem.getItemPrice()); +// } +// } // itemIds.add(itemId); - + // item.setItem_quantity(null); // ITEM_ID/SKU唯一编号表。 // product_id + sort(spec_item_id) = 构造唯一ITEM ID - String item_spec = item.getItem_spec(); cn.hutool.json.JSONArray array_item_spec = cn.hutool.json.JSONUtil.parseArray(item_spec); List spec_item_ids = new ArrayList<>(); List item_names = new ArrayList<>(); @@ -5840,12 +5915,9 @@ public class ShopProductBaseServiceImpl extends BaseServiceImpl list){ -// SqlSession sqlSession=sqlSessionFactory.openSession(); -// StopWatch stopWatch=new StopWatch(); -// stopWatch.start(); -// shopProductBaseService.saveBatch(list); -// sqlSession.commit(); -// stopWatch.stop(); -// } - - } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductSpecItemServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductSpecItemServiceImpl.java index 7de73d01..07bc3881 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductSpecItemServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/product/service/impl/ShopProductSpecItemServiceImpl.java @@ -1,13 +1,20 @@ package com.suisung.mall.shop.product.service.impl; +import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.suisung.mall.common.modules.product.ShopProductSpecItem; +import com.suisung.mall.core.web.service.RedisService; import com.suisung.mall.core.web.service.impl.BaseServiceImpl; import com.suisung.mall.shop.product.mapper.ShopProductSpecItemMapper; import com.suisung.mall.shop.product.service.ShopProductSpecItemService; +import com.suisung.mall.shop.sync.keymanage.RedisKey; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** @@ -20,8 +27,39 @@ import java.util.List; */ @Service public class ShopProductSpecItemServiceImpl extends BaseServiceImpl implements ShopProductSpecItemService { + @Autowired + private RedisService redisService; @Override public List getItems(QueryWrapper queryWrapper) { return find(queryWrapper); } + + @Override + public Map getExistItem(Integer storeId) { + Map map=new HashMap<>(); + String redisKey=RedisKey.STOREDATAPRODUCTSPECITEM+"storeId:"+storeId; + if(null!=redisService.get(redisKey)){ + map=(Map)redisService.get(redisKey); + return map; + } + QueryWrapper queryWrapper=new QueryWrapper<>(); + queryWrapper.eq("store_id",storeId); + List list= list(queryWrapper); + for(ShopProductSpecItem shopProductSpecItem:list){ + map.put(shopProductSpecItem.getSpec_item_name(),shopProductSpecItem.getSpec_item_id()); + } + if (CollUtil.isNotEmpty(map)) redisService.set(redisKey, map, 60 * 60); + + return map; + } + + @Override + public void clearExistItem(Integer storeId) { + String redisKey=RedisKey.STOREDATAPRODUCTSPECITEM+"storeId:"+storeId; + if(null!=redisService.get(redisKey)){ + redisService.del(redisKey); + } + } + + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/BigDecimalFormatter.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/BigDecimalFormatter.java new file mode 100644 index 00000000..4e286dfd --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/BigDecimalFormatter.java @@ -0,0 +1,29 @@ +package com.suisung.mall.shop.sync.Utils; + +import java.math.BigDecimal; + +public class BigDecimalFormatter { + public static String formatWithoutTrailingZeros(BigDecimal number) { + if (number == null) { + return null; + } + + // 去除末尾0并转换为普通字符串表示 + BigDecimal stripped = number.stripTrailingZeros(); + String result = stripped.toPlainString(); + + // 处理结果为负0的情况(返回"0"而不是"-0") + if (result.startsWith("-0")) { + if (result.indexOf('.') == -1) { + if (result.length() == 2) { // "-0" + return "0"; + } else if (result.matches("-0+")) { // "-000" + return "0"; + } + } else if (result.matches("-0\\.0*")) { // "-0.0" 或 "-0.00" + return "0"; + } + } + return result; + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/ProductPriceCalculator.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/ProductPriceCalculator.java new file mode 100644 index 00000000..136589f6 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/ProductPriceCalculator.java @@ -0,0 +1,94 @@ +package com.suisung.mall.shop.sync.Utils; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +public class ProductPriceCalculator { + /** + * 计算切割后的商品单价和数量 + * @param unitPricePerKg 千克单价(元/千克) + * @param totalWeightKg 总重量(千克) + * @param pieceWeight 切割单位重量(数值) + * @param weightUnit 重量单位("g"=克,"kg"=千克) + * @return 包含两个元素的数组:[切割后单价(元/单位), 完整单位数量] + */ + public static BigDecimal[] calculatePriceAndQuantity( + BigDecimal unitPricePerKg, + BigDecimal totalWeightKg, + BigDecimal pieceWeight, + String weightUnit) { + + // 参数校验 + if (unitPricePerKg == null || totalWeightKg == null || pieceWeight == null) { + throw new IllegalArgumentException("参数不能为空"); + } + if (unitPricePerKg.compareTo(BigDecimal.ZERO) <= 0 || + pieceWeight.compareTo(BigDecimal.ZERO) <= 0) { + throw new IllegalArgumentException("单价和切割重量必须大于0"); + } + if (!"g".equalsIgnoreCase(weightUnit) && !"kg".equalsIgnoreCase(weightUnit)) { + throw new IllegalArgumentException("单位必须是'g'或'kg'"); + } + + // 将切割单位统一转换为千克 + BigDecimal pieceWeightInKg = "g".equalsIgnoreCase(weightUnit) ? + pieceWeight.divide(BigDecimal.valueOf(1000), 10, RoundingMode.HALF_UP) : + pieceWeight; + + // 计算切割后单价(不受总重量影响) + BigDecimal piecePrice = unitPricePerKg.multiply(pieceWeightInKg) + .setScale(2, RoundingMode.HALF_UP); // 保留两位小数 + + // 特殊处理:总重量为负数时,数量固定返回99 + if (totalWeightKg.compareTo(BigDecimal.ZERO) < 0) { + return new BigDecimal[]{piecePrice, BigDecimal.valueOf(99)}; + } + + // 计算完整单位数量(向下取整) + BigDecimal quantity = totalWeightKg.divide(pieceWeightInKg, 0, RoundingMode.FLOOR); + + return new BigDecimal[]{piecePrice, quantity}; + } + + // 示例用法 + public static void main(String[] args) { + // 正常情况示例 + BigDecimal[] result1 = calculatePriceAndQuantity( + new BigDecimal("30"), + new BigDecimal("5"), + new BigDecimal("500"), + "g"); + System.out.println("正常情况 - 单价: " + result1[0] + " 元/单位, 数量: " + result1[1]); + + // 总重量为负数示例 + BigDecimal[] result2 = calculatePriceAndQuantity( + new BigDecimal("25"), + new BigDecimal("-3.5"), // 负数总重量 + new BigDecimal("250"), + "g"); + System.out.println("负总重量 - 单价: " + result2[0] + " 元/单位, 数量: " + result2[1]); + + // 千克单位示例 + BigDecimal[] result3 = calculatePriceAndQuantity( + new BigDecimal("100"), + new BigDecimal("2.5"), + new BigDecimal("0.5"), + "kg"); + System.out.println("千克单位 - 单价: " + result3[0] + " 元/单位, 数量: " + result3[1]); + + // 总重量不足一个单位示例 + BigDecimal[] result4 = calculatePriceAndQuantity( + new BigDecimal("40"), + new BigDecimal("0.3"), + new BigDecimal("0.5"), + "kg"); + System.out.println("不足单位 - 单价: " + result4[0] + " 元/单位, 数量: " + result4[1]); + + /* 预期输出: + 正常情况 - 单价: 15.00 元/单位, 数量: 10 + 负总重量 - 单价: 6.25 元/单位, 数量: 99 + 千克单位 - 单价: 50.00 元/单位, 数量: 5 + 不足单位 - 单价: 20.00 元/单位, 数量: 0 + */ + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/ShopJsonUtils.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/ShopJsonUtils.java new file mode 100644 index 00000000..c3a3eee1 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/Utils/ShopJsonUtils.java @@ -0,0 +1,87 @@ +package com.suisung.mall.shop.sync.Utils; + + + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.List; +import java.util.Map; + +public class ShopJsonUtils { + + /** + *shop_item的item_spec生成 + * 使用org.json库(需要org.json依赖) + * @param items 规格项列表 + * @param specItems 规格大类 + * @return JSON字符串 + */ + public static String generateJsonWithOrgJsonItemSpec(List> items, + List> specItems) { + JSONArray jsonArray = new JSONArray(); + for (int i = 0; i < Math.min(items.size(), specItems.size()); i++) { + JSONObject itemObj = new JSONObject(); + itemObj.put("name", items.get(i).get("name")); + itemObj.put("id", items.get(i).get("id")); + + JSONObject categoryObj = new JSONObject(); + categoryObj.put("item", itemObj); + categoryObj.put("name", specItems.get(i).get("name")); + categoryObj.put("id", specItems.get(i).get("id")); + + jsonArray.put(categoryObj); + } + return jsonArray.toString(); + } + + /** + *shop_index的product_spec生成, + * 使用org.json库(需要org.json依赖) + * @param items 规格项列表 + * @param specItems 规格大类 + * @return JSON字符串 + */ + public static String generateJsonWithOrgJsonProducSpec(List> items, + List> specItems) { + JSONArray jsonArray = new JSONArray(); + for (int i = 0; i < Math.min(items.size(), specItems.size()); i++) { + JSONArray specItemObj = new JSONArray(); + JSONObject itemObj = new JSONObject(); + itemObj.put("name", items.get(i).get("name")); + itemObj.put("id", items.get(i).get("id")); + specItemObj.put(itemObj); + JSONObject categoryObj = new JSONObject(); + categoryObj.put("item", specItemObj); + categoryObj.put("name", specItems.get(i).get("name")); + categoryObj.put("id", specItems.get(i).get("id")); + + jsonArray.put(categoryObj); + } + return jsonArray.toString(); + } + + /** + * shop_index 的product_uniqid生成 + * 使用org.json库生成JSON(无需Gson依赖) + * @param key 主键 规格列表id + * @param values 值数组 + * @return JSON字符串 + */ + public static String generateJsonWithOrgJson(String key, Object[] values) { + // 参数校验 + if (values == null || values.length != 4) { + throw new IllegalArgumentException("值数组必须包含4个元素"); + } + + JSONObject jsonObj = new JSONObject(); + org.json.JSONArray jsonArray = new org.json.JSONArray(); + jsonArray.put(values[0]); // 整数 + jsonArray.put(values[1]); // 浮点数 + jsonArray.put(values[2]); // 字符串 + jsonArray.put(values[3]); // 整数 + + jsonObj.put(key, jsonArray); + return jsonObj.toString(); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/ClientController.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/ClientController.java index cff03c8c..5444e65b 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/ClientController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/ClientController.java @@ -18,7 +18,7 @@ public class ClientController { @Autowired private SyncThirdDataService syncThirdDataService; - @ApiOperation(value = "下载客户端应用", notes = "获取加密密钥") + @ApiOperation(value = "下载客户端应用", notes = "下载客户端应用") @RequestMapping(value = "/downClientJar",produces = MediaType.APPLICATION_OCTET_STREAM_VALUE, method = RequestMethod.GET) public ResponseEntity downClientJar(@RequestParam String primaryKey,String clienVersionName) { return syncThirdDataService.downloadToClient(primaryKey,clienVersionName); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/ProductMappingController.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/ProductMappingController.java new file mode 100644 index 00000000..f1de75a1 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/ProductMappingController.java @@ -0,0 +1,220 @@ +package com.suisung.mall.shop.sync.controller; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONArray; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.api.IErrorCode; +import com.suisung.mall.common.modules.sync.ProductMapping; +import com.suisung.mall.common.service.impl.BaseControllerImpl; +import com.suisung.mall.shop.sync.exelModel.ImportResult; +import com.suisung.mall.shop.sync.service.ProductMappingService; +import io.swagger.annotations.ApiOperation; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Objects; + +@RestController +@RequestMapping("/admin/shop/shop-sync-productMapper") +@lombok.extern.slf4j.Slf4j +public class ProductMappingController extends BaseControllerImpl { + + + @Autowired + private ProductMappingService productMappingService; + + @Value("${file.upload-dir}") + private String uploadDir; + + /** + * 分页列表查询 + * @param pageNum + * @param pageSize + * @return + */ + @ApiOperation(value = "列表查询-分页列表查询商品映射实体", notes = "列表查询-分页列表查询商品映射实体") + @RequestMapping(value = "/list", method = RequestMethod.GET) + public CommonResult list(@RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum, + @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) { + ProductMapping productMapping=new ProductMapping(); + productMapping.setProductName(getParameter("productName")); + productMapping.setStoreId(getParameter("storeId",Integer.class)); + return productMappingService.findPageProductMapping(productMapping,pageNum,pageSize); + } + + /** + * 单笔获取 + * @param productMapping + * @return + */ + @ApiOperation(value = "单笔获取-商品映射实体", notes = "单笔获取-商品映射实体") + @RequestMapping(value = "/getProductMapping", method = RequestMethod.GET) + public CommonResult getProductMapping(@RequestBody ProductMapping productMapping) { + if (productMapping == null|| null==productMapping.getId()) { + return CommonResult.failed("id不能为空"); + } + return CommonResult.success(productMappingService.getById(productMapping.getId())); + } + + /** + * 新增 + * @param productMapping + * @return + */ + @ApiOperation(value = "新增-店商品映射实体", notes = "新增-商品映射实体") + @RequestMapping(value = "/saveProductMapping", method = RequestMethod.POST) + public CommonResult saveProductMapping(@Valid @RequestBody ProductMapping productMapping, BindingResult result) { + if(result.hasErrors()) { + return CommonResult.failed(Objects.requireNonNull(result.getFieldError()).getDefaultMessage()); + } + return productMappingService.saveProductMapping(productMapping); + } + + /** + * 批量新增 + * @param + * @return + */ + @ApiOperation(value = "批量新增-店商品映射实体", notes = "批量新增-商品映射实体") + @RequestMapping(value = "/saveProductMappingBatch", method = RequestMethod.POST) + public CommonResult saveProductMappingBatch(@RequestBody JSONArray jsonProductMappings) { + if(jsonProductMappings==null|| jsonProductMappings.isEmpty()){ + return CommonResult.failed("数据不能为空"); + } + Gson gson = new Gson(); + List productMappings= gson.fromJson(jsonProductMappings.toString(),new TypeToken>(){}.getType()); + productMappingService.saveBatch(productMappings,productMappings.size()); + return CommonResult.success(true); + } + + /** + * 更新 + * @param productMapping + * @return + */ + @ApiOperation(value = "更新-商品映射实体", notes = "更新-商品映射实体") + @RequestMapping(value = "/udpateProductMapping", method = RequestMethod.PUT) + public CommonResult udpateProductMapping(@RequestBody ProductMapping productMapping) { + if(productMapping==null|| null==productMapping.getId()) { + return CommonResult.failed("缺少必要参数"); + } + if(ObjectUtil.isNotEmpty(productMappingService.getById(productMapping.getId()))) { + if(productMappingService.saveOrUpdate(productMapping)){ + return CommonResult.success(true); + } + }else { + return CommonResult.failed("不存在更新参数"); + } + return CommonResult.failed("更新失败"); + } + + /** + * 删除 + * @param productMapping + * @return + */ + @ApiOperation(value = "删除-商品映射实体", notes = "删除-商品映射实体") + @RequestMapping(value = "/delProductMapping", method = RequestMethod.DELETE) + public CommonResult delProductMapping(@RequestBody ProductMapping productMapping) { + if(productMapping==null|| null==productMapping.getId()) { + return CommonResult.failed("缺少必要参数"); + } + if(ObjectUtil.isNotEmpty(productMappingService.getById(productMapping.getId()))) { + if(productMappingService.removeById(productMapping.getId())){ + return CommonResult.success(true); + } + }else { + return CommonResult.failed("不存在更新参数"); + } + return CommonResult.failed("删除失败"); + } + + /** + * 自动计算并上架商品 + * @return + */ + @ApiOperation(value = "自动计算并上架商品", notes = "自动计算并上架商品") + @RequestMapping(value = "/syncProductMaping", method = RequestMethod.PUT) + public CommonResult syncProductMaping() { + return productMappingService.syncAllProductMapping(); + } + + /** + * 查找为同步未分配的商品数据,批量手填 + * @return + */ + @ApiOperation(value = "查找为同步的商品数据", notes = "删除查找为同步的商品数据") + @RequestMapping(value = "/getSyncBaseMapingProducts", method = RequestMethod.GET) + public CommonResult getSyncBaseMapingProducts() { + return productMappingService.getSyncProductUnchecked(); + } + + /** + * 模板下载 + * @return + */ + @ApiOperation(value = "导入模板下载", notes = "模板下载") + @RequestMapping(value = "/template", method = RequestMethod.GET) + public void downloadTemplate(HttpServletResponse response) { + productMappingService.downloadTemplate(response); + } + + /** + * 导入数据 + * @return + */ + @ApiOperation(value = "模板数据导入", notes = "模板数据导入") + @RequestMapping(value = "/importData", method = RequestMethod.POST) + public CommonResult importData(@RequestParam("file") MultipartFile file) { + ImportResult result = productMappingService.importData(file); + return !result.getErrorMessages().isEmpty() ?CommonResult.failed((IErrorCode) result.getErrorMessages()):CommonResult.success(result); + } + + /** + * 导出筛选数据 + * @param ids + * @param response + */ + @PostMapping("/exportSelected") + public void exportSelectedData(@RequestBody List ids, HttpServletResponse response) { + List data = productMappingService.listByIds(ids); + productMappingService.exportData(response, data); + } + + /** + * 下载错误报告 + * @param file + * @param response + */ + @GetMapping("/download") + public void downloadFile(@RequestParam String file, HttpServletResponse response) { + try { + Path filePath = Paths.get(uploadDir, file); + if (!Files.exists(filePath)) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return; + } + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment; filename=" + file); + Files.copy(filePath, response.getOutputStream()); + response.getOutputStream().flush(); + } catch (IOException e) { + log.error("下载文件失败", e); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/StoreDbConfigController.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/StoreDbConfigController.java index e1745d30..26f0a23b 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/StoreDbConfigController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/StoreDbConfigController.java @@ -12,6 +12,8 @@ import com.suisung.mall.common.api.CommonResult; import com.suisung.mall.common.modules.sync.StoreDbConfig; import com.suisung.mall.common.modules.sync.SyncApp; import com.suisung.mall.common.modules.sync.SyncFileLog; +import com.suisung.mall.common.service.impl.BaseControllerImpl; +import com.suisung.mall.core.web.controller.BaseController; import com.suisung.mall.shop.sync.service.StoreDbConfigService; import com.suisung.mall.shop.sync.service.SyncFileLogService; import io.swagger.annotations.Api; @@ -30,23 +32,26 @@ import org.springframework.web.bind.annotation.*; @Api(tags = "页面导航表-店铺数据库连接配置") @RestController @RequestMapping("/admin/shop/shop-sync-storeDbConfig") -public class StoreDbConfigController { +public class StoreDbConfigController extends BaseControllerImpl { @Autowired private StoreDbConfigService storeDbConfigService; /** * 分页列表查询 - * @param storeDbConfig + * @param * @param pageNum * @param pageSize * @return */ @ApiOperation(value = "列表查询-分页列表查询店铺数据库连接配置", notes = "列表查询-分页列表查询店铺数据库连接配置") @RequestMapping(value = "/list", method = RequestMethod.GET) - public CommonResult list(@RequestBody StoreDbConfig storeDbConfig , - @RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum, + public CommonResult list(@RequestParam(name = "pageNum", defaultValue = "1") Integer pageNum, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) { + StoreDbConfig storeDbConfig=new StoreDbConfig(); + storeDbConfig.setStoreId(getParameter("storeId")); + storeDbConfig.setHasInternet(getParameter("hasInternet")); + storeDbConfig.setHasStart(getParameter("hasStart")); return storeDbConfigService.findStoreDbConfigPageList(storeDbConfig, pageNum, pageSize); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/SyncThirdDataController.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/SyncThirdDataController.java index dc86f801..8a24a639 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/SyncThirdDataController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/controller/SyncThirdDataController.java @@ -107,12 +107,7 @@ public class SyncThirdDataController { @RequestParam String appKey, @RequestParam String sign, @RequestParam String syncType) { -// new Thread(new Runnable() { -// @Override -// public void run() { - syncThirdDataService.SyncReadSxFileData(appKey,sign,syncType,folders); -// } -// }).start(); + syncThirdDataService.SyncReadSxFileData(appKey,sign,syncType,folders); return new ThirdApiRes().success("服务器已处理文件"); } @@ -150,4 +145,5 @@ public class SyncThirdDataController { return syncThirdDataService.getStoreDataRelease(appKey,sign); } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/excleHandle/ExportStyleHandler.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/excleHandle/ExportStyleHandler.java new file mode 100644 index 00000000..822784f5 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/excleHandle/ExportStyleHandler.java @@ -0,0 +1,39 @@ +package com.suisung.mall.shop.sync.excleHandle; + +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.write.handler.AbstractCellWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Font; + +import java.util.List; + +public class ExportStyleHandler extends AbstractCellWriteHandler { + + // 设置数据行样式 + @Override + public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, + Boolean isHead) { + if (isHead) { + // 表头样式 + CellStyle cellStyle = cell.getSheet().getWorkbook().createCellStyle(); + Font font = cell.getSheet().getWorkbook().createFont(); + font.setBold(true); + cellStyle.setFont(font); + cell.setCellStyle(cellStyle); + } else { + // 数据行样式 - 设置边框 + CellStyle cellStyle = cell.getSheet().getWorkbook().createCellStyle(); + cellStyle.setBorderTop(BorderStyle.THIN); + cellStyle.setBorderBottom(BorderStyle.THIN); + cellStyle.setBorderLeft(BorderStyle.THIN); + cellStyle.setBorderRight(BorderStyle.THIN); + cell.setCellStyle(cellStyle); + } + } +} \ No newline at end of file diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/excleHandle/TemplateStyleHandler.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/excleHandle/TemplateStyleHandler.java new file mode 100644 index 00000000..4be1e26a --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/excleHandle/TemplateStyleHandler.java @@ -0,0 +1,33 @@ +package com.suisung.mall.shop.sync.excleHandle; + +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.write.handler.AbstractCellWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import org.apache.poi.ss.usermodel.*; + +import java.util.List; + +public class TemplateStyleHandler extends AbstractCellWriteHandler { + + // 设置表头样式 + @Override + public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + List> cellDataList, Cell cell, Head head, Integer relativeRowIndex, + Boolean isHead) { + if (isHead) { + // 设置表头背景色 + CellStyle cellStyle = cell.getSheet().getWorkbook().createCellStyle(); + Font font = cell.getSheet().getWorkbook().createFont(); + font.setBold(true); + font.setColor(IndexedColors.WHITE.getIndex()); + cellStyle.setFont(font); + cellStyle.setFillForegroundColor(IndexedColors.DARK_BLUE.getIndex()); + cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + cell.setCellStyle(cellStyle); + } + } +} + + diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/exelModel/ImportResult.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/exelModel/ImportResult.java new file mode 100644 index 00000000..172a0ed6 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/exelModel/ImportResult.java @@ -0,0 +1,20 @@ +package com.suisung.mall.shop.sync.exelModel; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ImportResult { + private int totalCount; // 总记录数 + private int successCount; // 成功记录数 + private int failCount; // 失败记录数 + private int insertCount; // 新增记录数 + private int updateCount; // 更新记录数 + private List errorMessages; // 错误信息 + private String downloadUrl; // 错误报告下载URL +} \ No newline at end of file diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/exelModel/ProductMappingExcel.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/exelModel/ProductMappingExcel.java new file mode 100644 index 00000000..806e805b --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/exelModel/ProductMappingExcel.java @@ -0,0 +1,63 @@ +package com.suisung.mall.shop.sync.exelModel; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.suisung.mall.common.modules.sync.ProductMapping; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class ProductMappingExcel { + @ExcelProperty(value = "商品名称", index = 0) + private String productName; + + @ExcelProperty(value = "店铺编号", index = 1) + private Integer storeId; + + @ExcelProperty(value = "规格数据", index = 2) + private BigDecimal specValue; + + @ExcelProperty(value = "规格单位", index = 3) + private String specUnit; + + @ExcelProperty(value = "商品描述", index = 4) + private String description; + + @ExcelProperty(value = "排序值", index = 5) + private Integer sortOrder; + + // 转换为实体对象 + public ProductMapping toEntity() { + ProductMapping entity = new ProductMapping(); + entity.setProductName(this.productName); + entity.setStoreId(this.storeId); + entity.setSpecValue(this.specValue); + entity.setSpecUnit(this.specUnit); + entity.setDescription(this.description); + entity.setSortOrder(this.sortOrder); + return entity; + } + + // 从实体对象转换 + public static ProductMappingExcel fromEntity(ProductMapping entity) { + ProductMappingExcel excel = new ProductMappingExcel(); + excel.setProductName(entity.getProductName()); + excel.setStoreId(entity.getStoreId()); + excel.setSpecValue(entity.getSpecValue()); + excel.setSpecUnit(entity.getSpecUnit()); + excel.setDescription(entity.getDescription()); + excel.setSortOrder(entity.getSortOrder()); + return excel; + } + + /** + * 生成唯一键:productName + storeId + specValue + specUnit + */ + public String getUniqueKey() { + return String.format("%s|%d|%s|%s", + productName, + storeId, + specValue.stripTrailingZeros().toPlainString(), + specUnit); + } +} \ No newline at end of file diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/keymanage/RedisKey.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/keymanage/RedisKey.java index 17ae3d69..da034770 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/keymanage/RedisKey.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/keymanage/RedisKey.java @@ -5,4 +5,14 @@ public class RedisKey { //public static final String SXCLIENTKEYVERSION="sxclientKey:version";//客户端版本 public static final String STOREDATARELEASE="storedata:release"; + + public static final String STOREDATAPRODUCTMAPING="storedata:productMaping"; + + public static final String STOREDATASHOPBASEPRODUCTSPEC="storedata:shopBaseProductSpec"; + + + public static final String STOREDATASPECITEMID="storedata:SpecItemId"; + + public static final String STOREDATAPRODUCTSPECITEM="storedata:ProductSpecItem"; + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/mapper/ProductMappingMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/mapper/ProductMappingMapper.java new file mode 100644 index 00000000..0154aa35 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/mapper/ProductMappingMapper.java @@ -0,0 +1,17 @@ +package com.suisung.mall.shop.sync.mapper; + + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.suisung.mall.common.modules.sync.ProductMapping; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface ProductMappingMapper extends BaseMapper { + + List findPageProductMapping(Page page); + + Integer getCount(); +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/ProductMappingService.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/ProductMappingService.java new file mode 100644 index 00000000..f5ece34b --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/ProductMappingService.java @@ -0,0 +1,39 @@ +package com.suisung.mall.shop.sync.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.modules.product.ShopProductBase; +import com.suisung.mall.common.modules.sync.ProductMapping; +import com.suisung.mall.shop.sync.exelModel.ImportResult; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; +import java.util.Map; + +public interface ProductMappingService extends IService { + + CommonResult findPageProductMapping(ProductMapping productMapping,Integer pageNum,Integer pageSize); + + void computeProductMapping(List shopProductBaseList,Integer storeId, boolean isUpdate); + + Map getProductMapping(Integer storeId); + + CommonResult syncAllProductMapping(); + + CommonResult getSyncProductUnchecked(); + + // 下载导入模板 + void downloadTemplate(HttpServletResponse response); + + // 导入Excel数据 + ImportResult importData(MultipartFile file); + + // 导出数据到Excel + void exportData(HttpServletResponse response, List data); + + + // 保存数据 + CommonResult saveProductMapping(ProductMapping data); + +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/ProductMappingServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/ProductMappingServiceImpl.java new file mode 100644 index 00000000..c2916f2f --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/ProductMappingServiceImpl.java @@ -0,0 +1,699 @@ +/* + * Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.shop.sync.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.suisung.mall.common.api.CommonResult; +import com.suisung.mall.common.api.StateCode; +import com.suisung.mall.common.modules.base.ShopBaseProductSpec; +import com.suisung.mall.common.modules.product.*; +import com.suisung.mall.common.modules.sync.ProductMapping; + +import com.suisung.mall.common.utils.ContextUtil; +import com.suisung.mall.common.utils.StringUtils; +import com.suisung.mall.core.web.service.impl.BaseServiceImpl; + +import com.suisung.mall.shop.base.service.ShopBaseProductSpecService; +import com.suisung.mall.shop.number.service.ShopNumberSeqService; +import com.suisung.mall.shop.product.service.*; +import com.suisung.mall.shop.sixun.utils.CommonUtil; +import com.suisung.mall.shop.sync.Utils.BigDecimalFormatter; +import com.suisung.mall.shop.sync.Utils.ProductPriceCalculator; +import com.suisung.mall.shop.sync.Utils.ShopJsonUtils; +import com.suisung.mall.shop.sync.excleHandle.ExportStyleHandler; +import com.suisung.mall.shop.sync.excleHandle.TemplateStyleHandler; +import com.suisung.mall.shop.sync.exelModel.ImportResult; +import com.suisung.mall.shop.sync.exelModel.ProductMappingExcel; +import com.suisung.mall.shop.sync.mapper.ProductMappingMapper; +import com.suisung.mall.shop.sync.service.*; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import javax.validation.ValidationException; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.net.URLEncoder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.stream.Collectors; + + +@Service +@Transactional(rollbackFor = Exception.class) +@Slf4j +public class ProductMappingServiceImpl extends BaseServiceImpl implements ProductMappingService { + + @Autowired + private ShopProductBaseService shopProductBaseService; + @Autowired + private ShopProductItemService shopProductItemService; + @Autowired + private ShopProductInfoService shopProductInfoService; + + @Autowired + private ShopProductSpecItemService shopProductSpecItemService; + @Autowired + private ShopBaseProductSpecService baseProductSpecService; + + @Autowired + private ShopNumberSeqService shopNumberSeqService; + + @Autowired + private ShopProductIndexService shopProductIndexService; + + @Autowired + private ProductMappingService productMappingService; + + @Value("${file.upload-dir}") + private String uploadDir; + + private static final String TEMPLATE_NAME = "商品映射模板.xlsx"; + private static final String EXPORT_NAME = "商品映射数据.xlsx"; + + private final Integer SHOPBASEPAGE=500; + + @Override + public CommonResult findPageProductMapping(ProductMapping productMapping,Integer pageNum,Integer pageSize) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + if(StringUtils.isNotEmpty(productMapping.getProductName())){ + queryWrapper.eq("product_name",productMapping.getProductName()); + // queryWrapper.and(mapping ->mapping.like("product_name", productMapping.getProductName())); + } + if(ObjectUtil.isNotEmpty(productMapping.getStoreId())){ + queryWrapper.and(m->m.eq("store_id",productMapping.getStoreId()).or().eq("store_id",0)); + // queryWrapper.and(mapping ->mapping.like("product_name", productMapping.getProductName())); + } + + return CommonResult.success(this.lists(queryWrapper,pageNum,pageSize)); + } + + @Override + public void computeProductMapping(List shopProductBaseList,Integer storeId,boolean isUpdate) { + shopProductBaseList= shopProductBaseList.stream().filter(base ->StateCode.PRODUCT_STATE_OFF_THE_SHELF_UNCHECK==(base.getProduct_state_id())).collect(Collectors.toList()); + if (CollUtil.isEmpty(shopProductBaseList)) { + log.info("没有规格数据要处理"); + return; + } + Map shopProductSpecItemMap = shopProductSpecItemService.getExistItem(storeId); + Map productMappingMap = this.getProductMapping(storeId); + Map ShopBaseProductSpecMap = baseProductSpecService.getShopBaseProductSpecMap(storeId); + dealData(shopProductBaseList,shopProductSpecItemMap,ShopBaseProductSpecMap,productMappingMap,isUpdate); + } + + @Override + public Map getProductMapping(Integer storeId) { + Map map=new HashMap(); + QueryWrapper queryWrapper= new QueryWrapper<>(); + //queryWrapper.eq("store_id", storeId); + queryWrapper.and(m->m.eq("store_id",storeId).or().eq("store_id",0)).orderByDesc("sort_order"); + List list= this.list(queryWrapper); + for (ProductMapping productMapping:list){ + map.put(productMapping.getProductName(),productMapping); + } + return map; + } + + /** + * 处理数据,生成规格列表 + * @param shopProductBaseList + * @param shopProductSpecItemMap + * @param ShopBaseProductSpecMap + * @param productMappingMap + */ + public void dealData(List shopProductBaseList,Map shopProductSpecItemMap,Map ShopBaseProductSpecMap, Map productMappingMap,boolean isUpdate){ + List shopProductItems=findShopProductItemsList(shopProductBaseList); + List shopProductInfoList=findShopProductInfoList(shopProductBaseList); + List addShopProductSpecItemList=new ArrayList<>(); + List updateShopProductSpecItemList=new ArrayList<>(); + + List updateShopProductBaseList=new ArrayList<>(); + List updateShopProductItemList=new ArrayList<>(); + List updateShopProductInfoList=new ArrayList<>(); + //找出需要更新的列表 + for (int i = 0; i < shopProductBaseList.size(); i++){ + ShopProductSpecItem shopProductSpecItem=processShopProductSpecItem(shopProductBaseList.get(i),shopProductItems.get(i).getCategory_id(),shopProductSpecItemMap,ShopBaseProductSpecMap,productMappingMap,null); + if(shopProductSpecItem!=null){ + shopProductBaseList.get(i).setProduct_state_id(StateCode.PRODUCT_STATE_NORMAL); + shopProductItems.get(i).setItem_enable(StateCode.PRODUCT_STATE_NORMAL); + shopProductItems.get(i).setItem_is_default(1); + if(shopProductSpecItem.isUpdate()){ + shopProductBaseList.get(i).setProduct_unit_price(shopProductSpecItem.getItemPrice()); + updateShopProductSpecItemList.add(shopProductSpecItem); + }else { + shopProductBaseList.get(i).setProduct_unit_price(shopProductSpecItem.getItemPrice()); + shopProductBaseList.get(i).setProduct_market_price(shopProductSpecItem.getItemPrice()); + addShopProductSpecItemList.add(shopProductSpecItem); + } + updateShopProductBaseList.add(shopProductBaseList.get(i)); + updateShopProductItemList.add(shopProductItems.get(i)); + updateShopProductInfoList.add(shopProductInfoList.get(i)); + proccessItemAndInfo(shopProductItems.get(i),shopProductInfoList.get(i),shopProductSpecItem,isUpdate); + } + } +//再次变量根据addShopProductSpecItemList算出id,这样防止多次链接redis + if(!addShopProductSpecItemList.isEmpty()){ + List integers= shopNumberSeqService.getBatchSpecItemId(addShopProductSpecItemList.size()); + int index=0; + for (int i = 0; i < shopProductBaseList.size(); i++){ + if(index==integers.size()){ + break; + } + ShopProductSpecItem shopProductSpecItem=processShopProductSpecItem(shopProductBaseList.get(i),shopProductItems.get(i).getCategory_id(),shopProductSpecItemMap,ShopBaseProductSpecMap,productMappingMap,integers.get(index)); + if(shopProductSpecItem!=null){ + if(!shopProductSpecItem.isUpdate()){ + addShopProductSpecItemList.set(index,shopProductSpecItem); + index++; + } + proccessItemAndInfo(shopProductItems.get(i),shopProductInfoList.get(i),shopProductSpecItem,isUpdate); + } + } + } + if(CollUtil.isNotEmpty(addShopProductSpecItemList)){ + shopProductSpecItemService.saveBatch(addShopProductSpecItemList,addShopProductSpecItemList.size()); + } + if(CollUtil.isNotEmpty(updateShopProductSpecItemList)){ + shopProductSpecItemService.updateBatchById(updateShopProductSpecItemList); + } + if(CollUtil.isNotEmpty(updateShopProductBaseList)){ + shopProductBaseService.updateBatchById(updateShopProductBaseList); + saveShopProductIndexList(updateShopProductBaseList); + } + if(CollUtil.isNotEmpty(updateShopProductItemList)){ + shopProductItemService.updateBatchById(updateShopProductItemList); + } + if(CollUtil.isNotEmpty(updateShopProductInfoList)){ + shopProductInfoService.updateBatchById(updateShopProductInfoList); + } + } + + /** + * @param item + */ + private void proccessItemAndInfo(ShopProductItem item,ShopProductInfo shopProductInfo,ShopProductSpecItem shopProductSpecItem,boolean isUpdate){ + String item_spec = item.getItem_spec(); + String productSpec=""; + if(null!=shopProductSpecItem){ + item_spec=shopProductSpecItem.getItem_spec(); + productSpec=shopProductSpecItem.getProduct_spec(); + if(isUpdate){ + item.setItem_unit_price(shopProductSpecItem.getItemPrice()); + }else { + item.setItem_unit_price(shopProductSpecItem.getItemPrice()); + item.setItem_market_price(shopProductSpecItem.getItemPrice()); + } + } + JSONArray array_item_spec = JSONUtil.parseArray(item_spec); + List spec_item_ids = new ArrayList<>(); + for (Object josn_item_spec : array_item_spec) { + JSONObject itemJ = (JSONObject) ((JSONObject) josn_item_spec).get("item"); + Integer id = Convert.toInt(itemJ.get("id")); + if (ObjectUtil.isNotNull(id)) spec_item_ids.add(id); + } + if (CollUtil.isNotEmpty(spec_item_ids)) Collections.sort(spec_item_ids); + //用来判断是否使用 + item.setSpec_item_ids(CollUtil.join(spec_item_ids, ",")); + if(StringUtils.isNotEmpty(item_spec)){ + item.setItem_spec(item_spec); + shopProductInfo.setProduct_spec(productSpec); + } + String product_uniqid=ShopJsonUtils.generateJsonWithOrgJson(item.getSpec_item_ids(),new Object[]{item.getItem_id(),item.getItem_unit_price(),"",1002}); + shopProductInfo.setProduct_uniqid(product_uniqid); + } + + /** + * 更新index状态为正常 + * @param shopProductBaseList + */ + private void saveShopProductIndexList(List shopProductBaseList){ + if (CollUtil.isEmpty(shopProductBaseList)) { + return ; + } + // 使用IN查询优化(根据数据库特性可能需要分批) + QueryWrapper query = new QueryWrapper<>(); + query.select("product_id", "product_name", "store_id"); + + // 构建OR条件 (store_id=X AND product_number=Y) OR (store_id=A AND product_number=B)... + shopProductBaseList.forEach(base -> { + query.or(q -> q.eq("store_id", base.getStore_id()) + .eq("product_id", base.getProduct_id())); + }); + List updateShopProductIndexList= shopProductIndexService.list(query); + updateShopProductIndexList.forEach(shopProductIndex -> { + shopProductIndex.setProduct_state_id(StateCode.PRODUCT_STATE_NORMAL); + }); + shopProductIndexService.updateBatchById(updateShopProductIndexList); + } + + /** + * + * @param shopProductBaseList + * @return + */ + private List findShopProductItemsList(List shopProductBaseList){ + if (CollUtil.isEmpty(shopProductBaseList)) { + return Collections.emptyList(); + } + // 使用IN查询优化(根据数据库特性可能需要分批) + QueryWrapper query = new QueryWrapper<>(); + query.select("product_id", "store_id", "item_id","item_unit_price","item_unit_price","item_market_price","category_id"); + + // 构建OR条件 (store_id=X AND product_number=Y) OR (store_id=A AND product_number=B)... + shopProductBaseList.forEach(base -> { + query.or(q -> q.eq("store_id", base.getStore_id()) + .eq("product_id", base.getProduct_id())); + }); + return shopProductItemService.list(query); + } + + /** + * + * @param shopProductBaseList + * @return + */ + private List findShopProductInfoList(List shopProductBaseList){ + if (CollUtil.isEmpty(shopProductBaseList)) { + return Collections.emptyList(); + } + + // 使用IN查询优化(根据数据库特性可能需要分批) + QueryWrapper query = new QueryWrapper<>(); + query.select("product_id", "product_number", "product_uniqid","product_weight"); + + // 构建OR条件 (store_id=X AND product_number=Y) OR (store_id=A AND product_number=B)... + shopProductBaseList.forEach(base -> { + query.or(q -> q.eq("product_id", base.getProduct_id())); + }); + return shopProductInfoService.list(query); + } + + /** + * 计算并产生规格 与商品配置表匹配,匹配正确则新增规格商品 + * @return + */ + private ShopProductSpecItem processShopProductSpecItem(ShopProductBase base,Integer categoryId,Map shopProductSpecItemMap,Map ShopBaseProductSpecMap, Map productMappingMap,Integer specItemId){ + String productName=base.getProduct_name(); + if(null!=productMappingMap.get(productName)){ + ShopBaseProductSpec shopBaseProductSpec= (ShopBaseProductSpec) ShopBaseProductSpecMap.get(categoryId); + if(null==shopBaseProductSpec){ + shopBaseProductSpec= (ShopBaseProductSpec) ShopBaseProductSpecMap.get(String.valueOf(categoryId)); + } + Integer specId= shopBaseProductSpec.getSpec_id(); + ProductMapping productMapping= (ProductMapping) productMappingMap.get(productName); + String Spec_item_name=productMapping.getProductName()+ BigDecimalFormatter.formatWithoutTrailingZeros(productMapping.getSpecValue())+productMapping.getSpecUnit();// + Integer Spec_item_id = null; + ShopProductSpecItem addShopProductSpecItem=new ShopProductSpecItem(); + addShopProductSpecItem.setUpdate(true); + if(ObjectUtil.isNotEmpty(shopProductSpecItemMap.get(Spec_item_name))){ + Spec_item_id= (Integer) shopProductSpecItemMap.get(Spec_item_name); + }else { + if(ObjectUtil.isNotEmpty(specItemId)){ + Spec_item_id=specItemId; + } + addShopProductSpecItem.setUpdate(false); + } + addShopProductSpecItem.setStore_id(base.getStore_id()); + addShopProductSpecItem.setCategory_id(categoryId); + addShopProductSpecItem.setSpec_item_id(Spec_item_id); + addShopProductSpecItem.setSpec_id(specId);//根据规格获取 + addShopProductSpecItem.setSpec_item_name(Spec_item_name); + addShopProductSpecItem.setSpec_item_enable(1);//上架 + addShopProductSpecItem.setSpec_item_order("10"); + BigDecimal[] bigDecimals= ProductPriceCalculator.calculatePriceAndQuantity(base.getUnit_price(),base.getShop_weight(),productMapping.getSpecValue(),productMapping.getSpecUnit()); + addShopProductSpecItem.setItemPrice(bigDecimals[0]); + addShopProductSpecItem.setItemQuantity(bigDecimals[1]); + List> items=new ArrayList<>(); + Map item=new HashMap<>(); + item.put("name",addShopProductSpecItem.getSpec_item_name());//规格列表 + item.put("id",Spec_item_id); + items.add(item); + List> specItems=new ArrayList<>(); + Map specItem=new HashMap<>(); + specItem.put("name",shopBaseProductSpec.getSpec_name());//规格名称 + specItem.put("id",specId); + specItems.add(specItem); + String item_spec= ShopJsonUtils.generateJsonWithOrgJsonItemSpec(items,specItems); + String product_spec= ShopJsonUtils.generateJsonWithOrgJsonProducSpec(items,specItems); + addShopProductSpecItem.setItem_spec(item_spec); + addShopProductSpecItem.setProduct_spec(product_spec); + // addShopProductSpecItem.setProduct_uniqid(product_uniqid); + return addShopProductSpecItem; + } + return null; + } + + @Override + public CommonResult syncAllProductMapping() { + Integer storeId= Integer.valueOf(Objects.requireNonNull(ContextUtil.getCurrentUser()).getStore_id()); + //找出范围内的规格产品 + QueryWrapper queryWrapper= new QueryWrapper<>(); + queryWrapper.eq("product_state_id", StateCode.PRODUCT_STATE_OFF_THE_SHELF_UNCHECK); + queryWrapper.eq("store_id", storeId); + long total=shopProductBaseService.count(queryWrapper); + + int pages= CommonUtil.getPagesCount(Math.toIntExact(total),SHOPBASEPAGE); + + ExecutorService executor = Executors.newFixedThreadPool(6); + List> futures = new ArrayList<>(); + for (int i=1;i<=pages;i++){ + int finalI = i; + futures.add(executor.submit(() -> { + this.computeProductMapping(shopProductBaseService.lists(queryWrapper, finalI,SHOPBASEPAGE).getRecords(),storeId,false); + return "成功" + finalI; + })); + } + // 等待所有任务完成 + for (Future future : futures) { + try { + System.out.println("任务结果: " + future.get()); + } catch (Exception e) { + System.err.println("任务执行异常: " + e.getMessage()); + } + } + executor.shutdown(); + + shopNumberSeqService.clearKeyStoreItemSepcId(); + + return CommonResult.success(true); + } + + @Override + public CommonResult getSyncProductUnchecked() { + Integer storeId= Integer.valueOf(Objects.requireNonNull(ContextUtil.getCurrentUser()).getStore_id()); + //找出范围内的规格产品 + QueryWrapper queryWrapper= new QueryWrapper<>(); + queryWrapper.eq("product_state_id", StateCode.PRODUCT_STATE_OFF_THE_SHELF_UNCHECK); + queryWrapper.eq("store_id", storeId); + return CommonResult.success(shopProductBaseService.list(queryWrapper)); + } + + @Override + public void downloadTemplate(HttpServletResponse response) { + try { + // 设置响应头 + setExcelResponseHeader(response, TEMPLATE_NAME); + + // 创建空模板 + EasyExcel.write(response.getOutputStream(), ProductMappingExcel.class) + .sheet("商品映射") + .registerWriteHandler(new TemplateStyleHandler()) + .doWrite(new ArrayList<>()); + } catch (IOException e) { + log.error("下载模板失败", e); + throw new RuntimeException("下载模板失败"); + } + } + + @Override + public ImportResult importData(MultipartFile file) { + ImportResult result = new ImportResult( 0,0, 0, 0,0, new ArrayList<>(), null); + String fileName = storeUploadedFile(file); + + try { + // 1. 读取Excel数据 + List excelList = readExcelData(fileName); + result.setTotalCount(excelList.size()); + + // 2. 构建唯一键映射 + Map existingMap = loadExistingMappings(excelList); + + // 3. 处理导入数据 + List toUpdate = new ArrayList<>(); + List toInsert = new ArrayList<>(); + + for (int i = 0; i < excelList.size(); i++) { + ProductMappingExcel excel = excelList.get(i); + int rowNum = i + 2; // Excel行号(标题行+1) + + try { + // 验证数据 + validateExcelData(excel, rowNum); + + // 转换为实体 + ProductMapping entity = excel.toEntity(); + String uniqueKey = excel.getUniqueKey(); + + // 检查是否已存在 + if (existingMap.containsKey(uniqueKey)) { + ProductMapping existing = existingMap.get(uniqueKey); + updateExistingEntity(existing, entity); + toUpdate.add(existing); + result.setUpdateCount(result.getUpdateCount() + 1); + } else { + toInsert.add(entity); + result.setInsertCount(result.getInsertCount() + 1); + } + + result.setSuccessCount(result.getSuccessCount() + 1); + } catch (ValidationException e) { + result.setFailCount(result.getFailCount() + 1); + result.getErrorMessages().add(e.getMessage()); + } + } + + // 4. 批量操作 + if (!toInsert.isEmpty()) { + productMappingService.saveBatch(toInsert,toInsert.size()); + } + if (!toUpdate.isEmpty()) { + productMappingService.updateBatchById(toUpdate,toInsert.size()); + } + + // 5. 生成错误报告(如果有错误) + if (result.getFailCount() > 0) { + result.setDownloadUrl(generateErrorReport(result.getErrorMessages(), fileName)); + } + + return result; + } catch (Exception e) { + log.error("导入数据失败", e); + throw new RuntimeException("导入数据失败: " + e.getMessage()); + } + } + + @Override + public void exportData(HttpServletResponse response, List data) { + try { + // 设置响应头 + setExcelResponseHeader(response, EXPORT_NAME); + + // 转换为Excel对象 + List excelData = data.stream() + .map(ProductMappingExcel::fromEntity) + .collect(Collectors.toList()); + + // 导出Excel + EasyExcel.write(response.getOutputStream(), ProductMappingExcel.class) + .sheet("商品映射数据") + .registerWriteHandler(new ExportStyleHandler()) + .doWrite(excelData); + } catch (IOException e) { + log.error("导出数据失败", e); + throw new RuntimeException("导出数据失败"); + } + } + + // ================ 私有方法 ================ + // 加载数据库中已存在的映射 + private Map loadExistingMappings(List excelList) { + // 收集所有唯一键 + Set uniqueKeys = excelList.stream() + .map(ProductMappingExcel::getUniqueKey) + .collect(Collectors.toSet()); + + if (uniqueKeys.isEmpty()) { + return Collections.emptyMap(); + } + + // 分批查询数据库(避免SQL过长) + int batchSize = 100; + Map resultMap = new HashMap<>(); + List keyList = new ArrayList<>(uniqueKeys); + + for (int i = 0; i < keyList.size(); i += batchSize) { + int end = Math.min(i + batchSize, keyList.size()); + List batchKeys = keyList.subList(i, end); + + // 构建查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply(buildUniqueKeyCondition(batchKeys)); + + // 查询数据库 + List existingList = productMappingService.list(wrapper); + + // 添加到结果映射 + existingList.forEach(entity -> + resultMap.put(entity.getUniqueKey(), entity)); + } + + return resultMap; + } + + // 构建唯一键查询条件 + private String buildUniqueKeyCondition(List uniqueKeys) { + StringBuilder sb = new StringBuilder(); + sb.append("CONCAT_WS('|', product_name, store_id, TRIM(TRAILING '.' FROM TRIM(TRAILING '0' FROM CAST(spec_value AS CHAR))), spec_unit) IN ("); + + for (int i = 0; i < uniqueKeys.size(); i++) { + if (i > 0) sb.append(","); + sb.append("'").append(uniqueKeys.get(i).replace("'", "''")).append("'"); + } + + sb.append(")"); + return sb.toString(); + } + + // 更新现有实体 + private void updateExistingEntity(ProductMapping existing, ProductMapping newEntity) { + existing.setDescription(newEntity.getDescription()); + existing.setSortOrder(newEntity.getSortOrder()); + // 可根据需要更新其他字段 + } + + // 验证Excel数据 + private void validateExcelData(ProductMappingExcel data, int rowNum) { + if (StringUtils.isBlank(data.getProductName())) { + throw new ValidationException("第" + rowNum + "行: 商品名称不能为空"); + } + + if (data.getStoreId() == null || data.getStoreId() <= 0) { + throw new ValidationException("第" + rowNum + "行: 店铺编号必须大于0"); + } + + if (data.getSpecValue() == null || data.getSpecValue().compareTo(BigDecimal.ZERO) <= 0) { + throw new ValidationException("第" + rowNum + "行: 规格数据必须大于0"); + } + + if (StringUtils.isBlank(data.getSpecUnit())) { + throw new ValidationException("第" + rowNum + "行: 规格单位不能为空"); + } + + if (data.getSortOrder() == null || data.getSortOrder() < 0) { + throw new ValidationException("第" + rowNum + "行: 排序值不能为负数"); + } + } + + // 设置Excel响应头 + private void setExcelResponseHeader(HttpServletResponse response, String fileName) { + try { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20"); + response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodedFileName); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("文件名编码失败"); + } + } + + // 存储上传文件 + private String storeUploadedFile(MultipartFile file) { + if (file.isEmpty()) { + throw new RuntimeException("上传文件为空"); + } + + try { + String fileName = System.currentTimeMillis() + "_" + file.getOriginalFilename(); + Path filePath = Paths.get(uploadDir, fileName); + Files.createDirectories(filePath.getParent()); + Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING); + return filePath.toString(); + } catch (IOException e) { + log.error("存储上传文件失败", e); + throw new RuntimeException("存储上传文件失败"); + } + } + + // 读取Excel数据 + private List readExcelData(String filePath) { + return EasyExcel.read(filePath) + .head(ProductMappingExcel.class) + .sheet() + .doReadSync(); + } + + // 生成错误报告 + private String generateErrorReport(List errors, String originalFilePath) { + try { + String errorFileName = "ERROR_" + Paths.get(originalFilePath).getFileName().toString(); + Path errorFilePath = Paths.get(uploadDir, errorFileName); + + List errorData = new ArrayList<>(); + for (int i = 0; i < errors.size(); i++) { + errorData.add(new ErrorInfo(i + 1, errors.get(i))); + } + + EasyExcel.write(errorFilePath.toString()) + .head(ErrorInfo.class) + .sheet("导入错误") + .doWrite(errorData); + + return "/admin/shop/shop-sync-productMapper/download?file=" + URLEncoder.encode(errorFileName, "UTF-8"); + } catch (Exception e) { + log.error("生成错误报告失败", e); + return null; + } + } + + + @Override + public CommonResult saveProductMapping(ProductMapping data) { + List batchKeys = Arrays.asList(data.getUniqueKey().split(",")); + + // 构建查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.apply(buildUniqueKeyCondition(batchKeys)); + List productMappings= productMappingService.list(wrapper); + if(!productMappings.isEmpty()){ + return CommonResult.failed("存在相同的映射商品数据"); + } + boolean result= productMappingService.save(data); + if(result){ + return CommonResult.success(); + } + return CommonResult.success(false); + } + + + // 错误信息类 + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class ErrorInfo { + @ExcelProperty("行号") + private Integer rowNum; + + @ExcelProperty("错误信息") + private String errorMessage; + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/StoreDbConfigServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/StoreDbConfigServiceImpl.java index 7e895f9d..067f0e49 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/StoreDbConfigServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/StoreDbConfigServiceImpl.java @@ -45,12 +45,19 @@ public class StoreDbConfigServiceImpl extends BaseServiceImpl queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("store_id", storeId); - queryWrapper.eq("has_internet", storeDbConfig.getHasInternet()); - queryWrapper.eq("has_start", storeDbConfig.getHasInternet()); + if(!StringUtils.isEmpty(storeId)){ + queryWrapper.eq("store_id", storeId); + } + if(!ObjectUtil.isEmpty(storeDbConfig.getHasInternet())){ + queryWrapper.eq("has_internet", storeDbConfig.getHasInternet()); + } + if(!ObjectUtil.isEmpty(storeDbConfig.getHasStart())){ + queryWrapper.eq("has_start", storeDbConfig.getHasStart()); + } return CommonResult.success(this.lists(queryWrapper,pageNum,pageSize)); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncBaseThirdSxAbstract.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncBaseThirdSxAbstract.java index 112d3cf1..7bcf6d2e 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncBaseThirdSxAbstract.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncBaseThirdSxAbstract.java @@ -14,6 +14,7 @@ import com.alibaba.excel.util.DateUtils; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.suisung.mall.common.api.StateCode; import com.suisung.mall.common.constant.CommonConstant; +import com.suisung.mall.common.enums.DicEnum; import com.suisung.mall.common.exception.ApiException; import com.suisung.mall.common.feignService.AccountService; import com.suisung.mall.common.feignService.PayService; @@ -21,6 +22,7 @@ import com.suisung.mall.common.modules.account.AccountUserBase; import com.suisung.mall.common.modules.account.AccountUserInfo; import com.suisung.mall.common.modules.base.ShopBaseProductBrand; import com.suisung.mall.common.modules.base.ShopBaseProductCategory; +import com.suisung.mall.common.modules.base.ShopBaseProductSpec; import com.suisung.mall.common.modules.base.ShopBaseProductType; import com.suisung.mall.common.modules.number.ShopNumberSeq; import com.suisung.mall.common.modules.pay.PayUserResource; @@ -34,13 +36,18 @@ import com.suisung.mall.common.utils.I18nUtil; import com.suisung.mall.common.utils.StringUtils; import com.suisung.mall.shop.base.service.ShopBaseProductBrandService; import com.suisung.mall.shop.base.service.ShopBaseProductCategoryService; +import com.suisung.mall.shop.base.service.ShopBaseProductSpecService; import com.suisung.mall.shop.base.service.ShopBaseProductTypeService; +import com.suisung.mall.shop.number.service.ShopNumberSeqService; import com.suisung.mall.shop.number.service.impl.ShopNumberSeqServiceImpl; import com.suisung.mall.shop.product.service.ShopProductBaseService; +import com.suisung.mall.shop.product.service.ShopProductItemService; import com.suisung.mall.shop.product.service.impl.ShopProductBaseServiceImpl; import com.suisung.mall.shop.product.service.impl.ShopProductItemServiceImpl; import com.suisung.mall.shop.sixun.dto.SxGoosModel; import com.suisung.mall.shop.store.service.ShopStoreBaseService; +import com.suisung.mall.shop.sync.service.ProductMappingService; +import org.apache.commons.lang3.math.NumberUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -51,6 +58,9 @@ import java.math.BigDecimal; import java.text.ParseException; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import static com.baomidou.mybatisplus.extension.toolkit.Db.list; @Service public abstract class SyncBaseThirdSxAbstract{ @@ -70,11 +80,16 @@ public abstract class SyncBaseThirdSxAbstract{ @Autowired private PayService payService; @Autowired - private ShopNumberSeqServiceImpl shopNumberSeqServiceImpl; + private ShopNumberSeqService shopNumberSeqService; + @Autowired - private ShopProductBaseServiceImpl shopProductBaseServiceImpl; + private ShopProductItemService shopProductItemService; + @Autowired - private ShopProductItemServiceImpl shopProductItemServiceImpl; + private ShopBaseProductSpecService shopBaseProductSpecService; + + @Autowired + private ProductMappingService productMappingService; /** * 对商品分类进行保存 @@ -86,17 +101,20 @@ public abstract class SyncBaseThirdSxAbstract{ public int baseSaveOrUpdateShopBaseProductCategoryBatch(List list ,JSONArray categoryListJSON, String storeId){ int count = 0; + List productTypeList = new ArrayList<>(); for (int i = 0; i < list.size(); i++) { list.get(i).setStore_id(storeId); // app 记录传进来 list.get(i).setData_source(2); // 思迅数据来源 list.get(i).setCategory_is_enable(1); JSONObject o = (JSONObject) categoryListJSON.get(i); + ShopBaseProductType productType=new ShopBaseProductType(); if (o != null) { // 重要:分类类型处理(强调共性) Integer typeId = 1001; + if (StrUtil.isNotBlank(o.getStr("product_type"))) { - ShopBaseProductType productType = productTypeService.getProductTypeByName(o.getStr("product_type")); + productType = productTypeService.getProductTypeByName(o.getStr("product_type")); if (productType != null) { typeId = productType.getType_id(); } else { @@ -107,6 +125,7 @@ public abstract class SyncBaseThirdSxAbstract{ if (productTypeService.save(newProductType)) { typeId = newProductType.getType_id(); } + productType=newProductType; } list.get(i).setType_id(typeId); } @@ -157,8 +176,6 @@ public abstract class SyncBaseThirdSxAbstract{ } } } - - } ShopBaseProductCategory productCategoryTemp = productCategoryService.getCategoryByName(list.get(i).getCategory_parent_id(), list.get(i).getCategory_name(), list.get(i).getStore_id()); @@ -173,13 +190,16 @@ public abstract class SyncBaseThirdSxAbstract{ } else { continue; } + } if (productCategoryService.saveOrUpdate(list.get(i))) { count++; } + productType.setType_category_id(list.get(i).getCategory_id()); + productTypeList.add(productType); } - + saveBatchShopProductProductSpec(storeId,productTypeList); return count; } @@ -522,6 +542,10 @@ public abstract class SyncBaseThirdSxAbstract{ } goodsListJSON.stream().parallel().forEach(object -> { final JSONObject jsonObj= (JSONObject) object; + String productName= (String) jsonObj.get("product_name"); + if(productName.equals(DicEnum.GOODS_UN_SYNC_SX.getValue())){//todo 后期改为数据库存储的黑名单 + return; + } Date currentDate = new Date(); String cateGoryId=""; if(null!=categoryMap.get(jsonObj.get("first_category_name"))){ @@ -530,24 +554,37 @@ public abstract class SyncBaseThirdSxAbstract{ Integer categoryId = Convert.toInt(cateGoryId, 0); Integer storeIdInt = Convert.toInt(storeId); - ShopProductBase shopProductBase = new ShopProductBase(); + shopProductBase.setCategoryId(categoryId); shopProductBase.setProduct_sale_time(Convert.toDate(DateUtil.current() + 600)); //10分钟 shopProductBase.setStore_id(storeIdInt); shopProductBase.setProduct_number((String) jsonObj.get("product_number")); shopProductBase.setProduct_name((String) jsonObj.get("product_name")); + shopProductBase.setStore_name(store_row.getStore_name()); shopProductBase.setProduct_tips(""); shopProductBase.setProduct_video(""); shopProductBase.setTransport_type_id(StateCode.DELIVERY_TYPE_SAME_CITY); - shopProductBase.setProduct_state_id(StateCode.PRODUCT_STATE_NORMAL); + shopProductBase.setProduct_inventory_lock(1002); //库存锁定(ENUM):1001-下单锁定;1002-支付锁定; shopProductBase.setProduct_fx_enable(0); // 供应商是否允许批发市场分销 shopProductBase.setProduct_dist_enable(0); // 是否允许三级分销 shopProductBase.setProduct_from(1005);// 商品来源(ENUM):1000-发布;1001-天猫;1002-淘宝;1003-阿里巴巴;1004-京东;1005-思迅; shopProductBase.setProduct_add_time(currentDate.getTime()); - + shopProductBase.setProduct_unit_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price"))); + //商品总量 + if(ObjectUtil.isNotEmpty(jsonObj.getStr("unit"))&&ObjectUtil.isNotEmpty(jsonObj.getStr("stock")) + && "KG,kg,公斤".contains(jsonObj.getStr("unit"))){ + shopProductBase.setShop_weight(jsonObj.getBigDecimal("stock")); + shopProductBase.setUnit_name(jsonObj.getStr("unit")); + shopProductBase.setProduct_state_id(StateCode.PRODUCT_STATE_OFF_THE_SHELF_UNCHECK); + shopProductBase.setUnit_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price"))); + }else { + shopProductBase.setShop_weight(jsonObj.getBigDecimal("stock")); + shopProductBase.setProduct_state_id(StateCode.PRODUCT_STATE_NORMAL); + shopProductBase.setUnit_price(BigDecimal.valueOf(jsonObj.getDouble("retail_price"))); + } // ShopProductIndex ShopProductIndex shopProductIndex = new ShopProductIndex(); shopProductIndex.setProduct_add_time(currentDate.getTime()); @@ -616,12 +653,19 @@ public abstract class SyncBaseThirdSxAbstract{ shopProductItem.setItem_market_price(BigDecimal.valueOf(jsonObj.getDouble("original_price"))); //积分价 shopProductItem.setItem_unit_points(new BigDecimal(jsonObj.getInt("points"))); - shopProductItem.setItem_quantity(jsonObj.getInt("stock")); // 库存 + + //todo 特色商品切割 + //负数产品判断 + if(jsonObj.getInt("stock",99)<0){ + shopProductItem.setItem_quantity(99); // 库存 + shopProductItem.setItem_weight(new BigDecimal("0"));//切割重量 + } + shopProductItem.setItem_quantity_frozen(0); shopProductItem.setItem_number(jsonObj.getStr("product_number"));// SKU商家编码 shopProductItem.setItem_barcode(jsonObj.getStr("product_number")); // 条形码正常情况下就是货号 shopProductItem.setItem_is_default(1); - shopProductItem.setItem_enable(1); + shopProductItem.setItem_enable(shopProductBase.getProduct_state_id()); //添加数据到list synchronized(shopProductBaseList){ @@ -633,30 +677,9 @@ public abstract class SyncBaseThirdSxAbstract{ shopProductInfoList.add(shopProductInfo); shopProductItemLists.add(shopProductItemList); } -// synchronized(shopProductIndexList){ -// shopProductIndexList.add(shopProductIndex); -// } -// -// synchronized(shopProductDataList){ -// shopProductDataList.add(shopProductData); -// } -// -// synchronized(shopProductDetailList){ -// shopProductDetailList.add(shopProductDetail); -// } -// -// synchronized(shopProductInfoList){ -// shopProductInfoList.add(shopProductInfo); -// } -// -// synchronized(shopProductItemLists){ -// shopProductItemLists.add(shopProductItemList); -// } - - // 保存数据 - resultCount.addAndGet(1); }); + // 保存数据 shopProductBaseService.saveProductBatch(shopProductBaseList,shopProductIndexList,shopProductDataList,shopProductDetailList,shopProductInfoList,shopProductItemLists, new ArrayList>(), new ArrayList(), @@ -671,7 +694,7 @@ public abstract class SyncBaseThirdSxAbstract{ List shopNumberSeqList=new ArrayList<>(); QueryWrapper baseWrapper=new QueryWrapper<>(); baseWrapper.select("MAX(product_id) as product_id"); - ShopProductBase shopProductBase= shopProductBaseServiceImpl.getOne(baseWrapper); + ShopProductBase shopProductBase= shopProductBaseService.getOne(baseWrapper); Long productId= shopProductBase.getProduct_id(); //QueryWrapper baseSeWrapper=new QueryWrapper(); //baseSeWrapper.eq("prefix", "product_id"); @@ -682,7 +705,7 @@ public abstract class SyncBaseThirdSxAbstract{ //查询产品item QueryWrapper itemQuery=new QueryWrapper<>(); itemQuery.select("MAX(item_id) as item_id"); - ShopProductItem shopProductItem= shopProductItemServiceImpl.getOne(itemQuery); + ShopProductItem shopProductItem= shopProductItemService.getOne(itemQuery); Long itemtId= shopProductItem.getItem_id(); // QueryWrapper itemWrapper=new QueryWrapper(); //itemWrapper.eq("prefix", "item_id"); @@ -691,9 +714,101 @@ public abstract class SyncBaseThirdSxAbstract{ shopNumberSeqItem.setPrefix("item_id"); shopNumberSeqList.add(shopNumberSeqBase); shopNumberSeqList.add(shopNumberSeqItem); - shopNumberSeqServiceImpl.batchUpdateSeq(shopNumberSeqList); - shopNumberSeqServiceImpl.clearRelateGoodsId(); + shopNumberSeqService.batchUpdateSeq(shopNumberSeqList); + shopNumberSeqService.clearRelateGoodsId(); + } + + /** + * 根据商品分类生成规格主体 + * @param storeId + */ + private synchronized void saveBatchShopProductProductSpec(String storeId,List shopBaseProductTypes){ + Map categoryMap= productCategoryService.getCategoryListByStoreId(storeId); + List shopBaseProductSpecList=new ArrayList<>(); + Set categoryMapSet= categoryMap.entrySet(); + for(Map.Entry categoryMapEntry:categoryMapSet){ + ShopBaseProductSpec shopBaseProductSpec=new ShopBaseProductSpec(); + if(categoryMapEntry.getKey()!=null&& !(NumberUtils.isCreatable(String.valueOf(categoryMapEntry.getKey())))){ + shopBaseProductSpec.setStore_id(Integer.valueOf(storeId)); + shopBaseProductSpec.setSpec_category_id((Integer) categoryMapEntry.getValue()); + shopBaseProductSpec.setSpec_name(categoryMapEntry.getKey()+"规格"); + shopBaseProductSpecList.add(shopBaseProductSpec); + } + } + Map existIdMap= checkExistingShopBaseProductSpec(shopBaseProductSpecList); + List insertShopBaseProductSpecList=new ArrayList<>(); + List updateShopBaseProductSpecList=new ArrayList<>(); + QueryWrapper queryWrapper= new QueryWrapper<>(); + queryWrapper.select("max(spec_id) as spec_id"); + int spec_id=shopBaseProductSpecService.getOne(queryWrapper).getSpec_id()+1; + //int i=0; + for(int i=0;i { + if((shopBaseProductType.getType_name()+"规格").equals(shopBaseProductSpecList.get(finalI).getSpec_name())){ + shopBaseProductType.setType_spec_ids(String.valueOf(existIdMap.get(shopBaseProductSpecList.get(finalI).getSpec_name()))); + } + }); + }else { + shopBaseProductSpecList.get(i).setSpec_id(spec_id); + int finalSpec_id = spec_id; + int finalI1 = i; + shopBaseProductTypes.forEach(shopBaseProductType -> { + if((shopBaseProductType.getType_name()+"规格").equals(shopBaseProductSpecList.get(finalI1).getSpec_name())){ + shopBaseProductType.setType_spec_ids(String.valueOf(finalSpec_id)); + } + }); + insertShopBaseProductSpecList.add(shopBaseProductSpecList.get(i)); + } + spec_id++; + } + if(CollectionUtil.isNotEmpty(insertShopBaseProductSpecList)){ + shopBaseProductSpecService.saveBatch(insertShopBaseProductSpecList,insertShopBaseProductSpecList.size()); + } + if(CollectionUtil.isNotEmpty(updateShopBaseProductSpecList)){ + shopBaseProductSpecService.updateBatchById(updateShopBaseProductSpecList,updateShopBaseProductSpecList.size()); + } + if(CollectionUtil.isNotEmpty(shopBaseProductTypes)){ + productTypeService.updateBatchById(shopBaseProductTypes,shopBaseProductTypes.size()); + } + } + /** + * 检查哪些商品已存在 + */ + private Map checkExistingShopBaseProductSpec(List productSpecs) { + List storeProductPairs = productSpecs.stream() + .map(ShopBaseProductSpec::getSpec_name) + .distinct() + .collect(Collectors.toList()); + List existing = batchGetByStoreAndShopBaseProductSpec(storeProductPairs); + return existing.stream() + .collect(Collectors.toMap( + ShopBaseProductSpec::getSpec_name, + ShopBaseProductSpec::getSpec_id + )); + } + + /** + * 批量根据店铺和货号查询商品 + */ + private List batchGetByStoreAndShopBaseProductSpec(List ShopBaseProductSpecStr) { + if (CollUtil.isEmpty(ShopBaseProductSpecStr)) { + return Collections.emptyList(); + } + QueryWrapper query = new QueryWrapper<>(); + query.select("spec_id", "spec_name"); + ShopBaseProductSpecStr.forEach(specName -> { + query.or(q -> q.eq("spec_name", specName)); + }); + + return shopBaseProductSpecService.list(query); + } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java index d25273af..9efc2319 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/sync/service/impl/SyncThirdDataServiceImpl.java @@ -39,14 +39,15 @@ import com.suisung.mall.common.modules.sync.SyncFileLog; import com.suisung.mall.common.pojo.req.SyncThirdMemberReq; import com.suisung.mall.common.pojo.res.ThirdApiRes; -import com.suisung.mall.common.utils.ContextUtil; import com.suisung.mall.common.utils.I18nUtil; import com.suisung.mall.common.utils.StringUtils; import com.suisung.mall.core.web.service.RedisService; import com.suisung.mall.shop.base.service.ShopBaseProductCategoryService; +import com.suisung.mall.shop.base.service.ShopBaseProductSpecService; import com.suisung.mall.shop.number.service.ShopNumberSeqService; import com.suisung.mall.shop.page.service.OssService; +import com.suisung.mall.shop.product.service.ShopProductSpecItemService; import com.suisung.mall.shop.sixun.dao.SxDataDao; import com.suisung.mall.shop.sixun.dto.DataBaseInfo; import com.suisung.mall.shop.sixun.dto.SxCategoryModel; @@ -68,7 +69,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.InputStreamSource; import org.springframework.core.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -130,6 +130,11 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements @Autowired private FileUtils fileUtils; + @Autowired + private ShopProductSpecItemService shopProductSpecItemService; + + @Autowired + private ShopBaseProductSpecService baseProductSpecService; /** * 批量保存商品的分类 @@ -531,6 +536,8 @@ public class SyncThirdDataServiceImpl extends SyncBaseThirdSxAbstract implements syncPrimaryKey(); shopNumberSeqService.clearKey(); shopBaseProductCategoryService.clearCategoryCache(storeId); + shopProductSpecItemService.clearExistItem(Integer.valueOf(storeId)); + baseProductSpecService.clearShopBaseProductSpecMap(Integer.valueOf(storeId)); List syncFileLogs=new ArrayList<>(); for (int i = 0; i < failFolders.size(); i++) { String path=failFolders.get(i); diff --git a/mall-shop/src/main/resources/bootstrap.yml b/mall-shop/src/main/resources/bootstrap.yml index 416db8f1..46792ce9 100644 --- a/mall-shop/src/main/resources/bootstrap.yml +++ b/mall-shop/src/main/resources/bootstrap.yml @@ -5,4 +5,6 @@ spring: name: mall-shop jackson: date-format: yyyy-MM-dd HH:mm:ss - time-zone: GMT+8 \ No newline at end of file + time-zone: GMT+8 +file: + upload-dir: /tmp/excel_uploads \ No newline at end of file diff --git a/sql/shop/dev/20250602_ddl.sql b/sql/shop/dev/20250602_ddl.sql new file mode 100644 index 00000000..cef2dea8 --- /dev/null +++ b/sql/shop/dev/20250602_ddl.sql @@ -0,0 +1,25 @@ +CREATE TABLE `product_mapping` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `product_name` varchar(255) NOT NULL COMMENT '商品名称', + `spec_value` decimal(18,4) NOT NULL COMMENT '规格数据', + `spec_unit` varchar(20) NOT NULL COMMENT '规格单位', + `description` text , + `sort_order` int(11) NOT NULL DEFAULT '0' COMMENT '排序值', + `store_id` int unsigned NOT NULL DEFAULT '0' COMMENT '店铺编号', + PRIMARY KEY (`id`), + KEY `idx_product_name` (`product_name`) USING BTREE, + KEY `idx_store_id` (`store_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品映射表'; + +alter table shop_product_base add column `unit_name` varchar(2) DEFAULT NULL COMMENT '总量单位'; +alter table shop_product_base add column `shop_weight` DECIMAL(18,4) NOT NULL COMMENT '总重量' +alter table shop_product_base add column `unit_price` DECIMAL(18,4) NOT NULL COMMENT '单价'; + +alter table shop_base_product_spec add column `store_id` int unsigned NOT NULL DEFAULT '0' COMMENT '店铺编号'; +alter table shop_base_product_spec add index `store_id` (`store_id`) USING BTREE; + +INSERT INTO mall_dev.shop_base_product_state +(product_state_id, product_state_name, product_state_text_1, product_state_text_2, product_state_remark) +VALUES(1003, 'PRODUCT_STATE_OFF_THE_SHELF_UNCHECK', '下架未分配商品', '同步数据未分配', ''); + +alter table store_db_config add column refresh_time datetime DEFAULT NULL COMMENT '刷新时间';