Compare commits

30 Commits

Author SHA1 Message Date
87dd4cc3ba 条件开通 2025-12-25 19:27:39 +08:00
5df01f5192 订单 累计 2025-12-25 18:40:12 +08:00
3b83d210dc 订单 统计 2025-12-25 18:29:21 +08:00
d70546f55e 更新会员成长值 不对
订单退款 全额 部分 问题
2025-12-25 18:02:31 +08:00
c6102dd4b4 消费返现
充值触发条件成为会员
霸王餐触发条件成为会员
2025-12-25 17:18:46 +08:00
gong
f374c335c4 transactionSafeRun 2025-12-25 17:04:42 +08:00
b171b1a81f 订单 退款 问题 2025-12-25 16:28:19 +08:00
0b5ec53187 空值问题 2025-12-25 15:46:09 +08:00
ec59490f3a 会员 问题 2025-12-25 15:02:57 +08:00
7d434ff5c7 开通 问题 2025-12-25 14:37:11 +08:00
ef48e4e51d 开通 问题 2025-12-25 14:22:28 +08:00
5cb895ac19 数签子 2025-12-25 14:06:43 +08:00
e125eed517 会员 条件开通 2025-12-25 14:06:31 +08:00
gong
621bf2401d 管理端获取商品详情接口 2025-12-25 11:46:14 +08:00
bae1762dba ocr 数签子
登录更新了用户名称的问题
更新用户信息的问题
2025-12-25 11:18:14 +08:00
gong
22a5ae8f68 删除测试方法 2025-12-24 17:43:53 +08:00
gong
ae65bf1814 小程序商品返回相关推荐 2025-12-24 17:42:08 +08:00
gong
b1215acca5 apifox 归类注释 2025-12-24 15:31:52 +08:00
gong
a6dd4f4611 添加商品关联推荐 2025-12-24 15:23:02 +08:00
506e74747a 问题 2025-12-24 14:55:12 +08:00
72c9379e87 Merge branch 'prod' into test 2025-12-24 14:52:16 +08:00
a8bcf991fe 显式抛出 2025-12-24 14:03:38 +08:00
240d672211 sysParam 获取值问题 2025-12-24 13:57:40 +08:00
gong
302504b891 Merge remote-tracking branch 'origin/test' into test 2025-12-23 16:07:32 +08:00
gong
a76c3f75a4 分页总数量为 -1 的情况2 2025-12-23 16:07:27 +08:00
a05d8083bc 返回默认值 2025-12-23 16:03:09 +08:00
ed1b6b2ecf Merge remote-tracking branch 'origin/test' into test 2025-12-23 15:34:11 +08:00
7c9c6d6a02 菜单问题 2025-12-23 15:33:30 +08:00
gong
658c7f14b2 分页总数量为 -1 的情况 2025-12-23 15:15:42 +08:00
8635c42506 用户列表 1 2025-12-23 14:23:58 +08:00
86 changed files with 1545 additions and 815 deletions

1
.gitignore vendored
View File

@@ -61,3 +61,4 @@ build/
/cash-api/product-server/src/main/resources/application-zs.yml
/cash-api/system-server/src/main/resources/application-zs.yml
/cash-service/code-generator/src/main/java/com/czg/Main.java
/cash-api/product-server/logs/

View File

@@ -147,32 +147,4 @@ public class NotifyController {
}
return resultMap;
}
public static void main(String[] args) {
String str = "<xml><ToUserName><![CDATA[gh_11fc27b7ef34]]></ToUserName><FromUserName><![CDATA[owWHW7Tzeh2gx3WmFsFSxBq2JUTk]]></FromUserName><CreateTime>1761095747</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[subscribe]]></Event><EventKey><![CDATA[qrscene_275]]></EventKey><Ticket><![CDATA[gQGF8DwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyUTZDVHRTMXhmbUoxYUlYdk5GY2sAAgSsLvhoAwQAjScA]]></Ticket></xml>";
// 2. 解析 XML 为 Map便于获取字段
Map<String, String> messageMap = new HashMap<>();
try {
messageMap = parseXmlToMap(str);
} catch (DocumentException e) {
log.error("XML 解析失败,", e);
}
log.info("微信 POST 消息内容: {}", messageMap);
//携带参数
String eventKey = messageMap.get("EventKey");
Long userId = null;
if (eventKey != null && eventKey.startsWith("qrscene_")) {
try {
// 截取 "qrscene_" 前缀后的字符串(长度为 8并转为 Long
String numberStr = eventKey.substring("qrscene_".length());
userId = Long.parseLong(numberStr);
} catch (NumberFormatException e) {
log.error("EventKey 后缀不是有效数字eventKey: {}", eventKey, e);
}
}
System.out.println("userId: " + userId);
}
}

View File

@@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.RestController;
* @author GYJoker
*/
@RestController
@RequestMapping("/test")
@RequestMapping("/notify/test")
public class TestController {
@Resource
private ShopUserFlowService shopUserFlowService;

View File

@@ -24,6 +24,7 @@ import java.util.Map;
/**
* 会员配置管理
* @author ww
*/
@RestController

View File

@@ -89,6 +89,14 @@ public class PpPackageController {
return CzgResult.success(ppPackageService.getPackagePage(reqVo, true));
}
/**
* 获取套餐详情
*/
@GetMapping("/detail/{id}")
public CzgResult<PpPackageVO> getPackageDetail(@PathVariable Long id, Long shopId) {
return CzgResult.success(ppPackageService.getPackageDetail(id, shopId));
}
/**
* 获取套餐推广开关
* 0: 关闭 1: 开启

View File

@@ -1,7 +1,6 @@
package com.czg.controller.admin;
import com.czg.market.dto.MkShopRechargeDTO;
import com.czg.market.entity.MkShopConsumeDiscountRecord;
import com.czg.market.entity.MkShopRechargeFlow;
import com.czg.market.service.MkRechargeFlowService;
import com.czg.market.service.MkShopConsumeDiscountRecordService;
@@ -30,12 +29,6 @@ public class ShopRechargeController {
@Resource
private MkShopConsumeDiscountRecordService shopConsumeDiscountRecordService;
@GetMapping("/test")
public CzgResult<MkShopConsumeDiscountRecord> get(@RequestParam Long shopId) {
// return CzgResult.success(shopConsumeDiscountRecordService.get(shopId));
return null;
}
/**
* 配置信息获取
* 权限标识: activate:list

View File

@@ -4,7 +4,6 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.CzgPayUtils;
import com.czg.account.service.ShopUserService;
import com.czg.constants.PayTypeConstants;
import com.czg.entity.CzgBaseRespParams;
import com.czg.market.entity.MkShopConsumeDiscountRecord;
@@ -38,10 +37,6 @@ import java.io.IOException;
@RequestMapping("/notify")
public class NotifyController {
private static final String SUCCESS = "SUCCESS";
@Resource
private ShopUserService shopUserService;
@Resource
private OrderInfoCustomService orderInfoCustomService;
@Resource

View File

@@ -8,6 +8,7 @@ import com.czg.market.service.GbWareService;
import com.czg.order.dto.GbOrderQueryParam;
import com.czg.order.service.GbOrderService;
import com.czg.order.vo.GbOrderCountVO;
import com.czg.order.vo.GbWareVO;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.utils.AssertUtil;
@@ -87,4 +88,12 @@ public class GbWareController {
AssertUtil.isNull(id, "操作失败,请选择商品");
return CzgResult.success(wareService.deleteGbWare(id));
}
/**
* 拼团商品详情
*/
@GetMapping("/ware/detail")
public CzgResult<GbWareVO> getWareDetail(@RequestParam Long shopId, @RequestParam Long wareId) {
return CzgResult.success(gbOrderService.getWareDetail(shopId, wareId, null));
}
}

View File

@@ -5,6 +5,7 @@ import cn.hutool.core.util.URLUtil;
import com.czg.log.annotation.OperationLog;
import com.czg.product.dto.ConsStockFlowDTO;
import com.czg.product.dto.OcrDTO;
import com.czg.product.entity.MkOcrService;
import com.czg.product.param.ConsCheckStockParam;
import com.czg.product.param.ConsInOutStockHeadParam;
import com.czg.product.param.ConsReportDamageParam;
@@ -37,6 +38,8 @@ public class ConsStockFlowController {
@Resource
private ConsStockFlowService consStockFlowService;
@Resource
private MkOcrService ocrService;
/**
* 入库单识别
@@ -46,17 +49,18 @@ public class ConsStockFlowController {
URI uri = new URI(ocrDTO.getUrl());
URL url = uri.toURL();
InputStream stream = URLUtil.getStream(url);
return CzgResult.success(consStockFlowService.ocr(FileUtil.getName(ocrDTO.getUrl()), stream));
return CzgResult.success(ocrService.ocr(FileUtil.getName(ocrDTO.getUrl()), stream, "cons"));
}
/**
* ocr识别结果
*
* @param id ocrId
* @return 识别结果
*/
@GetMapping("/ocrResult")
public CzgResult<ConsInOutStockHeadParam> ocrResult(@RequestParam Long id) {
return CzgResult.success(consStockFlowService.ocrDetail(id));
return CzgResult.success(ocrService.ocrDetail(id));
}

View File

@@ -33,7 +33,7 @@ import java.util.List;
/**
* 商品管理 - 商品列表
* 管理端/商品管理 - 商品列表
*
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-02-16

View File

@@ -0,0 +1,38 @@
package com.czg.controller.admin;
import com.czg.product.service.MkOcrCountStickService;
import com.czg.resp.CzgResult;
import com.czg.utils.AssertUtil;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
/**
* 拍照数签子
* @author ww
*/
@RestController
@RequestMapping("/admin/stick")
public class StickCountController {
@Resource
private MkOcrCountStickService stickCountService;
/**
* 文件上传并返回点数统计结果
*
* @param file 上传的图片文件
* @return 点数统计结果
*/
@PostMapping("/count")
public CzgResult<Integer> uploadAndCount(MultipartFile file) throws IOException {
AssertUtil.isNull(file, "上传文件不能为空");
// 9. 返回成功结果
return CzgResult.success(stickCountService.getCountStick(file.getBytes(), file.getOriginalFilename()));
}
}

View File

@@ -9,7 +9,6 @@ import com.czg.product.vo.ShopProductSkuInfoVo;
import com.czg.product.vo.ShopProductVo;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
import com.czg.utils.AssertUtil;
import com.czg.validator.ValidatorUtil;
import com.czg.validator.group.DefaultGroup;
@@ -24,7 +23,7 @@ import java.util.Map;
/**
* 店铺商品
* 用户端/店铺商品
*
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-02-16
@@ -34,7 +33,6 @@ import java.util.Map;
@RequestMapping("/user/product")
public class UProductController {
private final UProductService uProductService;
private final RedisService redisService;
/**
* 小程序点餐-热销商品列表

View File

@@ -0,0 +1,33 @@
package com.czg.service;
import com.alibaba.fastjson2.JSONObject;
import com.czg.product.dto.ProductDTO;
import com.czg.product.service.ProductService;
import com.czg.product.service.UProductService;
import com.czg.product.vo.ShopGroupProductVo;
import com.czg.product.vo.ShopProductVo;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
/**
* @author yjjie
* @date 2025/12/24 13:36
*/
@SpringBootTest
public class ProductTest {
@Resource
private ProductService productService;
@Resource
private UProductService uProductService;
@Test
public void testGetById() {
// ProductDTO product = productService.getProductById(169L);
// System.out.println(JSONObject.toJSONString( product));
}
}

View File

@@ -14,6 +14,8 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author GYJoker
@@ -94,18 +96,19 @@ public class VersionController {
@GetMapping(value = "/getCredentials")
public CzgResult<Object> getCredentials() {
try {
Map<String, String> ossKeyMap = paramsService.getParamsByMap("ossKeySet", ParamCodeCst.OSS_KEY_SET);
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
.setAccessKeyId(paramsService.getSysParamValue(ParamCodeCst.AliYun.ALI_OSS_ACCESS_KEY))
.setAccessKeyId(ossKeyMap.get(ParamCodeCst.AliYun.ALI_OSS_ACCESS_KEY))
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
.setAccessKeySecret(paramsService.getSysParamValue(ParamCodeCst.AliYun.ALI_OSS_ACCESS_SECRET));
.setAccessKeySecret(ossKeyMap.get(ParamCodeCst.AliYun.ALI_OSS_ACCESS_SECRET));
// Endpoint 请参考 https://api.aliyun.com/product/Sts
config.endpoint = paramsService.getSysParamValue(ParamCodeCst.AliYun.ALI_OSS_ENDPOINT);
config.endpoint = ossKeyMap.get(ParamCodeCst.AliYun.ALI_OSS_ENDPOINT);
com.aliyun.sts20150401.Client client = new com.aliyun.sts20150401.Client(config);
com.aliyun.sts20150401.models.AssumeRoleRequest assumeRoleRequest = new com.aliyun.sts20150401.models.AssumeRoleRequest();
assumeRoleRequest.setRoleArn(paramsService.getSysParamValue(ParamCodeCst.AliYun.ALI_OSS_ROLE_ARN));
assumeRoleRequest.setRoleArn(ossKeyMap.get(ParamCodeCst.AliYun.ALI_OSS_ROLE_ARN));
assumeRoleRequest.setRoleSessionName("test");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
// 复制代码运行请自行打印 API 的返回值

View File

@@ -26,6 +26,7 @@ public class FilteredNacosRegistry extends NacosRegistry {
"removeByMap",
"getByIdOpt",
"getOneOpt",
"getOneAs",
"getObjOpt",
"getObjAs",
"getObjAsOpt",

View File

@@ -133,6 +133,7 @@ public class RabbitPublisher {
/**
* 订单商品状态消息
* type bc 广播
*/
public void sendOrderDetailStatusMsg(String shopId, String type) {
sendMsg(RabbitConstants.Queue.ORDER_DETAIL_STATUS_QUEUE, JSONObject.toJSONString(Map.of(

View File

@@ -280,5 +280,9 @@ public class ShopInfoEditDTO {
* 上菜时间 分钟
*/
private Integer serveTime;
/**
* 数签子
*/
private Integer isCountStick;
}

View File

@@ -27,5 +27,6 @@ public class ShopUserDTO extends ShopUser {
private String memberLevelName;
private String nextMemberLevelName;
private Long nextExperience;
private Long pointBalance;
private boolean isNew;
}

View File

@@ -127,6 +127,10 @@ public class ShopConfig implements Serializable {
* 套餐推广 开关
*/
private Integer isPackagePromotion;
/**
* 数签子
*/
private Integer isCountStick;
private String dingAppKey;

View File

@@ -352,6 +352,11 @@ public class ShopInfo implements Serializable {
private Integer serveTime;
@Column(ignore = true)
private Integer isGroupBuy;
/**
* 数签子
*/
@Column(ignore = true)
private Integer isCountStick;
/**
* 运营端余额

View File

@@ -1,5 +1,7 @@
package com.czg.constants;
import java.util.Set;
/**
* 系统参数编码常量类
*
@@ -9,6 +11,65 @@ package com.czg.constants;
*/
public interface ParamCodeCst {
/**
* 用户小程序参数
*/
Set<String> USER_MINI_KEY_SET = Set.of(Wechat.Mini.USER_WX_APP_ID, Wechat.Mini.USER_WX_SECRETE);
/**
* 商家小程序参数
*/
Set<String> SHOP_MINI_KEY_SET = Set.of(Wechat.Mini.SHOP_WX_APP_ID, Wechat.Mini.SHOP_WX_SECRETE);
/**
* 商家公众号参数 推送 库存不足等消息
*/
Set<String> SHOP_AC_KEY_SET = Set.of(Wechat.Ac.SHOP_WX_AC_APP_ID, Wechat.Ac.SHOP_WX_AC_SECRETE);
/**
* 用户公众号参数 推送商家模板消息
*/
Set<String> USER_AC_KEY_SET = Set.of(Wechat.Ac.USER_WX_AC_APP_ID, Wechat.Ac.USER_WX_AC_SECRETE);
/**
* 微信支付参数KEY
*/
Set<String> PAY_KEY_SET = Set.of(
Wechat.Pay.WX_PUB_KEY,
Wechat.Pay.WX_API_CLIENT_KEY,
Wechat.Pay.WX_API_CLIENT_CERT,
Wechat.Pay.WX_MCH_ID,
Wechat.Pay.WX_V3_KEY,
System.NATIVE_NOTIFY_URL
);
/**
* 支付宝参数KEY
*/
Set<String> ALI_PAY_KEY_SET = Set.of(
Alipay.Web.ALI_GATEWAY,
Alipay.Mini.ALI_MINI_APP_ID,
Alipay.Mini.ALI_MINI_PRIVATE_KEY,
Alipay.Mini.ALI_MINI_PUBLIC_KEY,
Alipay.Web.ALI_ACCOUNT_APP_ID,
Alipay.Web.ALI_ACCOUNT_PRIVATE_KEY,
Alipay.Web.ALI_ACCOUNT_PUBLIC_KEY
);
/**
* 阿里云OSS参数KEY
*/
Set<String> ALI_OSS_KEY_SET = Set.of(
ParamCodeCst.AliYun.ALI_SMS_KEY,
ParamCodeCst.AliYun.ALI_SMS_SECRET,
ParamCodeCst.AliYun.ALI_SMS_TEMPLATE_CODE
);
/**
* 阿里云临时凭证
*/
Set<String> OSS_KEY_SET = Set.of(AliYun.ALI_OSS_ACCESS_KEY, AliYun.ALI_OSS_ACCESS_SECRET, AliYun.ALI_OSS_ENDPOINT, AliYun.ALI_OSS_ROLE_ARN);
/**
* 系统通用配置项
* <p>存放跨业务模块的通用系统配置</p>

View File

@@ -9,7 +9,7 @@ import com.czg.market.entity.MkConsumeCashback;
import java.math.BigDecimal;
/**
* 服务层。
* 服务层。
*
* @author zs
* @since 2025-10-13
@@ -21,11 +21,17 @@ public interface MkConsumeCashbackService extends IService<MkConsumeCashback> {
/**
* 消费返现
* @param shopId 店铺id
* @param userId 用户id
* @param amount 金额
*
* @param shopId 店铺id
* @param userId 用户id
* @param amount 金额
* @param orderId 订单id
* @param orderNo 订单号
*/
void cashback(Long shopId, Long userId, BigDecimal amount, Long orderId, String orderNo);
/**
* 订单退款 删除返现
*/
void removeCashback(Long shopId, Long userId, Long orderId, String orderNo);
}

View File

@@ -17,4 +17,9 @@ public interface MkPointsConfigService extends IService<MkPointsConfig> {
*
*/
void consumeAwardPoints(ShopUser shopUser, OrderInfo orderInfo);
/**
* 订单退款成功,通过计算 给用户赠送积分
*/
void removeConsumeAwardPoints(Long shopId, Long userId, Long orderId, String orderNo);
}

View File

@@ -29,9 +29,9 @@ public interface MkPointsUserService extends IService<MkPointsUser> {
* 获取用户积分信息
* 返回的数据ID可能为空 不影响修改用户积分 统一接口的处理
*
* @param shopId 店铺Id
* @param shopId 店铺Id
* @param shopUserId 店铺用户Id
* @param userId 会员Id
* @param userId 会员Id
*/
MkPointsUser getPointsUser(Long shopId, Long shopUserId, Long userId);
@@ -48,4 +48,9 @@ public interface MkPointsUserService extends IService<MkPointsUser> {
*/
Long alterPoints(Long userId, Long shopUserId, @NotNull Long shopId, @NotNull PointsConstant floatType,
@NotNull Integer points, Long sourceId, @NotBlank String reason);
/**
* 订单退款 赠送的积分 扣除
*/
void removePointByOrder(Long shopId, Long userId, Long orderId, String orderNo, String reason);
}

View File

@@ -22,6 +22,12 @@ public interface MkShopConsumerCouponService extends IService<MkShopConsumerCoup
*/
void receiveConsumerCoupon(Long shopId, Long orderId, BigDecimal orderAmount, Long userId, Long shopUserId);
/**
* 订单退款 移除消费赠券
*
*/
void removeConsumerCoupon(Long shopId, Long userId, Long orderId);
MkShopConsumerCouponDTO getConsumerCouponById(Long id);
void addConsumerCoupon(MkShopConsumerCouponDTO param);

View File

@@ -22,13 +22,19 @@ import java.util.List;
public interface MkShopRechargeService extends IService<MkShopRecharge> {
MkShopRechargeVO detail(Long shopId);
MkShopRechargeVO detailApp(Long shopId);
Boolean edit(Long shopId, MkShopRechargeDTO shopRechargeDTO);
BigDecimal checkRecharge(Long mainShopId, @NotNull(message = "店铺不能为空") Long shopId, Long userId, Long rechargeDetailId, @DecimalMin("0.01") BigDecimal money);
void recharge(Long shopId, Long shopUserId, Long rechargeDetailId, BigDecimal amount, Long paymentId, String payType, ShopUserFlowBizEnum bizEnum);
/**
* 充值
* @param isNoJoin 是否没有执行 加入会员的方法
* 会员如果是条件开通 则 需要统计
*/
void recharge(Long shopId, Long shopUserId, Long rechargeDetailId, BigDecimal amount, Long paymentId, String payType, ShopUserFlowBizEnum bizEnum, boolean isNoJoin);
List<RechargeListVO> getList(long loginIdAsLong);

View File

@@ -1,12 +1,14 @@
package com.czg.order.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 拼团参与 DTO
*
* @author ww
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class GroupJoinDTO extends LtPayOtherDTO{
/**

View File

@@ -1,20 +0,0 @@
package com.czg.order.dto;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.math.BigDecimal;
/**
* 积分商品兑换信息
*
* @author ww
*/
@Data
public class PointGoodsExchangeDTO extends LtPayOtherDTO{
/**
* 积分商品id
*/
@NotNull(message = "积分商品不能为空")
private Long pointsGoodsId;
}

View File

@@ -3,6 +3,8 @@ package com.czg.order.service;
import com.mybatisflex.core.service.IService;
import com.czg.order.entity.OrderPayment;
import java.math.BigDecimal;
/**
* 支付详情 服务层。
*
@@ -11,4 +13,5 @@ import com.czg.order.entity.OrderPayment;
*/
public interface OrderPaymentService extends IService<OrderPayment> {
BigDecimal countMemberInAmount(Long shopId, Long shopUserId);
}

View File

@@ -1,12 +1,15 @@
package com.czg.product.dto;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.annotation.JSONField;
import com.czg.product.vo.ProductGroupVo;
import com.czg.validator.group.DefaultGroup;
import com.czg.validator.group.InsertGroup;
import com.czg.validator.group.UpdateGroup;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.validation.constraints.*;
import lombok.Data;
@@ -235,6 +238,12 @@ public class ProductDTO implements Serializable {
* 是否可售时间 1-是 0-否
*/
private Integer isSaleTime;
/**
* 相关推荐商品
*/
private List<RelatedProductDTO> relatedRecommendJson;
@JsonIgnore
private String relatedRecommend;
public Object getImages() {
return JSON.parseArray(Convert.toStr(images, "[]"));
@@ -250,4 +259,16 @@ public class ProductDTO implements Serializable {
public Object getGroupSnap() {
return JSON.parseArray(Convert.toStr(groupSnap, "[]"));
}
public String getRelatedRecommendStr() {
if (CollUtil.isNotEmpty(relatedRecommendJson)) {
JSONArray array = new JSONArray();
for (RelatedProductDTO relatedProductDTO : relatedRecommendJson) {
array.add(relatedProductDTO.getId());
}
return array.toJSONString();
}
return "[]";
}
}

View File

@@ -0,0 +1,31 @@
package com.czg.product.dto;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* 相关推荐 商品 DTO
*
* @author yjjie
* @date 2025/12/24 13:34
*/
@Data
public class RelatedProductDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 商品 ID
*/
private Long id;
/**
* 商品名称
*/
private String name;
/**
* 商品图片
*/
private String coverImg;
}

View File

@@ -0,0 +1,58 @@
package com.czg.product.entity;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 数签子的外链渠道 实体类。
*
* @author ww
* @since 2025-12-24
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("mk_ocr_count_stick")
public class MkOcrCountStick implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Id
private Long id;
/**
* 渠道名称
*/
private String name;
/**
* 标记
*/
private String mark;
/**
* 地址
*/
private String url;
/**
* 状态 0/1
*/
private Integer status;
private Integer sort;
private String token;
private String account;
private String pwd;
}

View File

@@ -1,8 +1,11 @@
package com.czg.product.entity;
import com.czg.product.param.ConsInOutStockHeadParam;
import com.mybatisflex.core.service.IService;
import com.czg.market.entity.MkOcr;
import java.io.InputStream;
/**
* ocr识别结果 服务层。
*
@@ -11,4 +14,7 @@ import com.czg.market.entity.MkOcr;
*/
public interface MkOcrService extends IService<MkOcr> {
ConsInOutStockHeadParam ocrDetail(Long id);
Integer ocr(String originalFilename, InputStream inputStream, String type);
}

View File

@@ -142,6 +142,10 @@ public class Product implements Serializable {
* 退款是否退回库存
*/
private Integer isRefundStock;
/**
* 相关推荐
*/
private String relatedRecommend;
/**
* 创建时间
*/

View File

@@ -10,7 +10,6 @@ import com.czg.product.vo.ConsCheckStockRecordVo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
import java.io.InputStream;
import java.util.List;
/**
@@ -25,7 +24,6 @@ public interface ConsStockFlowService extends IService<ConsStockFlow> {
* 手动入库
*
* @param param 手动出库入参
* @return
*/
ConsInOutStockHeadParam inStock(ConsInOutStockHeadParam param);
@@ -78,8 +76,4 @@ public interface ConsStockFlowService extends IService<ConsStockFlow> {
* @param entity 库存变动记录实体
*/
void saveFlow(ConsStockFlow entity);
Integer ocr(String originalFilename, InputStream inputStream);
ConsInOutStockHeadParam ocrDetail(Long id);
}

View File

@@ -0,0 +1,15 @@
package com.czg.product.service;
import com.czg.product.entity.MkOcrCountStick;
import com.mybatisflex.core.service.IService;
/**
* 数签子的外链渠道 服务层。
*
* @author ww
* @since 2025-12-24
*/
public interface MkOcrCountStickService extends IService<MkOcrCountStick> {
int getCountStick(byte[] stream, String fileName);
}

View File

@@ -1,6 +1,7 @@
package com.czg.product.service;
import com.czg.product.dto.ProductDTO;
import com.czg.product.dto.RelatedProductDTO;
import com.czg.product.entity.Product;
import com.czg.product.entity.ProductStockFlow;
import com.czg.product.param.*;

View File

@@ -3,12 +3,14 @@ package com.czg.product.vo;
import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalTime;
import java.util.List;
/**
* 商品规格详情
@@ -109,6 +111,12 @@ public class ShopProductInfoVo implements Serializable {
*/
@JSONField(serialize = false)
private LocalTime endTime;
/**
* 相关推荐商品
*/
private List<ShopProductVo> relatedRecommendJson;
@JsonIgnore
private String relatedRecommend;
public Object getImages() {
return JSON.parseArray(Convert.toStr(images, "[]"));

View File

@@ -72,9 +72,7 @@ public interface SysParamsService extends IService<SysParams> {
* dubbo 调用需要 显式抛出 异常类型
*
* @param type 参数类型
* userMiniKeys 用户小程序参数 appId appSecret
* shopMiniKeys 商家小程序参数 appId appSecret
* payKeys 微信支付参数
* @param keyList 内容为 {@link com.czg.constants.ParamCodeCst}的Set集合
*/
Map<String, String> getParamsByMap(String type, Set<String> keyList) throws CzgException;
}

View File

@@ -11,6 +11,8 @@ public enum ShopUserFlowBizEnum {
// 会员充值
CASH_IN("cashIn", "会员充值"),
CASHBACK("cashback", "消费返现"),
CASHBACK_REFUND("cashback_refund", "消费返现扣减"),
FREE_IN("freeIn", "霸王餐充值"),
// 重置奖励
AWARD_IN("awardIn", "充值奖励"),

View File

@@ -16,9 +16,6 @@ import com.czg.exception.CzgException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.io.DataOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;
@@ -35,9 +32,8 @@ public class AliOcrUtil {
/**
* <b>description</b> :
* <p>使用凭据初始化账号Client</p>
* @return Client
*
* @throws Exception
* @return Client
*/
public static com.aliyun.bailian20231229.Client createClient() {
@@ -56,7 +52,6 @@ public class AliOcrUtil {
}
public static ApplyFileUploadLeaseResponseBody.ApplyFileUploadLeaseResponseBodyData applyFileUpload(byte[] bytes, String fileName) {
String md5 = DigestUtil.md5Hex(bytes);
@@ -95,7 +90,7 @@ public class AliOcrUtil {
.setCategoryId("default")
.setCategoryType("SESSION_FILE");
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
java.util.Map<String, String> headers = new java.util.HashMap<>();
java.util.Map<String, String> headers = new java.util.HashMap<>();
try {
// 复制代码运行请自行打印 API 的返回值
AddFileResponse addFileResponse = client.addFileWithOptions("llm-9zg04s7wlbvi32tq", addFileRequest, headers, runtime);
@@ -110,7 +105,7 @@ public class AliOcrUtil {
}
}
public static boolean getFileStatus(String fileId) {
public static boolean getFileStatus(String fileId) {
com.aliyun.bailian20231229.Client client = createClient();
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
java.util.Map<String, String> headers = new java.util.HashMap<>();
@@ -118,7 +113,7 @@ public class AliOcrUtil {
// 复制代码运行请自行打印 API 的返回值
DescribeFileResponse describeFileResponse = client.describeFileWithOptions("llm-9zg04s7wlbvi32tq", fileId, headers, runtime);
log.info("file status: {}", describeFileResponse.getBody());
log.info("file status: {}", describeFileResponse.getStatusCode());
return describeFileResponse.getBody().getData() != null && "FILE_IS_READY".equals(describeFileResponse.getBody().getData().getStatus());
} catch (Exception error) {
throw new RuntimeException(error);
@@ -158,18 +153,18 @@ public class AliOcrUtil {
}
public static String appCall(byte[] bytes, String fileName) {
String id = null;
//地址 https://bailian.console.aliyun.com
public static String appCall(byte[] bytes, String fileName, String detail) {
String id;
try {
id = getSessionId(bytes, fileName);
} catch (Exception e) {
throw new RuntimeException(e);
}
ApplicationParam param = ApplicationParam.builder()
ApplicationParam param = ApplicationParam.builder()
.apiKey("sk-2343af4413834ad1ab43b036e3a903de")
.appId("cd612ac509a4499f8ac68a656532d4ae")
.prompt("你是一名票据OCR结构化专家请从我提供的票据图片中智能提取信息并只输出JSON不得添加解释、不补充不存在内容、不得返回空字符串、字段缺失填null、字段不可省略、数字一律用字符串使用以下固定JSON结构{\"documentType\":\"\",\"orderNumber\":\"\",\"date\":\"\",\"customerName\":\"\",\"operator\":\"\",\"items\":[{\"conName\":\"\",\"spec\":\"\",\"unitName\":\"\",\"inOutNumber\":\"\",\"purchasePrice\":\"\",\"subTotal\":\"\"}],\"totalAmount\":\"\",\"remark\":\"\"}。字段映射规则documentType对应单据类型/销售单/采购单/出货单orderNumber对应单号/编号/Nodate对应日期/开单日期customerName对应客户名称/收货单位/供应商operator对应业务员/经办人/制单人/操作员items.conName对应品名/名称items.spec对应规格/型号items.unitName对应单位items.inOutNumber对应数量items.purchasePrice对应单价items.subTotal对应金额/小计totalAmount对应总金额/合计金额remark对应备注。严禁生成图片中不存在的字段内容看不清或未出现的字段必须为null不允许推测或补全不得生成多余字段items只能根据识别到的行生成不得虚构。必须能识别旋转、倾斜、模糊、撕裂、光照差异、列顺序混乱、无表格线等情况并尽量恢复信息。最终输出必须是纯JSON不得包含任何非JSON字符。")
.prompt(detail)
.ragOptions(RagOptions.builder()
.sessionFileIds(List.of(id))
.build())
@@ -187,11 +182,4 @@ public class AliOcrUtil {
return result.getOutput().getText();
}
public static void main(String[] args) {
}
static void main() throws Exception {
}
}

View File

@@ -2,9 +2,12 @@ package com.czg.utils;
import cn.hutool.core.lang.func.Func0;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.function.Consumer;
/**
* @author zs
*/
@Slf4j
public class FunUtils {
/**
@@ -38,4 +41,27 @@ public class FunUtils {
log.error(errorMsg, args, e);
}
}
/**
* 在事务提交后执行方法
* 异步 执行
*
* @param func 方法
*/
public static void transactionSafeRun(Runnable func) {
try {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
safeRunVoid(func, "");
}
});
} else {
safeRunVoid(func, "");
}
} catch (Exception e) {
log.error("方法执行失败: {}", e.getMessage());
}
}
}

View File

@@ -62,6 +62,15 @@ public class PageUtil {
return new Page<>(pageNum, pageSize);
}
/**
* 获取空Page对象
*/
public <T> Page<T> emptyPage() {
return Page.of(1,10,0) ;
}
/**
* 构造排序QueryWrapper
* 从param体获取

View File

@@ -22,7 +22,6 @@ import com.czg.market.vo.MemberConfigVO;
import com.czg.order.entity.OrderInfo;
import com.czg.sa.StpKit;
import com.czg.service.account.mapper.ShopUserMapper;
import com.czg.system.service.SysParamsService;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
@@ -35,7 +34,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.List;
@@ -57,8 +55,6 @@ public class AShopUserServiceImpl implements AShopUserService {
@Resource
private UserInfoService userInfoService;
@DubboReference
private SysParamsService sysParamsService;
@DubboReference
private OrderInfoService orderInfoService;
@DubboReference
private MkShopCouponRecordService couponRecordService;
@@ -66,8 +62,6 @@ public class AShopUserServiceImpl implements AShopUserService {
private MemberLevelConfigService memberLevelConfigService;
@DubboReference
private TbMemberConfigService memberConfigService;
// @DubboReference
// private MkShopConsumeDiscountRecordService consumeDiscountService;
private ShopUser getUserInfo(Long shopUserId) {
ShopUser shopUser = shopUserService.queryChain().eq(ShopUser::getId, shopUserId).one();
@@ -94,12 +88,8 @@ public class AShopUserServiceImpl implements AShopUserService {
public Page<ShopUserDTO> getPage(String key, Integer isVip, BigDecimal amount) {
Long mainIdByShopId = shopInfoService.getMainIdByShopId(StpKit.USER.getShopId());
PageHelper.startPage(PageUtil.buildPageHelp());
PageInfo<ShopUserDTO> shopUserDTOPageInfo = new PageInfo<>(shopUserMapper.selectPageByKeyAndIsVip(mainIdByShopId, isVip, key, amount));
// shopUserDTOPageInfo.getList().forEach(item -> {
// item.setNew(consumeDiscountService.isNewUser(item, StpKit.USER.getShopId()));
// setUserDiscount(item);
// });
return PageUtil.convert(shopUserDTOPageInfo);
PageInfo<ShopUserDTO> shopUsers = new PageInfo<>(shopUserMapper.selectPageByKeyAndIsVip(mainIdByShopId, isVip, key, amount));
return PageUtil.convert(shopUsers);
}
@Override
@@ -177,16 +167,6 @@ public class AShopUserServiceImpl implements AShopUserService {
return shopUserService.save(shopUser);
}
private void setUserDiscount(ShopUserDTO shopUserDTO) {
if (shopUserDTO.getMemberLevelId() != null) {
MemberLevelConfig memberLevelConfig = memberLevelConfigService.getById(shopUserDTO.getMemberLevelId());
shopUserDTO.setMemberLevelName(memberLevelConfig == null ? null : memberLevelConfig.getName());
if (memberLevelConfig != null) {
shopUserDTO.setDiscount(memberLevelConfig.getDiscount());
}
}
}
@Override
public ShopUser getDetail(Integer id, Integer userId) {
Long mainId = shopInfoService.getMainIdByShopId(StpKit.USER.getShopId());

View File

@@ -473,7 +473,7 @@ public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable
} else {
List<CallTable> list = queryChain().eq(CallTable::getShopId, shopId).eq(CallTable::getState, 1).list();
if (list.isEmpty()) {
return new Page<>();
return PageUtil.emptyPage();
}
tableIds = list.stream()
.map(CallTable::getId)

View File

@@ -1,16 +1,13 @@
package com.czg.service.account.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.czg.account.dto.ShopConfigDTO;
import com.czg.account.entity.ShopConfig;
import com.czg.account.entity.ShopInfo;
import com.czg.account.service.ShopConfigService;
import com.czg.exception.CzgException;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
import com.czg.service.account.mapper.ShopConfigMapper;
import com.czg.service.account.mapper.ShopInfoMapper;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
@@ -90,19 +87,10 @@ public class ShopConfigServiceImpl extends ServiceImpl<ShopConfigMapper, ShopCon
});
if (isEnable == 0 && !onyUpValid) {
updateChain().or(or -> {
or.eq(ShopConfig::getId, mainShopId);
}).or(or -> {
or.in(ShopConfig::getId, childShopIdList);
}).set(property, 0).update();
updateChain().in(ShopConfig::getId, childShopIdList).set(property, 0).update();
}else {
if ("all".equals(useShopType)) {
updateChain().or(or -> {
or.eq(ShopConfig::getId, mainShopId);
}).or(or -> {
or.in(ShopConfig::getId, childShopIdList);
}).set(property, 1).update();
updateChain().in(ShopConfig::getId, childShopIdList).set(property, 1).update();
}else {
if (shopIdList.isEmpty()) {
updateChain().eq(ShopConfig::getId, mainShopId).set(property, 1).update();
@@ -115,7 +103,6 @@ public class ShopConfigServiceImpl extends ServiceImpl<ShopConfigMapper, ShopCon
}
}
extistList.forEach(item -> redisService.del("shopInfo::" + item));
redisService.del("shopInfo::" + mainShopId);
}

View File

@@ -152,9 +152,6 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
// Step 2: 解析 apiInfo 并判断菜单是否已绑定
for (BaseMenu menu : menuList) {
if (menu.getMenuId() == 1L) {
continue;
}
// 解析 apiInfo
if (StrUtil.isNotBlank(menu.getApiInfo())) {
List<MenuApiInfoItemDTO> itemDTOS = JSONArray.parseArray(menu.getApiInfo())
@@ -180,9 +177,6 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
List<SysMenu> matchedMenus = sysMenuService.list(wrapper);
for (SysMenu matched : matchedMenus) {
if (matched.getMenuId() == 1L) {
continue;
}
long count = sysRolesMenusService.count(new QueryWrapper()
.eq("menu_id", matched.getMenuId())
.eq("role_id", roleId)

View File

@@ -6,7 +6,6 @@ import com.alibaba.fastjson2.JSONObject;
import com.czg.account.dto.auth.GetPhoneDTO;
import com.czg.account.dto.auth.LoginTokenDTO;
import com.czg.account.dto.auth.UserAuthorizationLoginDTO;
import com.czg.account.dto.auth.WechatRawDataDTO;
import com.czg.account.entity.UserInfo;
import com.czg.account.service.UserAuthorizationService;
import com.czg.account.service.UserInfoService;
@@ -95,19 +94,13 @@ public class UserAuthorizationServiceImpl implements UserAuthorizationService {
openId = wechatAuthUtil.getSessionKeyOrOpenId(userAuthorizationLoginDTO.getCode(), false);
userInfo = userInfoService.queryChain().eq(UserInfo::getWechatOpenId, openId).one();
userInfo = userInfo == null ? new UserInfo() : userInfo;
if (StrUtil.isNotBlank(userAuthorizationLoginDTO.getRawData())) {
WechatRawDataDTO wechatRawDataDTO = JSONObject.parseObject(userAuthorizationLoginDTO.getRawData(), WechatRawDataDTO.class);
userInfo.setHeadImg(wechatRawDataDTO.getAvatarUrl());
userInfo.setNickName(StrUtil.isNotBlank(wechatRawDataDTO.getNickName()) ? wechatRawDataDTO.getNickName() : "微信用户");
} else {
userInfo.setNickName("微信用户");
}
userInfo.setNickName(StrUtil.isNotBlank(userInfo.getNickName()) ? userInfo.getNickName() : "微信用户");
userInfo.setWechatOpenId(openId);
} else {
openId = alipayUtil.getOpenId(userAuthorizationLoginDTO.getCode(), false);
userInfo = userInfoService.queryChain().eq(UserInfo::getAlipayOpenId, openId).one();
userInfo = userInfo == null ? new UserInfo() : userInfo;
userInfo.setNickName("支付宝用户");
userInfo.setNickName(StrUtil.isNotBlank(userInfo.getNickName()) ? userInfo.getNickName() : "支付宝用户");
userInfo.setAlipayOpenId(openId);
}

View File

@@ -10,6 +10,7 @@ import com.czg.account.dto.user.userinfo.UserInfoEditDTO;
import com.czg.account.dto.user.userinfo.UserInfoPwdEditDTO;
import com.czg.account.entity.ShopUser;
import com.czg.account.entity.UserInfo;
import com.czg.account.service.ShopInfoService;
import com.czg.account.service.UserInfoService;
import com.czg.config.RedisCst;
import com.czg.exception.CzgException;
@@ -38,6 +39,8 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
@Resource
private ShopUserMapper shopUserMapper;
@Resource
private ShopInfoService shopInfoService;
@Resource
private RedisService redisService;
@Resource
private AcAccountUtil acAccountUtil;
@@ -62,9 +65,10 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
UserInfo userInfo = getById(userId);
BeanUtil.copyProperties(userInfoEditDTO, userInfo);
if (updateById(userInfo)) {
if (shopId != -1L) {
if (shopId != 0L) {
ShopUser shopUser = BeanUtil.copyProperties(userInfo, ShopUser.class);
return shopUserMapper.updateByQuery(shopUser, new QueryWrapper().eq(ShopUser::getSourceShopId, shopId).eq(ShopUser::getUserId, userId)) > 0;
Long mainIdByShopId = shopInfoService.getMainIdByShopId(shopId);
return shopUserMapper.updateByQuery(shopUser, new QueryWrapper().eq(ShopUser::getMainShopId, mainIdByShopId).eq(ShopUser::getUserId, userId)) > 0;
}
return true;
}

View File

@@ -15,6 +15,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 微信公众号
@@ -90,8 +91,10 @@ public class AcAccountUtil {
if (StrUtil.isNotEmpty(accessToken)) {
return accessToken;
}
String acAppId = paramsService.getSysParamValue(ParamCodeCst.Wechat.Ac.USER_WX_AC_APP_ID);
String acSecrete = paramsService.getSysParamValue(ParamCodeCst.Wechat.Ac.USER_WX_AC_SECRETE);
Map<String, String> userAc = paramsService.getParamsByMap("user_ac_key_set", ParamCodeCst.USER_AC_KEY_SET);
// 用户小程序参数
String acAppId = userAc.get(ParamCodeCst.Wechat.Ac.USER_WX_AC_APP_ID);
String acSecrete = userAc.get(ParamCodeCst.Wechat.Ac.USER_WX_AC_SECRETE);
String resp = HttpUtil.get(StrUtil.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}", acAppId, acSecrete));
JSONObject respInfo = JSONObject.parseObject(resp);
if (!respInfo.containsKey("access_token")) {
@@ -103,26 +106,4 @@ public class AcAccountUtil {
redisService.set("wx:ac:AccessToken", accessToken, expiresIn - 10);
return accessToken;
}
public static void main(String[] args) {
// String resp = HttpUtil.get(StrUtil.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}", "wx1fb600d0f5ea6279", "b4c0534c9b5e6c84a7fe5c2078dff876"));
// System.out.println(resp);
// String accessToken = "97_HZVThQrtvOiCZGrr23ZHN0cVpHBJHc18RSFHU6dvkQDMAme4GsG0NU-Dax1HP5Wx-aGa1l35KaqiMVv61TCj0Qk8DK1LC6kQ8uKLDfgRYVJjX3QjcelmIjp4PCkERBeABAUHR";
// JSONObject bodyJson = new JSONObject();
// //二维码有效时间最大2592000仅临时二维码需要
// bodyJson.put("expire_seconds", "2592000");
// //二维码类型QR_SCENE(临时整型)/QR_STR_SCENE(临时字符串)/QR_LIMIT_SCENE(永久整型)/QR_LIMIT_STR_SCENE(永久字符串)
// bodyJson.put("action_name", "QR_STR_SCENE");
// JSONObject actionInfo = new JSONObject();
// JSONObject scene = new JSONObject();
// scene.put("scene_str", "43525423");
// actionInfo.put("scene", scene);
// bodyJson.put("action_info", actionInfo);
// System.out.println(bodyJson);
//创建临时二维码失败,发送参数: {"action_info":{"scene":{"scene_id":36449}},"action_name":"QR_SCENE","expire_seconds":"2592000"}, 响应内容: {"errcode":40052,"errmsg":"invalid action name rid: 68f5fa37-20fb3162-0f87b4f2"}
//创建临时二维码失败,发送参数: {"action_info":{"scene":{"scene_id":36449}},"action_name":"QR_SCENE","expire_seconds":"2592000"}, 响应内容: {"errcode":40052,"errmsg":"invalid action name rid: 68f5f970-2a84749c-78e4d78f"}
// String resps = HttpUtil.post(StrUtil.format("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={}", accessToken), JSONObject.toJSONString(bodyJson));
// JSONObject respInfos = JSONObject.parseObject(resps);
// System.out.println(respInfos);
}
}

View File

@@ -17,6 +17,9 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Set;
/**
* 支付宝通用SDK工具类
*
@@ -37,13 +40,15 @@ public class AlipayUtil {
*/
@SneakyThrows
public AlipayClient createClient(boolean isAccount) {
String serverUrl = sysParamsService.getSysParamValue(ParamCodeCst.Alipay.Web.ALI_GATEWAY);
String appId = sysParamsService.getSysParamValue(ParamCodeCst.Alipay.Mini.ALI_MINI_APP_ID);
String privateKey = sysParamsService.getSysParamValue(ParamCodeCst.Alipay.Mini.ALI_MINI_PRIVATE_KEY);
String alipayPublicKey = sysParamsService.getSysParamValue(ParamCodeCst.Alipay.Mini.ALI_MINI_PUBLIC_KEY);
String accountAppId = sysParamsService.getSysParamValue(ParamCodeCst.Alipay.Web.ALI_ACCOUNT_APP_ID);
String accountPrivateKey = sysParamsService.getSysParamValue(ParamCodeCst.Alipay.Web.ALI_ACCOUNT_PRIVATE_KEY);
String accountPublicKey = sysParamsService.getSysParamValue(ParamCodeCst.Alipay.Web.ALI_ACCOUNT_PUBLIC_KEY);
Map<String, String> aliPayKeySet = sysParamsService.getParamsByMap("ali_pay_key_set", ParamCodeCst.ALI_PAY_KEY_SET);
String serverUrl = aliPayKeySet.get(ParamCodeCst.Alipay.Web.ALI_GATEWAY);
String appId = aliPayKeySet.get(ParamCodeCst.Alipay.Mini.ALI_MINI_APP_ID);
String privateKey = aliPayKeySet.get(ParamCodeCst.Alipay.Mini.ALI_MINI_PRIVATE_KEY);
String alipayPublicKey = aliPayKeySet.get(ParamCodeCst.Alipay.Mini.ALI_MINI_PUBLIC_KEY);
String accountAppId = aliPayKeySet.get(ParamCodeCst.Alipay.Web.ALI_ACCOUNT_APP_ID);
String accountPrivateKey = aliPayKeySet.get(ParamCodeCst.Alipay.Web.ALI_ACCOUNT_PRIVATE_KEY);
String accountPublicKey = aliPayKeySet.get(ParamCodeCst.Alipay.Web.ALI_ACCOUNT_PUBLIC_KEY);
AlipayConfig alipayConfig = new AlipayConfig();
//设置网关地址
alipayConfig.setServerUrl(serverUrl);

View File

@@ -56,8 +56,9 @@ public class WechatAuthUtil {
}
public String getAccountOpenId(String code) {
String accountAppId = sysParamsService.getSysParamValue(ParamCodeCst.Wechat.Ac.SHOP_WX_AC_APP_ID);
String accountSecrete = sysParamsService.getSysParamValue(ParamCodeCst.Wechat.Ac.SHOP_WX_AC_SECRETE);
Map<String, String> shopAc = sysParamsService.getParamsByMap("shop_ac_key_set", ParamCodeCst.SHOP_AC_KEY_SET);
String accountAppId = shopAc.get(ParamCodeCst.Wechat.Ac.SHOP_WX_AC_APP_ID);
String accountSecrete = shopAc.get(ParamCodeCst.Wechat.Ac.SHOP_WX_AC_SECRETE);
String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?";
Map<String, Object> requestUrlParam = new HashMap<>();
// https://mp.weixin.qq.com/wxopen/devprofile?action=get_profile&token=164113089&lang=zh_CN
@@ -78,8 +79,10 @@ public class WechatAuthUtil {
//获取小程序token
private String getAccessToken() {
String appId = sysParamsService.getSysParamValue(ParamCodeCst.Wechat.Mini.USER_WX_APP_ID);
String secrete = sysParamsService.getSysParamValue(ParamCodeCst.Wechat.Mini.USER_WX_SECRETE);
Map<String, String> userMini = sysParamsService.getParamsByMap("user_mini_key_set", ParamCodeCst.USER_MINI_KEY_SET);
// 用户小程序参数
String appId = userMini.get(ParamCodeCst.Wechat.Mini.USER_WX_APP_ID);
String secrete = userMini.get(ParamCodeCst.Wechat.Mini.USER_WX_SECRETE);
String url = String.format("%s?grant_type=client_credential&appid=%s&secret=%s", TOKEN_URL, appId, secrete);
String response = HttpUtil.get(url);
com.alibaba.fastjson.JSONObject jsonResponse = com.alibaba.fastjson.JSONObject.parseObject(response);
@@ -120,8 +123,11 @@ public class WechatAuthUtil {
public JSONObject getSession(String code) {
String appId = sysParamsService.getSysParamValue(ParamCodeCst.Wechat.Mini.USER_WX_APP_ID);
String secrete = sysParamsService.getSysParamValue(ParamCodeCst.Wechat.Mini.USER_WX_SECRETE);
Map<String, String> userMini = sysParamsService.getParamsByMap("user_mini_key_set", ParamCodeCst.USER_MINI_KEY_SET);
// 用户小程序参数
String appId = userMini.get(ParamCodeCst.Wechat.Mini.USER_WX_APP_ID);
String secrete = userMini.get(ParamCodeCst.Wechat.Mini.USER_WX_SECRETE);
String requestUrl = "https://api.weixin.qq.com/sns/jscode2session";
Map<String, Object> requestUrlParam = new HashMap<>();
// https://mp.weixin.qq.com/wxopen/devprofile?action=get_profile&token=164113089&lang=zh_CN

View File

@@ -139,8 +139,9 @@ public class WechatMiniMsgUtil {
}
public String getAccountOpenId(String code) {
String accountAppId = sysParamsService.getSysParamValue(ParamCodeCst.Wechat.Ac.SHOP_WX_AC_APP_ID);
String accountSecrete = sysParamsService.getSysParamValue(ParamCodeCst.Wechat.Ac.SHOP_WX_AC_SECRETE);
Map<String, String> shopAc = sysParamsService.getParamsByMap("shop_ac_key_set", ParamCodeCst.SHOP_AC_KEY_SET);
String accountAppId = shopAc.get(ParamCodeCst.Wechat.Ac.SHOP_WX_AC_APP_ID);
String accountSecrete = shopAc.get(ParamCodeCst.Wechat.Ac.SHOP_WX_AC_SECRETE);
String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?";
Map<String, Object> requestUrlParam = new HashMap<>();
// https://mp.weixin.qq.com/wxopen/devprofile?action=get_profile&token=164113089&lang=zh_CN
@@ -165,8 +166,10 @@ public class WechatMiniMsgUtil {
if (StrUtil.isNotEmpty(accessToken)) {
return accessToken;
}
String appId = sysParamsService.getSysParamValue(ParamCodeCst.Wechat.Mini.SHOP_WX_APP_ID);
String secrete = sysParamsService.getSysParamValue(ParamCodeCst.Wechat.Mini.SHOP_WX_SECRETE);
// 商户小程序参数
Map<String, String> shopMiniKeyMap = sysParamsService.getParamsByMap("shop_mini_key_set", ParamCodeCst.SHOP_MINI_KEY_SET);
String appId = shopMiniKeyMap.get(ParamCodeCst.Wechat.Mini.SHOP_WX_APP_ID);
String secrete = shopMiniKeyMap.get(ParamCodeCst.Wechat.Mini.SHOP_WX_SECRETE);
String url = String.format("%s?grant_type=client_credential&appid=%s&secret=%s", TOKEN_URL, appId, secrete);
String response = HttpUtil.get(url);
@@ -211,8 +214,10 @@ public class WechatMiniMsgUtil {
public JSONObject getSession(String code) {
String appId = sysParamsService.getSysParamValue(ParamCodeCst.Wechat.Mini.USER_WX_APP_ID);
String secrete = sysParamsService.getSysParamValue(ParamCodeCst.Wechat.Mini.USER_WX_SECRETE);
Map<String, String> userMini = sysParamsService.getParamsByMap("user_mini_key_set", ParamCodeCst.USER_MINI_KEY_SET);
// 用户小程序参数
String appId = userMini.get(ParamCodeCst.Wechat.Mini.USER_WX_APP_ID);
String secrete = userMini.get(ParamCodeCst.Wechat.Mini.USER_WX_SECRETE);
String requestUrl = "https://api.weixin.qq.com/sns/jscode2session";
Map<String, Object> requestUrlParam = new HashMap<>();
// https://mp.weixin.qq.com/wxopen/devprofile?action=get_profile&token=164113089&lang=zh_CN

View File

@@ -5,7 +5,7 @@
<mapper namespace="com.czg.service.account.mapper.ShopUserMapper">
<update id="incrAccount">
update tb_shop_user
set amount = COALESCE(amount, 0) + #{money},
set amount = amount + #{money},
update_time = #{time}
where id = #{id}
@@ -44,7 +44,7 @@
</select>
<select id="selectVipCard" resultType="com.czg.account.dto.shopuser.ShopUserVipCardDTO">
select tb_shop_info.logo, tb_shop_info.shop_name shopName, tb_shop_user.amount, tb_shop_user.shop_id shopId
select tb_shop_info.logo, tb_shop_info.shop_name shopName, tb_shop_user.amount, tb_shop_user.main_shop_id shopId
from tb_shop_user
left join tb_shop_info on tb_shop_user.main_shop_id = tb_shop_info.id
${qwSql}
@@ -72,41 +72,20 @@
IFNULL(c.couponNum, 0) AS couponNum,
IFNULL(d.orderNumber, 0) AS orderNumber,
IFNULL(f.rechargeAmount, 0) AS rechargeAmount,
c.name as memberLevelName,
c.discount
point.point_balance as pointBalance,
c1.name as memberLevelName,
c1.discount
FROM tb_shop_user a
LEFT JOIN tb_user_info b ON b.id = a.user_id
LEFT JOIN tb_member_level_config c on c.id=a.member_level_id
LEFT JOIN tb_member_level_config c1 on c1.id=a.member_level_id
LEFT JOIN mk_points_user point on point.shop_user_id = a.id
-- 预计算优惠券数量
LEFT JOIN (
SELECT shop_user_id, COUNT(*) AS couponNum
FROM mk_shop_coupon_record
WHERE
is_del = 0
# AND status = 0
# AND use_start_time &lt; NOW()
# AND use_end_time > NOW()
GROUP BY shop_user_id
) c ON c.shop_user_id = a.id
LEFT JOIN (SELECT shop_user_id, COUNT(*) AS couponNum FROM mk_shop_coupon_record WHERE is_del = 0 GROUP BY shop_user_id ) c ON c.shop_user_id = a.id
-- 预计算订单数量
LEFT JOIN (
SELECT user_id, shop_id, COUNT(*) AS orderNumber
FROM tb_order_info
GROUP BY user_id, shop_id
) d ON d.user_id = a.user_id AND d.shop_id = a.main_shop_id
LEFT JOIN (SELECT user_id, shop_id, COUNT(*) AS orderNumber FROM tb_order_info GROUP BY user_id, shop_id) d ON d.user_id = a.user_id AND d.shop_id = a.main_shop_id
-- 预计算充值总金额
LEFT JOIN (
SELECT user_id, shop_id, SUM(amount) AS rechargeAmount
FROM tb_shop_user_flow
WHERE biz_code IN ('cashIn', 'wechatIn', 'alipayIn')
GROUP BY user_id, shop_id
) f ON f.user_id = a.user_id AND f.shop_id = a.main_shop_id
LEFT JOIN ( SELECT user_id, shop_id, SUM(amount) AS rechargeAmount
FROM tb_shop_user_flow WHERE biz_code IN ('cashIn', 'wechatIn', 'alipayIn') GROUP BY user_id, shop_id ) f ON f.user_id = a.user_id AND f.shop_id = a.main_shop_id
WHERE a.main_shop_id = #{shopId}
<if test="isVip != null">
AND a.is_vip = #{isVip}
</if>

View File

@@ -28,8 +28,6 @@ public class AppWxServiceImpl extends BaseWx {
@DubboReference
private SysParamsService paramsService;
private static final Set<String> USER_MINI_KEYS = Set.of(ParamCodeCst.Wechat.Mini.USER_WX_APP_ID, ParamCodeCst.Wechat.Mini.USER_WX_SECRETE);
public AppWxServiceImpl(@Autowired RedisService autoRedisService) {
this.redisService = autoRedisService;
config = new Config();
@@ -64,10 +62,10 @@ public class AppWxServiceImpl extends BaseWx {
@Override
public void init() throws CzgException {
// 用户小程序参数
Map<String, String> userMiniKeyMap = paramsService.getParamsByMap("userMiniKeys", USER_MINI_KEYS);
Map<String, String> userMiniKeyMap = paramsService.getParamsByMap("user_mini_key_set", ParamCodeCst.USER_MINI_KEY_SET);
// 微信支付参数
Map<String, String> payKeyMap = paramsService.getParamsByMap("payKeys", PAY_KEYS);
Map<String, String> payKeyMap = paramsService.getParamsByMap("pay_key_set", ParamCodeCst.PAY_KEY_SET);
// 小程序id
config.appId = userMiniKeyMap.get(ParamCodeCst.Wechat.Mini.USER_WX_APP_ID);

View File

@@ -59,18 +59,6 @@ public abstract class BaseWx {
*/
protected static final Long EXPIRES_OFFSET = 200L;
/**
* 支付参数KEY
*/
protected static final Set<String> PAY_KEYS = Set.of(
ParamCodeCst.Wechat.Pay.WX_PUB_KEY,
ParamCodeCst.Wechat.Pay.WX_API_CLIENT_KEY,
ParamCodeCst.Wechat.Pay.WX_API_CLIENT_CERT,
ParamCodeCst.Wechat.Pay.WX_MCH_ID,
ParamCodeCst.Wechat.Pay.WX_V3_KEY,
ParamCodeCst.System.NATIVE_NOTIFY_URL
);
/**
* 初始化配置信息
*/

View File

@@ -11,6 +11,7 @@ import com.czg.market.service.GbWareService;
import com.czg.sa.StpKit;
import com.czg.service.market.mapper.GbWareMapper;
import com.czg.utils.AssertUtil;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
@@ -32,7 +33,7 @@ public class GbWareServiceImpl extends ServiceImpl<GbWareMapper, GbWare> impleme
@Override
public Page<GbWare> getGbWarePage(GbWareQueryParamDTO param, Long shopId, boolean isAdmin) {
if (!isAdmin && !shopInfoService.checkSwitch(shopId, ShopSwitchTypeEnum.GROUP_BUY)) {
return new Page<>();
return PageUtil.emptyPage();
}
Long mainShopId = shopInfoService.getMainIdByShopId(shopId);
QueryWrapper queryWrapper = new QueryWrapper();
@@ -54,9 +55,7 @@ public class GbWareServiceImpl extends ServiceImpl<GbWareMapper, GbWare> impleme
});
Page<GbWare> page = page(Page.of(param.getPage(), param.getSize()), queryWrapper);
if (!isAdmin) {
page.getRecords().forEach(item -> {
item.setShopId(shopId);
});
page.getRecords().forEach(item -> item.setShopId(shopId));
}
return page;
}

View File

@@ -160,7 +160,7 @@ public class MkConsumeCashbackServiceImpl extends ServiceImpl<MkConsumeCashbackM
shopUserService.updateMoney(new ShopUserMoneyEditDTO().setId(shopUser.getId()).setType(1)
.setRelationId(mkConsumeCashbackRecord.getId()).setMoney(cashbackAmount).setBizEnum(ShopUserFlowBizEnum.CASHBACK)
.setRemark(StrUtil.format("订单消费: {}, 返现: {}", amount, cashbackAmount)));
log.info("订单返现 订单ID:{}, 店铺用户id: {}, 订单消费: {}, 返现: {}",orderId, shopUser.getId(), amount, cashbackAmount);
log.info("订单返现 订单ID:{}, 店铺用户id: {}, 订单消费: {}, 返现: {}", orderId, shopUser.getId(), amount, cashbackAmount);
AcUserMsg msg = new AcUserMsg()
.setUserId(userId)
@@ -176,4 +176,45 @@ public class MkConsumeCashbackServiceImpl extends ServiceImpl<MkConsumeCashbackM
}
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void removeCashback(Long shopId, Long userId, Long orderId, String orderNo) {
MkConsumeCashbackRecord record = consumeCashbackRecordService.getOne(query()
.eq(MkConsumeCashbackRecord::getShopId, shopId)
.eq(MkConsumeCashbackRecord::getUserId, userId)
.eq(MkConsumeCashbackRecord::getOrderNo, orderNo)
.eq(MkConsumeCashbackRecord::getOrderId, orderId));
if (record == null) {
return;
}
MkConsumeCashbackRecord mkConsumeCashbackRecord = new MkConsumeCashbackRecord()
.setOrderNo(orderNo)
.setOrderId(orderId)
.setMainShopId(record.getMainShopId())
.setShopId(shopId)
.setAmount(BigDecimal.ZERO)
.setCashbackAmount(record.getCashbackAmount().negate())
.setUserId(userId)
.setShopUserId(record.getShopUserId());
consumeCashbackRecordService.save(mkConsumeCashbackRecord);
shopUserService.updateMoney(new ShopUserMoneyEditDTO()
.setId(record.getShopUserId())
.setType(0)
.setRelationId(mkConsumeCashbackRecord.getId())
.setMoney(record.getCashbackAmount())
.setBizEnum(ShopUserFlowBizEnum.CASHBACK_REFUND)
.setRemark(StrUtil.format("订单退款,扣除返现: {}", record.getCashbackAmount())));
log.info("订单退款扣除返现 订单ID:{}, 店铺用户id: {}, 扣除返现: {}", orderId, record.getShopUserId(), record.getCashbackAmount());
AcUserMsg msg = new AcUserMsg()
.setUserId(userId)
.setShopId(shopId)
.setSourceId(orderId)
.setSourceType("order")
.setType("cash")
.setTitle("订单退款,消费返现扣除")
.setContent(StrUtil.format("返现扣除提醒: 订单退款扣除的{}元返现。订单编号:{}", record.getCashbackAmount(), orderNo));
acUserMsgService.addUserMsg(msg);
}
}

View File

@@ -65,4 +65,9 @@ public class MkPointsConfigServiceImpl extends ServiceImpl<MkPointsConfigMapper,
mkPointsUserService.alterPoints(null, shopUser.getId(), orderInfo.getShopId(), PointsConstant.ADD,
awardPoints.intValue(), orderInfo.getId(), StrUtil.format("消费¥{}送{}积分", payAmount, awardPoints.intValue()));
}
@Override
public void removeConsumeAwardPoints(Long shopId, Long userId, Long orderId, String orderNo) {
mkPointsUserService.removePointByOrder(shopId, userId, orderId, orderNo, "订单退款扣除赠送积分");
}
}

View File

@@ -19,7 +19,6 @@ import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -43,7 +42,7 @@ public class MkPointsGoodsServiceImpl extends ServiceImpl<MkPointsGoodsMapper, M
public Page<MkPointsGoods> getPointsGoodsPage(BaseQueryParam param, Long shopId) {
boolean exists = mkPointsConfigService.exists(query().eq(MkPointsConfig::getShopId, shopId).eq(MkPointsConfig::getEnablePointsMall, 1));
if (!exists) {
return new Page<>();
return PageUtil.emptyPage();
}
Page<MkPointsGoods> page = page(Page.of(param.getPage(), param.getSize()),
query()

View File

@@ -31,11 +31,11 @@ public class MkPointsUserRecordServiceImpl extends ServiceImpl<MkPointsUserRecor
@Override
public Page<MkPointsUserRecord> pageByPointsUserId(Integer page, Integer size, Long mkPointsUserId) {
if (mkPointsUserId == null) {
return new Page<>();
return PageUtil.emptyPage();
}
ShopInfo shopInfo = shopInfoService.getById(StpKit.USER.getShopId());
if (shopInfo == null) {
return new Page<>();
return PageUtil.emptyPage();
}
Page<MkPointsUserRecord> pages = page(Page.of(page, size),
query().eq(MkPointsUserRecord::getMkPointsUserId, mkPointsUserId).orderBy(MkPointsUserRecord::getCreateTime, false));
@@ -46,7 +46,7 @@ public class MkPointsUserRecordServiceImpl extends ServiceImpl<MkPointsUserRecor
@Override
public Page<MkPointsUserRecord> getPointsUserRecord(Integer page, Integer size, Long mkPointsUserId) {
if (mkPointsUserId == null) {
return new Page<>();
return PageUtil.emptyPage();
}
PageHelper.startPage(page, size);
List<MkPointsUserRecord> record = mapper.getPointsUserRecord(mkPointsUserId);

View File

@@ -17,11 +17,13 @@ import com.czg.market.service.MkPointsUserRecordService;
import com.czg.market.service.MkPointsUserService;
import com.czg.sa.StpKit;
import com.czg.service.market.mapper.MkPointsUserMapper;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@@ -50,7 +52,7 @@ public class MkPointsUserServiceImpl extends ServiceImpl<MkPointsUserMapper, MkP
if (StrUtil.isNotBlank(phone)) {
ShopUser one = shopUserService.getOne(query().eq(ShopUser::getPhone, phone).eq(ShopUser::getMainShopId, mainIdByShopId));
if (one == null) {
return new Page<>();
return PageUtil.emptyPage();
}
shopUserId = one.getId();
}
@@ -130,9 +132,6 @@ public class MkPointsUserServiceImpl extends ServiceImpl<MkPointsUserMapper, MkP
break;
case SUB:
pointsUser.setPointBalance(pointsUser.getPointBalance() - points);
if (pointsUser.getPointBalance() < 0) {
throw new CzgException("积分操作失败,积分不足");
}
points = -points;
break;
default:
@@ -169,4 +168,49 @@ public class MkPointsUserServiceImpl extends ServiceImpl<MkPointsUserMapper, MkP
acUserMsgService.addUserMsg(msg);
return record.getId();
}
@Override
@Transactional
public void removePointByOrder(Long shopId, Long userId, Long orderId, String orderNo, String reason) {
MkPointsUser pointsUser = getPointsUser(shopId, null, userId);
MkPointsUserRecord one = pointsUserRecordService.getOne(query()
.eq(MkPointsUserRecord::getMkPointsUserId, pointsUser.getId())
.eq(MkPointsUserRecord::getShopId, shopId)
.eq(MkPointsUserRecord::getSourceId, orderId.toString())
.eq(MkPointsUserRecord::getFloatType, PointsConstant.ADD.getValue())
.orderBy(MkPointsUserRecord::getId, true)
);
if (one == null) {
return;
}
Long floatPoints = Math.abs(one.getFloatPoints());
pointsUser.setPointBalance(pointsUser.getPointBalance() - floatPoints);
saveOrUpdate(pointsUser);
MkPointsUserRecord record = MkPointsUserRecord.builder()
.mkPointsUserId(pointsUser.getId())
.shopId(pointsUser.getShopId())
.shopUserId(pointsUser.getShopUserId())
.floatType(PointsConstant.SUB.getValue())
.floatPoints(floatPoints)
.balancePoints(pointsUser.getPointBalance())
.sourceId(orderId.toString())
.content(reason)
.build();
boolean save = pointsUserRecordService.save(record);
if (!save) {
throw new CzgException("积分操作失败,积分记录保存失败");
}
AcUserMsg msg = new AcUserMsg()
.setUserId(pointsUser.getUserId())
.setShopId(shopId)
.setSourceId(orderId)
.setSourceType("order")
.setType("points")
.setReadStatus(0)
.setTitle("积分扣除")
.setContent(StrUtil.format("订单退款积分扣除提醒:{} 积分已扣除,订单号:{}", floatPoints, orderNo));
acUserMsgService.addUserMsg(msg);
}
}

View File

@@ -110,6 +110,17 @@ public class MkShopConsumerCouponServiceImpl extends ServiceImpl<MkShopConsumerC
}
}
@Override
public void removeConsumerCoupon(Long shopId, Long userId, Long orderId) {
recordService.remove(query()
.eq(MkShopCouponRecord::getShopId, shopId)
.eq(MkShopCouponRecord::getUserId, userId)
.eq(MkShopCouponRecord::getSourceFlowId, orderId)
.eq(MkShopCouponRecord::getSource, "消费赠券")
);
}
@Override
public MkShopConsumerCouponDTO getConsumerCouponById(Long id) {
AssertUtil.isNull(id, "ID不能为空");

View File

@@ -20,6 +20,7 @@ import com.czg.market.enums.PointsConstant;
import com.czg.market.service.*;
import com.czg.market.vo.*;
import com.czg.utils.AssertUtil;
import com.czg.utils.FunUtils;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.czg.market.entity.MkShopRecharge;
@@ -45,6 +46,8 @@ public class MkShopRechargeServiceImpl extends ServiceImpl<MkShopRechargeMapper,
@Resource
private MkShopRechargeDetailService shopRechargeDetailService;
@Resource
private TbMemberConfigService memberConfigService;
@Resource
private ShopCouponService shopCouponService;
@DubboReference
private ShopUserService shopUserService;
@@ -159,7 +162,8 @@ public class MkShopRechargeServiceImpl extends ServiceImpl<MkShopRechargeMapper,
}
@Override
public void recharge(Long shopId, Long shopUserId, Long rechargeDetailId, BigDecimal amount, Long paymentId, String payType, ShopUserFlowBizEnum bizEnum) {
public void recharge(Long shopId, Long shopUserId, Long rechargeDetailId, BigDecimal amount, Long paymentId,
String payType, ShopUserFlowBizEnum bizEnum, boolean isNoJoin) {
log.info("充值回调, 用户id: {}, 金额: {}, rechargeDetailId: {}", shopUserId, amount, rechargeDetailId);
ShopUser shopUser = shopUserService.getById(shopUserId);
ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
@@ -168,7 +172,6 @@ public class MkShopRechargeServiceImpl extends ServiceImpl<MkShopRechargeMapper,
.setBizEnum(bizEnum)
.setRelationId(paymentId);
// 标准充值
if (rechargeDetailId != null) {
MkShopRechargeDetail rechargeDetail = shopRechargeDetailService.getById(rechargeDetailId);
@@ -195,10 +198,10 @@ public class MkShopRechargeServiceImpl extends ServiceImpl<MkShopRechargeMapper,
return;
}
// try {
shopCouponRecordService.grant(shopId, new MkRewardCouponDTO().setCouponId(item.getId())
.setNum(item.getNum())
.setUserId(shopUser.getUserId())
.setShopId(shopId), "充值赠券");
shopCouponRecordService.grant(shopId, new MkRewardCouponDTO().setCouponId(item.getId())
.setNum(item.getNum())
.setUserId(shopUser.getUserId())
.setShopId(shopId), "充值赠券");
// } catch (Exception e) {
// log.warn("发放优惠券失败", e);
// }
@@ -209,7 +212,9 @@ public class MkShopRechargeServiceImpl extends ServiceImpl<MkShopRechargeMapper,
shopUserMoneyEditDTO.setMoney(amount);
}
shopUserService.updateMoney(shopUserMoneyEditDTO);
if (isNoJoin) {
FunUtils.transactionSafeRun(() -> memberConfigService.joinMemberByCondition(shopId, shopUser.getUserId(), shopUser));
}
}
@Override

View File

@@ -20,6 +20,7 @@ import com.czg.sa.StpKit;
import com.czg.service.market.mapper.PpPackageMapper;
import com.czg.service.market.mapper.PpPackageOrderMapper;
import com.czg.utils.AssertUtil;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
@@ -168,7 +169,7 @@ public class PpPackageServiceImpl extends ServiceImpl<PpPackageMapper, PpPackage
Integer promotionSwitch = getPackagePromotionSwitch(shopId);
if (!isAdmin && SystemConstants.OneZero.ZERO == promotionSwitch) {
log.info("没有开启套餐推广");
return new Page<>();
return PageUtil.emptyPage();
}
Long mainShopId = shopInfoService.getMainIdByShopId(shopId);

View File

@@ -310,7 +310,7 @@ public class ShopCouponServiceImpl extends ServiceImpl<ShopCouponMapper, ShopCou
}
return PageUtil.convert(new PageInfo<>(coupons));
}
return new Page<>();
return PageUtil.emptyPage();
}
@Override

View File

@@ -11,7 +11,6 @@ import com.czg.account.entity.ShopUser;
import com.czg.account.service.ShopConfigService;
import com.czg.account.service.ShopInfoService;
import com.czg.account.service.ShopUserService;
import com.czg.account.service.UserInfoService;
import com.czg.constant.TableValueConstant;
import com.czg.exception.CzgException;
import com.czg.market.dto.MemberConfigDTO;
@@ -25,7 +24,6 @@ import com.czg.market.enums.PointsConstant;
import com.czg.market.service.*;
import com.czg.market.vo.*;
import com.czg.order.entity.OrderInfo;
import com.czg.order.entity.OrderPayment;
import com.czg.order.service.OrderPaymentService;
import com.czg.service.market.enums.OrderStatusEnums;
import com.czg.service.market.mapper.TbMemberConfigMapper;
@@ -59,8 +57,6 @@ public class TbMemberConfigServiceImpl extends ServiceImpl<TbMemberConfigMapper,
@Resource
private MemberLevelConfigService levelConfigService;
@DubboReference
private UserInfoService userInfoService;
@DubboReference
private ShopUserService shopUserService;
@Resource
private OrderInfoService orderInfoService;
@@ -121,21 +117,21 @@ public class TbMemberConfigServiceImpl extends ServiceImpl<TbMemberConfigMapper,
conditionMap.put("BIND_PHONE", StrUtil.isNotBlank(shopUserInfo.getPhone()));
break;
case "ORDER":
conditionMap.put("ORDER", orderInfoService.count(new QueryWrapper().eq(OrderInfo::getShopId, shopUserInfo.getSourceShopId()).eq(OrderInfo::getUserId, shopUserInfo.getUserId())
.notIn(OrderInfo::getStatus, OrderStatusEnums.UNPAID.getCode(), OrderStatusEnums.CANCELLED.getCode())) >= Integer.parseInt(item.getValue()));
conditionMap.put("ORDER", orderInfoService.count(query().eq(OrderInfo::getShopId, shopId).eq(OrderInfo::getUserId, shopUserInfo.getUserId())
.eq(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode())) >= Integer.parseInt(item.getValue()));
break;
case "COST_AMOUNT":
conditionMap.put("COST_AMOUNT", orderInfoService.list(new QueryWrapper().eq(OrderInfo::getShopId, shopUserInfo.getSourceShopId()).eq(OrderInfo::getUserId, shopUserInfo.getUserId())
.notIn(OrderInfo::getStatus, OrderStatusEnums.UNPAID.getCode(), OrderStatusEnums.CANCELLED.getCode()))
.stream().map(OrderInfo::getPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add).compareTo(new BigDecimal(item.getValue())) >= 0);
conditionMap.put("COST_AMOUNT", orderInfoService.getOneAs(query()
.select("IFNULL(sum(pay_amount), 0) as total_amount ")
.eq(OrderInfo::getShopId, shopId)
.eq(OrderInfo::getUserId, shopUserInfo.getUserId())
.eq(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode()), BigDecimal.class)
.compareTo(new BigDecimal(item.getValue())) >= 0);
break;
case "RECHARGE_AMOUNT":
conditionMap.put("RECHARGE_AMOUNT", paymentService.list(new QueryWrapper().eq(OrderPayment::getShopId, shopUserInfo.getSourceShopId())
.eq(OrderPayment::getSourceId, shopUserInfo.getId()).isNotNull(OrderPayment::getTradeNumber))
.stream().map(OrderPayment::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add).compareTo(new BigDecimal(item.getValue())) >= 0);
conditionMap.put("RECHARGE_AMOUNT", paymentService.countMemberInAmount(shopId, shopUserInfo.getId())
.compareTo(new BigDecimal(item.getValue())) >= 0);
break;
default:
throw new CzgException("会员开通条件类型错误");
@@ -199,7 +195,10 @@ public class TbMemberConfigServiceImpl extends ServiceImpl<TbMemberConfigMapper,
memberConfig.setMemberPriceShopIdList(JSONObject.toJSONString(memberDTO.getMemberPriceShopIdList()));
}
shopConfigService.editStatusByShopIdList(memberConfig.getShopId(), memberConfig.getIsOpen().intValue() == 1 && memberConfig.getIsMemberPrice() == 1 ? 1 : 0, false, "is_member_price",
shopConfigService.editStatusByShopIdList(memberConfig.getShopId(),
memberConfig.getIsOpen().intValue() == 1 && memberConfig.getIsMemberPrice() == 1 ? 1 : 0,
false,
"is_member_price",
"ALL".equals(memberConfig.getMemberPriceShopType()) ? "all" : "part",
StrUtil.isNotBlank(memberConfig.getMemberPriceShopIdList()) ? JSONArray.parseArray(memberConfig.getMemberPriceShopIdList()).toList(Long.class) : new ArrayList<>());
@@ -304,6 +303,7 @@ public class TbMemberConfigServiceImpl extends ServiceImpl<TbMemberConfigMapper,
return false;
}
ShopUser upShopUser = new ShopUser();
upShopUser.setId(shopUser.getId());
if (shopUser.getExperience() == null) {
upShopUser.setExperience(0L);
}
@@ -337,13 +337,11 @@ public class TbMemberConfigServiceImpl extends ServiceImpl<TbMemberConfigMapper,
}
if (levelVO.getCycleRewardCouponList() != null && !levelVO.getCycleRewardCouponList().isEmpty()) {
levelVO.getCycleRewardCouponList().forEach(item -> {
shopCouponRecordService.grant(shopUser.getMainShopId(), new MkRewardCouponDTO().setCouponId(item.getCoupon().getId())
.setNum(item.getNum())
.setUserId(shopUser.getUserId())
.setShopId(shopUser.getMainShopId()), "购买会员赠券");
});
levelVO.getCycleRewardCouponList().forEach(item ->
shopCouponRecordService.grant(shopUser.getMainShopId(), new MkRewardCouponDTO().setCouponId(item.getCoupon().getId())
.setNum(item.getNum())
.setUserId(shopUser.getUserId())
.setShopId(shopUser.getMainShopId()), "购买会员赠券"));
}
}
@@ -381,16 +379,17 @@ public class TbMemberConfigServiceImpl extends ServiceImpl<TbMemberConfigMapper,
@Override
@Transactional(rollbackFor = Exception.class)
public boolean joinMemberByCondition(Long shopId, Long userId, ShopUser shopUser) {
MemberConfigVO memberConfigVO = detail(shopId);
if (!memberConfigVO.getIsOpen().equals(1L)) {
log.info("超级会员未开启, 店铺id: {}", shopId);
return false;
}
if (shopUser == null) {
log.warn("用户不存在, 店铺id: {}, 用户id: {}", shopId, userId);
return false;
}
if (shopUser.getStartTime() != null && shopUser.getEndTime() != null && DateUtil.isIn(DateUtil.date(), DateUtil.date(shopUser.getStartTime()), DateUtil.date(shopUser.getEndTime()))) {
if (shopUser.getIsVip() == 1 && shopUser.getStartTime() != null && shopUser.getEndTime() != null &&
DateUtil.isIn(DateUtil.date(), DateUtil.date(shopUser.getStartTime()), DateUtil.date(shopUser.getEndTime()))) {
return false;
}
MemberConfigVO memberConfigVO = detail(shopId);
if (!memberConfigVO.getIsOpen().equals(1L)) {
log.info("超级会员未开启, 店铺id: {}", shopId);
return false;
}
MemberLevelConfig levelConfig = levelConfigService.getOne(new QueryWrapper().eq(MemberLevelConfig::getShopId, shopId).orderBy(MemberLevelConfig::getExperienceValue, true).limit(1));
@@ -411,16 +410,14 @@ public class TbMemberConfigServiceImpl extends ServiceImpl<TbMemberConfigMapper,
boolean canOpen = switch (item.getCode()) {
case "BIND_PHONE" -> StrUtil.isNotBlank(shopUser.getPhone());
case "ORDER" ->
orderInfoService.count(new QueryWrapper().eq(OrderInfo::getShopId, shopUser.getSourceShopId()).eq(OrderInfo::getUserId, shopUser.getUserId())
.notIn(OrderInfo::getStatus, OrderStatusEnums.UNPAID.getCode(), OrderStatusEnums.CANCELLED.getCode())) >= Integer.parseInt(item.getValue());
orderInfoService.count(query().eq(OrderInfo::getShopId, shopId).eq(OrderInfo::getUserId, shopUser.getUserId())
.eq(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode())) >= Integer.parseInt(item.getValue());
case "COST_AMOUNT" ->
orderInfoService.list(new QueryWrapper().eq(OrderInfo::getShopId, shopUser.getSourceShopId()).eq(OrderInfo::getUserId, shopUser.getUserId())
.notIn(OrderInfo::getStatus, OrderStatusEnums.UNPAID.getCode(), OrderStatusEnums.CANCELLED.getCode()))
.stream().map(OrderInfo::getPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add).compareTo(new BigDecimal(item.getValue())) >= 0;
case "RECHARGE_AMOUNT" ->
paymentService.list(new QueryWrapper().eq(OrderPayment::getShopId, shopUser.getSourceShopId())
.eq(OrderPayment::getSourceId, shopUser.getId()).isNotNull(OrderPayment::getTradeNumber))
.stream().map(OrderPayment::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add).compareTo(new BigDecimal(item.getValue())) >= 0;
orderInfoService.getOneAs(query().select("IFNULL(sum(pay_amount), 0) as total_amount").eq(OrderInfo::getShopId, shopId).eq(OrderInfo::getUserId, shopUser.getUserId())
.eq(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode()), BigDecimal.class)
.compareTo(new BigDecimal(item.getValue())) >= 0;
case "RECHARGE_AMOUNT" -> paymentService.countMemberInAmount(shopId, shopUser.getId())
.compareTo(new BigDecimal(item.getValue())) >= 0;
default -> throw new CzgException("会员开通条件类型错误");
};
if (!canOpen) {
@@ -431,10 +428,12 @@ public class TbMemberConfigServiceImpl extends ServiceImpl<TbMemberConfigMapper,
ShopUser upShopUser = new ShopUser();
upShopUser.setId(shopUser.getId());
upShopUser.setMemberLevelId(levelConfig.getId());
upShopUser.setStartTime(DateUtil.date().toLocalDateTime());
upShopUser.setEndTime(shopUser.getStartTime().plusDays(20000));
upShopUser.setStartTime(LocalDateTime.now());
upShopUser.setEndTime(upShopUser.getStartTime().plusDays(20000));
upShopUser.setIsVip(1);
if (shopUser.getJoinTime() != null) {
upShopUser.setJoinTime(LocalDateTime.now());
}
upShopUser.setOpenType("CONDITION");
return shopUserService.updateById(upShopUser);
}
@@ -557,20 +556,27 @@ public class TbMemberConfigServiceImpl extends ServiceImpl<TbMemberConfigMapper,
@Override
@Transactional
public MemberDetailVO getUserDetail(Long userId, Long shopId) {
Long mainIdByShopId = shopInfoService.getMainIdByShopId(shopId);
ShopInfo shopInfo = shopInfoService.getById(shopId);
Long mainIdByShopId = shopInfo.getMainId() == null ? shopId : shopInfo.getMainId();
ShopUser shopUser = shopUserService.getOne(new QueryWrapper().eq(ShopUser::getUserId, userId).eq(ShopUser::getMainShopId, mainIdByShopId));
MemberLevelVO levelVO = null;
if (shopUser.getMemberLevelId() != null) {
levelVO = levelConfigService.detail(shopUser.getMemberLevelId());
}
TbMemberConfig memberConfig = getOne(new QueryWrapper().eq(TbMemberConfig::getShopId, shopId));
if ("CONDITION".equals(memberConfig.getOpenType())) {
joinMemberByCondition(shopId, userId, shopUser);
MemberConfigVO memberConfig = detail(shopId);
long nextLevelExperience = 0;
if (memberConfig != null && memberConfig.getIsOpen() == 1) {
if ("CONDITION".equals(memberConfig.getOpenType())) {
joinMemberByCondition(shopId, userId, shopUser);
}
MemberLevelConfig nextLevel = levelConfigService.getOne(new QueryWrapper()
.eq(MemberLevelConfig::getShopId, mainIdByShopId)
.ge(MemberLevelConfig::getExperienceValue, shopUser.getExperience())
.ne(MemberLevelConfig::getId, shopUser.getMemberLevelId()).orderBy(MemberLevelConfig::getExperienceValue, true));
if (nextLevel != null) {
nextLevelExperience = nextLevel.getExperienceValue() - shopUser.getExperience();
}
}
ShopInfo shopInfo = shopInfoService.getById(shopUser.getSourceShopId());
MemberLevelConfig nextLevel = levelConfigService.getOne(new QueryWrapper().eq(MemberLevelConfig::getShopId, shopId).ge(MemberLevelConfig::getExperienceValue, shopUser.getExperience())
.ne(MemberLevelConfig::getId, shopUser.getMemberLevelId()).orderBy(MemberLevelConfig::getExperienceValue, true));
return new MemberDetailVO()
.setMemberCircleName(shopUser.getMemberCircleName())
.setMemberCircleReward(shopUser.getMemberCircleReward())
@@ -579,6 +585,6 @@ public class TbMemberConfigServiceImpl extends ServiceImpl<TbMemberConfigMapper,
.setMemberLevel(levelVO)
.setExperience(shopUser.getExperience())
.setEndTime(shopUser.getEndTime())
.setNextExperienceValue(nextLevel == null ? 0 : nextLevel.getExperienceValue() - shopUser.getExperience());
.setNextExperienceValue(nextLevelExperience);
}
}

View File

@@ -64,7 +64,7 @@ public class WxServiceImpl extends BaseWx {
@Override
public void init() {
// 商户小程序参数
Map<String, String> shopMiniKeyMap = paramsService.getParamsByMap("shopMiniKeys", shopMiniKeys);
Map<String, String> shopMiniKeyMap = paramsService.getParamsByMap("shop_mini_key_set", ParamCodeCst.SHOP_MINI_KEY_SET);
// 小程序id
config.appId = shopMiniKeyMap.get(ParamCodeCst.Wechat.Mini.SHOP_WX_APP_ID);
@@ -72,7 +72,7 @@ public class WxServiceImpl extends BaseWx {
config.appSecret = shopMiniKeyMap.get(ParamCodeCst.Wechat.Mini.SHOP_WX_SECRETE);
// 微信支付参数
Map<String, String> payKeyMap = paramsService.getParamsByMap("payKeys", PAY_KEYS);
Map<String, String> payKeyMap = paramsService.getParamsByMap("pay_key_set", ParamCodeCst.PAY_KEY_SET);
config.certPath = "";
// 微信支付公钥
config.pubKey = payKeyMap.get(ParamCodeCst.Wechat.Pay.WX_PUB_KEY);

View File

@@ -15,10 +15,7 @@
left join tb_shop_info s on o.shop_id = s.id
left join pp_package p on o.package_id = p.id
left join tb_user_info u on o.user_id = u.id
where 1=1
<if test="shopId != null">
and o.shop_id = #{shopId}
</if>
where o.shop_id = #{shopId}
<choose>
<!-- userId为空时拼接 and o.status != 'ing' -->
<when test="userId == null or userId == ''">

View File

@@ -151,7 +151,9 @@ public class GbOrderServiceImpl extends ServiceImpl<GbOrderMapper, GbOrder> impl
q.eq(GbOrderDetail::getStatus, "待成团").or(GbOrderDetail::getStatus).eq("退款中");
});
queryWrapper1.eq(GbOrderDetail::getGroupOrderNo, ing.getGroupOrderNo());
queryWrapper1.eq(GbOrderDetail::getUserId, userId);
if (userId != null) {
queryWrapper1.eq(GbOrderDetail::getUserId, userId);
}
boolean exists = detailService.exists(queryWrapper1);
if (exists) {
continue;

View File

@@ -162,7 +162,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
.like(OrderDetail::getProductName, productName);
like = orderDetailService.listAs(queryWrapper, Long.class);
if (CollUtil.isEmpty(like)) {
return new Page<>();
return PageUtil.emptyPage();
}
}
QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();
@@ -1060,8 +1060,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
distributionUserService.costUpgradeLevelBefore(orderInfo.getUserId(), orderInfo.getShopId());
// 分销奖励
distributionUserService.distribute(orderInfo.getId(), orderInfo.getOrderNo(), payment.getAmount(), orderInfo.getUserId(), orderInfo.getShopId(), "order");
}
else if (PayTypeConstants.SourceType.MEMBER_IN.equals(payment.getSourceType()) || PayTypeConstants.SourceType.FREE.equals(payment.getSourceType())) {
} else if (PayTypeConstants.SourceType.MEMBER_IN.equals(payment.getSourceType()) || PayTypeConstants.SourceType.FREE.equals(payment.getSourceType())) {
boolean isFree = PayTypeConstants.SourceType.FREE.equals(payment.getSourceType());
ShopUser shopUser = shopUserService.getById(payment.getSourceId());
OrderInfo orderInfo = null;
@@ -1089,99 +1088,41 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
.setRelationId(orderInfo.getId())
.setMoney(BigDecimal.valueOf(czgCallBackDto.getAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN));
shopUserService.updateMoney(shopUserMoneyEditDTO);
OrderInfo orderInfo1 = new OrderInfo();
orderInfo1.setId(orderInfo.getId());
orderInfo1.setIsFreeDine(1);
orderInfo1.setStatus(OrderStatusEnums.DONE.getCode());
orderInfo1.setPayAmount(BigDecimal.ZERO);
orderInfo1.setPaidTime(LocalDateTime.now());
orderInfo1.setPayType(PayEnums.FREE_PAY.getValue());
orderInfoService.updateById(orderInfo1);
orderDetailService.updateOrderDetailStatus(orderInfo.getId(), OrderStatusEnums.DONE.getCode());
redisService.del(RedisCst.classKeyExpired.EXPIRED_ORDER + orderInfo.getId());
upOrderInfo(orderInfo, BigDecimal.ZERO,
LocalDateTime.now(), null, PayEnums.FREE_PAY);
}
} else {
shopRechargeService.recharge(payment.getShopId(), payment.getSourceId(), payment.getRelatedId(),
BigDecimal.valueOf(czgCallBackDto.getAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN), payment.getId(), payment.getSourceType(), bizEnum);
//充值并支付 ↓
orderInfo = orderInfoService.getOne(new QueryWrapper()
.eq(OrderInfo::getPayOrderId, payment.getId())
.eq(OrderInfo::getPayType, PayEnums.VIP_PAY.getValue()));
if (orderInfo != null) {
OrderInfo upOrderInfo = new OrderInfo()
.setId(orderInfo.getId())
.setPayType(PayEnums.VIP_PAY.getValue())
.setPaidTime(LocalDateTime.now())
.setPayAmount(orderInfo.getOrderAmount())
.setStatus(OrderStatusEnums.DONE.getCode());
orderInfoService.updateById(upOrderInfo);
orderDetailService.updateOrderDetailStatus(orderInfo.getId(), OrderStatusEnums.DONE.getCode());
ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
.setId(shopUser.getId())
.setType(0)
.setBizEnum(ShopUserFlowBizEnum.ORDER_PAY)
.setRelationId(orderInfo.getId())
.setMoney(orderInfo.getOrderAmount());
shopUserService.updateMoney(shopUserMoneyEditDTO);
redisService.del(RedisCst.classKeyExpired.EXPIRED_ORDER + orderInfo.getId());
// 发放成长值
shopUser = shopUserService.getById(shopUser);
//充值
memberConfigService.deliver(shopUser,
TableValueConstant.MemberExpFlow.Type.RECHARGE,
BigDecimal.valueOf(czgCallBackDto.getAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN), null, orderInfo.getId());
if (TransactionSynchronizationManager.isSynchronizationActive()) {
OrderInfo finalOrderInfo = orderInfo;
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
// 事务成功提交后执行消息发送
String printParam = finalOrderInfo.getId() + "_" + (!"after-pay".equals(finalOrderInfo.getPayMode()) ? 1 : 0) + "_1";
rabbitPublisher.sendOrderPrintMsg(printParam, finalOrderInfo.getIsPrint() == 1);
// log.info("订单{}事务提交后,发送打印消息", orderId);
}
});
} else {
// 非事务环境下直接发送(兼容无事务场景)
String printParam = orderInfo.getId() + "_" + (!"after-pay".equals(orderInfo.getPayMode()) ? 1 : 0) + "_1";
rabbitPublisher.sendOrderPrintMsg(printParam, orderInfo.getIsPrint() == 1);
// log.info("非事务环境下,直接发送订单{}打印消息", orderId);
}
upOrderInfo(orderInfo, orderInfo.getOrderAmount(),
LocalDateTime.now(), null, PayEnums.VIP_PAY);
}
shopRechargeService.recharge(payment.getShopId(), payment.getSourceId(), payment.getRelatedId(),
BigDecimal.valueOf(czgCallBackDto.getAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN),
payment.getId(), payment.getSourceType(), bizEnum, orderInfo == null);
}
}
// 分销奖励
// if (shopUser != null) {
// distributionUserService.distribute(payment.getId(), payment.getOrderNo(), payment.getAmount(), shopUser.getUserId(), payment.getShopId(), "recharge");
// }
// if (orderInfo != null) {
// distributionUserService.distribute(payment.getId(), payment.getOrderNo(), payment.getAmount(), orderInfo.getUserId(), payment.getShopId(), "recharge");
// }
}
else if (PayTypeConstants.SourceType.MEMBER_PAY.equals(payment.getSourceType())) {
} else if (PayTypeConstants.SourceType.MEMBER_PAY.equals(payment.getSourceType())) {
//购买会员
ShopUser shopUser = shopUserService.getById(payment.getSourceId());
memberConfigService.joinMember(payment.getShopId(), shopUser.getUserId(), payment.getRelatedId());
// 充值赠送积分
// memberConfigService.deliver(shopUser.getMainShopId(), shopUser.getUserId(), TableValueConstant.MemberExpFlow.Type.COST, payment.getAmount(), null, payment.getId());
// 分销员开通
}
else if (PayTypeConstants.SourceType.DISTRIBUTION.equals(payment.getSourceType())) {
} else if (PayTypeConstants.SourceType.DISTRIBUTION.equals(payment.getSourceType())) {
distributionUserService.open(payment.getSourceId(), payment.getAmount(), payment.getShopId(), payment.getId());
}
else if (PayTypeConstants.SourceType.POINT.equals(payment.getSourceType())) {
} else if (PayTypeConstants.SourceType.POINT.equals(payment.getSourceType())) {
goodPayService.payCallBack(payment.getSourceId(), payment.getId());
}
else if (PayTypeConstants.SourceType.WARE.equals(payment.getSourceType())) {
} else if (PayTypeConstants.SourceType.WARE.equals(payment.getSourceType())) {
gbOrderService.payCallBack(payment.getSourceId(), payment.getId());
}
else if (PayTypeConstants.SourceType.PP.equals(payment.getSourceType())) {
} else if (PayTypeConstants.SourceType.PP.equals(payment.getSourceType())) {
ppPackageOrderService.paySuccess(payment.getSourceId(), payment.getId());
}
}
@@ -1306,14 +1247,14 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService {
shopUserUseInfo(orderInfo, shopUser);
// 后续 赠送等功能 挂账支付不赠送
if (!orderInfo.getPayType().equals(PayEnums.CREDIT_PAY.getValue())) {
FunUtils.safeRunVoid(() -> consumerCouponService.receiveConsumerCoupon(shopUser.getSourceShopId(), orderInfo.getId(),
orderInfo.getPayAmount(), shopUser.getUserId(), shopUser.getId()), "订单{}消费赠券失败", orderInfo.getId());
FunUtils.safeRunVoid(() -> pointsConfigService.consumeAwardPoints(shopUser, orderInfo), "订单{}赠送积分失败", orderInfo.getId());
FunUtils.safeRunVoid(() -> consumeCashbackService.cashback(orderInfo.getShopId(), shopUser.getUserId(),
orderInfo.getPayAmount(), orderInfo.getId(), orderInfo.getOrderNo()), "订单{}消费返现失败", orderInfo.getId());
if (!orderInfo.getPayType().equals(PayEnums.FREE_PAY.getValue())) {
FunUtils.safeRunVoid(() -> consumerCouponService.receiveConsumerCoupon(shopUser.getSourceShopId(), orderInfo.getId(),
orderInfo.getPayAmount(), shopUser.getUserId(), shopUser.getId()), "订单{}消费赠券失败", orderInfo.getId());
FunUtils.safeRunVoid(() -> pointsConfigService.consumeAwardPoints(shopUser, orderInfo), "订单{}赠送积分失败", orderInfo.getId());
FunUtils.safeRunVoid(() -> consumeCashbackService.cashback(orderInfo.getShopId(), shopUser.getUserId(),
orderInfo.getPayAmount(), orderInfo.getId(), orderInfo.getOrderNo()), "订单{}消费返现失败", orderInfo.getId());
}
FunUtils.safeRunVoid(() -> {
if (shopUser.getIsVip().equals(0)) {
// 消费累计成为会员的情况

View File

@@ -1,11 +1,14 @@
package com.czg.service.order.service.impl;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.czg.constants.PayTypeConstants;
import com.czg.order.entity.OrderPayment;
import com.czg.order.service.OrderPaymentService;
import com.czg.service.order.mapper.OrderPaymentMapper;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
/**
* 支付详情 服务层实现。
@@ -14,6 +17,15 @@ import org.springframework.stereotype.Service;
* @since 2025-02-15
*/
@DubboService
public class OrderPaymentServiceImpl extends ServiceImpl<OrderPaymentMapper, OrderPayment> implements OrderPaymentService{
public class OrderPaymentServiceImpl extends ServiceImpl<OrderPaymentMapper, OrderPayment> implements OrderPaymentService {
@Override
public BigDecimal countMemberInAmount(Long shopId, Long shopUserId) {
return getOneAs(QueryWrapper.create().select("sum(amount)")
.eq(OrderPayment::getShopId, 143)
.eq(OrderPayment::getSourceType, PayTypeConstants.SourceType.MEMBER_IN)
.eq(OrderPayment::getPayType, PayTypeConstants.PayType.PAY)
.eq(OrderPayment::getSourceId, 127452)
.eq(OrderPayment::getPayStatus, PayTypeConstants.PayStatus.SUCCESS), BigDecimal.class);
}
}

View File

@@ -24,6 +24,7 @@ import com.czg.market.dto.MemberOrderDTO;
import com.czg.market.entity.MemberOrder;
import com.czg.market.entity.MkShopCouponRecord;
import com.czg.market.entity.MkShopRechargeDetail;
import com.czg.market.enums.PointsConstant;
import com.czg.market.service.*;
import com.czg.market.vo.MkShopRechargeVO;
import com.czg.order.dto.CheckOrderPay;
@@ -51,12 +52,14 @@ import com.czg.service.order.service.PayService;
import com.czg.system.service.SysParamsService;
import com.czg.utils.AssertUtil;
import com.czg.utils.CzgRandomUtils;
import com.czg.utils.FunUtils;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotBlank;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -116,9 +119,15 @@ public class PayServiceImpl implements PayService {
@Resource
private MkShopRechargeDetailService shopRechargeDetailService;
@Resource
private TbMemberConfigService memberConfigService;
@Resource
private MkDistributionUserService distributionUserService;
@Resource
private MkShopConsumerCouponService consumerCouponService;
@Resource
private MkPointsUserService mkPointsUserService;
@Resource
private MkConsumeCashbackService consumeCashbackService;
@Resource
private MkPointsConfigService pointsConfigService;
private final BigDecimal MONEY_RATE = new BigDecimal("100");
@@ -152,7 +161,6 @@ public class PayServiceImpl implements PayService {
throw new CzgException("该店铺未启用霸王餐");
}
CheckOrderPay checkOrderPay = payParam.getCheckOrderPay();
// CheckOrderPay checkOrderPay = BeanUtil.copyProperties(payParam, CheckOrderPay.class);
OrderInfo orderInfo = orderInfoCustomService.checkOrderPay(checkOrderPay.setFreeDine(true).setWithCoupon(freeConfig.getWithCoupon()).setWithPoints(freeConfig.getWithPoints()));
payParam.setAmount(orderInfo.getOrderAmount().multiply(BigDecimal.valueOf(freeConfig.getRechargeTimes())));
return true;
@@ -245,14 +253,9 @@ public class PayServiceImpl implements PayService {
orderInfo.setRemark(payParam.getCheckOrderPay().getRemark());
}
// log.info("发放经验值");
// memberConfigService.deliver(shopUser, TableValueConstant.MemberExpFlow.Type.COST, orderInfo.getOrderAmount(), null, orderInfo.getId());
Long flowId = shopUserService.updateMoney(shopUserMoneyEditDTO);
orderInfoCustomService.upOrderInfo(orderInfo, orderInfo.getOrderAmount(),
LocalDateTime.now(), flowId, PayEnums.VIP_PAY);
return CzgResult.success();
}
@@ -261,9 +264,6 @@ public class PayServiceImpl implements PayService {
OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
ShopInfo shopInfo = shopInfoService.getById(payParam.getShopId());
AssertUtil.isNull(shopInfo, "店铺不存在");
// if (!shopInfo.getIsAccountPay().equals(1)) {
// return CzgResult.failure("支付失败,店铺暂未开启会员余额支付。");
// }
AssertUtil.isNull(payParam.getShopUserId(), "请选择付款人后重试");
ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
AssertUtil.isNull(shopUser, "支付失败 该店铺用户不存在");
@@ -427,15 +427,16 @@ public class PayServiceImpl implements PayService {
return CzgResult.failure("支付密码错误");
}
}
if (shopUser.getIsVip().equals(0)) {
//更新会员
ShopUser updateInfo = new ShopUser();
updateInfo.setIsVip(1);
updateInfo.setJoinTime(LocalDateTime.now());
updateInfo.setId(payParam.getShopUserId());
shopUserService.updateById(updateInfo);
}
shopRechargeService.recharge(shopUser.getMainShopId(), shopUser.getId(), payParam.getRechargeDetailId(), payParam.getAmount(), null, "cash", ShopUserFlowBizEnum.CASH_IN);
// if (shopUser.getIsVip().equals(0)) {
// //更新会员
// ShopUser updateInfo = new ShopUser();
// updateInfo.setIsVip(1);
// updateInfo.setJoinTime(LocalDateTime.now());
// updateInfo.setId(payParam.getShopUserId());
// shopUserService.updateById(updateInfo);
// }
shopRechargeService.recharge(shopUser.getMainShopId(), shopUser.getId(), payParam.getRechargeDetailId(),
payParam.getAmount(), null, "cash", ShopUserFlowBizEnum.CASH_IN, true);
return CzgResult.success();
}
@@ -687,6 +688,10 @@ public class PayServiceImpl implements PayService {
if (orderInfo.getStatus().equals(OrderStatusEnums.CANCELLED.getCode())) {
throw new CzgException("订单已过期不可退单");
}
boolean isFirstRefund = true;
if (orderInfo.getRefundAmount().compareTo(BigDecimal.ZERO) != 0) {
isFirstRefund = false;
}
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
Map<String, BigDecimal> returnProMap = new HashMap<>();
boolean isPay = true;
@@ -755,7 +760,6 @@ public class PayServiceImpl implements PayService {
}
} else {
orderInfo.setStatus(OrderStatusEnums.REFUND.getCode());
// ssss
List<OrderDetail> orderDetails = orderDetailService.queryChain()
.select(OrderDetail::getId, OrderDetail::getProductId, OrderDetail::getNum, OrderDetail::getReturnNum, OrderDetail::getPackAmount, OrderDetail::getReturnNum)
.eq(OrderDetail::getOrderId, orderInfo.getId())
@@ -812,16 +816,42 @@ public class PayServiceImpl implements PayService {
}
orderInfo.setRefundRemark(orderInfo.getRefundRemark() + param.getRefundReason());
orderInfoService.updateById(orderInfo);
//退款后续
//退款返还库存
if (!returnProMap.isEmpty()) {
rabbitPublisher.sendOrderRefundMsg(JSONObject.toJSONString(Map.of("orderId", orderInfo.getId(), "returnProMap", returnProMap)));
}
// 退款分销还原
distributionUserService.refund(orderInfo.getId(), orderInfo.getOrderNo());
refundOrderAfter(orderInfo.getId(), orderInfo.getShopId(), orderInfo.getUserId(), orderInfo.getOrderNo(),
orderInfo.getPointsNum(), isFirstRefund, orderInfo.getStatus().equals(OrderStatusEnums.REFUND.getCode()));
return CzgResult.success();
}
//触发订单退款时 后续处理
@Async
public void refundOrderAfter(@NonNull Long orderId, @NonNull Long shopId, Long userId, String orderNo,
Integer pointsNum, boolean isFirstRefund, boolean isAllRefund) {
if (isFirstRefund) {
// 退款分销还原
FunUtils.safeRunVoid(() -> distributionUserService.refund(orderId, orderNo),
"订单id:{} 退款,分销处理失败", orderId);
if (userId == null) {
return;
}
FunUtils.safeRunVoid(() -> consumerCouponService.removeConsumerCoupon(shopId, userId, orderId),
"订单id:{} 退款,消费赠券回撤处理失败", orderId);
FunUtils.safeRunVoid(() -> consumeCashbackService.removeCashback(shopId, userId, orderId, orderNo),
"订单id:{} 退款,消费返现扣除处理失败", orderId);
FunUtils.safeRunVoid(() -> pointsConfigService.removeConsumeAwardPoints(shopId, userId, orderId, orderNo),
"订单id:{} 退款,赠送积分扣除失败", orderId);
}
if (isAllRefund && userId != null && pointsNum != null && pointsNum > 0) {
FunUtils.safeRunVoid(() -> mkPointsUserService.alterPoints(userId, null, shopId, PointsConstant.ADD,
pointsNum, orderId, StrUtil.format("订单退款返还{}积分", pointsNum)),
"订单id:{} 退款,赠送积分扣除失败", orderId);
}
}
@Override
@Transactional
public void refundOrder(@NonNull Long shopId, @NonNull Long orderId, @NonNull Long payOrderId, @NonNull String refPayOrderNo,

View File

@@ -0,0 +1,14 @@
package com.czg.service.product.mapper;
import com.mybatisflex.core.BaseMapper;
import com.czg.product.entity.MkOcrCountStick;
/**
* 数签子的外链渠道 映射层。
*
* @author ww
* @since 2025-12-24
*/
public interface MkOcrCountStickMapper extends BaseMapper<MkOcrCountStick> {
}

View File

@@ -32,7 +32,7 @@ public interface ProductMapper extends BaseMapper<Product> {
List<ShopProductVo> selectHotsProductList(@Param("shopId") Long shopId);
List<ShopProductVo> selectGroupProductList(@Param("shopId") Long shopId);
List<ShopProductVo> selectGroupProductList(@Param("shopId") Long shopId, @Param("idList") List<Long> idList);
ShopProductInfoVo selectOneProductInfo(@Param("id") Long id, @Param("shopId") Long shopId);

View File

@@ -1,370 +1,279 @@
package com.czg.service.product.service.impl;
package com.czg.service.product.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.czg.exception.CzgException;
import com.czg.market.entity.MkOcr;
import com.czg.product.entity.MkOcrService;
import com.czg.product.dto.ConsStockFlowDTO;
import com.czg.product.dto.SaleOrderDTO;
import com.czg.product.entity.ConsInfo;
import com.czg.product.entity.ConsStockFlow;
import com.czg.product.enums.InOutItemEnum;
import com.czg.product.enums.InOutTypeEnum;
import com.czg.product.param.*;
import com.czg.product.service.ConsStockFlowService;
import com.czg.product.vo.ConsCheckStockRecordVo;
import com.czg.sa.StpKit;
import com.czg.service.product.mapper.ConsInfoMapper;
import com.czg.service.product.mapper.ConsStockFlowMapper;
import com.czg.service.product.mapper.ProductMapper;
import com.czg.service.product.util.WxAccountUtil;
import com.czg.utils.AliOcrUtil;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.czg.exception.CzgException;
import com.czg.product.dto.ConsStockFlowDTO;
import com.czg.product.entity.ConsInfo;
import com.czg.product.entity.ConsStockFlow;
import com.czg.product.enums.InOutItemEnum;
import com.czg.product.enums.InOutTypeEnum;
import com.czg.product.param.*;
import com.czg.product.service.ConsStockFlowService;
import com.czg.product.vo.ConsCheckStockRecordVo;
import com.czg.sa.StpKit;
import com.czg.service.product.mapper.ConsInfoMapper;
import com.czg.service.product.mapper.ConsStockFlowMapper;
import com.czg.service.product.mapper.ProductMapper;
import com.czg.service.product.util.WxAccountUtil;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* 耗材库存变动记录
*
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-02-21
*/
@AllArgsConstructor
@Service
@Slf4j
public class ConsStockFlowServiceImpl extends ServiceImpl<ConsStockFlowMapper, ConsStockFlow> implements ConsStockFlowService {
/**
* 耗材库存变动记录
*
* @author Tankaikai tankaikai@aliyun.com
* @since 1.0 2025-02-21
*/
@AllArgsConstructor
@Service
@Slf4j
public class ConsStockFlowServiceImpl extends ServiceImpl<ConsStockFlowMapper, ConsStockFlow> implements ConsStockFlowService {
private final ConsInfoMapper consInfoMapper;
private final ProductMapper productMapper;
@Resource
private WxAccountUtil wxAccountUtil;
@Resource
private MkOcrService ocrService;
private final ConsInfoMapper consInfoMapper;
private final ProductMapper productMapper;
@Resource
private WxAccountUtil wxAccountUtil;
private QueryWrapper buildQueryWrapper(ConsStockFlowDTO param) {
QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();
private QueryWrapper buildQueryWrapper(ConsStockFlowDTO param) {
QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();
/*if (StrUtil.isNotEmpty(param.getName())) {
queryWrapper.like(ConsStockFlow::getName, param.getName());
}*/
Long shopId = StpKit.USER.getShopId(0L);
queryWrapper.eq(ConsStockFlow::getShopId, shopId);
queryWrapper.orderBy(ConsStockFlow::getId, false);
return queryWrapper;
}
Long shopId = StpKit.USER.getShopId(0L);
queryWrapper.eq(ConsStockFlow::getShopId, shopId);
queryWrapper.orderBy(ConsStockFlow::getId, false);
return queryWrapper;
}
@Override
@Transactional(rollbackFor = Exception.class)
public ConsInOutStockHeadParam inStock(ConsInOutStockHeadParam param) {
Long shopId = StpKit.USER.getShopId(0L);
Long createUserId = StpKit.USER.getLoginIdAsLong();
String createUserName = StpKit.USER.getAccount();
ConsStockFlow head = BeanUtil.copyProperties(param, ConsStockFlow.class);
List<ConsStockFlow> entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class);
List<ConsStockFlow> insertList = new ArrayList<>();
List<ConsInfo> updateStockList = new ArrayList<>();
for (ConsInOutStockBodyParam entity : param.getBodyList()) {
@Override
@Transactional(rollbackFor = Exception.class)
public ConsInOutStockHeadParam inStock(ConsInOutStockHeadParam param) {
Long shopId = StpKit.USER.getShopId(0L);
Long createUserId = StpKit.USER.getLoginIdAsLong();
String createUserName = StpKit.USER.getAccount();
ConsStockFlow head = BeanUtil.copyProperties(param, ConsStockFlow.class);
List<ConsStockFlow> entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class);
List<ConsStockFlow> insertList = new ArrayList<>();
List<ConsInfo> updateStockList = new ArrayList<>();
for (ConsInOutStockBodyParam entity : param.getBodyList()) {
ConsStockFlow consStockFlow = BeanUtil.copyProperties(entity, ConsStockFlow.class);
BeanUtil.copyProperties(head, entity, CopyOptions.create().ignoreNullValue());
consStockFlow.setShopId(shopId);
consStockFlow.setInOutType(InOutTypeEnum.IN.value());
consStockFlow.setInOutItem(InOutItemEnum.MANUAL_IN.value());
consStockFlow.setCreateUserId(createUserId);
consStockFlow.setCreateUserName(createUserName);
consStockFlow.setVendorId(param.getVendorId());
String conId = entity.getConId();
ConsInfo consInfo;
if (StrUtil.isBlank(entity.getConId())) {
consInfo = consInfoMapper.selectOneByQuery(new QueryWrapper().like(ConsInfo::getConName, entity.getConName())
.eq(ConsInfo::getShopId, shopId).limit(1));
if (consInfo == null) {
entity.setFailReason("耗材不存在");
}else if (!consInfo.getConUnit().equals(entity.getUnitName())) {
entity.setFailReason("耗材单位不匹配");
consInfo = null;
}
entity.setConId(consInfo == null ? null : consInfo.getId().toString());
consStockFlow.setConId(consInfo == null ? null : consInfo.getId());
}else {
consInfo = consInfoMapper.selectOneById(conId);
}
ConsStockFlow consStockFlow = BeanUtil.copyProperties(entity, ConsStockFlow.class);
BeanUtil.copyProperties(head, entity, CopyOptions.create().ignoreNullValue());
consStockFlow.setShopId(shopId);
consStockFlow.setInOutType(InOutTypeEnum.IN.value());
consStockFlow.setInOutItem(InOutItemEnum.MANUAL_IN.value());
consStockFlow.setCreateUserId(createUserId);
consStockFlow.setCreateUserName(createUserName);
consStockFlow.setVendorId(param.getVendorId());
String conId = entity.getConId();
ConsInfo consInfo;
if (StrUtil.isBlank(entity.getConId())) {
consInfo = consInfoMapper.selectOneByQuery(new QueryWrapper().like(ConsInfo::getConName, entity.getConName())
.eq(ConsInfo::getShopId, shopId).limit(1));
if (consInfo == null) {
continue;
entity.setFailReason("耗材不存在");
} else if (!consInfo.getConUnit().equals(entity.getUnitName())) {
entity.setFailReason("耗材单位不匹配");
consInfo = null;
}
consStockFlow.setBeforeNumber(consInfo.getStockNumber());
consStockFlow.setAfterNumber(NumberUtil.add(consStockFlow.getBeforeNumber(), entity.getInOutNumber()));
insertList.add(consStockFlow);
consInfo.setStockNumber(consStockFlow.getAfterNumber());
updateStockList.add(consInfo);
}
if (!insertList.isEmpty()) {
mapper.insertBatchSelective(insertList, 50);
}
for (ConsInfo consInfo : updateStockList) {
consInfoMapper.update(consInfo);
}
return param;
entity.setConId(consInfo == null ? null : consInfo.getId().toString());
consStockFlow.setConId(consInfo == null ? null : consInfo.getId());
} else {
consInfo = consInfoMapper.selectOneById(conId);
}
if (consInfo == null) {
continue;
}
consStockFlow.setBeforeNumber(consInfo.getStockNumber());
consStockFlow.setAfterNumber(NumberUtil.add(consStockFlow.getBeforeNumber(), entity.getInOutNumber()));
insertList.add(consStockFlow);
consInfo.setStockNumber(consStockFlow.getAfterNumber());
updateStockList.add(consInfo);
}
if (!insertList.isEmpty()) {
mapper.insertBatchSelective(insertList, 50);
}
for (ConsInfo consInfo : updateStockList) {
consInfoMapper.update(consInfo);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void outStock(ConsInOutStockHeadParam param) {
Long shopId = StpKit.USER.getShopId(0L);
Long createUserId = StpKit.USER.getLoginIdAsLong();
String createUserName = StpKit.USER.getAccount();
ConsStockFlow head = BeanUtil.copyProperties(param, ConsStockFlow.class);
List<ConsStockFlow> entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class);
List<ConsStockFlow> insertList = new ArrayList<>();
List<ConsInfo> updateStockList = new ArrayList<>();
for (ConsStockFlow entity : entityList) {
BeanUtil.copyProperties(head, entity, CopyOptions.create().ignoreNullValue());
entity.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, entity.getInOutNumber()));
entity.setShopId(shopId);
entity.setInOutType(InOutTypeEnum.OUT.value());
entity.setInOutItem(InOutItemEnum.MANUAL_OUT.value());
entity.setCreateUserId(createUserId);
entity.setCreateUserName(createUserName);
Long conId = entity.getConId();
ConsInfo consInfo = consInfoMapper.selectOneById(conId);
if (consInfo == null) {
throw new CzgException(StrUtil.format("耗材{}不存在", entity.getConName()));
}
entity.setBeforeNumber(consInfo.getStockNumber());
entity.setAfterNumber(NumberUtil.add(entity.getBeforeNumber(), entity.getInOutNumber()));
insertList.add(entity);
consInfo.setStockNumber(entity.getAfterNumber());
updateStockList.add(consInfo);
}
mapper.insertBatchSelective(insertList, 50);
for (ConsInfo consInfo : updateStockList) {
consInfoMapper.update(consInfo);
}
}
return param;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void checkStock(ConsCheckStockParam param) {
Long shopId = StpKit.USER.getShopId(0L);
Long createUserId = StpKit.USER.getLoginIdAsLong();
String createUserName = StpKit.USER.getAccount();
ConsStockFlow entity = new ConsStockFlow();
@Override
@Transactional(rollbackFor = Exception.class)
public void outStock(ConsInOutStockHeadParam param) {
Long shopId = StpKit.USER.getShopId(0L);
Long createUserId = StpKit.USER.getLoginIdAsLong();
String createUserName = StpKit.USER.getAccount();
ConsStockFlow head = BeanUtil.copyProperties(param, ConsStockFlow.class);
List<ConsStockFlow> entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class);
List<ConsStockFlow> insertList = new ArrayList<>();
List<ConsInfo> updateStockList = new ArrayList<>();
for (ConsStockFlow entity : entityList) {
BeanUtil.copyProperties(head, entity, CopyOptions.create().ignoreNullValue());
entity.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, entity.getInOutNumber()));
entity.setShopId(shopId);
entity.setInOutType(InOutTypeEnum.OUT.value());
entity.setInOutItem(InOutItemEnum.MANUAL_OUT.value());
entity.setCreateUserId(createUserId);
entity.setCreateUserName(createUserName);
entity.setShopId(shopId);
entity.setConId(param.getConId());
entity.setConName(param.getConName());
entity.setPurchasePrice(param.getPrice());
ConsInfo consInfo = consInfoMapper.selectOneById(param.getConId());
Long conId = entity.getConId();
ConsInfo consInfo = consInfoMapper.selectOneById(conId);
if (consInfo == null) {
throw new CzgException(StrUtil.format("耗材{}不存在", entity.getConName()));
}
BigDecimal winLossNumber = NumberUtil.sub(param.getActualNumber(), param.getStockNumber());
if (!NumberUtil.equals(winLossNumber, param.getWinLossNumber())) {
throw new CzgException(StrUtil.format("耗材{}库存在发生变动,请刷新后重试", entity.getConName()));
}
entity.setBeforeNumber(consInfo.getStockNumber());
entity.setInOutNumber(winLossNumber);
entity.setAfterNumber(NumberUtil.add(entity.getBeforeNumber(), entity.getInOutNumber()));
if (NumberUtil.isLess(winLossNumber, BigDecimal.ZERO)) {
entity.setInOutType(InOutTypeEnum.OUT.value());
entity.setInOutItem(InOutItemEnum.LOSS_OUT.value());
} else {
entity.setInOutType(InOutTypeEnum.IN.value());
entity.setInOutItem(InOutItemEnum.WIN_IN.value());
}
entity.setSubTotal(NumberUtil.mul(winLossNumber, param.getPrice()));
entity.setRemark(param.getRemark());
saveFlow(entity);
insertList.add(entity);
consInfo.setStockNumber(entity.getAfterNumber());
updateStockList.add(consInfo);
}
mapper.insertBatchSelective(insertList, 50);
for (ConsInfo consInfo : updateStockList) {
consInfoMapper.update(consInfo);
}
@Override
public Page<ConsCheckStockRecordVo> getCheckStockRecordPage(Long conId) {
Long shopId = StpKit.USER.getShopId(0L);
return super.pageAs(PageUtil.buildPage(), query().eq(ConsStockFlow::getShopId, shopId).eq(ConsStockFlow::getConId, conId).orderBy(ConsStockFlow::getId, false), ConsCheckStockRecordVo.class);
}
@Override
public List<ConsCheckStockRecordVo> getCheckStockRecordList(Long conId) {
Long shopId = StpKit.USER.getShopId(0L);
return super.mapper.selectListByQueryAs(query().eq(ConsStockFlow::getShopId, shopId).eq(ConsStockFlow::getConId, conId).orderBy(ConsStockFlow::getId, false), ConsCheckStockRecordVo.class);
}
@Override
public void reportDamage(ConsReportDamageParam param) {
Long shopId = StpKit.USER.getShopId(0L);
Long createUserId = StpKit.USER.getLoginIdAsLong();
String createUserName = StpKit.USER.getAccount();
ConsInfo consInfo = consInfoMapper.selectOneById(param.getConId());
if (consInfo == null) {
throw new CzgException("耗材不存在");
}
ConsStockFlow entity = new ConsStockFlow();
entity.setCreateUserId(createUserId);
entity.setCreateUserName(createUserName);
entity.setShopId(shopId);
entity.setConId(param.getConId());
entity.setConName(consInfo.getConName());
entity.setPurchasePrice(consInfo.getPrice());
BigDecimal balance = NumberUtil.sub(consInfo.getStockNumber(), param.getNumber());
if (NumberUtil.isLess(balance, BigDecimal.ZERO)) {
throw new CzgException(StrUtil.format("耗材{}报损数量不能大于当前库存{}", entity.getConName(), consInfo.getStockNumber()));
}
entity.setBeforeNumber(consInfo.getStockNumber());
entity.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, param.getNumber()));
entity.setAfterNumber(balance);
entity.setInOutType(InOutTypeEnum.OUT.value());
entity.setInOutItem(InOutItemEnum.DAMAGE_OUT.value());
entity.setSubTotal(NumberUtil.mul(param.getNumber(), consInfo.getPrice()));
entity.setImgUrls(JSON.toJSONString(param.getImgUrls()));
saveFlow(entity);
consInfo.setStockNumber(entity.getAfterNumber());
consInfoMapper.update(consInfo);
}
@Override
public Page<ConsStockFlowDTO> findConsStockFlowPage(ConsStockFlowParam param) {
Long shopId = StpKit.USER.getShopId(0L);
PageHelper.startPage(PageUtil.buildPageHelp());
return PageUtil.convert(new PageInfo<>(mapper.findConsStockFlowPage(shopId, param.getInOutType(), param.getInOutItem(), param.getConId())));
}
@Override
public void saveFlow(ConsStockFlow entity) {
super.save(entity);
Long shopId = entity.getShopId();
BigDecimal afterNumber = entity.getAfterNumber();
ConsInfo consInfo = consInfoMapper.selectOneById(entity.getConId());
String shopName = "";
try {
shopName = StpKit.USER.getShopName();
} catch (Exception e) {
log.error("获取店铺名称失败");
}
if (StrUtil.isEmpty(shopName)) {
shopName = productMapper.getShopName(shopId);
}
BigDecimal conWarning = consInfo.getConWarning();
// 库存小于警告值,发送消息提醒
if (NumberUtil.isLess(afterNumber, conWarning)) {
List<String> openIdList = consInfoMapper.findOpenIdList(shopId, "con");
if (CollUtil.isEmpty(openIdList)) {
return;
}
String conName = StrUtil.format("{}数量<预警值{}", consInfo.getConName(), conWarning);
String finalShopName = shopName;
ThreadUtil.execAsync(() -> {
openIdList.parallelStream().forEach(openId -> {
wxAccountUtil.sendStockMsg(finalShopName, conName, afterNumber, openId);
});
});
}
}
@Override
public Integer ocr(String originalFilename, InputStream inputStream) {
Long shopId = StpKit.USER.getShopId();
byte[] readAllBytes = null;
try {
readAllBytes = inputStream.readAllBytes();
} catch (IOException e) {
throw new RuntimeException(e);
}
String md5 = DigestUtil.md5Hex(readAllBytes);
MkOcr ocr = ocrService.getOne(new QueryWrapper().eq(MkOcr::getShopId, shopId).eq(MkOcr::getMd5, md5));
if (ocr != null) {
return ocr.getId();
}
MkOcr mkOcr = new MkOcr();
mkOcr.setShopId(shopId);
mkOcr.setMd5(md5);
ocrService.save(mkOcr);
byte[] finalReadAllBytes1 = readAllBytes;
ThreadUtil.execAsync(() -> {
try {
String infoStr = AliOcrUtil.appCall(finalReadAllBytes1, originalFilename);
SaleOrderDTO saleOrderDTO = JSONObject.parseObject(infoStr, SaleOrderDTO.class);
ArrayList<ConsInOutStockBodyParam> bodyList = new ArrayList<>();
Set<String> nameList = saleOrderDTO.getItems().stream().map(SaleOrderDTO.Item::getConName).collect(Collectors.toSet());
Map<String, ConsInfo> consInfoMap = new HashMap<>();
if (!nameList.isEmpty()) {
consInfoMap = consInfoMapper.selectListByQuery(new QueryWrapper().in(ConsInfo::getConName, nameList).eq(ConsInfo::getShopId, shopId))
.stream().collect(Collectors.toMap(ConsInfo::getConName, consInfo -> consInfo));
}
ArrayList<SaleOrderDTO.Item> unInCons = new ArrayList<>();
for (SaleOrderDTO.Item item : saleOrderDTO.getItems()) {
ConsInOutStockBodyParam bodyParam = new ConsInOutStockBodyParam()
.setConName(item.getConName())
.setPurchasePrice(new BigDecimal(item.getPurchasePrice()))
.setUnitName(item.getUnitName())
.setSubTotal(new BigDecimal(item.getSubTotal()))
.setInOutNumber(new BigDecimal(item.getInOutNumber()));
ConsInfo consInfo = consInfoMap.get(item.getConName());
if (consInfo != null) {
unInCons.add(item);
bodyParam.setConId(consInfo.getId().toString());
}
bodyList.add(bodyParam);
}
ConsInOutStockHeadParam headParam = new ConsInOutStockHeadParam();
headParam.setBatchNo(saleOrderDTO.getOrderNumber())
.setInOutDate(LocalDate.parse(saleOrderDTO.getDate()))
.setAmountPayable(new BigDecimal(saleOrderDTO.getTotalAmount()))
.setBodyList(bodyList)
.setUnInCons(unInCons)
.setOcrSaleOrder(saleOrderDTO);
mkOcr.setStatus("SUCCESS");
mkOcr.setResp(JSON.toJSONString(headParam));
}catch (Exception e) {
mkOcr.setErr(e.getMessage());
mkOcr.setStatus("FAILED");
log.error("ocr失败:", e);
}finally {
ocrService.updateById(mkOcr);
}
});
return mkOcr.getId();
}
@Override
public ConsInOutStockHeadParam ocrDetail(Long id) {
MkOcr mkOcr = ocrService.getOne(new QueryWrapper().eq(MkOcr::getShopId, StpKit.USER.getShopId()).eq(MkOcr::getId, id));
if (StrUtil.isNotBlank(mkOcr.getResp())) {
return JSONObject.parseObject(mkOcr.getResp(), ConsInOutStockHeadParam.class);
}
return null;
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void checkStock(ConsCheckStockParam param) {
Long shopId = StpKit.USER.getShopId(0L);
Long createUserId = StpKit.USER.getLoginIdAsLong();
String createUserName = StpKit.USER.getAccount();
ConsStockFlow entity = new ConsStockFlow();
entity.setCreateUserId(createUserId);
entity.setCreateUserName(createUserName);
entity.setShopId(shopId);
entity.setConId(param.getConId());
entity.setConName(param.getConName());
entity.setPurchasePrice(param.getPrice());
ConsInfo consInfo = consInfoMapper.selectOneById(param.getConId());
if (consInfo == null) {
throw new CzgException(StrUtil.format("耗材{}不存在", entity.getConName()));
}
BigDecimal winLossNumber = NumberUtil.sub(param.getActualNumber(), param.getStockNumber());
if (!NumberUtil.equals(winLossNumber, param.getWinLossNumber())) {
throw new CzgException(StrUtil.format("耗材{}库存在发生变动,请刷新后重试", entity.getConName()));
}
entity.setBeforeNumber(consInfo.getStockNumber());
entity.setInOutNumber(winLossNumber);
entity.setAfterNumber(NumberUtil.add(entity.getBeforeNumber(), entity.getInOutNumber()));
if (NumberUtil.isLess(winLossNumber, BigDecimal.ZERO)) {
entity.setInOutType(InOutTypeEnum.OUT.value());
entity.setInOutItem(InOutItemEnum.LOSS_OUT.value());
} else {
entity.setInOutType(InOutTypeEnum.IN.value());
entity.setInOutItem(InOutItemEnum.WIN_IN.value());
}
entity.setSubTotal(NumberUtil.mul(winLossNumber, param.getPrice()));
entity.setRemark(param.getRemark());
saveFlow(entity);
consInfo.setStockNumber(entity.getAfterNumber());
consInfoMapper.update(consInfo);
}
@Override
public Page<ConsCheckStockRecordVo> getCheckStockRecordPage(Long conId) {
Long shopId = StpKit.USER.getShopId(0L);
return super.pageAs(PageUtil.buildPage(), query().eq(ConsStockFlow::getShopId, shopId).eq(ConsStockFlow::getConId, conId).orderBy(ConsStockFlow::getId, false), ConsCheckStockRecordVo.class);
}
@Override
public List<ConsCheckStockRecordVo> getCheckStockRecordList(Long conId) {
Long shopId = StpKit.USER.getShopId(0L);
return super.mapper.selectListByQueryAs(query().eq(ConsStockFlow::getShopId, shopId).eq(ConsStockFlow::getConId, conId).orderBy(ConsStockFlow::getId, false), ConsCheckStockRecordVo.class);
}
@Override
public void reportDamage(ConsReportDamageParam param) {
Long shopId = StpKit.USER.getShopId(0L);
Long createUserId = StpKit.USER.getLoginIdAsLong();
String createUserName = StpKit.USER.getAccount();
ConsInfo consInfo = consInfoMapper.selectOneById(param.getConId());
if (consInfo == null) {
throw new CzgException("耗材不存在");
}
ConsStockFlow entity = new ConsStockFlow();
entity.setCreateUserId(createUserId);
entity.setCreateUserName(createUserName);
entity.setShopId(shopId);
entity.setConId(param.getConId());
entity.setConName(consInfo.getConName());
entity.setPurchasePrice(consInfo.getPrice());
BigDecimal balance = NumberUtil.sub(consInfo.getStockNumber(), param.getNumber());
if (NumberUtil.isLess(balance, BigDecimal.ZERO)) {
throw new CzgException(StrUtil.format("耗材{}报损数量不能大于当前库存{}", entity.getConName(), consInfo.getStockNumber()));
}
entity.setBeforeNumber(consInfo.getStockNumber());
entity.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, param.getNumber()));
entity.setAfterNumber(balance);
entity.setInOutType(InOutTypeEnum.OUT.value());
entity.setInOutItem(InOutItemEnum.DAMAGE_OUT.value());
entity.setSubTotal(NumberUtil.mul(param.getNumber(), consInfo.getPrice()));
entity.setImgUrls(JSON.toJSONString(param.getImgUrls()));
saveFlow(entity);
consInfo.setStockNumber(entity.getAfterNumber());
consInfoMapper.update(consInfo);
}
@Override
public Page<ConsStockFlowDTO> findConsStockFlowPage(ConsStockFlowParam param) {
Long shopId = StpKit.USER.getShopId(0L);
PageHelper.startPage(PageUtil.buildPageHelp());
return PageUtil.convert(new PageInfo<>(mapper.findConsStockFlowPage(shopId, param.getInOutType(), param.getInOutItem(), param.getConId())));
}
@Override
public void saveFlow(ConsStockFlow entity) {
super.save(entity);
Long shopId = entity.getShopId();
BigDecimal afterNumber = entity.getAfterNumber();
ConsInfo consInfo = consInfoMapper.selectOneById(entity.getConId());
String shopName = "";
try {
shopName = StpKit.USER.getShopName();
} catch (Exception e) {
log.error("获取店铺名称失败");
}
if (StrUtil.isEmpty(shopName)) {
shopName = productMapper.getShopName(shopId);
}
BigDecimal conWarning = consInfo.getConWarning();
// 库存小于警告值,发送消息提醒
if (NumberUtil.isLess(afterNumber, conWarning)) {
List<String> openIdList = consInfoMapper.findOpenIdList(shopId, "con");
if (CollUtil.isEmpty(openIdList)) {
return;
}
String conName = StrUtil.format("{}数量<预警值{}", consInfo.getConName(), conWarning);
String finalShopName = shopName;
ThreadUtil.execAsync(() -> {
openIdList.parallelStream().forEach(openId -> {
wxAccountUtil.sendStockMsg(finalShopName, conName, afterNumber, openId);
});
});
}
}
}

View File

@@ -0,0 +1,72 @@
package com.czg.service.product.service.impl;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import com.czg.constants.SystemConstants;
import com.czg.product.entity.MkOcrCountStick;
import com.czg.product.service.MkOcrCountStickService;
import com.czg.service.RedisService;
import com.czg.service.product.mapper.MkOcrCountStickMapper;
import com.czg.service.product.util.AISmartCountUtils;
import com.czg.service.product.util.MuSmartCountUtils;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 数签子的外链渠道 服务层实现。
*
* @author ww
* @since 2025-12-24
*/
@Slf4j
@Service
public class MkOcrCountStickServiceImpl extends ServiceImpl<MkOcrCountStickMapper, MkOcrCountStick> implements MkOcrCountStickService {
@Resource
private RedisService redisService;
@Override
public int getCountStick(byte[] fileByte, String fileName) {
List<MkOcrCountStick> list = list(query().eq(MkOcrCountStick::getStatus, SystemConstants.OneZero.ONE).orderBy(MkOcrCountStick::getSort, true));
for (MkOcrCountStick mkOcrCountStick : list) {
if ("znds".equals(mkOcrCountStick.getMark())) {
try {
String tickCount = AISmartCountUtils.getTickCount(mkOcrCountStick.getToken(), fileByte, fileName);
if (StrUtil.isNotBlank(tickCount)) {
return Integer.parseInt(tickCount);
}
} catch (Exception e) {
mkOcrCountStick.setStatus(SystemConstants.OneZero.ZERO);
log.error("智能点数失败", e);
updateById(mkOcrCountStick);
}
} else if ("ygmh".equals(mkOcrCountStick.getMark())) {
try {
String token = getToken(mkOcrCountStick.getAccount(), mkOcrCountStick.getPwd());
return MuSmartCountUtils.detectBambooStick(Base64.encode(fileByte), token);
} catch (Exception e) {
mkOcrCountStick.setStatus(SystemConstants.OneZero.ZERO);
log.error("智能点数失败", e);
updateById(mkOcrCountStick);
}
}
}
return 0;
}
// 一个木涵 获取token
private String getToken(String username, String password) {
Object token = redisService.get("ocr:ygmh:token");
if (token != null) {
return token.toString();
}
String muToken = MuSmartCountUtils.login(username, password);
//时间为3个月减去60秒
redisService.set("ocr:ygmh:token", muToken, 7775940);
return muToken;
}
}

View File

@@ -1,18 +1,148 @@
package com.czg.service.product.service.impl;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.czg.product.dto.SaleOrderDTO;
import com.czg.product.entity.ConsInfo;
import com.czg.product.param.ConsInOutStockBodyParam;
import com.czg.product.param.ConsInOutStockHeadParam;
import com.czg.sa.StpKit;
import com.czg.service.product.mapper.ConsInfoMapper;
import com.czg.service.product.mapper.MkOcrMapper;
import com.czg.utils.AliOcrUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.czg.market.entity.MkOcr;
import com.czg.product.entity.MkOcrService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* ocr识别结果 服务层实现。
*
* @author zs
* @since 2025-11-26
*/
@Slf4j
@Service
public class MkOcrServiceImpl extends ServiceImpl<MkOcrMapper, MkOcr> implements MkOcrService{
public class MkOcrServiceImpl extends ServiceImpl<MkOcrMapper, MkOcr> implements MkOcrService {
@Resource
private ConsInfoMapper consInfoMapper;
String consOcrDetail = "你是一名票据OCR结构化专家请从我提供的票据图片中智能提取信息并只输出JSON不得添加解释、不补充不存在内容、不得返回空字符串、字段缺失填null、字段不可省略、数字一律用字符串" +
"使用以下固定JSON结构{\"documentType\":\"\",\"orderNumber\":\"\",\"date\":\"\",\"customerName\":\"\",\"operator\":\"\"," +
"\"items\":[{\"conName\":\"\",\"spec\":\"\",\"unitName\":\"\",\"inOutNumber\":\"\",\"purchasePrice\":\"\",\"subTotal\":\"\"}]," +
"\"totalAmount\":\"\",\"remark\":\"\"}。字段映射规则documentType对应单据类型/销售单/采购单/出货单orderNumber对应单号/编号/No" +
"date对应日期/开单日期customerName对应客户名称/收货单位/供应商operator对应业务员/经办人/制单人/操作员items.conName对应品名/名称;" +
"items.spec对应规格/型号items.unitName对应单位items.inOutNumber对应数量items.purchasePrice对应单价items.subTotal对应金额/小计;" +
"totalAmount对应总金额/合计金额remark对应备注。严禁生成图片中不存在的字段内容看不清或未出现的字段必须为null不允许推测或补全不得生成多余字段" +
"items只能根据识别到的行生成不得虚构。必须能识别旋转、倾斜、模糊、撕裂、光照差异、列顺序混乱、无表格线等情况并尽量恢复信息。" +
"最终输出必须是纯JSON不得包含任何非JSON字符。";
@Override
public ConsInOutStockHeadParam ocrDetail(Long id) {
MkOcr mkOcr = getOne(new QueryWrapper().eq(MkOcr::getShopId, StpKit.USER.getShopId()).eq(MkOcr::getId, id));
if (StrUtil.isNotBlank(mkOcr.getResp())) {
return JSONObject.parseObject(mkOcr.getResp(), ConsInOutStockHeadParam.class);
}
return null;
}
@Override
public Integer ocr(String originalFilename, InputStream inputStream, String type) {
Long shopId = StpKit.USER.getShopId();
byte[] readAllBytes = null;
try {
readAllBytes = inputStream.readAllBytes();
} catch (IOException e) {
throw new RuntimeException(e);
}
String md5 = DigestUtil.md5Hex(readAllBytes);
MkOcr ocr = getOne(new QueryWrapper().eq(MkOcr::getShopId, shopId).eq(MkOcr::getMd5, md5));
if (ocr != null) {
return ocr.getId();
}
MkOcr mkOcr = new MkOcr();
mkOcr.setShopId(shopId);
mkOcr.setMd5(md5);
save(mkOcr);
byte[] finalReadAllBytes1 = readAllBytes;
ThreadUtil.execAsync(() -> {
try {
if ("cons".equals(type)) {
mkOcr.setResp(ocrCons(finalReadAllBytes1, originalFilename, shopId));
} else {
}
mkOcr.setStatus("SUCCESS");
} catch (Exception e) {
mkOcr.setErr(e.getMessage());
mkOcr.setStatus("FAILED");
log.error("ocr失败:", e);
} finally {
updateById(mkOcr);
}
});
return mkOcr.getId();
}
/**
* 识别 入库单
*/
private String ocrCons(byte[] finalReadAllBytes1, String originalFilename, Long shopId) {
String infoStr = AliOcrUtil.appCall(finalReadAllBytes1, originalFilename, consOcrDetail);
SaleOrderDTO saleOrderDTO = JSONObject.parseObject(infoStr, SaleOrderDTO.class);
ArrayList<ConsInOutStockBodyParam> bodyList = new ArrayList<>();
Set<String> nameList = saleOrderDTO.getItems().stream().map(SaleOrderDTO.Item::getConName).collect(Collectors.toSet());
Map<String, ConsInfo> consInfoMap = new HashMap<>();
if (!nameList.isEmpty()) {
consInfoMap = consInfoMapper.selectListByQuery(new QueryWrapper().in(ConsInfo::getConName, nameList).eq(ConsInfo::getShopId, shopId))
.stream().collect(Collectors.toMap(ConsInfo::getConName, consInfo -> consInfo));
}
ArrayList<SaleOrderDTO.Item> unInCons = new ArrayList<>();
for (SaleOrderDTO.Item item : saleOrderDTO.getItems()) {
ConsInOutStockBodyParam bodyParam = new ConsInOutStockBodyParam()
.setConName(item.getConName())
.setPurchasePrice(new BigDecimal(item.getPurchasePrice()))
.setUnitName(item.getUnitName())
.setSubTotal(new BigDecimal(item.getSubTotal()))
.setInOutNumber(new BigDecimal(item.getInOutNumber()));
ConsInfo consInfo = consInfoMap.get(item.getConName());
if (consInfo != null) {
unInCons.add(item);
bodyParam.setConId(consInfo.getId().toString());
}
bodyList.add(bodyParam);
}
ConsInOutStockHeadParam headParam = new ConsInOutStockHeadParam();
headParam.setBatchNo(saleOrderDTO.getOrderNumber())
.setInOutDate(LocalDate.parse(saleOrderDTO.getDate()))
.setAmountPayable(new BigDecimal(saleOrderDTO.getTotalAmount()))
.setBodyList(bodyList)
.setUnInCons(unInCons)
.setOcrSaleOrder(saleOrderDTO);
return JSON.toJSONString(headParam);
}
}

View File

@@ -6,14 +6,12 @@ import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONWriter;
import com.czg.constant.CacheConstant;
import com.czg.constants.SystemConstants;
import com.czg.exception.CzgException;
import com.czg.product.dto.ProdConsRelationDTO;
import com.czg.product.dto.ProdSkuDTO;
import com.czg.product.dto.ProductDTO;
import com.czg.product.dto.ShopProdCategoryDTO;
import com.czg.product.dto.*;
import com.czg.product.entity.*;
import com.czg.product.enums.*;
import com.czg.product.param.*;
@@ -310,6 +308,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
dto.setSkuList(skuList);
List<ProdConsRelationDTO> consList = prodConsRelationMapper.selectListByProdId(dto.getId());
dto.setConsList(consList);
dto.setRelatedRecommendJson(getRelateProductList(dto.getRelatedRecommend()));
return dto;
}
@@ -336,6 +335,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
}
entity.setIsDel(SystemConstants.OneZero.ZERO);
entity.setShopId(shopId);
entity.setRelatedRecommend(dto.getRelatedRecommendStr());
super.save(entity);
dto.setId(entity.getId());
// 清除商品分类列表缓存
@@ -404,6 +404,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
if (!ProductTypeEnum.SKU.value().equals(entity.getType())) {
UpdateChain.of(Product.class).set(Product::getSpecId, null).eq(Product::getId, dto.getId()).update();
}
entity.setRelatedRecommend(dto.getRelatedRecommendStr());
super.updateById(entity);
// 清除商品分类列表缓存
clearProductCache(old.getCategoryId());
@@ -788,4 +789,16 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
String key = StrUtil.format(CacheConstant.SHOP_PRODUCT_STOCK, shopId, productId);
redisService.set(key, stockNumber);
}
private List<RelatedProductDTO> getRelateProductList(String relatedProduct) {
if (StrUtil.isNotBlank(relatedProduct) && !"[]".equals(relatedProduct)) {
List<Long> idList = JSONArray.parseArray(relatedProduct, Long.class);
QueryWrapper wrapper = QueryWrapper.create().select(Product::getId, Product::getName, Product::getCoverImg).eq(Product::getIsDel, SystemConstants.OneZero.ZERO)
.in(Product::getId, idList);
return super.listAs(wrapper, RelatedProductDTO.class);
}
return new ArrayList<>();
}
}

View File

@@ -6,6 +6,7 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.czg.constant.CacheConstant;
import com.czg.constants.SystemConstants;
import com.czg.exception.CzgException;
@@ -78,7 +79,7 @@ public class UProductServiceImpl extends ServiceImpl<ProductMapper, Product> imp
query().select(ProdGroup::getId, ProdGroup::getName, ProdGroup::getSortMode, ProdGroup::getUseTime, ProdGroup::getSaleStartTime, ProdGroup::getSaleEndTime)
.eq(ProdGroup::getShopId, shopId).eq(ProdGroup::getStatus,SystemConstants.OneZero.ONE)
.orderBy(ProdGroup::getSort, true), ShopGroupProductVo.class);
List<ShopProductVo> productAllList = productMapper.selectGroupProductList(shopId);
List<ShopProductVo> productAllList = productMapper.selectGroupProductList(shopId, null);
productAllList.forEach(item -> {
List<ProdSkuDTO> skuList = prodSkuMapper.selectListByQueryAs(query()
.eq(ProdSku::getProductId, item.getId())
@@ -130,6 +131,21 @@ public class UProductServiceImpl extends ServiceImpl<ProductMapper, Product> imp
if (data == null) {
throw new CzgException("商品不可售");
}
if (StrUtil.isBlank(data.getRelatedRecommend()) || "[]".equals(data.getRelatedRecommend())) {
data.setRelatedRecommendJson(new ArrayList<>());
} else {
List<ShopProductVo> productAllList = productMapper.selectGroupProductList(shopId, JSONArray.parseArray(data.getRelatedRecommend(), Long.class));
productAllList.forEach(item -> {
List<ProdSkuDTO> skuList = prodSkuMapper.selectListByQueryAs(query()
.eq(ProdSku::getProductId, item.getId())
.eq(ProdSku::getIsGrounding, SystemConstants.OneZero.ONE)
.eq(ProdSku::getIsDel, SystemConstants.OneZero.ZERO), ProdSkuDTO.class);
item.setSkuList(skuList);
});
data.setRelatedRecommendJson(productAllList);
}
return data;
}

View File

@@ -0,0 +1,132 @@
package com.czg.service.product.util;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.exception.CzgException;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.net.URLEncoder;
/**
* 智能点数上传工具类
* @author ww
*/
@Slf4j
public class AISmartCountUtils {
// 基础配置
private static final String BASE_URL = "https://api.aismartcount.com/api/v1";
private static final int TIMEOUT = 30000;
/**
* 示例:完整调用流程
*/
public static String getTickCount(String token, byte[] file, String fileName) throws Exception {
String uploadResponse = uploadImage(token, file, fileName);
return countImageDots(token, uploadResponse);
}
/**
* 上传图片接口
* 完全使用你提供的header(String, String)方法设置请求头
*
* @param imageData 图片数据InputStream / byte[] / File
* @return 上传响应结果
* @throws Exception 上传异常
*/
private static String uploadImage(String token, Object imageData, String fileName) {
// 1. 构建请求URL
String uploadUrl = BASE_URL + "/upload/image";
// 2. 构建POST请求并设置基础参数
HttpRequest postRequest = HttpUtil.createPost(uploadUrl)
.header("authorization", token)
.timeout(TIMEOUT);
// 3. 根据数据类型设置文件上传参数
if (imageData instanceof File files) {
postRequest.form("file", files);
} else if (imageData instanceof InputStream input) {
postRequest.form("file", input, fileName);
} else if (imageData instanceof byte[] bytes) {
postRequest.form("file", bytes, fileName);
} else {
throw new IllegalArgumentException("不支持的图片数据类型:" + (imageData == null ? "null" : imageData.getClass().getName()));
}
String body = postRequest.execute().body();
// 解析上传响应并校验状态码
JSONObject uploadResult = JSONUtil.parseObj(body);
// 1. 校验响应码(核心)
int code = uploadResult.getInt("code", -1);
if (code != 200) {
log.error("智能点数 图片上传失败 {}", uploadResult);
throw new CzgException("图片上传失败");
}
JSONObject dataObj = uploadResult.getJSONObject("data");
if (dataObj == null) {
log.error("智能点数 图片上传响应中未找到data字段 {}", uploadResult);
throw new CzgException("图片上传失败");
}
String imgUrl = dataObj.getStr("url");
if (StrUtil.isBlank(imgUrl)) {
log.error("智能点数 图片上传成功但未返回图片URL {}", uploadResult);
throw new CzgException("图片上传成功但未返回图片URL");
}
return imgUrl;
}
/**
* 统计图片点数接口
* 手动拼接URL参数使用header方法设置授权头
*
* @param imgUrl 图片URL
* @return 统计响应结果
* @throws Exception 请求异常
*/
private static String countImageDots(String token, String imgUrl) throws Exception {
String countUrl = BASE_URL + "/count/count-image-dots" +
"?img_url=" + encodeParam(imgUrl) +
"&type=stick&secure=true&upload_source=pc";
// 2. 构建请求(仅使用你提供的方法)
String countResponse = HttpUtil.createPost(countUrl)
.header("authorization", token)
.timeout(TIMEOUT)
.execute()
.body();
JSONObject countResult = JSONUtil.parseObj(countResponse);
int countCode = countResult.getInt("code", -1);
if (countCode != 200) {
log.error("智能点数 点数统计失败,未知错误 {}", countResult);
throw new CzgException("点数统计失败,未知错误");
}
// 3. 执行请求并返回结果
return countResult.getStr("total_count");
}
/**
* 通用URL参数编码
*
* @param param 要编码的参数
* @return 编码后的字符串
*/
private static String encodeParam(String param) {
if (StrUtil.isBlank(param)) {
return "";
}
try {
return URLEncoder.encode(param, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException("URL参数编码失败: " + param, e);
}
}
}

View File

@@ -0,0 +1,122 @@
package com.czg.service.product.util;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.czg.exception.CzgException;
import lombok.extern.slf4j.Slf4j;
/**
* 一个木涵
*
* @author: ww
*/
@Slf4j
public class MuSmartCountUtils {
// 基础配置
private static final String LOGIN_URL = "https://uapi.woobx.cn/user/login";
private static final String DETECT_URL = "https://uapi.woobx.cn/app/object-det/bamboo-stick";
// 请求超时时间(毫秒)
private static final int TIMEOUT = 10000;
/**
* 登录接口 - 获取认证Token线程安全
*
* @return 认证Token
*/
public static String login(String username, String password) {
// 构建登录请求
HttpResponse response = HttpRequest.post(LOGIN_URL)
.form("username", username)
.form("password", password)
.timeout(TIMEOUT)
.execute();
// 校验响应状态
if (!response.isOk()) {
log.error("登录失败,响应码:{},数据:{}", response.getStatus(), response.body());
throw new CzgException("登录失败");
}
// 解析响应结果
String responseStr = response.body();
JSONObject result = JSON.parseObject(responseStr);
if (200 != result.getIntValue("code")) {
log.error("登录失败,响应码:{},数据:{}", response.getStatus(), result);
throw new CzgException("登录失败");
}
// 提取并缓存Token
String token = result.getJSONObject("data").getString("authToken");
if (StrUtil.isBlank(token)) {
log.error("登录失败,响应码:{},数据:{}", response.getStatus(), result);
throw new CzgException("登录失败");
}
return token;
}
/**
* 竹签识别核心方法自动处理Token过期重试
*
* @param imageBase64 图片Base64编码字符串
* @return 识别结果JSON对象
* @throws Exception 识别异常
*/
public static int detectBambooStick(String imageBase64, String token) throws Exception {
// 参数校验
if (StrUtil.isBlank(imageBase64)) {
throw new CzgException("图片Base64编码不能为空");
}
// 第一次调用识别接口
JSONObject detectResult = doDetectRequest(imageBase64, token);
return MuSmartCountUtils.countBambooStick(detectResult);
}
/**
* 执行竹签识别请求(核心请求逻辑)
*
* @param imageBase64 图片Base64编码
* @param token 认证Token
* @return 识别结果
*/
private static JSONObject doDetectRequest(String imageBase64, String token){
// 构建识别请求
HttpResponse response = HttpRequest.post(DETECT_URL)
.header("authorization", "Bearer " + token)
.form("image", imageBase64)
.form("base64", "true")
.timeout(TIMEOUT)
.execute();
// 校验响应状态
if (!response.isOk()) {
throw new RuntimeException("识别请求失败,响应码:" + response.getStatus());
}
// 解析响应结果
String responseStr = response.body();
return JSON.parseObject(responseStr);
}
/**
* 解析识别结果,统计竹签数量(自定义分数阈值)
*
* @param detectResult 识别结果JSON
* @return 竹签数量
*/
private static int countBambooStick(JSONObject detectResult) {
// 参数校验
if (detectResult == null || 200 != detectResult.getIntValue("code")) {
return 0;
}
JSONArray dataArray = detectResult.getJSONArray("data");
if (dataArray == null || dataArray.isEmpty()) {
return 0;
}
return dataArray.size();
}
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.czg.service.product.mapper.MkOcrCountStickMapper">
</mapper>

View File

@@ -95,7 +95,8 @@
t1.pack_fee,
ifnull(t4.sales_volume, 0) as sales_volume,
t1.shop_id,
t1.is_stock
t1.is_stock,
t1.related_recommend
from tb_product t1
left join (select x.product_id,
x.id as sku_id,
@@ -147,6 +148,12 @@
and t2.sale_price is not null
and t1.shop_id = #{shopId}
</where>
<if test="idList != null">
and t1.id in
<foreach item="item" collection="idList" separator="," open="(" close=")">
#{item}
</foreach>
</if>
order by t1.sort desc,t1.id desc
</select>
<select id="selectOneProductInfo" resultType="com.czg.product.vo.ShopProductInfoVo">

View File

@@ -12,6 +12,9 @@ import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import java.util.Map;
import java.util.Set;
/**
* 验证码工具类
*
@@ -23,38 +26,24 @@ public class SmsServiceImpl implements SmsService {
@Resource
private SysParamsService sysParamsService;
/**
* 阿里云key
*/
private String key;
/**
* 阿里云secret
*/
private String secret;
/**
* 短信模板id
*/
private String templateCode;
@PostConstruct
public void init() {
key = sysParamsService.getSysParamValue(ParamCodeCst.AliYun.ALI_SMS_KEY);
secret = sysParamsService.getSysParamValue(ParamCodeCst.AliYun.ALI_SMS_SECRET);
templateCode = sysParamsService.getSysParamValue(ParamCodeCst.AliYun.ALI_SMS_TEMPLATE_CODE);
log.info("短信工具类初始化完毕key: {}, secret: {}, templateCode: {}", key, secret, templateCode);
}
public Client createClient() throws Exception {
public Client init() throws Exception {
Config config = new Config();
config.accessKeyId = key;
config.accessKeySecret = secret;
Map<String, String> aliOssKeys = sysParamsService.getParamsByMap("ali_oss_key_set", ParamCodeCst.ALI_OSS_KEY_SET);
config.accessKeyId = aliOssKeys.get(ParamCodeCst.AliYun.ALI_SMS_KEY);
config.accessKeySecret = aliOssKeys.get(ParamCodeCst.AliYun.ALI_SMS_SECRET);
templateCode = aliOssKeys.get(ParamCodeCst.AliYun.ALI_SMS_TEMPLATE_CODE);
return new Client(config);
}
@Override
public void sendCode(String phone, String checkCode) {
try {
Client client = createClient();
Client client = init();
// 1.发送短信
com.aliyun.dysmsapi20170525.models.SendSmsRequest sendSmsRequest = new com.aliyun.dysmsapi20170525.models.SendSmsRequest()
.setSignName("陕西超掌柜科技")
@@ -67,7 +56,7 @@ public class SmsServiceImpl implements SmsService {
if (sendSmsResponse.getStatusCode() != 200) {
throw new CzgException("短信发送失败");
}
}catch (Exception e) {
} catch (Exception e) {
log.info("发送短信失败", e);
}
}

View File

@@ -140,12 +140,12 @@ public class SysParamsServiceImpl extends ServiceImpl<SysParamsMapper, SysParams
@Cacheable(cacheNames = "params:entity", key = "#type")
@Override
public Map<String, String> getParamsByMap(String type, Set<String> keyList) throws CzgException{
public Map<String, String> getParamsByMap(String type, Set<String> keyList) throws CzgException {
Map<String, String> map = new HashMap<>();
for (String key : keyList) {
SysParams sysParam = getSysParam(key);
if (sysParam == null || StrUtil.isBlank(sysParam.getParamValue())) {
throw new CzgException(key + "参数不存在");
throw new CzgException("sysParam的类型" + type + "" + key + "参数不存在");
}
map.put(key, sysParam.getParamValue());
}