diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/constant/IotConstants.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/constant/IotConstants.java index dbfd279f..1a2e51e5 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/constant/IotConstants.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/constant/IotConstants.java @@ -86,6 +86,11 @@ public class IotConstants { public static final String COMMAND_SET_PASS = "pass"; + /** + * 命令 设置语音播报阈值(秒) + */ + public static final String COMMAND_SET_VOICE = "dj_set"; + /**----------------------------命令end----------------------------*/ } diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/TmPayService.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/TmPayService.java index 4e5d100f..c6772952 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/TmPayService.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/TmPayService.java @@ -23,8 +23,6 @@ import java.util.Map; @Service public class TmPayService { - private final static String SIGNKEY = "b4ixpiogfj5vu3tbkv23gj0dvo2j2ksz"; - @Autowired private TmPayConfig config; @@ -147,7 +145,7 @@ public class TmPayService { params.remove("sign"); // 按照请求时的签名逻辑,生成签名字符串 String paramsStr = TmPayUtil.getAsciiSort(params); // 按ASCII排序 - String generatedSign = TmPayUtil.getMD5Code(paramsStr + "&key=" + SIGNKEY).toUpperCase(); // 重新生成签名 + String generatedSign = TmPayUtil.getMD5Code(paramsStr + "&key=" + config.getSignKey()).toUpperCase(); // 重新生成签名 System.out.println("新生成的签名-----------:"+generatedSign); // 比较签名是否一致 return generatedSign.equals(receivedSign); diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/enums/PayStatus.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/enums/TmPayStatus.java similarity index 79% rename from smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/enums/PayStatus.java rename to smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/enums/TmPayStatus.java index ec1b55a1..de8a42f5 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/enums/PayStatus.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/enums/TmPayStatus.java @@ -10,7 +10,7 @@ import lombok.Getter; */ @Getter @AllArgsConstructor -public enum PayStatus { +public enum TmPayStatus { SUCCESS("SUCCESS", "支付成功"), NOTPAY("NOTPAY", "未支付"), @@ -36,6 +36,15 @@ public enum PayStatus { return SUCCESS.getCode().equals(code); } + /** + * 判断支付状态是否成功 + * @param status 支付状态 + * @return 是否成功 + */ + public static boolean isSuccess(TmPayStatus status) { + return status != null && SUCCESS.getCode().equals(status.getCode()); + } + /** * 判断支付状态是否转入退款 * @param code 支付状态码 @@ -50,8 +59,8 @@ public enum PayStatus { * @param code 支付状态码 * @return 对应的PayStatus枚举 */ - public static PayStatus getByCode(String code) { - for (PayStatus status : PayStatus.values()) { + public static TmPayStatus getByCode(String code) { + for (TmPayStatus status : TmPayStatus.values()) { if (status.getCode().equals(code)) { return status; } diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/enums/RefundStatus.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/enums/TmRefundStatus.java similarity index 84% rename from smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/enums/RefundStatus.java rename to smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/enums/TmRefundStatus.java index 49ab6b1a..826f2d64 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/enums/RefundStatus.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/enums/TmRefundStatus.java @@ -10,7 +10,7 @@ import lombok.Getter; */ @Getter @AllArgsConstructor -public enum RefundStatus { +public enum TmRefundStatus { FAILED(0, "退款失败"), REFUNDED(1, "转入退款"); @@ -31,8 +31,8 @@ public enum RefundStatus { * @param code 状态码 * @return 对应的 RefundStatus 枚举 */ - public static RefundStatus getByCode(int code) { - for (RefundStatus status : RefundStatus.values()) { + public static TmRefundStatus getByCode(int code) { + for (TmRefundStatus status : TmRefundStatus.values()) { if (status.getCode() == code) { return status; } diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/vo/RefundInfo.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/vo/RefundInfo.java index e0abca5f..bfd1dddf 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/vo/RefundInfo.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/vo/RefundInfo.java @@ -1,6 +1,6 @@ package com.ruoyi.common.pay.tm.vo; -import com.ruoyi.common.pay.tm.enums.RefundStatus; +import com.ruoyi.common.pay.tm.enums.TmRefundStatus; import lombok.Data; /** @@ -23,7 +23,7 @@ public class RefundInfo { private String fromType; // 订单来源: wx, alipay, web, mini, pos, pc, desktop, api private String refundTime; // 退款成功时间 private String refundMessage; // 退款失败原因 - private RefundStatus refundStatus; // 退款状态: RefundStatus 枚举 + private TmRefundStatus refundStatus; // 退款状态: RefundStatus 枚举 private String refundAmount; // 已退款金额 private String createTime; // 创建时间 } diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/vo/TmTradeInfo.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/vo/TmTradeInfo.java index d6a1fbdc..aa7d822d 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/vo/TmTradeInfo.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/pay/tm/vo/TmTradeInfo.java @@ -1,6 +1,6 @@ package com.ruoyi.common.pay.tm.vo; -import com.ruoyi.common.pay.tm.enums.PayStatus; +import com.ruoyi.common.pay.tm.enums.TmPayStatus; import lombok.Data; @Data @@ -132,7 +132,7 @@ public class TmTradeInfo { * OPERATE_SETTLING:押金消费已受理; * REVOKED_SUCCESS:预授权请求撤销成功 */ - private PayStatus payStatus; + private TmPayStatus payStatus; /** * 支付时间 diff --git a/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotService.java b/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotService.java index ada0c84b..52d00d75 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotService.java +++ b/smart-switch-service/src/main/java/com/ruoyi/iot/service/IotService.java @@ -1,9 +1,6 @@ package com.ruoyi.iot.service; -import com.ruoyi.iot.domain.CurrentDeviceData; -import com.ruoyi.iot.domain.HistoryDeviceData; -import com.ruoyi.iot.domain.IotDeviceDetail; import com.ruoyi.iot.domain.IotDeviceInfo; import com.ruoyi.iot.domain.response.CommandResponse; import com.ruoyi.iot.interfaces.IotDevice; @@ -145,4 +142,14 @@ public interface IotService { CommandResponse setWifi(IotDevice device, String wifiName, String wifiPwd); CommandResponse setWifi(String mac, String productId, String wifiName, String wifiPwd); + + /** + * 设置倒计时提醒 + * + * @param device 设备 + * @param seconds 倒计时(秒) + */ + boolean setVoice(IotDevice device, long seconds); + + boolean setVoice(String mac, String productId, long seconds); } diff --git a/smart-switch-service/src/main/java/com/ruoyi/iot/service/impl/IotServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/iot/service/impl/IotServiceImpl.java index e7c7d477..f8807982 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/iot/service/impl/IotServiceImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/iot/service/impl/IotServiceImpl.java @@ -31,8 +31,6 @@ import java.util.List; import java.util.Objects; import java.util.stream.Collectors; -import static org.bouncycastle.oer.its.Duration.seconds; - /** * @author wjh * 2024/3/20 @@ -452,5 +450,31 @@ public class IotServiceImpl implements IotService { return null; } + @Override + public boolean setVoice(IotDevice device, long seconds) { + if (device == null) { + return false; + } + + try { + boolean res = this.setVoice(device.iotMac1(), device.getProductId(), seconds); + ServiceUtil.assertion(!res, "设备MAC1设置语音播报时间失败"); + return true; + } catch (Exception e) { + log.warn("设备MAC1设置语音播报时间失败: {}", e.getMessage()); + return this.setVoice(device.iotMac2(), device.getProductId(), seconds); + } + } + + @Override + public boolean setVoice(String mac, String productId, long seconds) { + if (StringUtils.isBlank(mac) || StringUtils.isBlank(productId)) { + return false; + } + CommandResponse res = this.sendCommand(mac, IotConstants.COMMAND_SET_VOICE + seconds + IotConstants.COMMAND_SEPARATOR, productId); + ServiceUtil.assertion(!res.isSuccess(), "设置语音播报失败:" + res.getMsg()); + return res.isSuccess(); + } + } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/DeviceValidator.java b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/DeviceValidator.java index e05f9e2e..ec948dfc 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/DeviceValidator.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/DeviceValidator.java @@ -2,6 +2,7 @@ package com.ruoyi.ss.device.service; import com.ruoyi.common.core.domain.ValidateResult; import com.ruoyi.ss.device.domain.DeviceBO; +import com.ruoyi.ss.device.domain.vo.DeviceVO; import java.util.Collection; import java.util.List; @@ -50,4 +51,9 @@ public interface DeviceValidator { * 判断MAC是否重复 */ boolean isRepeatMac(Long deviceId, String mac); + + /** + * 后校验 + */ + void afterCheck(DeviceVO vo); } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceServiceImpl.java index 018aed23..08d2fa15 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceServiceImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceServiceImpl.java @@ -167,24 +167,26 @@ public class DeviceServiceImpl implements DeviceService ServiceUtil.assertion(StringUtils.isBlank(data.getMac()), "参数错误,MAC不允许为空"); String key = data.getDeviceNo(); - ServiceUtil.assertion(!redisLock.lock(RedisLockKey.ADD_DEVICE, key), "当前录入人数过多,请稍后再试"); + ServiceUtil.assertion(!redisLock.lock(RedisLockKey.ADD_DEVICE, key), "当前新增设备过于频繁,请稍后再试"); try { - ServiceUtil.assertion(deviceValidator.isRepeatMac(data.getDeviceId(), data.getMac()), "MAC-1重复:" + data.getMac()); - ServiceUtil.assertion(deviceValidator.isRepeatMac(data.getDeviceId(), data.getMac2()), "MAC-2重复:" + data.getMac2()); - ServiceUtil.assertion(deviceValidator.isRepeatSn(data.getDeviceId(), data.getDeviceNo()), "SN重复"); SmModelVO model = modelService.selectSmModelByModelId(data.getModelId()); ServiceUtil.assertion(model == null, "型号不存在"); - ServiceUtil.assertion(StringUtils.isBlank(model.getProductId()), "型号产品ID为空"); + ServiceUtil.assertion(StringUtils.isBlank(model.getProductId()), "型号产品ID未配置,请联系管理员处理"); data.setCreateTime(DateUtils.getNowDate()); data.setStatus(DeviceStatus.NORMAL.getStatus()); + data.setOnlineStatus(DeviceOnlineStatus.OFFLINE.getStatus()); Integer result = transactionTemplate.execute(status -> { // 创建设备 int insert = deviceMapper.insertSmDevice(data); ServiceUtil.assertion(insert != 1, "新增设备失败"); + // 后校验 + DeviceVO vo = this.selectSmDeviceByDeviceId(data.getDeviceId()); + deviceValidator.afterCheck(vo); + // 创建OneNet设备1 int code = iotService.create(data.getMac(), model.getProductId()); ServiceUtil.assertion(!IotHttpStatus.SUCCESS.equalCode(code) && !IotHttpStatus.DEVICE_EXIST.equalCode(code), "MAC-1注册失败"); @@ -209,11 +211,7 @@ public class DeviceServiceImpl implements DeviceService */ @Override @Transactional - public int updateSmDevice(DeviceBO data) - { - if (StringUtils.hasText(data.getDeviceNo())) { - ServiceUtil.assertion(deviceValidator.isRepeatSn(data.getDeviceId(), data.getDeviceNo()), "SN重复"); - } + public int updateSmDevice(DeviceBO data) { data.setUpdateTime(DateUtils.getNowDate()); @@ -222,6 +220,10 @@ public class DeviceServiceImpl implements DeviceService int update = deviceMapper.updateSmDevice(data); ServiceUtil.assertion(update != 1, "更新设备失败"); + // 后校验 + DeviceVO vo = this.selectSmDeviceByDeviceId(data.getDeviceId()); + deviceValidator.afterCheck(vo); + // 更新套餐关联 if (data.getSuitIds() != null) { // 删除设备套餐关联 diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceValidatorImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceValidatorImpl.java index 3cb7b68d..0d334566 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceValidatorImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/device/service/impl/DeviceValidatorImpl.java @@ -3,6 +3,8 @@ package com.ruoyi.ss.device.service.impl; import com.ruoyi.common.core.domain.BaseValidator; import com.ruoyi.common.core.domain.ValidateResult; import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.ServiceUtil; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.collection.CollectionUtils; import com.ruoyi.ss.device.domain.DeviceBO; import com.ruoyi.ss.device.domain.DeviceQuery; @@ -11,7 +13,6 @@ import com.ruoyi.ss.device.service.DeviceService; import com.ruoyi.ss.device.service.DeviceValidator; import com.ruoyi.ss.store.service.StoreValidator; import com.ruoyi.ss.suit.service.SuitValidator; -import org.apache.commons.lang.StringUtils; import org.eclipse.jetty.util.StringUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -159,4 +160,21 @@ public class DeviceValidatorImpl extends BaseValidator implements DeviceValidato } return false; } + + @Override + public void afterCheck(DeviceVO vo) { + if (vo == null) { + return; + } + if (StringUtils.hasText(vo.getMac()) || StringUtils.hasText(vo.getMac2())) { + ServiceUtil.assertion(Objects.equals(vo.getMac(), vo.getMac2()), "MAC-1和MAC-2不允许相同"); + } + if (vo.getUserId() != null || vo.getAgentId() != null) { + ServiceUtil.assertion(Objects.equals(vo.getUserId(), vo.getAgentId()), "代理商和商户不允许是同一个用户"); + } + ServiceUtil.assertion(this.isRepeatMac(vo.getDeviceId(), vo.getMac()), "MAC-1重复:" + vo.getMac()); + ServiceUtil.assertion(this.isRepeatMac(vo.getDeviceId(), vo.getMac2()), "MAC-2重复:" + vo.getMac2()); + ServiceUtil.assertion(this.isRepeatSn(vo.getDeviceId(), vo.getDeviceNo()), "SN重复"); + + } } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/service/impl/PayBillServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/service/impl/PayBillServiceImpl.java index fe42a9db..36c95e5c 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/service/impl/PayBillServiceImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/payBill/service/impl/PayBillServiceImpl.java @@ -5,6 +5,9 @@ import com.ruoyi.common.core.redis.enums.RedisLockKey; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.pay.syb.enums.SybTrxStatus; import com.ruoyi.common.pay.syb.service.SybPayService; +import com.ruoyi.common.pay.tm.TmPayService; +import com.ruoyi.common.pay.tm.enums.TmPayStatus; +import com.ruoyi.common.pay.tm.vo.TmTradeInfo; import com.ruoyi.common.pay.wx.service.WxPayService; import com.ruoyi.common.pay.wx.util.WxPayUtil; import com.ruoyi.common.utils.DateUtils; @@ -82,6 +85,9 @@ public class PayBillServiceImpl implements PayBillService @Autowired private SybPayService sybPayService; + @Autowired + private TmPayService tmPayService; + /** * 查询支付订单 * @@ -239,6 +245,10 @@ public class PayBillServiceImpl implements PayBillService } } } + // 太米微信 + else if (TransactionBillPayType.TM_WX.getType().equals(bill.getChannelId())) { + tmPayService.closeOrder(bill.getPayNo()); + } } } @@ -334,6 +344,8 @@ public class PayBillServiceImpl implements PayBillService vo.setPayParams(wxPayService.prepayWithRequestPayment(bill)); } else if (TransactionBillPayType.TL_WX.getType().equals(bill.getChannelId())) { vo.setPayParams(sybPayService.prepayWxApp(bill)); + } else if (TransactionBillPayType.TM_WX.getType().equals(bill.getChannelId())) { + vo.setPayParams(tmPayService.pay(bill)); } else { throw new ServiceException("暂不支持该支付方式"); } @@ -518,6 +530,14 @@ public class PayBillServiceImpl implements PayBillService } else { return PayResultVO.fail("暂未支付成功"); } + } else if (TransactionBillPayType.TM_WX.getType().equals(bill.getChannelId())) { + // 太米微信支付 + TmTradeInfo result = tmPayService.orderQuery(bill.getPayNo()); + if (result != null && TmPayStatus.isSuccess(result.getPayStatus())) { + return PayResultVO.success(LocalDateTime.now()); // TODO 支付时间 + } else { + return PayResultVO.fail("暂未支付成功"); + } } return PayResultVO.fail("暂不支持该支付方式"); } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/refund/service/impl/RefundServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/refund/service/impl/RefundServiceImpl.java index babba0be..93c9abec 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/refund/service/impl/RefundServiceImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/refund/service/impl/RefundServiceImpl.java @@ -3,6 +3,9 @@ package com.ruoyi.ss.refund.service.impl; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.pay.syb.enums.SybTrxStatus; import com.ruoyi.common.pay.syb.service.SybPayService; +import com.ruoyi.common.pay.tm.TmPayService; +import com.ruoyi.common.pay.tm.enums.TmRefundStatus; +import com.ruoyi.common.pay.tm.vo.RefundInfo; import com.ruoyi.common.pay.wx.service.WxPayService; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.ServiceUtil; @@ -56,6 +59,9 @@ public class RefundServiceImpl implements RefundService @Autowired private ScheduledExecutorService scheduledExecutorService; + @Autowired + private TmPayService tmPayService; + /** * 查询退款订单 @@ -204,7 +210,17 @@ public class RefundServiceImpl implements RefundService this.handleRefundSuccess(refund.getRefundNo()); }, 0, TimeUnit.SECONDS); } - } else { + } + // 太米支付 + else if (TransactionBillPayType.TM_WX.getType().equals(refund.getChannelId())) { + RefundInfo refundResult = tmPayService.refund(refundVO); + ServiceUtil.assertion(!TmRefundStatus.isSuccess(refundResult.getRefundStatus().getCode()), "发起退款失败:" + refundResult.getRefundMessage()); + // 太米退款是同步通知,直接处理退款成功 + scheduledExecutorService.schedule(() -> { + handleRefundSuccess(refund.getRefundNo()); + }, 0, TimeUnit.SECONDS); + } + else { throw new ServiceException("当前支付方式不支持退款"); } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/store/domain/StoreBO.java b/smart-switch-service/src/main/java/com/ruoyi/ss/store/domain/StoreBO.java index 2075cba1..63682dde 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/store/domain/StoreBO.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/store/domain/StoreBO.java @@ -30,6 +30,7 @@ public class StoreBO extends Store { bo.setContactName(getContactName()); bo.setContactMobile(getContactMobile()); bo.setShow(getShow()); + bo.setUseOutTime(getUseOutTime()); return bo; } @@ -52,6 +53,7 @@ public class StoreBO extends Store { bo.setContactName(getContactName()); bo.setContactMobile(getContactMobile()); bo.setShow(getShow()); + bo.setUseOutTime(getUseOutTime()); return bo; } @@ -76,6 +78,7 @@ public class StoreBO extends Store { bo.setContactName(getContactName()); bo.setContactMobile(getContactMobile()); bo.setShow(getShow()); + bo.setUseOutTime(getUseOutTime()); return bo; } @@ -102,6 +105,7 @@ public class StoreBO extends Store { bo.setShow(getShow()); bo.setStatus(StoreStatus.NORMAL.getStatus()); bo.setEnabled(true); + bo.setUseOutTime(getUseOutTime()); return bo; } } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/suit/domain/Suit.java b/smart-switch-service/src/main/java/com/ruoyi/ss/suit/domain/Suit.java index 807c3bfb..7c696c82 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/suit/domain/Suit.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/suit/domain/Suit.java @@ -114,4 +114,14 @@ public class Suit extends BaseEntity @Min(value = 0, message = "低功率关闭订单的功率值不允许小于0") @JsonView(JsonViewProfile.App.class) private BigDecimal lowPower; + + @Excel(name = "是否开启结束前语音播报") + @ApiModelProperty("是否开启结束前语音播报") + @JsonView(JsonViewProfile.App.class) + private Boolean enabledVoice; + + @Excel(name = "语音播报剩余时长", readConverterExp = "分=钟") + @ApiModelProperty("语音播报剩余时长(分钟)") + @JsonView(JsonViewProfile.App.class) + private BigDecimal voiceMinutes; } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/suit/domain/SuitBO.java b/smart-switch-service/src/main/java/com/ruoyi/ss/suit/domain/SuitBO.java index ea613d6c..54145135 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/suit/domain/SuitBO.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/suit/domain/SuitBO.java @@ -35,6 +35,8 @@ public class SuitBO extends Suit { bo.setGearTime(getGearTime()); bo.setEnabledLowPowerClose(getEnabledLowPowerClose()); bo.setLowPower(getLowPower()); + bo.setEnabledVoice(getEnabledVoice()); + bo.setVoiceMinutes(getVoiceMinutes()); return bo; } @@ -57,6 +59,8 @@ public class SuitBO extends Suit { bo.setGearTime(getGearTime()); bo.setEnabledLowPowerClose(getEnabledLowPowerClose()); bo.setLowPower(getLowPower()); + bo.setEnabledVoice(getEnabledVoice()); + bo.setVoiceMinutes(getVoiceMinutes()); return bo; } } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/suit/mapper/SuitMapper.xml b/smart-switch-service/src/main/java/com/ruoyi/ss/suit/mapper/SuitMapper.xml index f4f5a9e9..8f939977 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/suit/mapper/SuitMapper.xml +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/suit/mapper/SuitMapper.xml @@ -30,6 +30,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ss.gear_time, ss.enabled_low_power_close, ss.low_power, + ss.enabled_voice, + ss.voice_minutes, su.user_name as user_name from @@ -48,9 +50,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and ss.deleted = false and ss.deleted = #{deleted} and ss.user_id = #{userId} - and fee_mode = #{feeMode} - and fee_type = #{feeType} - and enabled_low_power_close = #{enabledLowPowerClose} + and ss.fee_mode = #{feeMode} + and ss.fee_type = #{feeType} + and ss.enabled_low_power_close = #{enabledLowPowerClose} + and ss.enabled_voice = #{enabledVoice} and ss.suit_id in ( select distinct sds.suit_id from ss_device_suit sds where sds.device_id = #{deviceId} @@ -125,6 +128,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" gear_time, enabled_low_power_close, low_power, + enabled_voice, + voice_minutes, #{name}, @@ -145,6 +150,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{gearTime,typeHandler=com.ruoyi.system.mapper.typehandler.IntegerSplitListTypeHandler}, #{enabledLowPowerClose}, #{lowPower}, + #{enabledVoice}, + #{voiceMinutes}, @@ -172,6 +179,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" gear_time = #{gearTime,typeHandler=com.ruoyi.system.mapper.typehandler.IntegerSplitListTypeHandler}, enabled_low_power_close = #{enabledLowPowerClose}, low_power = #{lowPower}, + enabled_voice = #{enabledVoice}, + voice_minutes = #{voiceMinutes}, diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/TransactionBill.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/TransactionBill.java index b9358453..08b7549e 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/TransactionBill.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/TransactionBill.java @@ -290,6 +290,22 @@ public class TransactionBill extends BaseEntity implements Payable @ApiModelProperty("代理商手机号") private String agentMobile; + @Excel(name = "套餐是否开启语音播报") + @ApiModelProperty("套餐是否开启语音播报") + private Boolean suitEnabledVoid; + + @Excel(name = "套餐语音播报阈值", readConverterExp = "分=钟") + @ApiModelProperty("套餐语音播报阈值") + private BigDecimal suitVoidMinute; + + @Excel(name = "套餐语音播报设置结果", readConverterExp = "1=-成功,2-失败") + @ApiModelProperty("套餐语音播报设置结果") + private String suitVoidResult; + + @Excel(name = "套餐语音播报设置结果描述") + @ApiModelProperty("套餐语音播报设置结果描述") + private String suitVoidMsg; + /** * 获取价格(分) */ diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/enums/RechargeVoiceStatus.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/enums/RechargeVoiceStatus.java new file mode 100644 index 00000000..abc5942e --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/enums/RechargeVoiceStatus.java @@ -0,0 +1,21 @@ +package com.ruoyi.ss.transactionBill.domain.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 语音开启状态 + * @author wjh + * 2024/9/30 + */ +@Getter +@AllArgsConstructor +public enum RechargeVoiceStatus { + + SUCCESS("1", "成功"), + FAIL("0", "失败"); + + private final String status; + private final String msg; + +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/enums/TransactionBillPayType.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/enums/TransactionBillPayType.java index c5541fc6..d634632c 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/enums/TransactionBillPayType.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/domain/enums/TransactionBillPayType.java @@ -24,8 +24,8 @@ public enum TransactionBillPayType { ALI(2L, "支付宝", AccountType.ALIPAY), BANK(3L, "银行卡", AccountType.BANK_CARD), BALANCE(4L, "余额支付", null), - TL_WX(5L, "通联微信支付", null) - ; + TL_WX(5L, "通联微信支付", null), + TM_WX(6L, "太米微信支付", null); private final Long type; private final String name; @@ -44,7 +44,10 @@ public enum TransactionBillPayType { return Arrays.stream(types).map(TransactionBillPayType::getType).collect(Collectors.toList()); } + /** + * 微信支付列表 + */ public static List wxList() { - return asList(WECHAT, TL_WX); + return asList(WECHAT, TL_WX, TM_WX); } } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/mapper/TransactionBillMapper.xml b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/mapper/TransactionBillMapper.xml index 5ac6a6ae..2d70cd97 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/mapper/TransactionBillMapper.xml +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/mapper/TransactionBillMapper.xml @@ -72,6 +72,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" stb.close_result, stb.agent_id, stb.agent_mobile, + stb.suit_enabled_void, + stb.suit_void_minute, + stb.suit_void_result, + stb.suit_void_msg, @@ -192,6 +196,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and stb.close_status = #{query.closeStatus} and stb.agent_id = #{query.agentId} and stb.agent_mobile like concat('%', #{query.agentMobile}, '%') + and stb.suit_enabled_void = #{query.suitEnabledVoid} + and stb.suit_void_result = #{query.suitVoidResult} and @@ -468,6 +474,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" close_result, agent_id, agent_mobile, + suit_enabled_void, + suit_void_minute, + suit_void_result, + suit_void_msg, #{billNo}, @@ -528,6 +538,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{closeResult}, #{agentId}, #{agentMobile}, + #{suitEnabledVoid}, + #{suitVoidMinute}, + #{suitVoidResult}, + #{suitVoidMsg}, @@ -606,6 +620,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" stb.close_result = #{data.closeResult}, stb.agent_id = #{data.agentId}, stb.agent_mobile = #{data.agentMobile}, + stb.suit_enabled_void = #{data.suitEnabledVoid}, + stb.suit_void_minute = #{data.suitVoidMinute}, + stb.suit_void_result = #{data.suitVoidResult}, + stb.suit_void_msg = #{data.suitVoidMsg}, diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillServiceImpl.java index 1bce4137..dc8359d3 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillServiceImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillServiceImpl.java @@ -447,6 +447,8 @@ public class TransactionBillServiceImpl implements TransactionBillService, After order.setSuitName(suit.getName()); order.setSuitEnableLowPowerClose(suit.getEnabledLowPowerClose()); order.setSuitLowPower(suit.getLowPower()); + order.setSuitEnabledVoid(suit.getEnabledVoice()); + order.setSuitVoidMinute(suit.getVoiceMinutes()); // 设备信息 order.setDeviceNo(dto.getDeviceNo()); @@ -954,14 +956,65 @@ public class TransactionBillServiceImpl implements TransactionBillService, After return updateCount; }); - // 充值设备,尝试1次 + // 操作成功 if (result != null && result == 1) { + // 充值设备,尝试1次 this.tryRechargeDevice(bill.getBillId(), 1); + + // 设备设置语音播报 + scheduledExecutorService.schedule(() -> { + this.trySetVoice(bill, 3); + }, 0, TimeUnit.SECONDS); } + return result == null ? 0 : result; } + /** + * 尝试设置语音播报 + */ + private void trySetVoice(TransactionBillVO bill, int tryCount) { + if (tryCount <= 0) { + return; + } + try { + transactionTemplate.execute(status -> { + // 设置为成功 + int update = this.updateVoiceResult(bill.getBillId(), RechargeVoiceStatus.SUCCESS, "成功"); + ServiceUtil.assertion(update != 1, "更新订单信息失败"); + + // 发送命令 + boolean res = false; + if (bill.getSuitEnabledVoid() == null || !bill.getSuitEnabledVoid() || bill.getSuitVoidMinute() == null) { + res = iotService.setVoice(bill, 0L); + } else { + res = iotService.setVoice(bill, bill.getSuitVoidMinute().multiply(BigDecimal.valueOf(60)).longValue()); + } + ServiceUtil.assertion(!res, "设备设置语音失败"); + + return res; + }); + } catch (Exception e) { + log.info("订单设置设备语音失败:{}, 剩余次数:{}", bill.getBillNo(), tryCount - 1); + if (tryCount <= 1) { + // 设置为失败 + int update = this.updateVoiceResult(bill.getBillId(), RechargeVoiceStatus.FAIL, e.getMessage()); + ServiceUtil.assertion(update != 1, "更新订单信息失败"); + } else { + this.trySetVoice(bill, tryCount - 1); + } + } + } + + private int updateVoiceResult(Long billId, RechargeVoiceStatus status, String msg) { + TransactionBill data = new TransactionBill(); + data.setBillId(billId); + data.setSuitVoidResult(status.getStatus()); + data.setSuitVoidMsg(msg); + return transactionBillMapper.updateSmTransactionBill(data); + } + /** * 异步尝试充值设备 * @param billId @@ -971,14 +1024,12 @@ public class TransactionBillServiceImpl implements TransactionBillService, After if (tryCount <= 0) { return; } -// scheduledExecutorService.schedule(()-> { try { boolean result = rechargeDevice(billId); ServiceUtil.assertion(!result, String.format("尝试充值设备失败:billId=%s:剩余次数:%s,", billId, tryCount - 1)); } catch (Exception e) { this.tryRechargeDevice(billId, tryCount - 1); } -// }, 0, TimeUnit.SECONDS); } @Override diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillValidatorImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillValidatorImpl.java index 0f1a17f1..3a5141a3 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillValidatorImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillValidatorImpl.java @@ -71,7 +71,7 @@ public class TransactionBillValidatorImpl extends BaseValidator implements Trans if (store != null) { LocalTime now = LocalTime.now(); if (!storeValidator.isBusinessTime(store, now)) { - return error(String.format("当前店铺不在营业时间内,无法下单。营业时间:%s - %s", store.getBusinessTimeStart(), store.getBusinessTimeEnd())); + return error(String.format("请在营业时间内使用该设备!营业时间:%s - %s", store.getBusinessTimeStart(), store.getBusinessTimeEnd())); } } diff --git a/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java b/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java index 9e11ce78..831d593e 100644 --- a/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java +++ b/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppPayController.java @@ -1,6 +1,7 @@ package com.ruoyi.web.controller.app; import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; import com.ruoyi.common.annotation.Anonymous; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; @@ -9,6 +10,8 @@ import com.ruoyi.common.pay.syb.enums.SybTrxCode; import com.ruoyi.common.pay.syb.enums.SybTrxStatus; import com.ruoyi.common.pay.syb.service.SybPayService; import com.ruoyi.common.pay.syb.util.SybUtil; +import com.ruoyi.common.pay.tm.TmPayService; +import com.ruoyi.common.pay.tm.enums.TmPayStatus; import com.ruoyi.common.pay.wx.domain.enums.WxNotifyEventType; import com.ruoyi.common.pay.wx.domain.enums.WxTransferBatchStatus; import com.ruoyi.common.pay.wx.util.WxPayUtil; @@ -38,6 +41,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; +import java.time.LocalDateTime; +import java.util.Map; import java.util.TreeMap; /** @@ -65,6 +70,9 @@ public class AppPayController extends BaseController { @Autowired private TransactionBillConverter transactionBillConverter; + @Autowired + private TmPayService tmPayService; + @ApiOperation("微信支付充值订单") @GetMapping("/wx/{billNo}") public AjaxResult wxPay(@PathVariable @ApiParam("订单编号") String billNo) { @@ -192,4 +200,35 @@ public class AppPayController extends BaseController { } } + + /** + * 太米微信支付回调 + */ + @ApiOperation(value = "太米微信支付回调") + @PostMapping("/notify/tm") + public String tmwx(HttpServletRequest request) { + try { + String body = HttpUtils.getBody(request); + log.info("【太米微信支付回调】接收对象 : " + body); + // 先把body转成map + Map params = JSON.parseObject(body, Map.class); + // 验证签名 + boolean sign = tmPayService.validSign(params); + if (sign) { + JSONObject tradeInfo = (JSONObject)params.get("tradeInfo"); + String payType = tradeInfo.getString("payType"); // 交易类型 + String outTradeId = tradeInfo.getString("outTradeId"); // 商户自定义订单号 + String payStatus = tradeInfo.getString("payStatus"); // 交易结果 + if(TmPayStatus.isSuccess(payStatus) && payType.equals("wx_pay")) { + payBillService.handleSuccess(outTradeId, LocalDateTime.now()); // TODO 支付时间待定 + } + }else { + throw new ServiceException("签名验证失败"); + } + return "{\"result\":\"SUCCESS\"}"; + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } + } + } diff --git a/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppTransactionBillController.java b/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppTransactionBillController.java index 437c1c82..ebdade50 100644 --- a/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppTransactionBillController.java +++ b/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppTransactionBillController.java @@ -282,7 +282,6 @@ public class AppTransactionBillController extends BaseController @ApiOperation("支付押金") @PutMapping("/payDeposit") public AjaxResult payDeposit(@RequestBody @Validated PayDepositDTO dto) { - dto.setChannelId(1L); return success(transactionBillService.payDeposit(transactionBillConverter.toRechargePayDepositBO(dto))); } @@ -355,7 +354,6 @@ public class AppTransactionBillController extends BaseController @ApiOperation("支付订单") @PutMapping("/pay") public AjaxResult pay(@RequestBody BillPayDTO dto) { - dto.setChannelId(1L); TransactionBillVO bill = transactionBillService.selectSmTransactionBillByBillNo(dto.getBillNo()); if (!transactionBillValidator.isUser(bill, getUserId())) { return error("这不是您的订单,无法支付"); diff --git a/smart-switch-web/src/main/resources/application-dev.yml b/smart-switch-web/src/main/resources/application-dev.yml index 9474375e..7bf1795b 100644 --- a/smart-switch-web/src/main/resources/application-dev.yml +++ b/smart-switch-web/src/main/resources/application-dev.yml @@ -110,6 +110,15 @@ syb: # 支付通知地址 notifyUrl: http://124.221.246.124:2290/app/pay/notify/tl +# 太米支付 +tm: + developerId: "100232" + shopId: "0034947" + signKey: b4ixpiogfj5vu3tbkv23gj0dvo2j2ksz + httpUrl: https://v5.taimi100.com + sn: "" + notifyUrl: http://124.221.246.124:2290/app/pay/notify/tm + # 活体检测跳转地址 liveness: returnUrl: http://192.168.2.81:3001/liveness