国际化
This commit is contained in:
1 parent
2a167fdf84
commit
348f83bfa5
59 files changed
+4112
-856
No files matched your search
+8
-6
@@ -16,7 +16,9 @@ import com.bsd.pjcloud.common.core.constant.CacheConstants;
|
||||
import com.bsd.pjcloud.common.core.constant.CommonConstants;
|
||||
import com.bsd.pjcloud.common.core.constant.SecurityConstants;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.CaptchaFlagTypeEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.ValidateCodeException;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.SpringContextHolder;
|
||||
import com.bsd.pjcloud.common.core.util.WebUtils;
|
||||
import jakarta.servlet.FilterChain;
|
||||
@@ -103,7 +105,7 @@ public class ValidateCodeFilter extends OncePerRequestFilter {
|
||||
String code = request.getParameter("code");
|
||||
|
||||
if (StrUtil.isBlank(code)) {
|
||||
throw new ValidateCodeException("验证码不能为空");
|
||||
throw new ValidateCodeException(MsgUtils.getMessage(ErrorCodes.AUTH_CAPTCHA_EMPTY));
|
||||
}
|
||||
|
||||
String randomStr = request.getParameter("randomStr");
|
||||
@@ -121,7 +123,7 @@ public class ValidateCodeFilter extends OncePerRequestFilter {
|
||||
vo.setCaptchaVerification(code);
|
||||
vo.setCaptchaType(CommonConstants.IMAGE_CODE_TYPE);
|
||||
if (!captchaService.verification(vo).isSuccess()) {
|
||||
throw new ValidateCodeException("验证码不能为空");
|
||||
throw new ValidateCodeException(MsgUtils.getMessage(ErrorCodes.AUTH_CAPTCHA_EMPTY));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -129,24 +131,24 @@ public class ValidateCodeFilter extends OncePerRequestFilter {
|
||||
|
||||
String key = CacheConstants.DEFAULT_CODE_KEY + randomStr;
|
||||
if (Boolean.FALSE.equals(redisTemplate.hasKey(key))) {
|
||||
throw new ValidateCodeException("验证码不合法");
|
||||
throw new ValidateCodeException(MsgUtils.getMessage(ErrorCodes.AUTH_CAPTCHA_INVALID));
|
||||
}
|
||||
|
||||
Object codeObj = redisTemplate.opsForValue().get(key);
|
||||
|
||||
if (codeObj == null) {
|
||||
throw new ValidateCodeException("验证码不合法");
|
||||
throw new ValidateCodeException(MsgUtils.getMessage(ErrorCodes.AUTH_CAPTCHA_INVALID));
|
||||
}
|
||||
|
||||
String saveCode = codeObj.toString();
|
||||
if (StrUtil.isBlank(saveCode)) {
|
||||
redisTemplate.delete(key);
|
||||
throw new ValidateCodeException("验证码不合法");
|
||||
throw new ValidateCodeException(MsgUtils.getMessage(ErrorCodes.AUTH_CAPTCHA_INVALID));
|
||||
}
|
||||
|
||||
if (!StrUtil.equals(saveCode, code)) {
|
||||
redisTemplate.delete(key);
|
||||
throw new ValidateCodeException("验证码不合法");
|
||||
throw new ValidateCodeException(MsgUtils.getMessage(ErrorCodes.AUTH_CAPTCHA_INVALID));
|
||||
}
|
||||
|
||||
redisTemplate.delete(key);
|
||||
|
||||
+5
-2
@@ -13,6 +13,9 @@ import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryMerchantStatsSummaryVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryOrderAppVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryRiderCommissionQueryVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryRiderCommissionSummaryVO;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.bsd.pjcloud.common.log.annotation.SysLog;
|
||||
@@ -133,7 +136,7 @@ public class CanteenDeliveryOrderController {
|
||||
Long uid = SecurityUtils.getUser().getId();
|
||||
return R.ok(canteenDeliveryOrderService.commissionQueryForRider(uid, start, end));
|
||||
} catch (DateTimeParseException ex) {
|
||||
return R.failed("日期格式应为 yyyy-MM-dd");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_DATE_FORMAT_YMD));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return R.failed(ex.getMessage());
|
||||
}
|
||||
@@ -146,7 +149,7 @@ public class CanteenDeliveryOrderController {
|
||||
Long uid = SecurityUtils.getUser().getId();
|
||||
CanteenDeliveryOrderAppVO vo = canteenDeliveryOrderService.detailForRider(uid, id);
|
||||
if (vo == null) {
|
||||
return R.failed("订单不存在或无权查看");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ORDER_NO_VIEW));
|
||||
}
|
||||
return R.ok(vo);
|
||||
}
|
||||
|
||||
+4
-2
@@ -16,6 +16,8 @@ import com.bsd.pjcloud.canteen.vo.app.CanteenOnlineSpuAppVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.MchSimpleAppVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.OnlineSpuChoiceGroupsVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.OnlineSpuChoiceGroupRuleVO;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.BeanUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.log.annotation.SysLog;
|
||||
@@ -395,10 +397,10 @@ public class CanteenOnlineSpuController {
|
||||
public R checkSpuStock(@RequestParam(value = "spuId") Long spuId, @RequestParam("incrCount") Integer incrCount) {
|
||||
CanteenOnlineSpuEntity canteenOnlineSpuEntity = canteenOnlineSpuService.getById(spuId);
|
||||
if (canteenOnlineSpuEntity == null) {
|
||||
return R.failed("商品不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_NOT_FOUND));
|
||||
}
|
||||
if (canteenOnlineSpuEntity.getStock() < Math.abs(incrCount)) {
|
||||
return R.failed("库存不足");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_STOCK_LOW));
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
+5
-3
@@ -24,6 +24,8 @@ import com.bsd.pjcloud.canteen.vo.ADCanteenSpuListVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.OnlineSpuComboItemVO;
|
||||
import com.bsd.pjcloud.canteen.vo.erp.CanteenSpuSimpleVO;
|
||||
import com.bsd.pjcloud.canteen.vo.erp.CanteenSpuStockVO;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.BeanUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.log.annotation.SysLog;
|
||||
@@ -357,7 +359,7 @@ public class CanteenSpuController {
|
||||
public R<ADCanteenSpuListVO> getCanteenSpuDetails(@RequestParam("id") Long id) {
|
||||
CanteenSpuEntity detail = canteenSpuService.getDetail(id);
|
||||
if (detail == null) {
|
||||
return R.failed("商品不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_NOT_FOUND));
|
||||
}
|
||||
ADCanteenSpuListVO vo = BeanUtils.toBean(detail, ADCanteenSpuListVO.class);
|
||||
vo.setIntroduction(detail.getIntroduction());
|
||||
@@ -450,10 +452,10 @@ public class CanteenSpuController {
|
||||
public R checkSpuStock(@RequestParam(value ="spuId")Long spuId,@RequestParam("incrCount")Integer incrCount) {
|
||||
CanteenSpuEntity canteenSpuEntity = canteenSpuService.getById(spuId);
|
||||
if (canteenSpuEntity == null) {
|
||||
R.failed("商品不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_NOT_FOUND));
|
||||
}
|
||||
if (canteenSpuEntity.getStock()<Math.abs(incrCount)){
|
||||
return R.failed("库存不足");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_STOCK_LOW));
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
+11
-8
@@ -1,5 +1,7 @@
|
||||
package com.bsd.pjcloud.canteen.push;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.bsd.pjcloud.admin.api.entity.SysDept;
|
||||
@@ -8,6 +10,7 @@ import com.bsd.pjcloud.admin.api.feign.RemoteDeptService;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.canteen.constants.CanteenDeliveryPushConstants;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenDeliveryOrderEntity;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.wallet.api.feign.RemoteMchService;
|
||||
import com.bsd.pjcloud.wallet.api.vo.MchManageVo;
|
||||
@@ -65,8 +68,8 @@ public class CanteenDeliveryMerchantNotifyPublisher {
|
||||
null,
|
||||
null,
|
||||
CanteenDeliveryPushConstants.BIZ_TYPE_SCHEDULED_MERCHANT_REMIND,
|
||||
"预约外送提醒",
|
||||
"您有一单预约外送即将进入备餐时段,请及时查看");
|
||||
MsgUtils.getMessage(ErrorCodes.DELIVERY_MCH_SCHEDULE_TITLE),
|
||||
MsgUtils.getMessage(ErrorCodes.DELIVERY_MCH_SCHEDULE_BODY));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,8 +95,8 @@ public class CanteenDeliveryMerchantNotifyPublisher {
|
||||
null,
|
||||
null,
|
||||
CanteenDeliveryPushConstants.BIZ_TYPE_MERCHANT_NEW_ORDER,
|
||||
"新外送订单",
|
||||
"您有一单新的食堂外送订单,请及时处理");
|
||||
MsgUtils.getMessage(ErrorCodes.DELIVERY_MCH_PUSH_TITLE),
|
||||
MsgUtils.getMessage(ErrorCodes.DELIVERY_MCH_PUSH_BODY));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,8 +122,8 @@ public class CanteenDeliveryMerchantNotifyPublisher {
|
||||
order.getExpectDeliveryEnd(),
|
||||
order.getExpectArriveTime(),
|
||||
CanteenDeliveryPushConstants.BIZ_TYPE_MERCHANT_NEW_ORDER,
|
||||
"新外送订单",
|
||||
"您有一单新的食堂外送订单,请及时处理");
|
||||
MsgUtils.getMessage(ErrorCodes.DELIVERY_MCH_PUSH_TITLE),
|
||||
MsgUtils.getMessage(ErrorCodes.DELIVERY_MCH_PUSH_BODY));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,8 +149,8 @@ public class CanteenDeliveryMerchantNotifyPublisher {
|
||||
order.getExpectDeliveryEnd(),
|
||||
order.getExpectArriveTime(),
|
||||
CanteenDeliveryPushConstants.BIZ_TYPE_SCHEDULED_MERCHANT_REMIND,
|
||||
"预约外送提醒",
|
||||
"您有一单预约外送即将进入备餐时段,请及时查看");
|
||||
MsgUtils.getMessage(ErrorCodes.DELIVERY_MCH_SCHEDULE_TITLE),
|
||||
MsgUtils.getMessage(ErrorCodes.DELIVERY_MCH_SCHEDULE_BODY));
|
||||
}
|
||||
|
||||
private List<Long> resolveMerchantStaffUserIds(CanteenDeliveryOrderEntity order) {
|
||||
|
||||
+6
-2
@@ -1,5 +1,9 @@
|
||||
package com.bsd.pjcloud.canteen.push;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
|
||||
import com.bsd.pjcloud.canteen.constants.CanteenDeliveryPushConstants;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
@@ -47,8 +51,8 @@ public class CanteenDeliveryRiderPushPublisher {
|
||||
ObjectNode envelope = objectMapper.createObjectNode();
|
||||
envelope.put("bizType", CanteenDeliveryPushConstants.BIZ_TYPE_ORDER_ASSIGNED);
|
||||
envelope.put("version", CanteenDeliveryPushConstants.PAYLOAD_VERSION);
|
||||
envelope.put("title", "新配送任务");
|
||||
envelope.put("body", "您有一单新的食堂外送,请及时处理");
|
||||
envelope.put("title", MsgUtils.getMessage(ErrorCodes.DELIVERY_RIDER_PUSH_TITLE));
|
||||
envelope.put("body", MsgUtils.getMessage(ErrorCodes.DELIVERY_RIDER_PUSH_BODY));
|
||||
envelope.set("payload", objectMapper.valueToTree(Map.of(
|
||||
"deliveryOrderId", deliveryOrderId,
|
||||
"sourceOrderId", sourceOrderId != null ? sourceOrderId : "",
|
||||
|
||||
+32
-28
@@ -1,5 +1,8 @@
|
||||
package com.bsd.pjcloud.canteen.service.impl;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
@@ -40,6 +43,7 @@ import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryOrderAppVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryRiderCommissionQueryVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.CanteenDeliveryRiderCommissionSummaryVO;
|
||||
import com.bsd.pjcloud.common.core.util.BeanUtils;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.security.util.SecurityUtils;
|
||||
import com.bsd.pjcloud.wallet.api.feign.RemoteMchService;
|
||||
@@ -101,7 +105,7 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
long exists = count(Wrappers.<CanteenDeliveryOrderEntity>lambdaQuery()
|
||||
.eq(CanteenDeliveryOrderEntity::getSourceOrderId, dto.getId()));
|
||||
if (exists > 0) {
|
||||
return R.failed("订单已同步过");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ORDER_ALREADY_SYNCED));
|
||||
}
|
||||
CanteenDeliveryOrderEntity entity = new CanteenDeliveryOrderEntity();
|
||||
entity.setSourceOrderId(dto.getId());
|
||||
@@ -142,7 +146,7 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
try {
|
||||
entity.setCarListJson(objectMapper.writeValueAsString(dto.getCarList()));
|
||||
} catch (JsonProcessingException e) {
|
||||
return R.failed("购物车序列化失败");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_CART_SERIALIZE_FAIL));
|
||||
}
|
||||
entity.setOrderAmount(calcOrderAmountFromCart(dto.getCarList()));
|
||||
entity.setMerchantAccepted(0);
|
||||
@@ -419,7 +423,7 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<Void> cancelBySourceOrderId(String sourceOrderId) {
|
||||
if (StrUtil.isBlank(sourceOrderId)) {
|
||||
return R.failed("订单号不能为空");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ORDER_NO_EMPTY));
|
||||
}
|
||||
CanteenDeliveryOrderEntity one = getOne(Wrappers.<CanteenDeliveryOrderEntity>lambdaQuery()
|
||||
.eq(CanteenDeliveryOrderEntity::getSourceOrderId, sourceOrderId));
|
||||
@@ -477,16 +481,16 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
private R<List<String>> resolveMerchantIdStringsForLoginUser() {
|
||||
var user = SecurityUtils.getUser();
|
||||
if (user == null || user.getId() == null) {
|
||||
return R.failed("未登录");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_NOT_LOGIN));
|
||||
}
|
||||
R<UserInfo> userInfoR = remoteUserService.getInnerByUserId(user.getId());
|
||||
if (userInfoR == null || !userInfoR.isOk() || userInfoR.getData() == null
|
||||
|| userInfoR.getData().getSysUser() == null) {
|
||||
return R.failed("用户信息不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_USER_NOT_EXIST));
|
||||
}
|
||||
Long rootDeptId = userInfoR.getData().getSysUser().getDeptId();
|
||||
if (rootDeptId == null) {
|
||||
return R.failed("用户部门不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_USER_DEPT_MISSING));
|
||||
}
|
||||
List<Long> deptIds;
|
||||
R<List<SysDept>> deptR = remoteDeptService.getDescendantList(rootDeptId);
|
||||
@@ -497,7 +501,7 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
}
|
||||
R<List<MchManageVo>> mchR = remoteMchService.getByDeptIds(deptIds);
|
||||
if (mchR == null || !mchR.isOk() || CollUtil.isEmpty(mchR.getData())) {
|
||||
String msg = mchR != null && StrUtil.isNotBlank(mchR.getMsg()) ? mchR.getMsg() : "商户不存在";
|
||||
String msg = mchR != null && StrUtil.isNotBlank(mchR.getMsg()) ? mchR.getMsg() : MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND);
|
||||
return R.failed(msg);
|
||||
}
|
||||
List<String> ids = mchR.getData().stream()
|
||||
@@ -507,7 +511,7 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
.distinct()
|
||||
.toList();
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return R.failed("商户不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
}
|
||||
return R.ok(ids);
|
||||
}
|
||||
@@ -596,10 +600,10 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
List<String> merchantIds = mchIdsR.getData();
|
||||
CanteenDeliveryOrderEntity e = getById(id);
|
||||
if (e == null || StrUtil.isBlank(e.getMerchantId()) || !merchantIds.contains(e.getMerchantId())) {
|
||||
return R.failed("订单不存在或无权查看");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ORDER_NO_VIEW));
|
||||
}
|
||||
if (!merchantScheduledOrderVisibleToMerchant(e)) {
|
||||
return R.failed("订单不存在或无权查看");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ORDER_NO_VIEW));
|
||||
}
|
||||
Map<Long, SysUser> riderById = loadRidersByIds(
|
||||
e.getRiderUserId() != null ? List.of(e.getRiderUserId()) : List.of());
|
||||
@@ -652,13 +656,13 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
public R<Void> pickup(Long riderUserId, CanteenDeliveryPhotoDTO dto) {
|
||||
CanteenDeliveryOrderEntity e = getById(dto.getId());
|
||||
if (e == null || !Objects.equals(e.getRiderUserId(), riderUserId)) {
|
||||
return R.failed("订单不存在或无权操作");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ORDER_NO_OPERATE));
|
||||
}
|
||||
if (!Objects.equals(e.getRiderAccepted(), 1)) {
|
||||
return R.failed("请先接单");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ACCEPT_FIRST));
|
||||
}
|
||||
if (e.getStatus() != CanteenDeliveryOrderStatus.WAIT_PICKUP) {
|
||||
return R.failed("当前状态不可上传取餐照");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_PICKUP_PHOTO_STATUS_INVALID));
|
||||
}
|
||||
e.setPickupPhotoUrl(dto.getPhotoUrl());
|
||||
e.setStatus(CanteenDeliveryOrderStatus.DELIVERING);
|
||||
@@ -673,10 +677,10 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
public R<Void> deliver(Long riderUserId, CanteenDeliveryPhotoDTO dto) {
|
||||
CanteenDeliveryOrderEntity e = getById(dto.getId());
|
||||
if (e == null || !Objects.equals(e.getRiderUserId(), riderUserId)) {
|
||||
return R.failed("订单不存在或无权操作");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ORDER_NO_OPERATE));
|
||||
}
|
||||
if (e.getStatus() != CanteenDeliveryOrderStatus.DELIVERING) {
|
||||
return R.failed("当前状态不可上传送达照");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_DELIVER_PHOTO_STATUS_INVALID));
|
||||
}
|
||||
e.setDeliveryPhotoUrl(dto.getPhotoUrl());
|
||||
e.setStatus(CanteenDeliveryOrderStatus.COMPLETED);
|
||||
@@ -841,10 +845,10 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
@Override
|
||||
public CanteenDeliveryRiderCommissionQueryVO commissionQueryForRider(Long riderUserId, LocalDate startDate, LocalDate endDate) {
|
||||
if (startDate == null || endDate == null) {
|
||||
throw new IllegalArgumentException("开始日期与结束日期不能为空");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_DATE_RANGE_REQUIRED);
|
||||
}
|
||||
if (endDate.isBefore(startDate)) {
|
||||
throw new IllegalArgumentException("结束日期不能早于开始日期");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_DATE_RANGE_INVALID);
|
||||
}
|
||||
LocalDateTime start = startDate.atStartOfDay();
|
||||
LocalDateTime end = endDate.plusDays(1).atStartOfDay();
|
||||
@@ -917,7 +921,7 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
try {
|
||||
ym = YearMonth.parse(month.trim());
|
||||
} catch (DateTimeParseException ex) {
|
||||
return R.failed("月份格式应为 yyyy-MM");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MONTH_FORMAT_YM));
|
||||
}
|
||||
LocalDateTime start = ym.atDay(1).atStartOfDay();
|
||||
LocalDateTime end = ym.plusMonths(1).atDay(1).atStartOfDay();
|
||||
@@ -943,10 +947,10 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
public R<Void> riderAcceptOrder(Long riderUserId, Long deliveryOrderId) {
|
||||
CanteenDeliveryOrderEntity e = getById(deliveryOrderId);
|
||||
if (e == null || !Objects.equals(e.getRiderUserId(), riderUserId)) {
|
||||
return R.failed("订单不存在或无权操作");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ORDER_NO_OPERATE));
|
||||
}
|
||||
if (!Objects.equals(e.getStatus(), CanteenDeliveryOrderStatus.RIDER_PENDING_ACCEPT)) {
|
||||
return R.failed("当前状态不可接单");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ACCEPT_STATUS_INVALID));
|
||||
}
|
||||
e.setRiderAccepted(1);
|
||||
e.setRiderAcceptTime(LocalDateTime.now());
|
||||
@@ -962,7 +966,7 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
return R.failed(mchIdsR.getMsg());
|
||||
}
|
||||
if (CollUtil.isEmpty(mchIdsR.getData())) {
|
||||
return R.failed("商户不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
}
|
||||
String merchantId = mchIdsR.getData().get(0);
|
||||
CanteenDeliveryAutoAcceptVO vo = new CanteenDeliveryAutoAcceptVO();
|
||||
@@ -979,7 +983,7 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
return R.failed(mchIdsR.getMsg());
|
||||
}
|
||||
if (CollUtil.isEmpty(mchIdsR.getData())) {
|
||||
return R.failed("商户不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
}
|
||||
String merchantId = mchIdsR.getData().get(0);
|
||||
saveMerchantAutoAcceptSetting(merchantId, Boolean.TRUE.equals(autoAccept));
|
||||
@@ -1034,16 +1038,16 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
.eq(CanteenDeliveryOrderEntity::getId, deliveryOrderId)
|
||||
.last("FOR UPDATE"));
|
||||
if (e == null || StrUtil.isBlank(e.getMerchantId()) || !merchantIds.contains(e.getMerchantId())) {
|
||||
return R.failed("订单不存在或无权操作");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ORDER_NO_OPERATE));
|
||||
}
|
||||
if (!merchantScheduledOrderVisibleToMerchant(e)) {
|
||||
return R.failed("订单不存在或无权操作");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ORDER_NO_OPERATE));
|
||||
}
|
||||
if (isMerchantAccepted(e)) {
|
||||
return R.failed("订单已接单");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ALREADY_ACCEPTED));
|
||||
}
|
||||
if (!Objects.equals(e.getStatus(), CanteenDeliveryOrderStatus.MERCHANT_PENDING)) {
|
||||
return R.failed("当前状态不可接单");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_ACCEPT_STATUS_INVALID));
|
||||
}
|
||||
e.setMerchantAccepted(1);
|
||||
e.setMerchantAcceptTime(LocalDateTime.now());
|
||||
@@ -1223,8 +1227,8 @@ public class CanteenDeliveryOrderServiceImpl extends ServiceImpl<CanteenDelivery
|
||||
dto.setStatus(status);
|
||||
R<Boolean> r = remoteHardOrderService.updateTakeOutStatus(dto);
|
||||
if (r == null || !r.isOk() || !Boolean.TRUE.equals(r.getData())) {
|
||||
String msg = r == null ? "无响应" : r.getMsg();
|
||||
throw new IllegalStateException("同步硬件外卖订单状态失败: " + msg);
|
||||
String msg = r == null ? MsgUtils.getMessage(ErrorCodes.DELIVERY_NO_RESPONSE) : r.getMsg();
|
||||
throw new I18nBizException(ErrorCodes.DELIVERY_SYNC_HARDWARE_FAIL, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-14
@@ -31,7 +31,10 @@ import com.bsd.pjcloud.canteen.vo.app.OnlineSpuChoiceGroupRuleVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.OnlineSpuComboItemVO;
|
||||
import com.bsd.pjcloud.canteen.vo.APPOnlineSpuVO;
|
||||
import com.bsd.pjcloud.canteen.vo.erp.CanteenOnlineSpuSimpleVO;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.BeanUtils;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.data.datascope.DataScope;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -435,16 +438,16 @@ public class CanteenOnlineSpuServiceImpl extends ServiceImpl<CanteenOnlineSpuMap
|
||||
for (CanteenOnlineSpuUpdateStockReqDTO.Item v : canteenOnlineSpuUpdateStockReqDTO.getItems()) {
|
||||
CanteenOnlineSpuEntity spu = baseMapper.selectById(v.getId());
|
||||
if (spu == null) {
|
||||
return R.failed("商品不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_NOT_FOUND));
|
||||
}
|
||||
if (v.getIncrCount() < 0 && Math.abs(v.getIncrCount()) > spu.getStock()) {
|
||||
return R.failed(spu.getName() + "库存不足,无法完成操作");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.HARD_PRODUCT_STOCK_LOW, spu.getName()));
|
||||
}
|
||||
}
|
||||
// 下单等场景:库存与销量联动(incrCount<0 视为售出)。并发条件更新失败时抛异常回滚整批。
|
||||
for (CanteenOnlineSpuUpdateStockReqDTO.Item v : canteenOnlineSpuUpdateStockReqDTO.getItems()) {
|
||||
if (baseMapper.updateStock(v.getId(), v.getIncrCount()) == 0) {
|
||||
throw new RuntimeException("库存不足,无法完成操作");
|
||||
throw new I18nBizException(ErrorCodes.CANTEEN_STOCK_INSUFFICIENT);
|
||||
}
|
||||
}
|
||||
return R.ok();
|
||||
@@ -463,7 +466,7 @@ public class CanteenOnlineSpuServiceImpl extends ServiceImpl<CanteenOnlineSpuMap
|
||||
if (StrUtil.isBlank(dto.getBizId()) || CollUtil.isEmpty(dto.getItems())
|
||||
|| (!deductOperation && !rollbackOperation)
|
||||
|| dto.getItems().stream().anyMatch(item -> item.getBeforeStock() == null)) {
|
||||
return R.failed("库存业务参数错误");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_STOCK_BIZ_PARAM_BAD));
|
||||
}
|
||||
String stateKey = ORDER_STOCK_BIZ_KEY_PREFIX + dto.getBizId();
|
||||
String state = stringRedisTemplate.opsForValue().get(stateKey);
|
||||
@@ -476,7 +479,7 @@ public class CanteenOnlineSpuServiceImpl extends ServiceImpl<CanteenOnlineSpuMap
|
||||
for (CanteenSpuUpdateStockReqDTO.Item item : dto.getItems()) {
|
||||
CanteenOnlineSpuEntity spu = baseMapper.selectById(item.getId());
|
||||
if (spu == null) {
|
||||
return R.failed("商品不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_NOT_FOUND));
|
||||
}
|
||||
int expectedStock = item.getBeforeStock();
|
||||
int targetStock = Math.addExact(expectedStock, item.getIncrCount());
|
||||
@@ -485,14 +488,14 @@ public class CanteenOnlineSpuServiceImpl extends ServiceImpl<CanteenOnlineSpuMap
|
||||
continue;
|
||||
}
|
||||
if (spu.getStock() != expectedStock) {
|
||||
return R.failed(spu.getName() + "库存已变化,请重新下单");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_STOCK_CHANGED, spu.getName()));
|
||||
}
|
||||
} else {
|
||||
if (spu.getStock() == expectedStock) {
|
||||
continue;
|
||||
}
|
||||
if (spu.getStock() != targetStock) {
|
||||
return R.failed(spu.getName() + "库存状态异常,无法自动补偿");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_STOCK_COMPENSATE_FAIL));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -505,7 +508,7 @@ public class CanteenOnlineSpuServiceImpl extends ServiceImpl<CanteenOnlineSpuMap
|
||||
? spu.getStock() == expectedStock
|
||||
: spu.getStock() == targetStock;
|
||||
if (needUpdate && baseMapper.updateStock(item.getId(), delta) == 0) {
|
||||
throw new RuntimeException("库存更新失败,请重试");
|
||||
throw new I18nBizException(ErrorCodes.CANTEEN_STOCK_UPDATE_FAIL);
|
||||
}
|
||||
}
|
||||
stringRedisTemplate.opsForValue().set(stateKey, deductOperation ? "DEDUCTED" : "ROLLED_BACK");
|
||||
@@ -517,13 +520,15 @@ public class CanteenOnlineSpuServiceImpl extends ServiceImpl<CanteenOnlineSpuMap
|
||||
for (CanteenOnlineSpuUpdateStockReqDTO.Item v : dto.getItems()) {
|
||||
CanteenOnlineSpuEntity spu = baseMapper.selectById(v.getId());
|
||||
if (spu == null) {
|
||||
return R.failed("商品不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_NOT_FOUND));
|
||||
}
|
||||
if (!Objects.equals(spu.getMerchantId(), merchantId)) {
|
||||
return R.failed("无权操作该商品:" + StrUtil.blankToDefault(spu.getName(), String.valueOf(spu.getId())));
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_NO_PRODUCT_PERM_NAMED,
|
||||
StrUtil.blankToDefault(spu.getName(), String.valueOf(spu.getId()))));
|
||||
}
|
||||
if (v.getIncrCount() < 0 && Math.abs(v.getIncrCount()) > spu.getStock()) {
|
||||
return R.failed(StrUtil.blankToDefault(spu.getName(), "商品") + "库存不足,无法完成操作");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.HARD_PRODUCT_STOCK_LOW,
|
||||
StrUtil.blankToDefault(spu.getName(), "商品")));
|
||||
}
|
||||
baseMapper.adjustStockOnly(v.getId(), v.getIncrCount());
|
||||
}
|
||||
@@ -534,14 +539,14 @@ public class CanteenOnlineSpuServiceImpl extends ServiceImpl<CanteenOnlineSpuMap
|
||||
public R updateOnlineSpuShelfStatus(Long merchantId, CanteenOnlineSpuShelfReqDTO dto) {
|
||||
Integer status = dto.getStatus();
|
||||
if (status == null || (status != 0 && status != 1)) {
|
||||
return R.failed("状态非法,仅支持 0-上架、1-下架");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_SHELF_STATUS_INVALID));
|
||||
}
|
||||
CanteenOnlineSpuEntity spu = baseMapper.selectById(dto.getId());
|
||||
if (spu == null) {
|
||||
return R.failed("商品不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_NOT_FOUND));
|
||||
}
|
||||
if (!Objects.equals(spu.getMerchantId(), merchantId)) {
|
||||
return R.failed("无权操作该商品");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_NO_PRODUCT_PERM));
|
||||
}
|
||||
LambdaUpdateWrapper<CanteenOnlineSpuEntity> uw = new LambdaUpdateWrapper<CanteenOnlineSpuEntity>()
|
||||
.eq(CanteenOnlineSpuEntity::getId, dto.getId())
|
||||
|
||||
+45
-43
@@ -36,6 +36,8 @@ import com.bsd.pjcloud.canteen.vo.app.OrderingFoodStatsSegmentCountVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.OrderingFoodStatsSegmentDetailVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.OrderingFoodStatsSegmentDishExportVO;
|
||||
import com.bsd.pjcloud.canteen.vo.app.OrderingFoodStatsSummaryVO;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.security.util.SecurityUtils;
|
||||
import com.bsd.pjcloud.wallet.api.entity.mch.MchManageEntity;
|
||||
@@ -86,14 +88,14 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
public R<List<OrderingFoodMealSegmentVO>> listMealSegments(String merchantId) {
|
||||
MchManageVo mch = loadMerchantOrFail(merchantId);
|
||||
if (mch == null) {
|
||||
return R.failed("商户不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
}
|
||||
if (!isOrderingFoodEnabled(mch)) {
|
||||
return R.failed("该商户未启用报餐");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_MCH_DISABLED));
|
||||
}
|
||||
List<OrderingFoodMealSegmentVO> segments = MchJobTimeMealSegmentUtils.parseMealSegments(mch.getJobTime());
|
||||
if (CollUtil.isEmpty(segments)) {
|
||||
return R.failed("商户未配置营业时间,无法获取餐段");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_JOB_TIME_MISSING_FOR_SEGMENT));
|
||||
}
|
||||
return R.ok(segments);
|
||||
}
|
||||
@@ -113,27 +115,27 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
public R<Integer> submit(OrderingFoodSubmitDTO dto) {
|
||||
var login = SecurityUtils.getUser();
|
||||
if (login == null || login.getId() == null) {
|
||||
return R.failed("未登录");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_NOT_LOGIN));
|
||||
}
|
||||
MchManageVo mch = loadMerchantOrFail(dto.getMerchantId());
|
||||
if (mch == null) {
|
||||
return R.failed("商户不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
}
|
||||
if (!isOrderingFoodEnabled(mch)) {
|
||||
return R.failed("该商户未启用报餐");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_MCH_DISABLED));
|
||||
}
|
||||
if (CollUtil.isEmpty(dto.getSelections())) {
|
||||
return R.failed("请选择报餐日期与餐段");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_SELECT_DATE_SEGMENT));
|
||||
}
|
||||
if (CollUtil.isEmpty(dto.getSpuItems())) {
|
||||
return R.failed("请选择报餐菜品");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_SELECT_DISH));
|
||||
}
|
||||
if (dto.getPeopleCount() == null || dto.getPeopleCount() < 1) {
|
||||
return R.failed("请填写报餐人数");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_FILL_PERSON_COUNT));
|
||||
}
|
||||
String jobTime = mch.getJobTime();
|
||||
if (MchJobTimeMealSegmentUtils.isBlankJobTime(jobTime)) {
|
||||
return R.failed("商户未配置营业时间");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_JOB_TIME_MISSING));
|
||||
}
|
||||
|
||||
LocalDate minDate = LocalDate.now();
|
||||
@@ -188,7 +190,7 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
Page<CanteenOrderingFoodEntity> page) {
|
||||
Long uid = loginUserIdOrNull();
|
||||
if (uid == null) {
|
||||
return R.failed("未登录");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_NOT_LOGIN));
|
||||
}
|
||||
Page<CanteenOrderingFoodEntity> p = normalizePage(page);
|
||||
var q = Wrappers.<CanteenOrderingFoodEntity>lambdaQuery()
|
||||
@@ -203,11 +205,11 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
public R<OrderingFoodAppVO> detailMyRecord(Long id) {
|
||||
Long uid = loginUserIdOrNull();
|
||||
if (uid == null) {
|
||||
return R.failed("未登录");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_NOT_LOGIN));
|
||||
}
|
||||
CanteenOrderingFoodEntity e = getById(id);
|
||||
if (e == null || !Objects.equals(e.getUserId(), uid)) {
|
||||
return R.failed("记录不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_RECORD_NOT_FOUND));
|
||||
}
|
||||
return R.ok(toAppVo(e));
|
||||
}
|
||||
@@ -217,14 +219,14 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
public R<Void> cancelMyRecord(Long id) {
|
||||
Long uid = loginUserIdOrNull();
|
||||
if (uid == null) {
|
||||
return R.failed("未登录");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_NOT_LOGIN));
|
||||
}
|
||||
CanteenOrderingFoodEntity e = getById(id);
|
||||
if (e == null || !Objects.equals(e.getUserId(), uid)) {
|
||||
return R.failed("记录不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_RECORD_NOT_FOUND));
|
||||
}
|
||||
if (!Objects.equals(e.getStatus(), CanteenOrderingFoodStatus.BOOKED.getCode())) {
|
||||
return R.failed("当前状态不可取消");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_CANCEL_STATUS_INVALID));
|
||||
}
|
||||
e.setStatus(CanteenOrderingFoodStatus.CANCELLED.getCode());
|
||||
e.setCancelTime(LocalDateTime.now());
|
||||
@@ -245,10 +247,10 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
}
|
||||
String mchId = resolveStatsMerchantId(merchantId, mchIdsR.getData());
|
||||
if (mchId == null) {
|
||||
return R.failed("请选择有效商户");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_SELECT_VALID_MCH));
|
||||
}
|
||||
if (!mchIdsR.getData().contains(mchId)) {
|
||||
return R.failed("无权查看该商户数据");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_NO_MCH_VIEW_PERM));
|
||||
}
|
||||
R<LocalDate[]> rangeR = normalizeDateRange(startDate, endDate);
|
||||
if (!rangeR.isOk()) {
|
||||
@@ -271,13 +273,13 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
}
|
||||
String mchId = resolveStatsMerchantId(merchantId, mchIdsR.getData());
|
||||
if (mchId == null) {
|
||||
return R.failed("请选择有效商户");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_SELECT_VALID_MCH));
|
||||
}
|
||||
if (!mchIdsR.getData().contains(mchId)) {
|
||||
return R.failed("无权查看该商户数据");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_NO_MCH_VIEW_PERM));
|
||||
}
|
||||
if (diningDate == null) {
|
||||
return R.failed("请选择日期");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_SELECT_DATE));
|
||||
}
|
||||
return R.ok(buildStatsDayDetail(mchId, diningDate, deptId, userId, segmentIndex));
|
||||
}
|
||||
@@ -375,11 +377,11 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
@Override
|
||||
public R<OrderingFoodAppVO> adminRecordDetail(Long id) {
|
||||
if (id == null) {
|
||||
return R.failed("记录不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_RECORD_NOT_FOUND));
|
||||
}
|
||||
CanteenOrderingFoodEntity e = getById(id);
|
||||
if (e == null) {
|
||||
return R.failed("记录不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_RECORD_NOT_FOUND));
|
||||
}
|
||||
R<String> mchR = resolveAdminMerchantId(e.getMerchantId());
|
||||
if (!mchR.isOk()) {
|
||||
@@ -431,7 +433,7 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
return R.failed(mchR.getMsg());
|
||||
}
|
||||
if (diningDate == null) {
|
||||
return R.failed("请选择日期");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_SELECT_DATE));
|
||||
}
|
||||
return R.ok(buildStatsDayDetail(mchR.getData(), diningDate, deptId, userId, segmentIndex));
|
||||
}
|
||||
@@ -466,7 +468,7 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
}
|
||||
Long rootDeptId = resolveLoginUserDeptId();
|
||||
if (rootDeptId == null) {
|
||||
return R.failed("用户部门不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_USER_DEPT_MISSING));
|
||||
}
|
||||
R<List<SysDept>> deptR = remoteDeptService.getDescendantList(rootDeptId);
|
||||
if (deptR != null && deptR.isOk() && CollUtil.isNotEmpty(deptR.getData())) {
|
||||
@@ -486,7 +488,7 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
} else {
|
||||
Long rootDeptId = resolveLoginUserDeptId();
|
||||
if (rootDeptId == null) {
|
||||
return R.failed("用户部门不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_USER_DEPT_MISSING));
|
||||
}
|
||||
R<List<SysDept>> deptR = remoteDeptService.getDescendantList(rootDeptId);
|
||||
if (deptR != null && deptR.isOk() && CollUtil.isNotEmpty(deptR.getData())) {
|
||||
@@ -504,7 +506,7 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
|
||||
private R<String> resolveAdminMerchantId(String merchantId) {
|
||||
if (StrUtil.isBlank(merchantId)) {
|
||||
return R.failed("请选择食堂商户");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_SELECT_CANTEEN_MCH));
|
||||
}
|
||||
R<List<String>> mchIdsR = resolveMerchantIdStringsForLoginUser();
|
||||
if (!mchIdsR.isOk()) {
|
||||
@@ -512,7 +514,7 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
}
|
||||
String mchId = merchantId.trim();
|
||||
if (!mchIdsR.getData().contains(mchId)) {
|
||||
return R.failed("无权查看该商户数据");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_NO_MCH_VIEW_PERM));
|
||||
}
|
||||
return R.ok(mchId);
|
||||
}
|
||||
@@ -842,7 +844,7 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
}
|
||||
long days = java.time.temporal.ChronoUnit.DAYS.between(start, end) + 1;
|
||||
if (days > MAX_STATS_RANGE_DAYS) {
|
||||
return R.failed("查询日期范围最多一个月(" + MAX_STATS_RANGE_DAYS + "天)");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_STATS_RANGE_TOO_LARGE, MAX_STATS_RANGE_DAYS));
|
||||
}
|
||||
return R.ok(new LocalDate[]{start, end});
|
||||
}
|
||||
@@ -857,15 +859,15 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
private R<Void> checkOnlineCanteenMchRole() {
|
||||
var login = SecurityUtils.getUser();
|
||||
if (login == null || login.getId() == null) {
|
||||
return R.failed("未登录");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_NOT_LOGIN));
|
||||
}
|
||||
R<com.bsd.pjcloud.admin.api.dto.UserInfo> userInfoR = remoteUserService.getInnerByUserId(login.getId());
|
||||
if (userInfoR == null || !userInfoR.isOk() || userInfoR.getData() == null) {
|
||||
return R.failed("用户信息不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_USER_INFO_MISSING));
|
||||
}
|
||||
String[] roleCodes = userInfoR.getData().getRoleCodes();
|
||||
if (roleCodes == null || !Arrays.asList(roleCodes).contains(CommonRoleConstant.ONLINE_CANTEEN_MCH)) {
|
||||
return R.failed("无权访问报餐统计");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_NO_STATS_PERM));
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
@@ -873,11 +875,11 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
private R<List<String>> resolveMerchantIdStringsForLoginUser() {
|
||||
var user = SecurityUtils.getUser();
|
||||
if (user == null || user.getId() == null) {
|
||||
return R.failed("未登录");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_NOT_LOGIN));
|
||||
}
|
||||
Long rootDeptId = resolveLoginUserDeptId();
|
||||
if (rootDeptId == null) {
|
||||
return R.failed("用户部门不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_USER_DEPT_MISSING));
|
||||
}
|
||||
List<Long> deptIds;
|
||||
R<List<SysDept>> deptR = remoteDeptService.getDescendantList(rootDeptId);
|
||||
@@ -888,7 +890,7 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
}
|
||||
R<List<MchManageVo>> mchR = remoteMchService.getByDeptIds(deptIds);
|
||||
if (mchR == null || !mchR.isOk() || CollUtil.isEmpty(mchR.getData())) {
|
||||
String msg = mchR != null && StrUtil.isNotBlank(mchR.getMsg()) ? mchR.getMsg() : "商户不存在";
|
||||
String msg = mchR != null && StrUtil.isNotBlank(mchR.getMsg()) ? mchR.getMsg() : MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND);
|
||||
return R.failed(msg);
|
||||
}
|
||||
List<String> ids = mchR.getData().stream()
|
||||
@@ -898,7 +900,7 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
.distinct()
|
||||
.toList();
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return R.failed("商户不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
}
|
||||
return R.ok(ids);
|
||||
}
|
||||
@@ -952,7 +954,7 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
List<OrderingFoodSelectionItemDTO> selections) {
|
||||
for (OrderingFoodSpuItemDTO item : items) {
|
||||
if (item == null || item.getId() == null || StrUtil.isBlank(item.getName())) {
|
||||
return "报餐菜品信息不完整";
|
||||
return MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_DISH_INFO_INCOMPLETE);
|
||||
}
|
||||
}
|
||||
boolean hasSegmentTag = items.stream().anyMatch(i -> i != null && i.getSegmentIndex() != null);
|
||||
@@ -967,7 +969,7 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
if (!hasDish) {
|
||||
OrderingFoodMealSegmentVO seg = MchJobTimeMealSegmentUtils.findSegment(jobTime, segIdx);
|
||||
String segName = seg != null ? seg.getMealSegmentName() : ("餐段" + (segIdx + 1));
|
||||
return "请为「" + segName + "」选择菜品";
|
||||
return MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_SELECT_DISH_FOR_SEGMENT, segName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -980,7 +982,7 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
if (item.getSegmentIndex() != null) {
|
||||
OrderingFoodMealSegmentVO seg = MchJobTimeMealSegmentUtils.findSegment(jobTime, item.getSegmentIndex());
|
||||
if (seg == null) {
|
||||
return "菜品餐段无效";
|
||||
return MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_DISH_SEGMENT_INVALID);
|
||||
}
|
||||
if (!MealSegmentCategoryUtils.matchesMealSegment(categoryType, seg.getMealSegmentType())) {
|
||||
return "「" + item.getName() + "」不适用于「" + seg.getMealSegmentName() + "」";
|
||||
@@ -1154,17 +1156,17 @@ public class CanteenOrderingFoodServiceImpl extends ServiceImpl<CanteenOrderingF
|
||||
List<OrderingFoodSelectionItemDTO> items = new ArrayList<>();
|
||||
for (OrderingFoodSelectionDTO sel : raw) {
|
||||
if (sel.getDiningDate() == null || sel.getSegmentIndex() == null) {
|
||||
return R.failed("报餐日期或餐段不完整");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_DATE_SEGMENT_INCOMPLETE));
|
||||
}
|
||||
if (sel.getDiningDate().isBefore(minDate) || sel.getDiningDate().isAfter(maxDate)) {
|
||||
return R.failed("仅支持报餐未来" + MAX_FUTURE_DAYS + "天内");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_FUTURE_DAYS_LIMIT, MAX_FUTURE_DAYS));
|
||||
}
|
||||
if (!MchJobTimeMealSegmentUtils.isValidSegmentIndex(jobTime, sel.getSegmentIndex())) {
|
||||
return R.failed("餐段无效,请刷新后重试");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_SEGMENT_INVALID));
|
||||
}
|
||||
String key = sel.getDiningDate() + "#" + sel.getSegmentIndex();
|
||||
if (!dedup.add(key)) {
|
||||
return R.failed("存在重复的日期餐段选择");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ORDERING_FOOD_DUPLICATE_DATE_SEGMENT));
|
||||
}
|
||||
OrderingFoodMealSegmentVO segment = MchJobTimeMealSegmentUtils.findSegment(jobTime, sel.getSegmentIndex());
|
||||
OrderingFoodSelectionItemDTO item = new OrderingFoodSelectionItemDTO();
|
||||
|
||||
+4
-1
@@ -1,11 +1,14 @@
|
||||
package com.bsd.pjcloud.canteen.service.impl;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenRiderBuildingBindEntity;
|
||||
import com.bsd.pjcloud.canteen.entity.CanteenRiderPoolEntity;
|
||||
import com.bsd.pjcloud.canteen.mapper.CanteenRiderBuildingBindMapper;
|
||||
import com.bsd.pjcloud.canteen.mapper.CanteenRiderPoolMapper;
|
||||
import com.bsd.pjcloud.canteen.service.CanteenRiderConfigService;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -25,7 +28,7 @@ public class CanteenRiderConfigServiceImpl implements CanteenRiderConfigService
|
||||
.eq(CanteenRiderBuildingBindEntity::getDeptId, deptId)
|
||||
.eq(CanteenRiderBuildingBindEntity::getBuildingId, buildingId));
|
||||
if (dup > 0) {
|
||||
return R.failed("该单位下楼栋已绑定骑手,请先解绑");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.DELIVERY_RIDER_BUILDING_BOUND));
|
||||
}
|
||||
CanteenRiderBuildingBindEntity e = new CanteenRiderBuildingBindEntity();
|
||||
e.setDeptId(deptId);
|
||||
|
||||
+23
-16
@@ -22,7 +22,10 @@ import com.bsd.pjcloud.canteen.vo.erp.CanteenSpuSimpleVO;
|
||||
import com.bsd.pjcloud.canteen.vo.erp.CanteenSpuStockVO;
|
||||
import com.bsd.pjcloud.canteen.vo.ADCanteenSpuListVO;
|
||||
import com.bsd.pjcloud.canteen.util.CanteenMerchantScopeHelper;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.BeanUtils;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.data.datascope.DataScope;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -77,28 +80,29 @@ public class CanteenSpuServiceImpl extends ServiceImpl<CanteenSpuMapper, Canteen
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R updateSkuStock(CanteenSpuUpdateStockReqDTO updateStockReqDTO) {
|
||||
if (updateStockReqDTO == null || CollUtil.isEmpty(updateStockReqDTO.getItems())) {
|
||||
return R.failed("库存商品不能为空");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_STOCK_ITEMS_EMPTY));
|
||||
}
|
||||
// 必须先校验完整批次再更新,后一个商品失败时由本地事务保证前面的商品不会单独提交。
|
||||
for (CanteenSpuUpdateStockReqDTO.Item item : updateStockReqDTO.getItems()) {
|
||||
if (item == null || item.getId() == null || item.getIncrCount() == null
|
||||
|| item.getIncrCount() == 0 || item.getIncrCount() == Integer.MIN_VALUE) {
|
||||
return R.failed("库存商品参数错误");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_STOCK_ITEM_PARAM_BAD));
|
||||
}
|
||||
CanteenSpuEntity spu = baseMapper.selectById(item.getId());
|
||||
if (spu == null) {
|
||||
return R.failed("商品不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_NOT_FOUND));
|
||||
}
|
||||
if (item.getIncrCount() == null || item.getIncrCount() == 0) {
|
||||
return R.failed(StrUtil.blankToDefault(spu.getName(), "商品") + "库存变化数量无效");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_STOCK_ITEM_PARAM_BAD));
|
||||
}
|
||||
if (item.getIncrCount() < 0 && (spu.getStock() == null || Math.abs(item.getIncrCount()) > spu.getStock())) {
|
||||
return R.failed(StrUtil.blankToDefault(spu.getName(), "商品") + "库存不足,无法完成操作");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.HARD_PRODUCT_STOCK_LOW,
|
||||
StrUtil.blankToDefault(spu.getName(), "商品")));
|
||||
}
|
||||
}
|
||||
for (CanteenSpuUpdateStockReqDTO.Item item : updateStockReqDTO.getItems()) {
|
||||
if (baseMapper.updateStock(item.getId(), item.getIncrCount()) == 0) {
|
||||
throw new RuntimeException("库存不足,无法完成操作");
|
||||
throw new I18nBizException(ErrorCodes.CANTEEN_STOCK_INSUFFICIENT);
|
||||
}
|
||||
}
|
||||
return R.ok();
|
||||
@@ -122,10 +126,10 @@ public class CanteenSpuServiceImpl extends ServiceImpl<CanteenSpuMapper, Canteen
|
||||
|| (!applyOperation && !rollbackOperation)
|
||||
|| dto.getItems().stream().anyMatch(item -> item == null || item.getId() == null
|
||||
|| item.getIncrCount() == null || item.getIncrCount() == 0 || item.getBeforeStock() == null)) {
|
||||
return R.failed("库存业务参数错误");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_STOCK_BIZ_PARAM_BAD));
|
||||
}
|
||||
if (dto.getItems().stream().map(CanteenSpuUpdateStockReqDTO.Item::getId).distinct().count() != dto.getItems().size()) {
|
||||
return R.failed("库存商品不能重复");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_STOCK_ITEM_DUP));
|
||||
}
|
||||
|
||||
String stateKey = ORDER_STOCK_BIZ_KEY_PREFIX + dto.getBizId();
|
||||
@@ -142,26 +146,29 @@ public class CanteenSpuServiceImpl extends ServiceImpl<CanteenSpuMapper, Canteen
|
||||
for (CanteenSpuUpdateStockReqDTO.Item item : dto.getItems()) {
|
||||
CanteenSpuEntity spu = baseMapper.selectById(item.getId());
|
||||
if (spu == null || spu.getStock() == null) {
|
||||
return R.failed("商品不存在或库存异常");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_STOCK_SPU_BAD));
|
||||
}
|
||||
int expectedStock = item.getBeforeStock();
|
||||
if (expectedStock < 0) {
|
||||
return R.failed("库存快照异常");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_STOCK_SNAPSHOT_BAD));
|
||||
}
|
||||
int targetStock = Math.addExact(expectedStock, item.getIncrCount());
|
||||
if (targetStock < 0) {
|
||||
return R.failed(StrUtil.blankToDefault(spu.getName(), "商品") + "库存不足,无法完成操作");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.HARD_PRODUCT_STOCK_LOW,
|
||||
StrUtil.blankToDefault(spu.getName(), "商品")));
|
||||
}
|
||||
if (applyOperation) {
|
||||
// 不得把“库存恰好等于目标值”当成本业务已经执行;该值可能由另一个业务号并发扣减得到。
|
||||
// 幂等成功只能依赖上方读取到的 APPLIED 状态,状态缺失时必须从调用方快照原子更新。
|
||||
if (spu.getStock() != expectedStock) {
|
||||
return R.failed(StrUtil.blankToDefault(spu.getName(), "商品") + "库存已变化,请重新操作");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.CANTEEN_STOCK_CHANGED,
|
||||
StrUtil.blankToDefault(spu.getName(), "商品")));
|
||||
}
|
||||
} else if ("APPLIED".equals(state)) {
|
||||
int rollbackDelta = -item.getIncrCount();
|
||||
if (rollbackDelta < 0 && spu.getStock() < Math.abs(rollbackDelta)) {
|
||||
return R.failed(StrUtil.blankToDefault(spu.getName(), "商品") + "库存不足,无法自动补偿");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.HARD_PRODUCT_STOCK_LOW,
|
||||
StrUtil.blankToDefault(spu.getName(), "商品")));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,13 +180,13 @@ public class CanteenSpuServiceImpl extends ServiceImpl<CanteenSpuMapper, Canteen
|
||||
// 补偿不能再要求库存等于本业务 APPLY 后的快照:期间可能已有其他订单合法改变同一 SPU。
|
||||
// 同一业务号由锁和 APPLIED 状态保证只反向一次,数据库条件更新只负责阻止库存扣成负数。
|
||||
if (baseMapper.updateStock(item.getId(), delta) == 0) {
|
||||
throw new RuntimeException("库存补偿失败,请重试");
|
||||
throw new I18nBizException(ErrorCodes.CANTEEN_STOCK_COMPENSATE_FAIL);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// 状态缺失的 ROLLBACK 说明没有可确认的成功 APPLY,只写入终态阻断延迟请求,不能按库存值猜测并恢复。
|
||||
if (applyOperation && baseMapper.updateStockIfMatch(item.getId(), delta, expectedStock) == 0) {
|
||||
throw new RuntimeException("库存已变化,请重新操作");
|
||||
throw new I18nBizException(ErrorCodes.CANTEEN_STOCK_CHANGED, "");
|
||||
}
|
||||
}
|
||||
String targetState = applyOperation ? "APPLIED"
|
||||
@@ -197,7 +204,7 @@ public class CanteenSpuServiceImpl extends ServiceImpl<CanteenSpuMapper, Canteen
|
||||
*/
|
||||
private void updateStockBizState(String stateKey, String previousState, String targetState) {
|
||||
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
throw new RuntimeException("库存事务状态异常,请稍后重试");
|
||||
throw new I18nBizException(ErrorCodes.CANTEEN_STOCK_TX_STATE_BAD);
|
||||
}
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||
/**
|
||||
|
||||
+1327
File diff suppressed because it is too large.
Load diff
@@ -37,3 +37,535 @@ sys.user.password.new.empty=New password cannot be empty
|
||||
sys.user.password.length=Password length must be 6-20 characters
|
||||
sys.user.password.chars.only=Password can only contain letters and digits
|
||||
sys.user.password.letter.digit=Password must contain both letters and digits
|
||||
common.not.login=Not signed in
|
||||
common.record.not.found=Record not found
|
||||
common.mch.not.found=Merchant not found
|
||||
common.user.dept.missing=User department not found
|
||||
ordering.food.mch.disabled=Meal ordering is not enabled for this merchant
|
||||
ordering.food.job.time.missing.for.segment=Business hours are not configured; meal slots unavailable
|
||||
ordering.food.job.time.missing=Business hours are not configured
|
||||
ordering.food.select.date.segment=Please select meal date and slot
|
||||
ordering.food.select.dish=Please select dishes
|
||||
ordering.food.fill.person.count=Please enter the number of diners
|
||||
ordering.food.cancel.status.invalid=Cannot cancel in the current status
|
||||
ordering.food.select.valid.mch=Please select a valid merchant
|
||||
ordering.food.no.mch.view.perm=No permission to view this merchant
|
||||
ordering.food.select.date=Please select a date
|
||||
ordering.food.user.dept.missing=User department not found
|
||||
ordering.food.select.canteen.mch=Please select a canteen merchant
|
||||
ordering.food.stats.range.too.large=Date range cannot exceed one month ({0} days)
|
||||
ordering.food.user.info.missing=User info not found
|
||||
ordering.food.no.stats.perm=No permission to access meal-order statistics
|
||||
ordering.food.date.segment.incomplete=Meal date or slot is incomplete
|
||||
ordering.food.future.days.limit=Only meals within the next {0} days are allowed
|
||||
ordering.food.segment.invalid=Invalid meal slot. Please refresh and try again
|
||||
ordering.food.duplicate.date.segment=Duplicate date and meal slot selection
|
||||
ordering.food.dish.info.incomplete=Dish information is incomplete
|
||||
ordering.food.select.dish.for.segment=Please select dishes for "{0}"
|
||||
ordering.food.dish.segment.invalid=Invalid dish meal slot
|
||||
common.order.not.found=Order not found
|
||||
common.cart.not.found=Cart not found
|
||||
common.wallet.not.found=User wallet not found
|
||||
common.wallet.balance.insufficient=Insufficient wallet balance
|
||||
common.product.not.found=Product not found
|
||||
common.product.stock.low=Insufficient stock
|
||||
common.user.not.exist=User not found
|
||||
common.user.not.exist.dup=User not found
|
||||
common.unsupported.pay.type=Unsupported payment method
|
||||
common.mch.id.empty=Merchant ID is required
|
||||
common.past.date.not.allowed=Cannot select a past date
|
||||
common.date.format.ymd=Date format must be yyyy-MM-dd
|
||||
common.date.range.required=Start and end dates are required
|
||||
common.date.range.invalid=End date cannot be earlier than start date
|
||||
common.month.format.ym=Month format must be yyyy-MM
|
||||
delivery.order.no.view=Order not found or no permission to view
|
||||
delivery.order.no.operate=Order not found or no permission to operate
|
||||
delivery.accept.first=Please accept the order first
|
||||
delivery.accept.status.invalid=Cannot accept in current status
|
||||
delivery.already.accepted=Order already accepted
|
||||
delivery.pickup.photo.status.invalid=Cannot upload pickup photo in current status
|
||||
delivery.deliver.photo.status.invalid=Cannot upload delivery photo in current status
|
||||
delivery.sync.hardware.fail=Failed to sync hardware takeout status: {0}
|
||||
delivery.no.response=No response
|
||||
delivery.order.already.synced=Order already synced
|
||||
delivery.cart.serialize.fail=Cart serialization failed
|
||||
delivery.order.no.empty=Order number is required
|
||||
delivery.rider.push.title=New delivery task
|
||||
delivery.rider.push.body=You have a new canteen delivery. Please handle it promptly.
|
||||
delivery.mch.push.title=New takeout order
|
||||
delivery.mch.push.body=You have a new canteen takeout order. Please handle it promptly.
|
||||
delivery.mch.schedule.title=Scheduled delivery reminder
|
||||
delivery.mch.schedule.body=A scheduled delivery is entering prep time. Please check it.
|
||||
delivery.rider.building.bound=Buildings under this unit already have riders. Unbind first.
|
||||
wallet.type.id.empty=Wallet type ID is required
|
||||
wallet.remark.empty=Remark is required
|
||||
wallet.not.found=Wallet not found
|
||||
wallet.freeze.dup=Request already submitted
|
||||
wallet.card.not.found=Card number not found
|
||||
wallet.card.already.bound=Card already bound to a user
|
||||
wallet.meal.card.not.found=Meal card wallet not found
|
||||
wallet.user.already.bound=User already has a meal card
|
||||
wallet.qr.gen.fail=Failed to generate wallet QR code
|
||||
wallet.relation.query.fail=Failed to query related person info
|
||||
wallet.user.relation.fail=Failed to query user relation
|
||||
wallet.face.query.fail=Failed to query face enrollment
|
||||
wallet.pending.appt.fail=Failed to query pending reservations
|
||||
wallet.package.amount.invalid=Invalid recharge package amount
|
||||
wallet.target.card.missing=Target meal card not found
|
||||
wallet.no.ward.perm=No permission for this ward
|
||||
wallet.ward.query.fail=Failed to query ward info
|
||||
wallet.ward.not.found=Ward not found
|
||||
wallet.identity.query.fail=Failed to query recharge identity
|
||||
wallet.canteen.missing=Wallet canteen not found
|
||||
wallet.identity.no.recharge=This identity cannot recharge the wallet
|
||||
wallet.card.canteen.missing=Meal card canteen not found
|
||||
wallet.pay.method.missing=Canteen has no payment methods configured
|
||||
wallet.proxy.record.missing=Proxy recharge record not found
|
||||
wallet.guardian.relation.fail=Failed to query guardian relation
|
||||
wallet.package.not.found=Recharge package not found
|
||||
wallet.package.disabled=Recharge package disabled
|
||||
wallet.meal.card.not.open=Meal card not opened
|
||||
wallet.meal.card.frozen=Meal card frozen
|
||||
wallet.card.status.no.recharge={0}; recharge unavailable
|
||||
wallet.target.user.missing=Target user info missing
|
||||
wallet.no.ward.tx.perm=No permission to view this ward's transactions
|
||||
wallet.tx.deduct.amount.mismatch=Duplicate deduction amount mismatch
|
||||
wallet.tx.credit.amount.mismatch=Duplicate credit amount mismatch
|
||||
wallet.tx.refund.amount.mismatch=Duplicate refund amount mismatch
|
||||
wallet.tx.payment.amount.mismatch=Payment amount does not match compensation
|
||||
wallet.order.payment.cancelled=Order payment was cancelled; deduction not allowed
|
||||
wallet.order.payment.compensated=Order payment was compensated; duplicate deduction not allowed
|
||||
wallet.tx.compensate.fail=Wallet compensation failed
|
||||
wallet.tx.batch.compensate.fail=Wallet batch compensation failed
|
||||
wallet.tx.payment.save.fail=Failed to save wallet payment transaction
|
||||
wallet.tx.refund.save.fail=Failed to save wallet compensation transaction
|
||||
wallet.tx.batch.empty=Wallet batch transaction details cannot be empty
|
||||
wallet.tx.batch.incomplete=Wallet batch transaction details are incomplete
|
||||
wallet.tx.batch.non.force.only=Wallet batch transactions support non-overdraft payment only
|
||||
wallet.tx.batch.dup.biz=Do not resubmit the same wallet business ID
|
||||
wallet.tx.processing=Wallet order transaction in progress; please retry later
|
||||
wallet.tx.lock.interrupted=Wallet order transaction wait interrupted; please retry later
|
||||
wallet.tx.tx.state.bad=Wallet batch transaction state invalid; please retry later
|
||||
wallet.tx.not.found=Wallet transaction not found or deleted
|
||||
wallet.reset.balance.fail=Failed to reset balance
|
||||
wallet.proxy.refund.not.paid=Proxy recharge not credited; refund not allowed
|
||||
wallet.proxy.pay.status.fail=Failed to update proxy recharge credit status
|
||||
wallet.proxy.refund.status.fail=Failed to update proxy recharge refund status
|
||||
wallet.card.no.user=This meal card is not bound to a user
|
||||
after.sale.refund.only=Only refund-only is supported
|
||||
after.sale.pending.dup=A pending refund already exists
|
||||
after.sale.partial.continue.unsupported=Partial refund continue is unsupported; please upgrade
|
||||
after.sale.amount.exceed=Refund exceeds remaining refundable amount
|
||||
after.sale.pay.amount.invalid=Order paid amount is invalid
|
||||
after.sale.not.found=After-sale order not found
|
||||
after.sale.order.not.found=After-sale order not found
|
||||
after.sale.payer.only=Only the payer can request a refund
|
||||
after.sale.app.mch.scope=App merchant can only review canteen reservations
|
||||
after.sale.cancel.status.invalid=Cancel failed; after-sale is not pending review
|
||||
after.sale.amount.gt.zero=Refund amount must be greater than 0
|
||||
after.sale.amount.gt.pay=Refund total exceeds paid amount
|
||||
after.sale.wallet.refund.fail=Wallet refund failed
|
||||
after.sale.wx.refund.fail=WeChat refund failed
|
||||
after.sale.wx.refund.fail.msg=WeChat refund failed: {0}
|
||||
after.sale.ali.refund.fail=Alipay refund failed
|
||||
after.sale.ali.refund.fail.msg=Alipay refund failed: {0}
|
||||
after.sale.unsupported.type=Unsupported refund type
|
||||
after.sale.wallet.clawback.fail=Failed to claw back wallet refund
|
||||
after.sale.order.fully.refunded=Order fully refunded
|
||||
after.sale.product.list.empty=After-sale product list cannot be empty
|
||||
after.sale.order.cart.missing=Order cart not found
|
||||
after.sale.refund.product.empty=Refund product cannot be empty
|
||||
after.sale.refund.product.missing=Refund product <{0}> not found
|
||||
after.sale.refund.qty.empty=Refund qty for <{0}> is required
|
||||
after.sale.refund.qty.negative=Refund qty for <{0}> cannot be negative
|
||||
after.sale.refund.qty.invalid=Refund qty for <{0}> is invalid
|
||||
after.sale.hist.qty.invalid=Historical refund qty is invalid
|
||||
after.sale.order.qty.invalid=Order product qty is invalid
|
||||
after.sale.refund.qty.bad=Refund product qty is invalid
|
||||
after.sale.refund.qty.exceed=Refund qty for <{0}> exceeds limit
|
||||
after.sale.order.type.no.refund=Order type does not support refund
|
||||
after.sale.order.status.no.refund=Order status does not support refund
|
||||
after.sale.refund.time.exceeded=Order is over 4 hours old; refund not allowed
|
||||
after.sale.auto.refund.lock=Auto refund in progress; manual cancel/review blocked
|
||||
after.sale.dup.product=Cannot submit the same product twice
|
||||
after.sale.product.not.in.order=Refund product not in this order
|
||||
after.sale.weighted.no.partial=Weighted items do not support per-unit online refund
|
||||
after.sale.refund.qty.out.range=Refund qty for <{0}> exceeds refundable range
|
||||
after.sale.refund.amount.invalid=Refund amount for <{0}> is invalid
|
||||
after.sale.select.product=Please select products to refund
|
||||
after.sale.order.product.bad=Order product data is invalid
|
||||
after.sale.order.amount.snapshot.bad=Order amount snapshot is invalid
|
||||
after.sale.alloc.weight.bad=Refund allocation weight is invalid
|
||||
after.sale.processing=Refund is processing; try again later
|
||||
after.sale.approve.status.invalid=Approve failed; not in review status
|
||||
after.sale.pending.handle.first=Handle pending refund before new refund
|
||||
after.sale.hist.detail.incomplete=Historical refund details incomplete; check in admin
|
||||
after.sale.order.type.error=Invalid order type
|
||||
after.sale.refund.list.empty=Refund product list cannot be empty
|
||||
after.sale.device.order.missing=Device order not found
|
||||
hard.cart.not.owned=Cart not found or not owned by current user
|
||||
hard.cart.no.view=Cart not found or no permission to view
|
||||
hard.cart.status.changed=Cart status changed; please reselect items
|
||||
hard.cart.amount.invalid=Cart amount is invalid
|
||||
hard.cart.product.bad=Cart product data invalid; please reselect
|
||||
hard.cart.product.not.in.mch=Cart product missing or not in this merchant
|
||||
hard.required.dish.missing=Required dish not selected
|
||||
hard.user.address.missing=User address not found
|
||||
hard.pickup.point.missing=Pickup point not found
|
||||
hard.mch.not.cooperate=Merchant is not a partner
|
||||
hard.app.pay.fail=Failed to start app payment
|
||||
hard.wallet.deduct.fail=Wallet deduction failed
|
||||
hard.unverified.self=You have {0} unverified reservation(s); verify first
|
||||
hard.unverified.diner=Diner has {0} unverified reservation(s); verify first
|
||||
hard.unverified.diner.limit=Diner has {0} unverified reservation(s); would exceed 200 limit
|
||||
hard.batch.wallet.only=Batch ordering currently supports wallet only
|
||||
hard.multi.diner.canteen.only=Multi-diner ordering is canteen-only
|
||||
hard.cart.already.ordered=Cart already ordered; do not resubmit
|
||||
hard.cart.already.ordered2=Cart already ordered; do not resubmit
|
||||
hard.cart.not.canteen=Cart merchant is not a canteen
|
||||
hard.diner.not.found=Diner not found
|
||||
hard.create.reserve.fail=Failed to create reservation order
|
||||
hard.reserve.tx.bad=Reservation transaction abnormal; retry later
|
||||
hard.reserve.group.empty=Reservation group cannot be empty
|
||||
hard.cart.dup.submit=Do not resubmit the same cart
|
||||
hard.reserve.processing=Reservation is processing; do not resubmit
|
||||
hard.daily.menu.canteen.only=Daily menu orders are canteen-only
|
||||
hard.not.daily.menu.scene=Cart is not daily-menu; please pay again
|
||||
hard.batch.same.mch=Batch order must be same merchant
|
||||
hard.dup.date.meal=Do not resubmit same date and meal slot
|
||||
hard.daily.menu.mode.off=Daily menu mode is not enabled
|
||||
hard.reserve.amount.bad=Reservation amount is invalid
|
||||
hard.diner.card.query.fail=Failed to query diner meal card; retry later
|
||||
hard.diner.query.fail=Failed to query diner
|
||||
hard.diner.card.data.bad=Diner meal card data invalid; contact admin
|
||||
hard.diner.card.dup={0} has duplicate meal cards; contact admin
|
||||
hard.diner.no.card={0} has no meal card
|
||||
hard.diner.card.owner.bad={0} meal card ownership invalid; contact admin
|
||||
hard.diner.balance.low={0} meal card balance insufficient
|
||||
hard.daily.menu.product.bad=Daily menu product missing/off-shelf/wrong merchant
|
||||
hard.product.price.bad={0} price invalid; contact merchant
|
||||
hard.product.mode.bad={0} product mode invalid; contact merchant
|
||||
hard.product.price.changed={0} price changed; reselect dishes
|
||||
hard.product.stock.low={0} is out of stock
|
||||
hard.one.item.per.slot=Only one item per date/slot for this merchant
|
||||
hard.diner.empty=Diner is required
|
||||
hard.diner.dup=Do not select the same diner twice
|
||||
hard.diner.invalid=Invalid or unauthorized diner
|
||||
hard.guardian.reserve.off=Guardian ordering is not enabled
|
||||
hard.diner.identity.invalid=Diner identity not allowed for this merchant
|
||||
hard.diner.slot.once=Same diner/date/slot can reserve once only
|
||||
hard.appt.processing=Reservation processing; do not resubmit
|
||||
hard.appt.tx.bad=Reservation transaction abnormal; retry later
|
||||
hard.diner.card.mismatch=Diner and meal card ownership mismatch
|
||||
hard.stock.deduct.fail=Insufficient stock or deduct failed
|
||||
hard.stock.restore.fail=Failed to restore stock
|
||||
hard.daily.stock.deduct.fail=Daily menu stock insufficient or deduct failed
|
||||
hard.daily.stock.restore.fail=Failed to restore daily menu stock
|
||||
hard.copy.cart.fail=Failed to copy reservation cart
|
||||
hard.copy.product.fail=Failed to copy reservation products
|
||||
hard.wallet.tx.bad=Reservation wallet transaction data invalid
|
||||
hard.update.pay.status.fail=Failed to update reservation pay status
|
||||
hard.update.cart.status.fail=Failed to update reservation cart status
|
||||
hard.mch.no.resp=No response querying merchant
|
||||
hard.diner.card.no.resp=No response querying diner meal card
|
||||
hard.daily.product.no.resp=No response querying daily menu products
|
||||
hard.daily.product.query.fail=Failed to query daily menu products
|
||||
hard.diner.identity.no.resp=No response querying diner identity
|
||||
hard.diner.identity.query.fail=Failed to query diner identity
|
||||
hard.daily.menu.batch.bad=Daily menu order batch data invalid
|
||||
hard.reserve.batch.bad=Reservation order batch data invalid
|
||||
hard.wallet.batch.deduct.bad=Wallet batch deduction result invalid
|
||||
hard.appt.cycle.rule.required=Cycle reservation rule required
|
||||
hard.appt.cycle.not.allowed=Merchant uses dynamic time window; cycle rule not allowed
|
||||
hard.appt.date.meal.required=Select reservation date and meal slot for cycle booking
|
||||
hard.appt.cycle.open.at=Opens on {0} at {1}
|
||||
hard.wallet.batch.deduct.no.resp=No response for wallet batch deduct
|
||||
hard.wallet.batch.comp.no.resp=No response for wallet batch compensate
|
||||
hard.stock.no.resp=No response querying product stock
|
||||
hard.appt.slot.missing=Reservation slot not found
|
||||
hard.appt.slot.mch.mismatch=Reservation slot does not match merchant
|
||||
hard.appt.slot.disabled=Reservation slot disabled
|
||||
hard.appt.slot.mode.mismatch=Reservation slot mismatches merchant mode
|
||||
hard.appt.date.out.range=Reservation date out of range
|
||||
hard.appt.date.no.slot=This date has no such reservation slot
|
||||
hard.appt.date.type.invalid=Invalid reservation date type
|
||||
hard.appt.dynamic.slot.empty=Dynamic reservation slot required
|
||||
hard.appt.period.closed=Current reservation period closed
|
||||
hard.appt.not.open=Reservation not open yet
|
||||
hard.appt.closed=Reservation closed
|
||||
hard.appt.rule.mode.invalid=Invalid reservation rule mode
|
||||
hard.appt.rule.incomplete=Reservation rule incomplete
|
||||
hard.appt.rule.time.invalid=Reservation rule time range invalid
|
||||
hard.appt.cycle.missing=Cycle rule missing or disabled
|
||||
hard.appt.mch.conf.fail=Failed to load merchant reservation config
|
||||
hard.appt.mch.mode.invalid=Invalid merchant reservation time mode
|
||||
hard.delivery.type.invalid=Invalid delivery time type
|
||||
hard.schedule.need.slot=Scheduled delivery requires date and slot
|
||||
hard.schedule.end.after.start=Slot end must be after start
|
||||
hard.mch.job.time.missing=Merchant business hours not configured
|
||||
hard.eta.out.of.hours=ETA outside business hours; reselect
|
||||
hard.no.schedule.without.hours=No business hours; scheduled delivery unavailable
|
||||
hard.job.time.format.bad=Invalid jobTime format; fix in admin
|
||||
hard.slot.out.of.hours=Slot outside business hours; reselect
|
||||
hard.qr.already.verified=QR code already verified
|
||||
hard.verify.diner.only=Only the diner can use the verification code
|
||||
hard.not.canteen.reserve=Not a canteen reservation order
|
||||
hard.no.mch.verify.perm=No merchant verification permission
|
||||
hard.no.mch.order.manage=No permission to manage this merchant's orders
|
||||
hard.reserve.not.verifiable=Reservation cannot be verified now
|
||||
hard.reserve.refunding.no.verify=Reservation is refunding; cannot verify
|
||||
hard.reserve.full.refund.no.verify=Reservation fully refunded; cannot verify
|
||||
hard.verify.status.changed=Order status changed; verify failed
|
||||
hard.restore.code.no.resp=No response restoring verification code
|
||||
hard.restore.code.fail=Failed to restore verification code
|
||||
hard.rollback.online.only=Only online reservations support verify rollback
|
||||
hard.rollback.biz.unsupported=Business type does not support verify rollback
|
||||
hard.rollback.verified.only=Only verified orders support rollback
|
||||
hard.rollback.refunding=Refunding; cannot rollback verification
|
||||
hard.rollback.full.refund=Fully refunded; cannot rollback verification
|
||||
hard.rollback.status.changed=Order status changed; rollback failed
|
||||
hard.act.ended=Verify failed; activity ended
|
||||
hard.act.not.started=Verify failed; activity not started
|
||||
hard.act.coupon.used=Verify failed; coupon already used
|
||||
hard.act.location.error=Verify failed; location error
|
||||
hard.act.verify.fail=Verification failed
|
||||
hard.act.qr.bad=Invalid verification QR code
|
||||
hard.act.device.no.perm=Device cannot verify this activity order
|
||||
hard.act.user.no.perm=User has no verify permission for activity
|
||||
hard.act.verify.user.missing=Verify user not found
|
||||
hard.act.coupon.user.missing=Coupon user not found
|
||||
hard.order.expired.rescan=Order expired; scan again
|
||||
hard.not.device.scan.pay=Not a device scan-pay order
|
||||
hard.not.device.scan=Not a device scan order
|
||||
hard.order.paid.or.changed=Order paid or status changed
|
||||
hard.pay.amount.zero=Payment amount is 0
|
||||
hard.user.no.wallet=User does not have this wallet
|
||||
hard.wallet.user.missing=Wallet user not found
|
||||
hard.shipment.no.missing=Tracking number not found
|
||||
hard.order.type.no.receipt=Order type does not support confirm receipt
|
||||
hard.order.status.no.receipt=Order status does not support confirm receipt
|
||||
hard.order.type.error=Invalid order type
|
||||
hard.order.status.error=Invalid order status
|
||||
hard.idem.create=Creating order; do not repeat
|
||||
hard.idem.verify=Verifying; do not repeat
|
||||
hard.idem.rollback=Rolling back verification; do not repeat
|
||||
hard.car.group.empty=Cart group cannot be empty
|
||||
hard.car.biz.incomplete=Cart business info incomplete
|
||||
hard.car.batch.same.user.mch=Batch cart must share user/merchant/type
|
||||
hard.car.save.fail=Failed to save cart products
|
||||
common.idempotent.retry=Duplicate request. Please try again later
|
||||
auth.captcha.empty=Verification code is required
|
||||
auth.captcha.invalid=Invalid verification code
|
||||
auth.wx.auth.fail=WeChat authorization failed: {0}
|
||||
auth.wx.openid.missing=WeChat authorization failed; user identifier not received
|
||||
auth.wx.auth.expired=WeChat authorization expired; please authorize again
|
||||
auth.apple.not.configured=Apple login is not configured
|
||||
auth.apple.not.enabled=Apple login is not enabled
|
||||
auth.mini.app.login.fail=WeChat mini program login failed
|
||||
auth.social.auth.expired=Authorization expired; please authorize again
|
||||
sys.app.sms.send.fail=Failed to send SMS code; please try again later
|
||||
sys.app.sms.code.invalid=SMS code is invalid or expired
|
||||
sys.user.password.same=New password must differ from old password
|
||||
sys.user.unbind.type.invalid=Unbind account type does not exist
|
||||
third.recharge.biz.id.invalid=Invalid recharge business ID
|
||||
third.proxy.recharge.biz.id.invalid=Invalid proxy recharge business ID
|
||||
third.proxy.recharge.invalid=Proxy recharge record missing or amount invalid
|
||||
third.ward.wallet.no.recharge=Target meal card cannot be recharged now
|
||||
third.pay.amount.gt.zero=Payment amount must be greater than 0
|
||||
third.wechat.pay.create.fail=Failed to create WeChat payment
|
||||
third.alipay.pay.create.fail=Failed to create Alipay payment
|
||||
third.user.no.mch=User does not belong to any canteen or shop
|
||||
third.user.no.canteen=User does not belong to any canteen
|
||||
third.shop.pay.mch.missing=Shop payment missing trusted merchant info
|
||||
third.shop.order.biz.id.invalid=Invalid shop order business ID
|
||||
third.shop.order.no.pay=Shop order not found or not payable
|
||||
third.shop.order.amount.mismatch=Shop order payment amount mismatch
|
||||
third.shop.order.mch.mismatch=Shop order merchant mismatch
|
||||
third.mch.pay.disabled=Receiving merchant is disabled
|
||||
third.mch.wechat.pay.config.missing=Merchant WeChat pay config is missing
|
||||
third.mch.alipay.pay.config.missing=Merchant Alipay pay config is missing
|
||||
third.order.code.processing=Order code payment in progress; do not resubmit
|
||||
third.pay.no.empty=Payment order number is required
|
||||
third.order.code.not.found=Order code payment order not found
|
||||
third.order.already.paid=Business order already paid; do not reorder
|
||||
third.order.code.other.platform=Pending order code exists on another platform
|
||||
third.order.code.data.error=Order code data error; please retry later
|
||||
third.order.closing=Previous order is closing; please retry later
|
||||
third.order.code.param.empty=Order code payment parameters are required
|
||||
third.order.code.biz.only=Order code payment supports cloud POS only
|
||||
third.order.code.platform.only=Order code payment supports Alipay or WeChat only
|
||||
third.pay.biz.id.empty=Payment business ID is required
|
||||
third.order.pending.mismatch=Pending order has different amount or merchant
|
||||
third.mch.info.mismatch=Receiving merchant info mismatch
|
||||
third.mch.alipay.config.disabled=Merchant Alipay pay config is disabled
|
||||
third.mch.wechat.config.disabled=Merchant WeChat pay config is disabled
|
||||
third.alipay.app.config.incomplete=Alipay app pay config is incomplete
|
||||
third.wechat.app.config.incomplete=WeChat service provider pay config is incomplete
|
||||
third.refund.processing=Previous refund is still processing; please retry later
|
||||
third.wx.oauth.incomplete=WeChat OAuth parameters are incomplete
|
||||
third.wx.oauth.fail=WeChat OAuth failed; please scan again
|
||||
third.fz.relation.unavailable=Payment revenue-sharing service unavailable
|
||||
third.wx.jsapi.create.fail=Failed to create WeChat JSAPI order; please scan again
|
||||
third.aggregate.sub.order.save.fail=Failed to save aggregate sub-order
|
||||
third.mch.wechat.config.incomplete=Merchant WeChat pay config is incomplete
|
||||
third.mch.wechat.sub.mch.missing=Merchant WeChat sub-merchant ID is missing
|
||||
third.pay.order.snapshot.missing=Payment order missing merchant config snapshot
|
||||
third.pay.order.snapshot.invalid=Payment order merchant config snapshot invalid
|
||||
third.alipay.auth.code.empty=Alipay authorization code is required
|
||||
third.alipay.oauth.fail=Alipay OAuth failed; please scan again
|
||||
third.alipay.oauth.no.payer=Alipay OAuth did not return payer identifier
|
||||
third.alipay.jsapi.create.fail=Failed to create Alipay order; please scan again
|
||||
third.alipay.client.init.fail=Failed to initialize Alipay client
|
||||
third.mch.alipay.config.incomplete=Merchant Alipay pay config is incomplete
|
||||
third.mch.alipay.sub.mch.missing=Merchant Alipay sub-merchant ID is missing
|
||||
third.wx.native.create.fail=Failed to create WeChat order code; please retry later
|
||||
third.wx.native.create.fail.code=Failed to create WeChat order code; WeChat error: {0}
|
||||
third.wx.native.no.qr=Failed to create WeChat order code; QR not returned
|
||||
|
||||
app.msg.title.wallet.payment=Order placed, wallet charged
|
||||
app.msg.title.wallet.refund=Refund credited
|
||||
app.msg.title.wallet.recharge=Top-up credited
|
||||
app.msg.title.wallet.reset=Wallet balance reset
|
||||
app.msg.title.meal.verified=Meal verified
|
||||
app.msg.event.wallet.update=Balance update
|
||||
app.msg.event.wallet.batch=Batch balance update
|
||||
app.msg.event.wallet.recharge=Top-up
|
||||
app.msg.event.wallet.payment=Payment
|
||||
app.msg.event.wallet.refund=Refund
|
||||
app.msg.event.wallet.transfer=Wallet transfer
|
||||
app.msg.event.wallet.transfer.refund=Transfer refund
|
||||
app.msg.event.wallet.return.canteen=Return to canteen
|
||||
app.msg.event.wallet.reset=Balance reset
|
||||
app.msg.event.meal.verified=Meal verification
|
||||
app.msg.wallet.default.name=Wallet
|
||||
app.msg.wallet.detail.inc={0} increased by {1}, balance {2}
|
||||
app.msg.wallet.detail.dec={0} decreased by {1}, balance {2}
|
||||
app.msg.wallet.detail.sep=;
|
||||
app.msg.wallet.content={0}: {1}
|
||||
app.msg.meal.default.name=This reserved meal
|
||||
app.msg.meal.content={0} has been verified. Enjoy your meal.
|
||||
app.msg.ward.fallback=Ward
|
||||
app.msg.relation.title={0}'s {1}
|
||||
app.msg.relation.content={0}: {1}
|
||||
|
||||
common.product.sku.not.found=Product SKU not found
|
||||
common.mch.service.error=Merchant service error
|
||||
mall.user.no.farmer.mch=No mall merchant assigned to this user
|
||||
mall.no.product.perm=No permission for this product
|
||||
mall.category.not.found=Category not found
|
||||
mall.no.category.perm=No permission for this category
|
||||
address.id.empty=Address ID is required
|
||||
address.not.found=Address not found
|
||||
address.dept.building.required=Department and building are required
|
||||
address.unit.required=Unit is required
|
||||
address.room.required=Room is required
|
||||
address.dept.not.found=Department not found
|
||||
address.building.not.found=Building not found
|
||||
address.building.dept.mismatch=Selected building does not belong to this department
|
||||
address.unit.not.found=Unit not found
|
||||
address.unit.building.mismatch=Selected unit does not belong to this building
|
||||
address.room.not.found=Room not found
|
||||
address.room.unit.mismatch=Selected room does not belong to this unit/building
|
||||
address.room.no.empty=Room number is required
|
||||
address.building.no.access=No access to this building
|
||||
address.unit.no.access=No access to this unit
|
||||
address.record.update.missing=Address not found, cannot update
|
||||
address.record.delete.missing=Address not found, cannot delete
|
||||
|
||||
hard.car.group.item.empty=Cart group {0} cannot be empty
|
||||
hard.car.group.item.incomplete=Cart group {0} has incomplete items or invalid quantity
|
||||
hard.car.group.parent.fail=Failed to create parent cart for group {0}
|
||||
hard.car.group.item.invalid=Cart group {0} contains invalid products
|
||||
mall.product.sku.missing=Mall product has no SKU. name:{0}, id:{1}. Contact admin
|
||||
|
||||
canteen.stock.items.empty=Stock items cannot be empty
|
||||
canteen.stock.item.param.bad=Invalid stock item parameters
|
||||
canteen.stock.biz.param.bad=Invalid stock business parameters
|
||||
canteen.stock.item.dup=Duplicate stock items are not allowed
|
||||
canteen.stock.spu.bad=Product not found or stock abnormal
|
||||
canteen.stock.snapshot.bad=Invalid stock snapshot
|
||||
canteen.stock.changed={0} stock changed, please retry
|
||||
canteen.stock.compensate.fail=Stock compensation failed, please retry
|
||||
canteen.stock.update.fail=Stock update failed, please retry
|
||||
canteen.stock.tx.state.bad=Stock transaction state abnormal, please retry later
|
||||
canteen.stock.insufficient=Insufficient stock
|
||||
canteen.no.product.perm=No permission for this product
|
||||
canteen.no.product.perm.named=No permission for product: {0}
|
||||
canteen.shelf.status.invalid=Invalid status; only 0 (on) and 1 (off) are allowed
|
||||
|
||||
hard.stock.tx.state.bad=Stock transaction state abnormal, please retry later
|
||||
hard.canteen.stock.aftersale.missing=Canteen stock refund requires after-sale ID
|
||||
hard.canteen.stock.car.missing=Canteen stock operation failed: cart not found
|
||||
hard.canteen.stock.refund.item.missing=Canteen stock operation failed: refund item not found
|
||||
hard.canteen.stock.no.resp=No response when querying canteen stock
|
||||
hard.canteen.stock.query.fail=Failed to query canteen stock
|
||||
hard.canteen.spu.bad=Canteen dish not found or not in this merchant
|
||||
hard.canteen.stock.op.fail=Canteen stock service operation failed
|
||||
hard.door.stock.fail=Smart locker stock {0} failed
|
||||
hard.stock.deduct.cart.missing=Stock deduct failed: cart not found
|
||||
hard.stock.op.fail={0} failed
|
||||
|
||||
wallet.transfer.source.low=Insufficient balance in source wallet {0}
|
||||
wallet.transfer.limit.exceeded=Transfer amount exceeds maximum limit
|
||||
wallet.transfer.not.found=Transfer record not found
|
||||
wallet.transfer.refund.dup=Already refunded; do not repeat
|
||||
wallet.transfer.refund.source.low=Insufficient balance in source wallet {0}; cannot refund
|
||||
wallet.apply.dup.submit=Application already submitted; do not repeat
|
||||
act.cancel.not.found=Redemption activity not found
|
||||
act.cancel.closed=Redemption activity is closed
|
||||
act.cancel.mch.missing=Redemption activity merchant not found
|
||||
act.cancel.already.received=Already claimed; do not repeat
|
||||
act.cancel.balance.low=Insufficient consume-wallet balance ({0}); cannot claim
|
||||
act.cancel.coupon.expired=Your coupon has expired
|
||||
act.coupon.not.found=Coupon not found
|
||||
act.not.found=Activity not found
|
||||
act.coupon.points.deduct.fail=Points deduction failed
|
||||
act.id.empty=Activity ID is required
|
||||
|
||||
sys.face.max.count=You can upload at most 3 face images
|
||||
sys.face.max.active=At most 3 faces in pending/approved status can be kept
|
||||
sys.face.dup.image=Do not resubmit the same face image
|
||||
sys.face.dept.missing=Your department is missing; cannot start face review
|
||||
sys.face.ward.only=You can only view or manage your own and valid wards' face records
|
||||
sys.face.record.missing=Face review record not found
|
||||
sys.face.revoke.status=Only pending face records can be revoked
|
||||
sys.face.status.changed=Face review status changed; please refresh
|
||||
sys.car.plate.dup=License plate already exists
|
||||
|
||||
hard.idem.applying=Application in progress; do not repeat
|
||||
hard.idem.canceling=Cancellation in progress; do not repeat
|
||||
hard.idem.processing=Processing; do not repeat
|
||||
hard.idem.refunding=Refund in progress; do not repeat
|
||||
hard.idem.batch.refund=Batch refund is being submitted; do not repeat
|
||||
act.idem.receiving=Claim in progress; do not repeat
|
||||
wallet.idem.applying=Application in progress; do not repeat
|
||||
wallet.idem.opening=Card opening in progress; do not repeat
|
||||
wallet.idem.processing=Processing; do not repeat
|
||||
wallet.idem.importing=Import in progress; do not repeat
|
||||
wallet.idem.recharging=Top-up in progress; do not repeat
|
||||
wallet.idem.uploading=Upload in progress; do not repeat
|
||||
wallet.idem.invoice=Regenerating invoice; do not repeat
|
||||
|
||||
mall.product.create.fail=Failed to create product
|
||||
mall.product.id.empty=Product ID is required
|
||||
mall.product.update.fail=Failed to update product
|
||||
mall.product.list.fail=Failed to load product list
|
||||
mall.product.delete.fail=Failed to delete product
|
||||
mall.category.create.fail=Failed to create category
|
||||
mall.category.id.empty=Category ID is required
|
||||
mall.category.update.fail=Failed to update category
|
||||
mall.category.delete.fail=Failed to delete category
|
||||
mall.category.list.fail=Failed to load category list
|
||||
|
||||
third.wx.profit.amount.min=WeChat profit-sharing amount must be greater than 10 fen
|
||||
third.wx.profit.amount.range=WeChat platform fee must be at least 1 fen and not exceed order amount
|
||||
third.pay.config.missing=Payment config not found
|
||||
third.wx.refund.amount.bad=WeChat refund amount must be > 0 and not exceed order amount
|
||||
third.pay.order.status.no.refund=Current payment order status does not allow refund
|
||||
third.ali.qr.create.fail=Failed to create Alipay QR code; please retry later
|
||||
third.ali.amount.invalid=Alipay amount must be greater than 0 fen
|
||||
third.ali.zt.amount.min=Alipay ZFT amount must be greater than 10 fen
|
||||
third.wx.refund.apply.error=WeChat refund application error
|
||||
third.wx.refund.queued=WeChat refund entered compensation queue; check later
|
||||
third.ali.refund.amount.bad=Alipay refund amount must be > 0 and not exceed order amount
|
||||
sys.register.suspended=Registration is temporarily suspended.
|
||||
@@ -37,3 +37,535 @@ sys.user.password.new.empty=新密码不能为空
|
||||
sys.user.password.length=密码长度需为6-20位
|
||||
sys.user.password.chars.only=密码只能包含字母和数字
|
||||
sys.user.password.letter.digit=密码需同时包含字母和数字
|
||||
common.not.login=未登录
|
||||
common.record.not.found=记录不存在
|
||||
common.mch.not.found=商户不存在
|
||||
common.user.dept.missing=用户部门不存在
|
||||
ordering.food.mch.disabled=该商户未启用报餐
|
||||
ordering.food.job.time.missing.for.segment=商户未配置营业时间,无法获取餐段
|
||||
ordering.food.job.time.missing=商户未配置营业时间
|
||||
ordering.food.select.date.segment=请选择报餐日期与餐段
|
||||
ordering.food.select.dish=请选择报餐菜品
|
||||
ordering.food.fill.person.count=请填写报餐人数
|
||||
ordering.food.cancel.status.invalid=当前状态不可取消
|
||||
ordering.food.select.valid.mch=请选择有效商户
|
||||
ordering.food.no.mch.view.perm=无权查看该商户数据
|
||||
ordering.food.select.date=请选择日期
|
||||
ordering.food.user.dept.missing=用户部门不存在
|
||||
ordering.food.select.canteen.mch=请选择食堂商户
|
||||
ordering.food.stats.range.too.large=查询日期范围最多一个月({0}天)
|
||||
ordering.food.user.info.missing=用户信息不存在
|
||||
ordering.food.no.stats.perm=无权访问报餐统计
|
||||
ordering.food.date.segment.incomplete=报餐日期或餐段不完整
|
||||
ordering.food.future.days.limit=仅支持报餐未来{0}天内
|
||||
ordering.food.segment.invalid=餐段无效,请刷新后重试
|
||||
ordering.food.duplicate.date.segment=存在重复的日期餐段选择
|
||||
ordering.food.dish.info.incomplete=报餐菜品信息不完整
|
||||
ordering.food.select.dish.for.segment=请为「{0}」选择菜品
|
||||
ordering.food.dish.segment.invalid=菜品餐段无效
|
||||
common.order.not.found=订单不存在
|
||||
common.cart.not.found=购物车不存在
|
||||
common.wallet.not.found=用户钱包不存在
|
||||
common.wallet.balance.insufficient=钱包余额不足
|
||||
common.product.not.found=商品不存在
|
||||
common.product.stock.low=库存不足
|
||||
common.user.not.exist=用户不存在
|
||||
common.user.not.exist.dup=用户不存在不存在
|
||||
common.unsupported.pay.type=不支持的支付方式
|
||||
common.mch.id.empty=商户ID不能为空
|
||||
common.past.date.not.allowed=不能选择过去的日期
|
||||
common.date.format.ymd=日期格式应为 yyyy-MM-dd
|
||||
common.date.range.required=开始日期与结束日期不能为空
|
||||
common.date.range.invalid=结束日期不能早于开始日期
|
||||
common.month.format.ym=月份格式应为 yyyy-MM
|
||||
delivery.order.no.view=订单不存在或无权查看
|
||||
delivery.order.no.operate=订单不存在或无权操作
|
||||
delivery.accept.first=请先接单
|
||||
delivery.accept.status.invalid=当前状态不可接单
|
||||
delivery.already.accepted=订单已接单
|
||||
delivery.pickup.photo.status.invalid=当前状态不可上传取餐照
|
||||
delivery.deliver.photo.status.invalid=当前状态不可上传送达照
|
||||
delivery.sync.hardware.fail=同步硬件外卖订单状态失败: {0}
|
||||
delivery.no.response=无响应
|
||||
delivery.order.already.synced=订单已同步过
|
||||
delivery.cart.serialize.fail=购物车序列化失败
|
||||
delivery.order.no.empty=订单号不能为空
|
||||
delivery.rider.push.title=新配送任务
|
||||
delivery.rider.push.body=您有一单新的食堂外送,请及时处理
|
||||
delivery.mch.push.title=新外送订单
|
||||
delivery.mch.push.body=您有一单新的食堂外送订单,请及时处理
|
||||
delivery.mch.schedule.title=预约外送提醒
|
||||
delivery.mch.schedule.body=您有一单预约外送即将进入备餐时段,请及时查看
|
||||
delivery.rider.building.bound=该单位下楼栋已绑定骑手,请先解绑
|
||||
wallet.type.id.empty=钱包类型id不能为空
|
||||
wallet.remark.empty=备注不能为空
|
||||
wallet.not.found=钱包不存在
|
||||
wallet.freeze.dup=已提交申请,请勿重复提交
|
||||
wallet.card.not.found=卡号不存在
|
||||
wallet.card.already.bound=该卡号已经绑定用户
|
||||
wallet.meal.card.not.found=饭卡钱包不存在
|
||||
wallet.user.already.bound=用户已绑定饭卡
|
||||
wallet.qr.gen.fail=钱包二维码生成错误
|
||||
wallet.relation.query.fail=查询关系人信息失败
|
||||
wallet.user.relation.fail=查询用户关系失败
|
||||
wallet.face.query.fail=查询用户人脸情况失败
|
||||
wallet.pending.appt.fail=查询用户待核销预约失败
|
||||
wallet.package.amount.invalid=充值套餐金额无效
|
||||
wallet.target.card.missing=目标饭卡不存在
|
||||
wallet.no.ward.perm=无权操作该被监护人
|
||||
wallet.ward.query.fail=查询被监护人信息失败
|
||||
wallet.ward.not.found=被监护人不存在
|
||||
wallet.identity.query.fail=查询充值用户身份失败
|
||||
wallet.canteen.missing=钱包所属食堂不存在
|
||||
wallet.identity.no.recharge=当前人员身份不支持钱包充值
|
||||
wallet.card.canteen.missing=饭卡所属食堂不存在
|
||||
wallet.pay.method.missing=饭卡所属食堂暂未配置支付方式
|
||||
wallet.proxy.record.missing=代充值记录不存在
|
||||
wallet.guardian.relation.fail=查询监护关系失败
|
||||
wallet.package.not.found=钱包充值套餐不存在
|
||||
wallet.package.disabled=钱包充值套餐已禁用
|
||||
wallet.meal.card.not.open=未开通饭卡
|
||||
wallet.meal.card.frozen=饭卡已冻结
|
||||
wallet.card.status.no.recharge={0},暂不可充值
|
||||
wallet.target.user.missing=缺少目标用户信息
|
||||
wallet.no.ward.tx.perm=无权查看该被监护人的钱包流水
|
||||
wallet.tx.deduct.amount.mismatch=重复业务扣款金额不一致
|
||||
wallet.tx.credit.amount.mismatch=重复业务入账金额不一致
|
||||
wallet.tx.refund.amount.mismatch=重复业务退款金额不一致
|
||||
wallet.tx.payment.amount.mismatch=支付流水金额与补偿金额不一致
|
||||
wallet.order.payment.cancelled=订单支付已经取消,不能继续扣款
|
||||
wallet.order.payment.compensated=订单支付已经补偿,不能重复扣款
|
||||
wallet.tx.compensate.fail=钱包补偿失败
|
||||
wallet.tx.batch.compensate.fail=钱包批量补偿失败
|
||||
wallet.tx.payment.save.fail=保存钱包支付流水失败
|
||||
wallet.tx.refund.save.fail=保存钱包补偿流水失败
|
||||
wallet.tx.batch.empty=钱包批量交易明细不能为空
|
||||
wallet.tx.batch.incomplete=钱包批量交易明细不完整
|
||||
wallet.tx.batch.non.force.only=钱包批量交易仅支持非透支支付
|
||||
wallet.tx.batch.dup.biz=请勿重复提交同一钱包业务号
|
||||
wallet.tx.processing=订单钱包交易正在处理中,请稍后重试
|
||||
wallet.tx.lock.interrupted=订单钱包交易等待已中断,请稍后重试
|
||||
wallet.tx.tx.state.bad=钱包批量交易事务状态异常,请稍后重试
|
||||
wallet.tx.not.found=钱包流水不存在或已删除
|
||||
wallet.reset.balance.fail=重置余额失败
|
||||
wallet.proxy.refund.not.paid=代充值尚未到账,不能退款
|
||||
wallet.proxy.pay.status.fail=更新代充值到账状态失败
|
||||
wallet.proxy.refund.status.fail=更新代充值退款状态失败
|
||||
wallet.card.no.user=该饭卡没有绑定用户
|
||||
after.sale.refund.only=当前仅支持仅退款
|
||||
after.sale.pending.dup=当前订单已有退款申请待审核,请勿重复提交
|
||||
after.sale.partial.continue.unsupported=当前版本不支持部分退款后的继续申请,请升级应用后重试
|
||||
after.sale.amount.exceed=本次退款金额超出订单剩余可退金额
|
||||
after.sale.pay.amount.invalid=订单实付金额异常
|
||||
after.sale.not.found=售后单不存在
|
||||
after.sale.order.not.found=售后订单不存在
|
||||
after.sale.payer.only=仅订单付款人可以申请退款
|
||||
after.sale.app.mch.scope=当前 App 商户仅支持审核食堂预约订单
|
||||
after.sale.cancel.status.invalid=取消售后单失败,售后单状态不是【待审核】
|
||||
after.sale.amount.gt.zero=退款金额必须大于0
|
||||
after.sale.amount.gt.pay=退款总金额大于支付总金额
|
||||
after.sale.wallet.refund.fail=钱包退款错误
|
||||
after.sale.wx.refund.fail=微信退款错误
|
||||
after.sale.wx.refund.fail.msg=微信退款错误:{0}
|
||||
after.sale.ali.refund.fail=支付宝退款错误
|
||||
after.sale.ali.refund.fail.msg=支付宝退款错误:{0}
|
||||
after.sale.unsupported.type=不支持的退款类型
|
||||
after.sale.wallet.clawback.fail=钱包退款金额扣回失败
|
||||
after.sale.order.fully.refunded=订单已全部退款
|
||||
after.sale.product.list.empty=售后商品列表不能为空
|
||||
after.sale.order.cart.missing=订单购物车不存在
|
||||
after.sale.refund.product.empty=退款商品不能为空
|
||||
after.sale.refund.product.missing=退款商品<{0}>不存在
|
||||
after.sale.refund.qty.empty=退款商品<{0}>数量不能为空
|
||||
after.sale.refund.qty.negative=退款商品<{0}>数量不能为负数
|
||||
after.sale.refund.qty.invalid=退款商品<{0}>数量异常
|
||||
after.sale.hist.qty.invalid=历史退款商品数量异常
|
||||
after.sale.order.qty.invalid=订单商品数量异常
|
||||
after.sale.refund.qty.bad=退款商品数量异常
|
||||
after.sale.refund.qty.exceed=退款商品<{0}>数量超出
|
||||
after.sale.order.type.no.refund=该订单类型不支持退款
|
||||
after.sale.order.status.no.refund=当前订单状态不支持退款
|
||||
after.sale.refund.time.exceeded=订单已超过4个小时,不能退款
|
||||
after.sale.auto.refund.lock=自动退款处理中,当前售后单不允许人工取消或审核
|
||||
after.sale.dup.product=同一商品不能重复提交
|
||||
after.sale.product.not.in.order=退款商品不属于当前订单
|
||||
after.sale.weighted.no.partial=称重商品暂不支持在线逐份退款
|
||||
after.sale.refund.qty.out.range=退款商品<{0}>数量超出可退范围
|
||||
after.sale.refund.amount.invalid=退款商品<{0}>退款金额异常
|
||||
after.sale.select.product=请选择需要退款的商品
|
||||
after.sale.order.product.bad=订单商品数据异常
|
||||
after.sale.order.amount.snapshot.bad=订单商品金额快照异常
|
||||
after.sale.alloc.weight.bad=退款分摊权重异常
|
||||
after.sale.processing=订单退款正在处理中,请稍后重试
|
||||
after.sale.approve.status.invalid=审批失败,售后状态不处于审批中
|
||||
after.sale.pending.handle.first=当前订单已有退款申请待审核,请先处理后再退款
|
||||
after.sale.hist.detail.incomplete=历史退款商品明细不完整,请通过后台核对后处理
|
||||
after.sale.order.type.error=订单类型错误
|
||||
after.sale.refund.list.empty=退款商品列表不能为空
|
||||
after.sale.device.order.missing=设备订单不存在
|
||||
hard.cart.not.owned=购物车不存在或不属于当前用户
|
||||
hard.cart.no.view=购物车不存在或无权查看
|
||||
hard.cart.status.changed=购物车状态已变更,请重新选择商品
|
||||
hard.cart.amount.invalid=购物车金额异常
|
||||
hard.cart.product.bad=购物车商品数据异常,请重新选择商品
|
||||
hard.cart.product.not.in.mch=购物车商品不存在或不属于当前商户
|
||||
hard.required.dish.missing=未选择必选菜品
|
||||
hard.user.address.missing=用户地址不存在
|
||||
hard.pickup.point.missing=查询自提点不存在
|
||||
hard.mch.not.cooperate=该商家未合作
|
||||
hard.app.pay.fail=发起app支付失败
|
||||
hard.wallet.deduct.fail=钱包扣款错误
|
||||
hard.unverified.self=您有{0}笔未核销的预约订单,请先核销
|
||||
hard.unverified.diner=用餐人已有{0}笔未核销的预约订单,请先核销
|
||||
hard.unverified.diner.limit=用餐人已有{0}笔未核销的预约订单,本次订餐后将超过200笔上限
|
||||
hard.batch.wallet.only=批量订餐暂仅支持钱包支付
|
||||
hard.multi.diner.canteen.only=仅食堂购物车可以多人订餐
|
||||
hard.cart.already.ordered=该购物车已创建订单,请勿重复提交
|
||||
hard.cart.already.ordered2=购物车已创建订单,请勿重复提交
|
||||
hard.cart.not.canteen=购物车商户不是食堂商户
|
||||
hard.diner.not.found=用餐人不存在
|
||||
hard.create.reserve.fail=创建订餐订单失败
|
||||
hard.reserve.tx.bad=订餐事务状态异常,请稍后重试
|
||||
hard.reserve.group.empty=订餐分组不能为空
|
||||
hard.cart.dup.submit=请勿重复提交同一购物车
|
||||
hard.reserve.processing=订餐订单正在处理中,请勿重复提交
|
||||
hard.daily.menu.canteen.only=仅食堂购物车可以提交每日菜谱订单
|
||||
hard.not.daily.menu.scene=购物车不是每日菜谱场景,请重新点击去支付
|
||||
hard.batch.same.mch=批量订餐必须属于同一商户
|
||||
hard.dup.date.meal=请勿重复提交同一天同一餐段
|
||||
hard.daily.menu.mode.off=当前商户未开启每日菜谱订餐模式
|
||||
hard.reserve.amount.bad=订餐金额异常
|
||||
hard.diner.card.query.fail=查询用餐人饭卡失败,请稍后重试
|
||||
hard.diner.query.fail=查询用餐人失败
|
||||
hard.diner.card.data.bad=用餐人饭卡数据异常,请联系管理员
|
||||
hard.diner.card.dup={0}存在重复饭卡数据,请联系管理员
|
||||
hard.diner.no.card={0}未开通饭卡
|
||||
hard.diner.card.owner.bad={0}的饭卡归属异常,请联系管理员
|
||||
hard.diner.balance.low={0}饭卡余额不足
|
||||
hard.daily.menu.product.bad=每日菜谱商品不存在、已下架或不属于当前商户
|
||||
hard.product.price.bad={0}价格异常,请联系商户
|
||||
hard.product.mode.bad={0}商品模式异常,请联系商户
|
||||
hard.product.price.changed={0}价格已变化,请重新选择菜品
|
||||
hard.product.stock.low={0}库存不足
|
||||
hard.one.item.per.slot=该商户每个日期餐段仅允许选择一份商品
|
||||
hard.diner.empty=用餐人不能为空
|
||||
hard.diner.dup=请勿重复选择用餐人
|
||||
hard.diner.invalid=存在无效或无权代订的用餐人
|
||||
hard.guardian.reserve.off=当前商户未开启监护关系代订餐
|
||||
hard.diner.identity.invalid=存在不符合当前商户可订餐身份的用餐人
|
||||
hard.diner.slot.once=同一用餐人同一天同一餐段只能预约一次,请勿重复预约
|
||||
hard.appt.processing=预约正在处理中,请勿重复提交
|
||||
hard.appt.tx.bad=预约事务状态异常,请稍后重试
|
||||
hard.diner.card.mismatch=用餐人与饭卡归属不一致
|
||||
hard.stock.deduct.fail=库存不足或扣减失败
|
||||
hard.stock.restore.fail=恢复库存失败
|
||||
hard.daily.stock.deduct.fail=每日菜谱库存不足或扣减失败
|
||||
hard.daily.stock.restore.fail=每日菜谱库存恢复失败
|
||||
hard.copy.cart.fail=复制订餐购物车失败
|
||||
hard.copy.product.fail=复制订餐商品失败
|
||||
hard.wallet.tx.bad=订餐钱包交易数据异常
|
||||
hard.update.pay.status.fail=更新订餐订单支付状态失败
|
||||
hard.update.cart.status.fail=更新订餐购物车状态失败
|
||||
hard.mch.no.resp=查询商户无响应
|
||||
hard.diner.card.no.resp=查询用餐人饭卡无响应
|
||||
hard.daily.product.no.resp=查询每日菜谱商品无响应
|
||||
hard.daily.product.query.fail=查询每日菜谱商品失败
|
||||
hard.diner.identity.no.resp=查询用餐人身份无响应
|
||||
hard.diner.identity.query.fail=查询用餐人身份失败
|
||||
hard.daily.menu.batch.bad=每日菜谱订单批次数据异常
|
||||
hard.reserve.batch.bad=订餐订单批次数据异常
|
||||
hard.wallet.batch.deduct.bad=钱包批量扣款结果异常
|
||||
hard.appt.cycle.rule.required=周期预约规则不能为空
|
||||
hard.appt.cycle.not.allowed=当前商户使用动态时间窗,不能提交周期预约规则
|
||||
hard.appt.date.meal.required=周期预约需要选择预约日期和餐端
|
||||
hard.appt.cycle.open.at=周{0}{1}开放
|
||||
hard.wallet.batch.deduct.no.resp=钱包批量扣款无响应
|
||||
hard.wallet.batch.comp.no.resp=钱包批量补偿无响应
|
||||
hard.stock.no.resp=查询商品库存无响应
|
||||
hard.appt.slot.missing=预约餐段不存在
|
||||
hard.appt.slot.mch.mismatch=预约餐段与当前商户不匹配
|
||||
hard.appt.slot.disabled=预约餐段已停用
|
||||
hard.appt.slot.mode.mismatch=预约餐段与商户当前模式不匹配
|
||||
hard.appt.date.out.range=该预约日期不在可选范围内
|
||||
hard.appt.date.no.slot=该日期未配置此预约餐段
|
||||
hard.appt.date.type.invalid=预约日期类型无效
|
||||
hard.appt.dynamic.slot.empty=动态预约餐段不能为空
|
||||
hard.appt.period.closed=本期预约已截止
|
||||
hard.appt.not.open=预约尚未开放
|
||||
hard.appt.closed=预约已截止
|
||||
hard.appt.rule.mode.invalid=预约规则模式无效
|
||||
hard.appt.rule.incomplete=预约规则配置不完整
|
||||
hard.appt.rule.time.invalid=预约规则时间范围无效
|
||||
hard.appt.cycle.missing=周期预约规则不存在或已停用
|
||||
hard.appt.mch.conf.fail=获取商户预约配置失败
|
||||
hard.appt.mch.mode.invalid=商户预约时间模式无效
|
||||
hard.delivery.type.invalid=配送时间类型无效
|
||||
hard.schedule.need.slot=预约配送须选择日期与时段
|
||||
hard.schedule.end.after.start=预约时段结束须晚于开始
|
||||
hard.mch.job.time.missing=商户未配置营业时间
|
||||
hard.eta.out.of.hours=预计送达时间不在商户营业时间内,请重新选择
|
||||
hard.no.schedule.without.hours=商户未配置营业时间,暂不可预约配送
|
||||
hard.job.time.format.bad=商户营业时间格式无效,请先在后台正确配置 jobTime
|
||||
hard.slot.out.of.hours=预约时段不在商户营业时间内,请重新选择
|
||||
hard.qr.already.verified=该二维码已被核销
|
||||
hard.verify.diner.only=仅实际用餐人可以使用预约核销码
|
||||
hard.not.canteen.reserve=该订单不是食堂预约订单
|
||||
hard.no.mch.verify.perm=当前用户没有商户核销权限
|
||||
hard.no.mch.order.manage=无权管理该商户订单
|
||||
hard.reserve.not.verifiable=该预约订单当前不可核销
|
||||
hard.reserve.refunding.no.verify=该预约订单正在退款,不能核销
|
||||
hard.reserve.full.refund.no.verify=该预约订单商品已全部退款,不能核销
|
||||
hard.verify.status.changed=订单状态已变化,核销失败
|
||||
hard.restore.code.no.resp=恢复预约核销码无响应
|
||||
hard.restore.code.fail=恢复预约核销码失败
|
||||
hard.rollback.online.only=仅线上预订订单支持退回到核销前
|
||||
hard.rollback.biz.unsupported=当前业务类型不支持退回到核销前
|
||||
hard.rollback.verified.only=仅已核销订单支持退回到核销前
|
||||
hard.rollback.refunding=该预约订单正在退款,不能退回到核销前
|
||||
hard.rollback.full.refund=该预约订单商品已全部退款,不能退回到核销前
|
||||
hard.rollback.status.changed=订单状态已变化,退回核销状态失败
|
||||
hard.act.ended=核销失败,活动已结束
|
||||
hard.act.not.started=核销失败,活动未开始
|
||||
hard.act.coupon.used=核销失败,您领取的优惠券已核销
|
||||
hard.act.location.error=核销失败,位置的错误
|
||||
hard.act.verify.fail=核销失败
|
||||
hard.act.qr.bad=核销二维码错误
|
||||
hard.act.device.no.perm=当前设备不能核销该活动订单
|
||||
hard.act.user.no.perm=当前活动,该用户没有核销权限
|
||||
hard.act.verify.user.missing=核销用户不存在不存在
|
||||
hard.act.coupon.user.missing=领券用户不存在不存在
|
||||
hard.order.expired.rescan=订单已失效,请重新扫码
|
||||
hard.not.device.scan.pay=该订单不是设备扫码支付订单
|
||||
hard.not.device.scan=该订单不是设备扫一扫订单
|
||||
hard.order.paid.or.changed=该订单已支付或状态已变更
|
||||
hard.pay.amount.zero=支付金额为0元
|
||||
hard.user.no.wallet=该用户没有这个钱包
|
||||
hard.wallet.user.missing=钱包用户不存在
|
||||
hard.shipment.no.missing=快递单号不存在
|
||||
hard.order.type.no.receipt=该订单类型不支持确认收货
|
||||
hard.order.status.no.receipt=该订单状态不支持确认收货
|
||||
hard.order.type.error=订单类型错误
|
||||
hard.order.status.error=订单状态错误
|
||||
hard.idem.create=正在创建订单中,请勿重复操作
|
||||
hard.idem.verify=正在核销中,请勿重复操作
|
||||
hard.idem.rollback=正在退回核销状态,请勿重复操作
|
||||
hard.car.group.empty=购物车分组不能为空
|
||||
hard.car.biz.incomplete=购物车业务信息不完整
|
||||
hard.car.batch.same.user.mch=批量购物车必须属于同一用户、商户和业务类型
|
||||
hard.car.save.fail=购物车商品保存失败
|
||||
common.idempotent.retry=重复请求,请稍后重试
|
||||
auth.captcha.empty=验证码不能为空
|
||||
auth.captcha.invalid=验证码不合法
|
||||
auth.wx.auth.fail=微信授权失败:{0}
|
||||
auth.wx.openid.missing=微信授权失败,未获取到用户标识
|
||||
auth.wx.auth.expired=微信授权已过期,请重新授权
|
||||
auth.apple.not.configured=未配置Apple登录
|
||||
auth.apple.not.enabled=未启用Apple登录
|
||||
auth.mini.app.login.fail=微信小程序登录失败
|
||||
auth.social.auth.expired=授权已过期,请重新授权
|
||||
sys.app.sms.send.fail=短信验证码发送失败,请稍后重试
|
||||
sys.app.sms.code.invalid=短信验证码错误或已过期
|
||||
sys.user.password.same=新旧密码不能相同
|
||||
sys.user.unbind.type.invalid=解绑账号类型不存在
|
||||
third.recharge.biz.id.invalid=充值业务id解析错误
|
||||
third.proxy.recharge.biz.id.invalid=代充值业务id解析错误
|
||||
third.proxy.recharge.invalid=代充值记录不存在或金额无效
|
||||
third.ward.wallet.no.recharge=目标饭卡当前不可充值
|
||||
third.pay.amount.gt.zero=支付金额必须大于0
|
||||
third.wechat.pay.create.fail=创建微信支付错误
|
||||
third.alipay.pay.create.fail=创建支付宝支付错误
|
||||
third.user.no.mch=用户不属于任何食堂或者商城
|
||||
third.user.no.canteen=用户不属于任何食堂
|
||||
third.shop.pay.mch.missing=商城支付缺少可信商户信息
|
||||
third.shop.order.biz.id.invalid=商城订单业务id解析错误
|
||||
third.shop.order.no.pay=商城订单不存在或无权支付
|
||||
third.shop.order.amount.mismatch=商城订单支付金额不一致
|
||||
third.shop.order.mch.mismatch=商城订单收款商户不一致
|
||||
third.mch.pay.disabled=收款商户已停用
|
||||
third.mch.wechat.pay.config.missing=商户未配置微信支付参数
|
||||
third.mch.alipay.pay.config.missing=商户未配置支付宝支付参数
|
||||
third.order.code.processing=订单码支付正在处理中,请勿重复提交
|
||||
third.pay.no.empty=支付订单号不能为空
|
||||
third.order.code.not.found=订单码支付订单不存在
|
||||
third.order.already.paid=该业务订单已支付,请勿重复下单
|
||||
third.order.code.other.platform=该业务订单已有其他平台的待支付订单码
|
||||
third.order.code.data.error=订单码数据异常,请稍后重试
|
||||
third.order.closing=上一笔订单正在确认关闭,请稍后重试
|
||||
third.order.code.param.empty=订单码支付参数不能为空
|
||||
third.order.code.biz.only=订单码支付仅支持云消费机支付业务
|
||||
third.order.code.platform.only=订单码支付仅支持支付宝或微信
|
||||
third.pay.biz.id.empty=支付业务id不能为空
|
||||
third.order.pending.mismatch=该业务订单已有不同金额或商户的待支付订单
|
||||
third.mch.info.mismatch=收款商户信息不一致
|
||||
third.mch.alipay.config.disabled=商户未启用支付宝支付配置
|
||||
third.mch.wechat.config.disabled=商户未启用微信支付配置
|
||||
third.alipay.app.config.incomplete=支付宝应用支付配置不完整
|
||||
third.wechat.app.config.incomplete=微信服务商支付配置不完整
|
||||
third.refund.processing=上一笔退款仍在处理中,请稍后重试
|
||||
third.wx.oauth.incomplete=微信用户授权参数不完整
|
||||
third.wx.oauth.fail=微信用户授权失败,请重新扫码
|
||||
third.fz.relation.unavailable=支付平台分佣关系服务不可用
|
||||
third.wx.jsapi.create.fail=创建微信支付订单失败,请重新扫码
|
||||
third.aggregate.sub.order.save.fail=聚合支付子订单保存失败
|
||||
third.mch.wechat.config.incomplete=商户微信支付配置不完整
|
||||
third.mch.wechat.sub.mch.missing=商户微信子商户号未配置
|
||||
third.pay.order.snapshot.missing=支付订单缺少商户配置快照
|
||||
third.pay.order.snapshot.invalid=支付订单商户配置快照无效
|
||||
third.alipay.auth.code.empty=支付宝授权码不能为空
|
||||
third.alipay.oauth.fail=支付宝用户授权失败,请重新扫码
|
||||
third.alipay.oauth.no.payer=支付宝用户授权未返回付款人标识
|
||||
third.alipay.jsapi.create.fail=创建支付宝支付订单失败,请重新扫码
|
||||
third.alipay.client.init.fail=支付宝客户端初始化失败
|
||||
third.mch.alipay.config.incomplete=商户支付宝支付配置不完整
|
||||
third.mch.alipay.sub.mch.missing=商户支付宝直付通二级商户标识未配置
|
||||
third.wx.native.create.fail=创建微信订单码失败,请稍后重试
|
||||
third.wx.native.create.fail.code=创建微信订单码失败,微信错误码:{0}
|
||||
third.wx.native.no.qr=创建微信订单码失败,微信未返回二维码
|
||||
|
||||
app.msg.title.wallet.payment=下单成功,钱包已扣款
|
||||
app.msg.title.wallet.refund=退款已到账
|
||||
app.msg.title.wallet.recharge=充值已到账
|
||||
app.msg.title.wallet.reset=钱包余额已重置
|
||||
app.msg.title.meal.verified=用餐核销成功
|
||||
app.msg.event.wallet.update=余额更新
|
||||
app.msg.event.wallet.batch=批量余额更新
|
||||
app.msg.event.wallet.recharge=充值到账
|
||||
app.msg.event.wallet.payment=消费支付
|
||||
app.msg.event.wallet.refund=退款到账
|
||||
app.msg.event.wallet.transfer=钱包转账
|
||||
app.msg.event.wallet.transfer.refund=转账退款
|
||||
app.msg.event.wallet.return.canteen=退还食堂
|
||||
app.msg.event.wallet.reset=余额重置
|
||||
app.msg.event.meal.verified=用餐核销
|
||||
app.msg.wallet.default.name=钱包
|
||||
app.msg.wallet.detail.inc={0}增加{1}元,余额{2}元
|
||||
app.msg.wallet.detail.dec={0}减少{1}元,余额{2}元
|
||||
app.msg.wallet.detail.sep=;
|
||||
app.msg.wallet.content={0}:{1}
|
||||
app.msg.meal.default.name=本次预约用餐
|
||||
app.msg.meal.content={0}已核销,祝您用餐愉快。
|
||||
app.msg.ward.fallback=被监护人
|
||||
app.msg.relation.title={0}的{1}
|
||||
app.msg.relation.content={0}:{1}
|
||||
|
||||
common.product.sku.not.found=商品SKU不存在
|
||||
common.mch.service.error=商户服务异常
|
||||
mall.user.no.farmer.mch=该用户未分配共富商户
|
||||
mall.no.product.perm=无权限处理此商品
|
||||
mall.category.not.found=分类不存在
|
||||
mall.no.category.perm=无权限处理此分类
|
||||
address.id.empty=地址ID不能为空
|
||||
address.not.found=地址不存在
|
||||
address.dept.building.required=单位与楼栋不能为空
|
||||
address.unit.required=单元不能为空
|
||||
address.room.required=房间不能为空
|
||||
address.dept.not.found=单位不存在
|
||||
address.building.not.found=楼栋不存在
|
||||
address.building.dept.mismatch=所选楼栋不属于该单位
|
||||
address.unit.not.found=单元不存在
|
||||
address.unit.building.mismatch=所选单元不属于该楼栋
|
||||
address.room.not.found=房间不存在
|
||||
address.room.unit.mismatch=所选房间不属于该单元/楼栋
|
||||
address.room.no.empty=房间号不能为空
|
||||
address.building.no.access=无权访问该楼栋
|
||||
address.unit.no.access=无权访问该单元
|
||||
address.record.update.missing=地址记录不存在,无法修改
|
||||
address.record.delete.missing=地址记录不存在,无法删除
|
||||
|
||||
hard.car.group.item.empty=第{0}组购物车不能为空
|
||||
hard.car.group.item.incomplete=第{0}组购物车商品信息不完整或数量无效
|
||||
hard.car.group.parent.fail=第{0}组父购物车创建失败
|
||||
hard.car.group.item.invalid=第{0}组存在无效商品
|
||||
mall.product.sku.missing=共富商城商品无SKU信息,商品名:{0},商品ID:{1},请联系管理员
|
||||
|
||||
canteen.stock.items.empty=库存商品不能为空
|
||||
canteen.stock.item.param.bad=库存商品参数错误
|
||||
canteen.stock.biz.param.bad=库存业务参数错误
|
||||
canteen.stock.item.dup=库存商品不能重复
|
||||
canteen.stock.spu.bad=商品不存在或库存异常
|
||||
canteen.stock.snapshot.bad=库存快照异常
|
||||
canteen.stock.changed={0}库存已变化,请重新操作
|
||||
canteen.stock.compensate.fail=库存补偿失败,请重试
|
||||
canteen.stock.update.fail=库存更新失败,请重试
|
||||
canteen.stock.tx.state.bad=库存事务状态异常,请稍后重试
|
||||
canteen.stock.insufficient=库存不足,无法完成操作
|
||||
canteen.no.product.perm=无权操作该商品
|
||||
canteen.no.product.perm.named=无权操作该商品:{0}
|
||||
canteen.shelf.status.invalid=状态非法,仅支持 0-上架、1-下架
|
||||
|
||||
hard.stock.tx.state.bad=库存事务状态异常,请稍后重试
|
||||
hard.canteen.stock.aftersale.missing=食堂菜品退款库存缺少售后单 ID
|
||||
hard.canteen.stock.car.missing=食堂菜品库存操作失败,购物车不存在
|
||||
hard.canteen.stock.refund.item.missing=食堂菜品库存操作失败,退款商品不存在
|
||||
hard.canteen.stock.no.resp=查询食堂菜品库存无响应
|
||||
hard.canteen.stock.query.fail=查询食堂菜品库存失败
|
||||
hard.canteen.spu.bad=食堂菜品不存在或不属于当前商户
|
||||
hard.canteen.stock.op.fail=食堂菜品库存服务操作失败
|
||||
hard.door.stock.fail=扣减智能柜库存{0}错误
|
||||
hard.stock.deduct.cart.missing=扣减库存错误,购物车不存在
|
||||
hard.stock.op.fail={0}错误
|
||||
|
||||
wallet.transfer.source.low=源钱包{0}余额不足
|
||||
wallet.transfer.limit.exceeded=已经超过最大转账金额限制
|
||||
wallet.transfer.not.found=查询不到转账记录
|
||||
wallet.transfer.refund.dup=已退回请勿重复操作
|
||||
wallet.transfer.refund.source.low=源钱包{0}余额不足,无法退回
|
||||
wallet.apply.dup.submit=已提交申请,请勿重复提交
|
||||
act.cancel.not.found=核销活动不存在
|
||||
act.cancel.closed=核销活动已关闭
|
||||
act.cancel.mch.missing=核销活动商户不存在
|
||||
act.cancel.already.received=您已经领,请勿重复领取
|
||||
act.cancel.balance.low=消费钱包余额不足{0}元,无法领取
|
||||
act.cancel.coupon.expired=您领取的优惠券已过期
|
||||
act.coupon.not.found=优惠券不存在
|
||||
act.not.found=活动不存在
|
||||
act.coupon.points.deduct.fail=扣减积分错误
|
||||
act.id.empty=活动id不能为空
|
||||
|
||||
sys.face.max.count=最多只能上传3张人脸图片
|
||||
sys.face.max.active=审核中和已通过的人脸合计最多只能保留3张
|
||||
sys.face.dup.image=请勿重复提交同一张人脸图片
|
||||
sys.face.dept.missing=当前用户所属部门不存在,无法发起人脸审核
|
||||
sys.face.ward.only=仅可查看或操作本人及有效被监护人的人脸审核记录
|
||||
sys.face.record.missing=人脸审核记录不存在
|
||||
sys.face.revoke.status=只有审核中的人脸记录可以撤销
|
||||
sys.face.status.changed=人脸审核状态已发生变化,请刷新后重试
|
||||
sys.car.plate.dup=车牌号不能重复
|
||||
|
||||
hard.idem.applying=正在申请中,请勿重复操作
|
||||
hard.idem.canceling=正在取消中,请勿重复操作
|
||||
hard.idem.processing=正在处理中,请勿重复操作
|
||||
hard.idem.refunding=正在退款中,请勿重复操作
|
||||
hard.idem.batch.refund=批量退款任务正在提交,请勿重复操作
|
||||
act.idem.receiving=正在领取中,请勿重复操作
|
||||
wallet.idem.applying=正在申请中,请勿重复操作
|
||||
wallet.idem.opening=正在开卡中,请勿重复提交
|
||||
wallet.idem.processing=正在处理中,请勿重复提交
|
||||
wallet.idem.importing=正在导入中,请勿重复操作
|
||||
wallet.idem.recharging=正在充值中,请勿重复操作
|
||||
wallet.idem.uploading=正在上传中,请勿重复操作
|
||||
wallet.idem.invoice=正在重新生成发票中,请勿重复操作
|
||||
|
||||
mall.product.create.fail=商品创建失败
|
||||
mall.product.id.empty=商品ID不能为空
|
||||
mall.product.update.fail=商品更新失败
|
||||
mall.product.list.fail=获取商品列表失败
|
||||
mall.product.delete.fail=商品删除失败
|
||||
mall.category.create.fail=商品分类创建失败
|
||||
mall.category.id.empty=分类ID不能为空
|
||||
mall.category.update.fail=分类更新失败
|
||||
mall.category.delete.fail=分类删除失败
|
||||
mall.category.list.fail=获取分类列表失败
|
||||
|
||||
third.wx.profit.amount.min=微信分账支付金额必须大于10分
|
||||
third.wx.profit.amount.range=微信平台抽佣金额必须不少于1分且不能超过订单金额
|
||||
third.pay.config.missing=支付配置不存在
|
||||
third.wx.refund.amount.bad=微信退款金额必须大于0且不能超过订单金额
|
||||
third.pay.order.status.no.refund=支付订单当前状态不允许退款
|
||||
third.ali.qr.create.fail=创建支付宝订单码失败,请稍后重试
|
||||
third.ali.amount.invalid=支付宝支付金额必须大于0分
|
||||
third.ali.zt.amount.min=支付宝直付通支付金额必须大于10分
|
||||
third.wx.refund.apply.error=微信退款申请错误异常
|
||||
third.wx.refund.queued=微信退款请求已进入补偿队列,请稍后查询结果
|
||||
third.ali.refund.amount.bad=支付宝退款金额必须大于0且不能超过订单金额
|
||||
sys.register.suspended=暂时停止注册!
|
||||
@@ -37,3 +37,535 @@ sys.user.password.new.empty=新密碼不能為空
|
||||
sys.user.password.length=密碼長度需為6-20位
|
||||
sys.user.password.chars.only=密碼只能包含字母和數字
|
||||
sys.user.password.letter.digit=密碼需同時包含字母和數字
|
||||
common.not.login=未登入
|
||||
common.record.not.found=記錄不存在
|
||||
common.mch.not.found=商戶不存在
|
||||
common.user.dept.missing=用戶部門不存在
|
||||
ordering.food.mch.disabled=該商戶未啟用報餐
|
||||
ordering.food.job.time.missing.for.segment=商戶未配置營業時間,無法獲取餐段
|
||||
ordering.food.job.time.missing=商戶未配置營業時間
|
||||
ordering.food.select.date.segment=請選擇報餐日期與餐段
|
||||
ordering.food.select.dish=請選擇報餐菜品
|
||||
ordering.food.fill.person.count=請填寫報餐人數
|
||||
ordering.food.cancel.status.invalid=當前狀態不可取消
|
||||
ordering.food.select.valid.mch=請選擇有效商戶
|
||||
ordering.food.no.mch.view.perm=無權查看該商戶數據
|
||||
ordering.food.select.date=請選擇日期
|
||||
ordering.food.user.dept.missing=用戶部門不存在
|
||||
ordering.food.select.canteen.mch=請選擇食堂商戶
|
||||
ordering.food.stats.range.too.large=查詢日期範圍最多一個月({0}天)
|
||||
ordering.food.user.info.missing=用戶資訊不存在
|
||||
ordering.food.no.stats.perm=無權訪問報餐統計
|
||||
ordering.food.date.segment.incomplete=報餐日期或餐段不完整
|
||||
ordering.food.future.days.limit=僅支援報餐未來{0}天內
|
||||
ordering.food.segment.invalid=餐段無效,請刷新後重試
|
||||
ordering.food.duplicate.date.segment=存在重複的日期餐段選擇
|
||||
ordering.food.dish.info.incomplete=報餐菜品資訊不完整
|
||||
ordering.food.select.dish.for.segment=請為「{0}」選擇菜品
|
||||
ordering.food.dish.segment.invalid=菜品餐段無效
|
||||
common.order.not.found=訂單不存在
|
||||
common.cart.not.found=購物車不存在
|
||||
common.wallet.not.found=用戶錢包不存在
|
||||
common.wallet.balance.insufficient=錢包餘額不足
|
||||
common.product.not.found=商品不存在
|
||||
common.product.stock.low=庫存不足
|
||||
common.user.not.exist=用戶不存在
|
||||
common.user.not.exist.dup=用戶不存在
|
||||
common.unsupported.pay.type=不支持的支付方式
|
||||
common.mch.id.empty=商戶ID不能為空
|
||||
common.past.date.not.allowed=不能選擇過去的日期
|
||||
common.date.format.ymd=日期格式應為 yyyy-MM-dd
|
||||
common.date.range.required=開始日期與結束日期不能為空
|
||||
common.date.range.invalid=結束日期不能早於開始日期
|
||||
common.month.format.ym=月份格式應為 yyyy-MM
|
||||
delivery.order.no.view=訂單不存在或無權查看
|
||||
delivery.order.no.operate=訂單不存在或無權操作
|
||||
delivery.accept.first=請先接單
|
||||
delivery.accept.status.invalid=當前狀態不可接單
|
||||
delivery.already.accepted=訂單已接單
|
||||
delivery.pickup.photo.status.invalid=當前狀態不可上傳取餐照
|
||||
delivery.deliver.photo.status.invalid=當前狀態不可上傳送達照
|
||||
delivery.sync.hardware.fail=同步硬件外賣訂單狀態失敗: {0}
|
||||
delivery.no.response=無響應
|
||||
delivery.order.already.synced=訂單已同步過
|
||||
delivery.cart.serialize.fail=購物車序列化失敗
|
||||
delivery.order.no.empty=訂單號不能為空
|
||||
delivery.rider.push.title=新配送任務
|
||||
delivery.rider.push.body=您有一單新的食堂外送,請及時處理
|
||||
delivery.mch.push.title=新外送訂單
|
||||
delivery.mch.push.body=您有一單新的食堂外送訂單,請及時處理
|
||||
delivery.mch.schedule.title=預約外送提醒
|
||||
delivery.mch.schedule.body=您有一單預約外送即將進入備餐時段,請及時查看
|
||||
delivery.rider.building.bound=該單位下樓棟已綁定騎手,請先解綁
|
||||
wallet.type.id.empty=錢包類型id不能為空
|
||||
wallet.remark.empty=備註不能為空
|
||||
wallet.not.found=錢包不存在
|
||||
wallet.freeze.dup=已提交申請,請勿重複提交
|
||||
wallet.card.not.found=卡號不存在
|
||||
wallet.card.already.bound=該卡號已經綁定用戶
|
||||
wallet.meal.card.not.found=飯卡錢包不存在
|
||||
wallet.user.already.bound=用戶已綁定飯卡
|
||||
wallet.qr.gen.fail=錢包二維碼生成錯誤
|
||||
wallet.relation.query.fail=查詢關係人資訊失敗
|
||||
wallet.user.relation.fail=查詢用戶關係失敗
|
||||
wallet.face.query.fail=查詢用戶人臉情況失敗
|
||||
wallet.pending.appt.fail=查詢用戶待核銷預約失敗
|
||||
wallet.package.amount.invalid=充值套餐金額無效
|
||||
wallet.target.card.missing=目標飯卡不存在
|
||||
wallet.no.ward.perm=無權操作該被監護人
|
||||
wallet.ward.query.fail=查詢被監護人資訊失敗
|
||||
wallet.ward.not.found=被監護人不存在
|
||||
wallet.identity.query.fail=查詢充值用戶身份失敗
|
||||
wallet.canteen.missing=錢包所屬食堂不存在
|
||||
wallet.identity.no.recharge=當前人員身份不支持錢包充值
|
||||
wallet.card.canteen.missing=飯卡所屬食堂不存在
|
||||
wallet.pay.method.missing=飯卡所屬食堂暫未配置支付方式
|
||||
wallet.proxy.record.missing=代充值記錄不存在
|
||||
wallet.guardian.relation.fail=查詢監護關係失敗
|
||||
wallet.package.not.found=錢包充值套餐不存在
|
||||
wallet.package.disabled=錢包充值套餐已禁用
|
||||
wallet.meal.card.not.open=未開通飯卡
|
||||
wallet.meal.card.frozen=飯卡已凍結
|
||||
wallet.card.status.no.recharge={0},暫不可充值
|
||||
wallet.target.user.missing=缺少目標用戶資訊
|
||||
wallet.no.ward.tx.perm=無權查看該被監護人的錢包流水
|
||||
wallet.tx.deduct.amount.mismatch=重複業務扣款金額不一致
|
||||
wallet.tx.credit.amount.mismatch=重複業務入賬金額不一致
|
||||
wallet.tx.refund.amount.mismatch=重複業務退款金額不一致
|
||||
wallet.tx.payment.amount.mismatch=支付流水金額與補償金額不一致
|
||||
wallet.order.payment.cancelled=訂單支付已經取消,不能繼續扣款
|
||||
wallet.order.payment.compensated=訂單支付已經補償,不能重複扣款
|
||||
wallet.tx.compensate.fail=錢包補償失敗
|
||||
wallet.tx.batch.compensate.fail=錢包批量補償失敗
|
||||
wallet.tx.payment.save.fail=保存錢包支付流水失敗
|
||||
wallet.tx.refund.save.fail=保存錢包補償流水失敗
|
||||
wallet.tx.batch.empty=錢包批量交易明細不能為空
|
||||
wallet.tx.batch.incomplete=錢包批量交易明細不完整
|
||||
wallet.tx.batch.non.force.only=錢包批量交易僅支持非透支支付
|
||||
wallet.tx.batch.dup.biz=請勿重複提交同一錢包業務號
|
||||
wallet.tx.processing=訂單錢包交易正在處理中,請稍後重試
|
||||
wallet.tx.lock.interrupted=訂單錢包交易等待已中斷,請稍後重試
|
||||
wallet.tx.tx.state.bad=錢包批量交易事務狀態異常,請稍後重試
|
||||
wallet.tx.not.found=錢包流水不存在或已刪除
|
||||
wallet.reset.balance.fail=重置餘額失敗
|
||||
wallet.proxy.refund.not.paid=代充值尚未到賬,不能退款
|
||||
wallet.proxy.pay.status.fail=更新代充值到賬狀態失敗
|
||||
wallet.proxy.refund.status.fail=更新代充值退款狀態失敗
|
||||
wallet.card.no.user=該飯卡沒有綁定用戶
|
||||
after.sale.refund.only=當前僅支持僅退款
|
||||
after.sale.pending.dup=當前訂單已有退款申請待審核,請勿重複提交
|
||||
after.sale.partial.continue.unsupported=當前版本不支持部分退款後的繼續申請,請升級應用後重試
|
||||
after.sale.amount.exceed=本次退款金額超出訂單剩餘可退金額
|
||||
after.sale.pay.amount.invalid=訂單實付金額異常
|
||||
after.sale.not.found=售後單不存在
|
||||
after.sale.order.not.found=售後訂單不存在
|
||||
after.sale.payer.only=僅訂單付款人可以申請退款
|
||||
after.sale.app.mch.scope=當前 App 商戶僅支持審核食堂預約訂單
|
||||
after.sale.cancel.status.invalid=取消售後單失敗,售後單狀態不是【待審核】
|
||||
after.sale.amount.gt.zero=退款金額必須大於0
|
||||
after.sale.amount.gt.pay=退款總金額大於支付總金額
|
||||
after.sale.wallet.refund.fail=錢包退款錯誤
|
||||
after.sale.wx.refund.fail=微信退款錯誤
|
||||
after.sale.wx.refund.fail.msg=微信退款錯誤:{0}
|
||||
after.sale.ali.refund.fail=支付寶退款錯誤
|
||||
after.sale.ali.refund.fail.msg=支付寶退款錯誤:{0}
|
||||
after.sale.unsupported.type=不支持的退款類型
|
||||
after.sale.wallet.clawback.fail=錢包退款金額扣回失敗
|
||||
after.sale.order.fully.refunded=訂單已全部退款
|
||||
after.sale.product.list.empty=售後商品列表不能為空
|
||||
after.sale.order.cart.missing=訂單購物車不存在
|
||||
after.sale.refund.product.empty=退款商品不能為空
|
||||
after.sale.refund.product.missing=退款商品<{0}>不存在
|
||||
after.sale.refund.qty.empty=退款商品<{0}>數量不能為空
|
||||
after.sale.refund.qty.negative=退款商品<{0}>數量不能為負數
|
||||
after.sale.refund.qty.invalid=退款商品<{0}>數量異常
|
||||
after.sale.hist.qty.invalid=歷史退款商品數量異常
|
||||
after.sale.order.qty.invalid=訂單商品數量異常
|
||||
after.sale.refund.qty.bad=退款商品數量異常
|
||||
after.sale.refund.qty.exceed=退款商品<{0}>數量超出
|
||||
after.sale.order.type.no.refund=該訂單類型不支持退款
|
||||
after.sale.order.status.no.refund=當前訂單狀態不支持退款
|
||||
after.sale.refund.time.exceeded=訂單已超過4個小時,不能退款
|
||||
after.sale.auto.refund.lock=自動退款處理中,當前售後單不允許人工取消或審核
|
||||
after.sale.dup.product=同一商品不能重複提交
|
||||
after.sale.product.not.in.order=退款商品不屬於當前訂單
|
||||
after.sale.weighted.no.partial=稱重商品暫不支持在線逐份退款
|
||||
after.sale.refund.qty.out.range=退款商品<{0}>數量超出可退範圍
|
||||
after.sale.refund.amount.invalid=退款商品<{0}>退款金額異常
|
||||
after.sale.select.product=請選擇需要退款的商品
|
||||
after.sale.order.product.bad=訂單商品數據異常
|
||||
after.sale.order.amount.snapshot.bad=訂單商品金額快照異常
|
||||
after.sale.alloc.weight.bad=退款分攤權重異常
|
||||
after.sale.processing=訂單退款正在處理中,請稍後重試
|
||||
after.sale.approve.status.invalid=審批失敗,售後狀態不處於審批中
|
||||
after.sale.pending.handle.first=當前訂單已有退款申請待審核,請先處理後再退款
|
||||
after.sale.hist.detail.incomplete=歷史退款商品明細不完整,請通過後台核對後處理
|
||||
after.sale.order.type.error=訂單類型錯誤
|
||||
after.sale.refund.list.empty=退款商品列表不能為空
|
||||
after.sale.device.order.missing=設備訂單不存在
|
||||
hard.cart.not.owned=購物車不存在或不屬於當前用戶
|
||||
hard.cart.no.view=購物車不存在或無權查看
|
||||
hard.cart.status.changed=購物車狀態已變更,請重新選擇商品
|
||||
hard.cart.amount.invalid=購物車金額異常
|
||||
hard.cart.product.bad=購物車商品數據異常,請重新選擇商品
|
||||
hard.cart.product.not.in.mch=購物車商品不存在或不屬於當前商戶
|
||||
hard.required.dish.missing=未選擇必選菜品
|
||||
hard.user.address.missing=用戶地址不存在
|
||||
hard.pickup.point.missing=查詢自提點不存在
|
||||
hard.mch.not.cooperate=該商家未合作
|
||||
hard.app.pay.fail=發起app支付失敗
|
||||
hard.wallet.deduct.fail=錢包扣款錯誤
|
||||
hard.unverified.self=您有{0}筆未核銷的預約訂單,請先核銷
|
||||
hard.unverified.diner=用餐人已有{0}筆未核銷的預約訂單,請先核銷
|
||||
hard.unverified.diner.limit=用餐人已有{0}筆未核銷的預約訂單,本次訂餐後將超過200筆上限
|
||||
hard.batch.wallet.only=批量訂餐暫僅支持錢包支付
|
||||
hard.multi.diner.canteen.only=僅食堂購物車可以多人訂餐
|
||||
hard.cart.already.ordered=該購物車已創建訂單,請勿重複提交
|
||||
hard.cart.already.ordered2=購物車已創建訂單,請勿重複提交
|
||||
hard.cart.not.canteen=購物車商戶不是食堂商戶
|
||||
hard.diner.not.found=用餐人不存在
|
||||
hard.create.reserve.fail=創建訂餐訂單失敗
|
||||
hard.reserve.tx.bad=訂餐事務狀態異常,請稍後重試
|
||||
hard.reserve.group.empty=訂餐分組不能為空
|
||||
hard.cart.dup.submit=請勿重複提交同一購物車
|
||||
hard.reserve.processing=訂餐訂單正在處理中,請勿重複提交
|
||||
hard.daily.menu.canteen.only=僅食堂購物車可以提交每日菜譜訂單
|
||||
hard.not.daily.menu.scene=購物車不是每日菜譜場景,請重新點擊去支付
|
||||
hard.batch.same.mch=批量訂餐必須屬於同一商戶
|
||||
hard.dup.date.meal=請勿重複提交同一天同一餐段
|
||||
hard.daily.menu.mode.off=當前商戶未開啟每日菜譜訂餐模式
|
||||
hard.reserve.amount.bad=訂餐金額異常
|
||||
hard.diner.card.query.fail=查詢用餐人飯卡失敗,請稍後重試
|
||||
hard.diner.query.fail=查詢用餐人失敗
|
||||
hard.diner.card.data.bad=用餐人飯卡數據異常,請聯繫管理員
|
||||
hard.diner.card.dup={0}存在重複飯卡數據,請聯繫管理員
|
||||
hard.diner.no.card={0}未開通飯卡
|
||||
hard.diner.card.owner.bad={0}的飯卡歸屬異常,請聯繫管理員
|
||||
hard.diner.balance.low={0}飯卡餘額不足
|
||||
hard.daily.menu.product.bad=每日菜譜商品不存在、已下架或不屬於當前商戶
|
||||
hard.product.price.bad={0}價格異常,請聯繫商戶
|
||||
hard.product.mode.bad={0}商品模式異常,請聯繫商戶
|
||||
hard.product.price.changed={0}價格已變化,請重新選擇菜品
|
||||
hard.product.stock.low={0}庫存不足
|
||||
hard.one.item.per.slot=該商戶每個日期餐段僅允許選擇一份商品
|
||||
hard.diner.empty=用餐人不能為空
|
||||
hard.diner.dup=請勿重複選用餐人
|
||||
hard.diner.invalid=存在無效或無權代訂的用餐人
|
||||
hard.guardian.reserve.off=當前商戶未開啟監護關係代訂餐
|
||||
hard.diner.identity.invalid=存在不符合當前商戶可訂餐身份的用餐人
|
||||
hard.diner.slot.once=同一用餐人同一天同一餐段只能預約一次,請勿重複預約
|
||||
hard.appt.processing=預約正在處理中,請勿重複提交
|
||||
hard.appt.tx.bad=預約事務狀態異常,請稍後重試
|
||||
hard.diner.card.mismatch=用餐人與飯卡歸屬不一致
|
||||
hard.stock.deduct.fail=庫存不足或扣減失敗
|
||||
hard.stock.restore.fail=恢復庫存失敗
|
||||
hard.daily.stock.deduct.fail=每日菜譜庫存不足或扣減失敗
|
||||
hard.daily.stock.restore.fail=每日菜譜庫存恢復失敗
|
||||
hard.copy.cart.fail=複製訂餐購物車失敗
|
||||
hard.copy.product.fail=複製訂餐商品失敗
|
||||
hard.wallet.tx.bad=訂餐錢包交易數據異常
|
||||
hard.update.pay.status.fail=更新訂餐訂單支付狀態失敗
|
||||
hard.update.cart.status.fail=更新訂餐購物車狀態失敗
|
||||
hard.mch.no.resp=查詢商戶無響應
|
||||
hard.diner.card.no.resp=查詢用餐人飯卡無響應
|
||||
hard.daily.product.no.resp=查詢每日菜譜商品無響應
|
||||
hard.daily.product.query.fail=查詢每日菜譜商品失敗
|
||||
hard.diner.identity.no.resp=查詢用餐人身份無響應
|
||||
hard.diner.identity.query.fail=查詢用餐人身份失敗
|
||||
hard.daily.menu.batch.bad=每日菜譜訂單批次數據異常
|
||||
hard.reserve.batch.bad=訂餐訂單批次數據異常
|
||||
hard.wallet.batch.deduct.bad=錢包批量扣款結果異常
|
||||
hard.appt.cycle.rule.required=週期預約規則不能為空
|
||||
hard.appt.cycle.not.allowed=當前商戶使用動態時間窗,不能提交週期預約規則
|
||||
hard.appt.date.meal.required=週期預約需要選擇預約日期和餐端
|
||||
hard.appt.cycle.open.at=週{0}{1}開放
|
||||
hard.wallet.batch.deduct.no.resp=錢包批量扣款無響應
|
||||
hard.wallet.batch.comp.no.resp=錢包批量補償無響應
|
||||
hard.stock.no.resp=查詢商品庫存無響應
|
||||
hard.appt.slot.missing=預約餐段不存在
|
||||
hard.appt.slot.mch.mismatch=預約餐段與當前商戶不匹配
|
||||
hard.appt.slot.disabled=預約餐段已停用
|
||||
hard.appt.slot.mode.mismatch=預約餐段與商戶當前模式不匹配
|
||||
hard.appt.date.out.range=該預約日期不在可選範圍內
|
||||
hard.appt.date.no.slot=該日期未配置此預約餐段
|
||||
hard.appt.date.type.invalid=預約日期類型無效
|
||||
hard.appt.dynamic.slot.empty=動態預約餐段不能為空
|
||||
hard.appt.period.closed=本期預約已截止
|
||||
hard.appt.not.open=預約尚未開放
|
||||
hard.appt.closed=預約已截止
|
||||
hard.appt.rule.mode.invalid=預約規則模式無效
|
||||
hard.appt.rule.incomplete=預約規則配置不完整
|
||||
hard.appt.rule.time.invalid=預約規則時間範圍無效
|
||||
hard.appt.cycle.missing=週期預約規則不存在或已停用
|
||||
hard.appt.mch.conf.fail=獲取商戶預約配置失敗
|
||||
hard.appt.mch.mode.invalid=商戶預約時間模式無效
|
||||
hard.delivery.type.invalid=配送時間類型無效
|
||||
hard.schedule.need.slot=預約配送須選擇日期與時段
|
||||
hard.schedule.end.after.start=預約時段結束須晚於開始
|
||||
hard.mch.job.time.missing=商戶未配置營業時間
|
||||
hard.eta.out.of.hours=預計送達時間不在商戶營業時間內,請重新選擇
|
||||
hard.no.schedule.without.hours=商戶未配置營業時間,暫不可預約配送
|
||||
hard.job.time.format.bad=商戶營業時間格式無效,請先在後台正確配置 jobTime
|
||||
hard.slot.out.of.hours=預約時段不在商戶營業時間內,請重新選擇
|
||||
hard.qr.already.verified=該二維碼已被核銷
|
||||
hard.verify.diner.only=僅實際用餐人可以使用預約核銷碼
|
||||
hard.not.canteen.reserve=該訂單不是食堂預約訂單
|
||||
hard.no.mch.verify.perm=當前用戶沒有商戶核銷權限
|
||||
hard.no.mch.order.manage=無權管理該商戶訂單
|
||||
hard.reserve.not.verifiable=該預約訂單當前不可核銷
|
||||
hard.reserve.refunding.no.verify=該預約訂單正在退款,不能核銷
|
||||
hard.reserve.full.refund.no.verify=該預約訂單商品已全部退款,不能核銷
|
||||
hard.verify.status.changed=訂單狀態已變化,核銷失敗
|
||||
hard.restore.code.no.resp=恢復預約核銷碼無響應
|
||||
hard.restore.code.fail=恢復預約核銷碼失敗
|
||||
hard.rollback.online.only=僅線上預訂訂單支持退回到核銷前
|
||||
hard.rollback.biz.unsupported=當前業務類型不支持退回到核銷前
|
||||
hard.rollback.verified.only=僅已核銷訂單支持退回到核銷前
|
||||
hard.rollback.refunding=該預約訂單正在退款,不能退回到核銷前
|
||||
hard.rollback.full.refund=該預約訂單商品已全部退款,不能退回到核銷前
|
||||
hard.rollback.status.changed=訂單狀態已變化,退回核銷狀態失敗
|
||||
hard.act.ended=核銷失敗,活動已結束
|
||||
hard.act.not.started=核銷失敗,活動未開始
|
||||
hard.act.coupon.used=核銷失敗,您領取的優惠券已核銷
|
||||
hard.act.location.error=核銷失敗,位置錯誤
|
||||
hard.act.verify.fail=核銷失敗
|
||||
hard.act.qr.bad=核銷二維碼錯誤
|
||||
hard.act.device.no.perm=當前設備不能核銷該活動訂單
|
||||
hard.act.user.no.perm=當前活動,該用戶沒有核銷權限
|
||||
hard.act.verify.user.missing=核銷用戶不存在
|
||||
hard.act.coupon.user.missing=領券用戶不存在
|
||||
hard.order.expired.rescan=訂單已失效,請重新掃碼
|
||||
hard.not.device.scan.pay=該訂單不是設備掃碼支付訂單
|
||||
hard.not.device.scan=該訂單不是設備掃一掃訂單
|
||||
hard.order.paid.or.changed=該訂單已支付或狀態已變更
|
||||
hard.pay.amount.zero=支付金額為0元
|
||||
hard.user.no.wallet=該用戶沒有這個錢包
|
||||
hard.wallet.user.missing=錢包用戶不存在
|
||||
hard.shipment.no.missing=快遞單號不存在
|
||||
hard.order.type.no.receipt=該訂單類型不支持確認收貨
|
||||
hard.order.status.no.receipt=該訂單狀態不支持確認收貨
|
||||
hard.order.type.error=訂單類型錯誤
|
||||
hard.order.status.error=訂單狀態錯誤
|
||||
hard.idem.create=正在創建訂單中,請勿重複操作
|
||||
hard.idem.verify=正在核銷中,請勿重複操作
|
||||
hard.idem.rollback=正在退回核銷狀態,請勿重複操作
|
||||
hard.car.group.empty=購物車分組不能為空
|
||||
hard.car.biz.incomplete=購物車業務資訊不完整
|
||||
hard.car.batch.same.user.mch=批量購物車必須屬於同一用戶、商戶和業務類型
|
||||
hard.car.save.fail=購物車商品保存失敗
|
||||
common.idempotent.retry=重複請求,請稍後重試
|
||||
auth.captcha.empty=驗證碼不能為空
|
||||
auth.captcha.invalid=驗證碼不合法
|
||||
auth.wx.auth.fail=微信授權失敗:{0}
|
||||
auth.wx.openid.missing=微信授權失敗,未獲取到用戶標識
|
||||
auth.wx.auth.expired=微信授權已過期,請重新授權
|
||||
auth.apple.not.configured=未配置Apple登錄
|
||||
auth.apple.not.enabled=未啟用Apple登錄
|
||||
auth.mini.app.login.fail=微信小程序登錄失敗
|
||||
auth.social.auth.expired=授權已過期,請重新授權
|
||||
sys.app.sms.send.fail=短信驗證碼發送失敗,請稍後重試
|
||||
sys.app.sms.code.invalid=短信驗證碼錯誤或已過期
|
||||
sys.user.password.same=新舊密碼不能相同
|
||||
sys.user.unbind.type.invalid=解綁賬號類型不存在
|
||||
third.recharge.biz.id.invalid=充值業務id解析錯誤
|
||||
third.proxy.recharge.biz.id.invalid=代充值業務id解析錯誤
|
||||
third.proxy.recharge.invalid=代充值記錄不存在或金額無效
|
||||
third.ward.wallet.no.recharge=目標飯卡當前不可充值
|
||||
third.pay.amount.gt.zero=支付金額必須大於0
|
||||
third.wechat.pay.create.fail=創建微信支付錯誤
|
||||
third.alipay.pay.create.fail=創建支付寶支付錯誤
|
||||
third.user.no.mch=用戶不屬於任何食堂或者商城
|
||||
third.user.no.canteen=用戶不屬於任何食堂
|
||||
third.shop.pay.mch.missing=商城支付缺少可信商戶信息
|
||||
third.shop.order.biz.id.invalid=商城訂單業務id解析錯誤
|
||||
third.shop.order.no.pay=商城訂單不存在或無權支付
|
||||
third.shop.order.amount.mismatch=商城訂單支付金額不一致
|
||||
third.shop.order.mch.mismatch=商城訂單收款商戶不一致
|
||||
third.mch.pay.disabled=收款商戶已停用
|
||||
third.mch.wechat.pay.config.missing=商戶未配置微信支付參數
|
||||
third.mch.alipay.pay.config.missing=商戶未配置支付寶支付參數
|
||||
third.order.code.processing=訂單碼支付正在處理中,請勿重複提交
|
||||
third.pay.no.empty=支付訂單號不能為空
|
||||
third.order.code.not.found=訂單碼支付訂單不存在
|
||||
third.order.already.paid=該業務訂單已支付,請勿重複下單
|
||||
third.order.code.other.platform=該業務訂單已有其他平台的待支付訂單碼
|
||||
third.order.code.data.error=訂單碼數據異常,請稍後重試
|
||||
third.order.closing=上一筆訂單正在確認關閉,請稍後重試
|
||||
third.order.code.param.empty=訂單碼支付參數不能為空
|
||||
third.order.code.biz.only=訂單碼支付僅支持雲消費機支付業務
|
||||
third.order.code.platform.only=訂單碼支付僅支持支付寶或微信
|
||||
third.pay.biz.id.empty=支付業務id不能為空
|
||||
third.order.pending.mismatch=該業務訂單已有不同金額或商戶的待支付訂單
|
||||
third.mch.info.mismatch=收款商戶信息不一致
|
||||
third.mch.alipay.config.disabled=商戶未啟用支付寶支付配置
|
||||
third.mch.wechat.config.disabled=商戶未啟用微信支付配置
|
||||
third.alipay.app.config.incomplete=支付寶應用支付配置不完整
|
||||
third.wechat.app.config.incomplete=微信服務商支付配置不完整
|
||||
third.refund.processing=上一筆退款仍在處理中,請稍後重試
|
||||
third.wx.oauth.incomplete=微信用戶授權參數不完整
|
||||
third.wx.oauth.fail=微信用戶授權失敗,請重新掃碼
|
||||
third.fz.relation.unavailable=支付平台分佣關係服務不可用
|
||||
third.wx.jsapi.create.fail=創建微信支付訂單失敗,請重新掃碼
|
||||
third.aggregate.sub.order.save.fail=聚合支付子訂單保存失敗
|
||||
third.mch.wechat.config.incomplete=商戶微信支付配置不完整
|
||||
third.mch.wechat.sub.mch.missing=商戶微信子商戶號未配置
|
||||
third.pay.order.snapshot.missing=支付訂單缺少商戶配置快照
|
||||
third.pay.order.snapshot.invalid=支付訂單商戶配置快照無效
|
||||
third.alipay.auth.code.empty=支付寶授權碼不能為空
|
||||
third.alipay.oauth.fail=支付寶用戶授權失敗,請重新掃碼
|
||||
third.alipay.oauth.no.payer=支付寶用戶授權未返回付款人標識
|
||||
third.alipay.jsapi.create.fail=創建支付寶支付訂單失敗,請重新掃碼
|
||||
third.alipay.client.init.fail=支付寶客戶端初始化失敗
|
||||
third.mch.alipay.config.incomplete=商戶支付寶支付配置不完整
|
||||
third.mch.alipay.sub.mch.missing=商戶支付寶直付通二級商戶標識未配置
|
||||
third.wx.native.create.fail=創建微信訂單碼失敗,請稍後重試
|
||||
third.wx.native.create.fail.code=創建微信訂單碼失敗,微信錯誤碼:{0}
|
||||
third.wx.native.no.qr=創建微信訂單碼失敗,微信未返回二維碼
|
||||
|
||||
app.msg.title.wallet.payment=下單成功,錢包已扣款
|
||||
app.msg.title.wallet.refund=退款已到賬
|
||||
app.msg.title.wallet.recharge=充值已到賬
|
||||
app.msg.title.wallet.reset=錢包餘額已重置
|
||||
app.msg.title.meal.verified=用餐核銷成功
|
||||
app.msg.event.wallet.update=餘額更新
|
||||
app.msg.event.wallet.batch=批量餘額更新
|
||||
app.msg.event.wallet.recharge=充值到賬
|
||||
app.msg.event.wallet.payment=消費支付
|
||||
app.msg.event.wallet.refund=退款到賬
|
||||
app.msg.event.wallet.transfer=錢包轉賬
|
||||
app.msg.event.wallet.transfer.refund=轉賬退款
|
||||
app.msg.event.wallet.return.canteen=退還食堂
|
||||
app.msg.event.wallet.reset=餘額重置
|
||||
app.msg.event.meal.verified=用餐核銷
|
||||
app.msg.wallet.default.name=錢包
|
||||
app.msg.wallet.detail.inc={0}增加{1}元,餘額{2}元
|
||||
app.msg.wallet.detail.dec={0}減少{1}元,餘額{2}元
|
||||
app.msg.wallet.detail.sep=;
|
||||
app.msg.wallet.content={0}:{1}
|
||||
app.msg.meal.default.name=本次預約用餐
|
||||
app.msg.meal.content={0}已核銷,祝您用餐愉快。
|
||||
app.msg.ward.fallback=被監護人
|
||||
app.msg.relation.title={0}的{1}
|
||||
app.msg.relation.content={0}:{1}
|
||||
|
||||
common.product.sku.not.found=商品SKU不存在
|
||||
common.mch.service.error=商戶服務異常
|
||||
mall.user.no.farmer.mch=該用戶未分配共富商戶
|
||||
mall.no.product.perm=無權限處理此商品
|
||||
mall.category.not.found=分類不存在
|
||||
mall.no.category.perm=無權限處理此分類
|
||||
address.id.empty=地址ID不能為空
|
||||
address.not.found=地址不存在
|
||||
address.dept.building.required=單位與樓棟不能為空
|
||||
address.unit.required=單元不能為空
|
||||
address.room.required=房間不能為空
|
||||
address.dept.not.found=單位不存在
|
||||
address.building.not.found=樓棟不存在
|
||||
address.building.dept.mismatch=所選樓棟不屬於該單位
|
||||
address.unit.not.found=單元不存在
|
||||
address.unit.building.mismatch=所選單元不屬於該樓棟
|
||||
address.room.not.found=房間不存在
|
||||
address.room.unit.mismatch=所選房間不屬於該單元/樓棟
|
||||
address.room.no.empty=房間號不能為空
|
||||
address.building.no.access=無權訪問該樓棟
|
||||
address.unit.no.access=無權訪問該單元
|
||||
address.record.update.missing=地址記錄不存在,無法修改
|
||||
address.record.delete.missing=地址記錄不存在,無法刪除
|
||||
|
||||
hard.car.group.item.empty=第{0}組購物車不能為空
|
||||
hard.car.group.item.incomplete=第{0}組購物車商品信息不完整或數量無效
|
||||
hard.car.group.parent.fail=第{0}組父購物車創建失敗
|
||||
hard.car.group.item.invalid=第{0}組存在無效商品
|
||||
mall.product.sku.missing=共富商城商品無SKU信息,商品名:{0},商品ID:{1},請聯繫管理員
|
||||
|
||||
canteen.stock.items.empty=庫存商品不能為空
|
||||
canteen.stock.item.param.bad=庫存商品參數錯誤
|
||||
canteen.stock.biz.param.bad=庫存業務參數錯誤
|
||||
canteen.stock.item.dup=庫存商品不能重複
|
||||
canteen.stock.spu.bad=商品不存在或庫存異常
|
||||
canteen.stock.snapshot.bad=庫存快照異常
|
||||
canteen.stock.changed={0}庫存已變化,請重新操作
|
||||
canteen.stock.compensate.fail=庫存補償失敗,請重試
|
||||
canteen.stock.update.fail=庫存更新失敗,請重試
|
||||
canteen.stock.tx.state.bad=庫存事務狀態異常,請稍後重試
|
||||
canteen.stock.insufficient=庫存不足,無法完成操作
|
||||
canteen.no.product.perm=無權操作該商品
|
||||
canteen.no.product.perm.named=無權操作該商品:{0}
|
||||
canteen.shelf.status.invalid=狀態非法,僅支持 0-上架、1-下架
|
||||
|
||||
hard.stock.tx.state.bad=庫存事務狀態異常,請稍後重試
|
||||
hard.canteen.stock.aftersale.missing=食堂菜品退款庫存缺少售後單 ID
|
||||
hard.canteen.stock.car.missing=食堂菜品庫存操作失敗,購物車不存在
|
||||
hard.canteen.stock.refund.item.missing=食堂菜品庫存操作失敗,退款商品不存在
|
||||
hard.canteen.stock.no.resp=查詢食堂菜品庫存無響應
|
||||
hard.canteen.stock.query.fail=查詢食堂菜品庫存失敗
|
||||
hard.canteen.spu.bad=食堂菜品不存在或不屬於當前商戶
|
||||
hard.canteen.stock.op.fail=食堂菜品庫存服務操作失敗
|
||||
hard.door.stock.fail=扣減智能櫃庫存{0}錯誤
|
||||
hard.stock.deduct.cart.missing=扣減庫存錯誤,購物車不存在
|
||||
hard.stock.op.fail={0}錯誤
|
||||
|
||||
wallet.transfer.source.low=源錢包{0}餘額不足
|
||||
wallet.transfer.limit.exceeded=已經超過最大轉賬金額限制
|
||||
wallet.transfer.not.found=查詢不到轉賬記錄
|
||||
wallet.transfer.refund.dup=已退回請勿重複操作
|
||||
wallet.transfer.refund.source.low=源錢包{0}餘額不足,無法退回
|
||||
wallet.apply.dup.submit=已提交申請,請勿重複提交
|
||||
act.cancel.not.found=核銷活動不存在
|
||||
act.cancel.closed=核銷活動已關閉
|
||||
act.cancel.mch.missing=核銷活動商戶不存在
|
||||
act.cancel.already.received=您已經領,請勿重複領取
|
||||
act.cancel.balance.low=消費錢包餘額不足{0}元,無法領取
|
||||
act.cancel.coupon.expired=您領取的優惠券已過期
|
||||
act.coupon.not.found=優惠券不存在
|
||||
act.not.found=活動不存在
|
||||
act.coupon.points.deduct.fail=扣減積分錯誤
|
||||
act.id.empty=活動id不能為空
|
||||
|
||||
sys.face.max.count=最多只能上傳3張人臉圖片
|
||||
sys.face.max.active=審核中和已通過的人臉合計最多只能保留3張
|
||||
sys.face.dup.image=請勿重複提交同一張人臉圖片
|
||||
sys.face.dept.missing=當前用戶所屬部門不存在,無法發起人臉審核
|
||||
sys.face.ward.only=僅可查看或操作本人及有效被監護人的人臉審核記錄
|
||||
sys.face.record.missing=人臉審核記錄不存在
|
||||
sys.face.revoke.status=只有審核中的人臉記錄可以撤銷
|
||||
sys.face.status.changed=人臉審核狀態已發生變化,請刷新後重試
|
||||
sys.car.plate.dup=車牌號不能重複
|
||||
|
||||
hard.idem.applying=正在申請中,請勿重複操作
|
||||
hard.idem.canceling=正在取消中,請勿重複操作
|
||||
hard.idem.processing=正在處理中,請勿重複操作
|
||||
hard.idem.refunding=正在退款中,請勿重複操作
|
||||
hard.idem.batch.refund=批量退款任務正在提交,請勿重複操作
|
||||
act.idem.receiving=正在領取中,請勿重複操作
|
||||
wallet.idem.applying=正在申請中,請勿重複操作
|
||||
wallet.idem.opening=正在開卡中,請勿重複提交
|
||||
wallet.idem.processing=正在處理中,請勿重複提交
|
||||
wallet.idem.importing=正在導入中,請勿重複操作
|
||||
wallet.idem.recharging=正在充值中,請勿重複操作
|
||||
wallet.idem.uploading=正在上傳中,請勿重複操作
|
||||
wallet.idem.invoice=正在重新生成發票中,請勿重複操作
|
||||
|
||||
mall.product.create.fail=商品創建失敗
|
||||
mall.product.id.empty=商品ID不能為空
|
||||
mall.product.update.fail=商品更新失敗
|
||||
mall.product.list.fail=獲取商品列表失敗
|
||||
mall.product.delete.fail=商品刪除失敗
|
||||
mall.category.create.fail=商品分類創建失敗
|
||||
mall.category.id.empty=分類ID不能為空
|
||||
mall.category.update.fail=分類更新失敗
|
||||
mall.category.delete.fail=分類刪除失敗
|
||||
mall.category.list.fail=獲取分類列表失敗
|
||||
|
||||
third.wx.profit.amount.min=微信分賬支付金額必須大於10分
|
||||
third.wx.profit.amount.range=微信平台抽佣金額必須不少於1分且不能超過訂單金額
|
||||
third.pay.config.missing=支付配置不存在
|
||||
third.wx.refund.amount.bad=微信退款金額必須大於0且不能超過訂單金額
|
||||
third.pay.order.status.no.refund=支付訂單當前狀態不允許退款
|
||||
third.ali.qr.create.fail=創建支付寶訂單碼失敗,請稍後重試
|
||||
third.ali.amount.invalid=支付寶支付金額必須大於0分
|
||||
third.ali.zt.amount.min=支付寶直付通支付金額必須大於10分
|
||||
third.wx.refund.apply.error=微信退款申請錯誤異常
|
||||
third.wx.refund.queued=微信退款請求已進入補償隊列,請稍後查詢結果
|
||||
third.ali.refund.amount.bad=支付寶退款金額必須大於0且不能超過訂單金額
|
||||
sys.register.suspended=暫時停止註冊!
|
||||
+28
-1
@@ -67,7 +67,7 @@ public class GlobalBizExceptionHandler {
|
||||
|
||||
// 业务异常交由 sentinel 记录
|
||||
Tracer.trace(e);
|
||||
return R.failed(e.getLocalizedMessage());
|
||||
return R.failed(resolveClientMessage(e.getLocalizedMessage()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -153,4 +153,31 @@ public class GlobalBizExceptionHandler {
|
||||
return R.failed(exception.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将已知的硬编码中文(如幂等注解 info)映射为当前语言文案。
|
||||
*/
|
||||
private String resolveClientMessage(String message) {
|
||||
if (message == null || message.isBlank()) {
|
||||
return message;
|
||||
}
|
||||
return switch (message) {
|
||||
case "正在创建订单中,请勿重复操作" -> MsgUtils.getMessage(ErrorCodes.HARD_IDEM_CREATE);
|
||||
case "正在核销中,请勿重复操作" -> MsgUtils.getMessage(ErrorCodes.HARD_IDEM_VERIFY);
|
||||
case "正在退回核销状态,请勿重复操作" -> MsgUtils.getMessage(ErrorCodes.HARD_IDEM_ROLLBACK);
|
||||
case "正在申请中,请勿重复操作" -> MsgUtils.getMessage(ErrorCodes.HARD_IDEM_APPLYING);
|
||||
case "正在取消中,请勿重复操作" -> MsgUtils.getMessage(ErrorCodes.HARD_IDEM_CANCELING);
|
||||
case "正在处理中,请勿重复操作", "正在处理中,请勿重复提交" -> MsgUtils.getMessage(ErrorCodes.HARD_IDEM_PROCESSING);
|
||||
case "正在退款中,请勿重复操作" -> MsgUtils.getMessage(ErrorCodes.HARD_IDEM_REFUNDING);
|
||||
case "批量退款任务正在提交,请勿重复操作" -> MsgUtils.getMessage(ErrorCodes.HARD_IDEM_BATCH_REFUND);
|
||||
case "正在领取中,请勿重复操作" -> MsgUtils.getMessage(ErrorCodes.ACT_IDEM_RECEIVING);
|
||||
case "正在开卡中,请勿重复提交" -> MsgUtils.getMessage(ErrorCodes.WALLET_IDEM_OPENING);
|
||||
case "正在导入中,请勿重复操作" -> MsgUtils.getMessage(ErrorCodes.WALLET_IDEM_IMPORTING);
|
||||
case "正在充值中,请勿重复操作" -> MsgUtils.getMessage(ErrorCodes.WALLET_IDEM_RECHARGING);
|
||||
case "正在上传中,请勿重复操作" -> MsgUtils.getMessage(ErrorCodes.WALLET_IDEM_UPLOADING);
|
||||
case "正在重新生成发票中,请勿重复操作" -> MsgUtils.getMessage(ErrorCodes.WALLET_IDEM_INVOICE);
|
||||
case "重复请求,请稍后重试" -> MsgUtils.getMessage("common.idempotent.retry");
|
||||
default -> message;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
+4
-1
@@ -1,4 +1,7 @@
|
||||
package com.bsd.pjcloud.hard.controller.order;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.api.encrypt.annotation.crypto.ApiCryptoAes;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
@@ -63,7 +66,7 @@ public class HardCarController {
|
||||
public R<HardParentCarEntity> appGetParentCar(@RequestParam Long id) {
|
||||
HardParentCarEntity parentCar = hardParentCarService.getById(id);
|
||||
if (parentCar == null || !ObjectUtil.equals(parentCar.getUserId(), SecurityUtils.getUser().getId())) {
|
||||
throw new RuntimeException("购物车不存在或无权查看");
|
||||
throw new I18nBizException(ErrorCodes.HARD_CART_NO_VIEW);
|
||||
}
|
||||
return R.ok(parentCar);
|
||||
}
|
||||
|
||||
+8
-7
@@ -1,5 +1,8 @@
|
||||
package com.bsd.pjcloud.hard.service.impl;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.hard.api.constant.HardApptReserveModeEnum;
|
||||
@@ -22,23 +25,21 @@ public class HardApptMerchantModeServiceImpl implements HardApptMerchantModeServ
|
||||
@Override
|
||||
public MerchantModeContext resolve(Long mchId) {
|
||||
if (ObjectUtil.isEmpty(mchId)) {
|
||||
throw new RuntimeException("商户ID不能为空");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_MCH_ID_EMPTY);
|
||||
}
|
||||
|
||||
R<MchManageVo> result;
|
||||
try {
|
||||
result = remoteMchService.getById(mchId);
|
||||
} catch (RuntimeException exception) {
|
||||
throw new RuntimeException("获取商户预约配置失败", exception);
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_MCH_CONF_FAIL);
|
||||
}
|
||||
if (result == null || !result.isOk()) {
|
||||
String message = result == null || ObjectUtil.isEmpty(result.getMsg())
|
||||
? "获取商户预约配置失败" : result.getMsg();
|
||||
throw new RuntimeException(message);
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_MCH_CONF_FAIL);
|
||||
}
|
||||
MchManageVo merchant = result.getData();
|
||||
if (merchant == null) {
|
||||
throw new RuntimeException("商户不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_MCH_NOT_FOUND);
|
||||
}
|
||||
|
||||
MchManageEntity.TableReservationConf conf = merchant.getTableReservationConf();
|
||||
@@ -46,7 +47,7 @@ public class HardApptMerchantModeServiceImpl implements HardApptMerchantModeServ
|
||||
HardApptReserveModeEnum reserveMode = HardApptReserveModeEnum.valueOfByType(
|
||||
modeValue == null ? null : modeValue.trim());
|
||||
if (reserveMode == null) {
|
||||
throw new RuntimeException("商户预约时间模式无效");
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_MCH_MODE_INVALID);
|
||||
}
|
||||
return new MerchantModeContext(merchant, reserveMode);
|
||||
}
|
||||
|
||||
+59
-32
@@ -1,5 +1,9 @@
|
||||
package com.bsd.pjcloud.hard.service.impl;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
@@ -294,11 +298,10 @@ public class HardApptReservationServiceImpl implements HardApptReservationServic
|
||||
return Availability.available(start, end);
|
||||
}
|
||||
if (now.isBefore(start)) {
|
||||
String reason = "周" + weekdayLabel(rule.getOpenWeekday())
|
||||
+ rule.getOpenTime().format(TIME_FORMATTER) + "开放";
|
||||
return Availability.unavailable(reason, start, end);
|
||||
return Availability.unavailableI18n(ErrorCodes.HARD_APPT_CYCLE_OPEN_AT, start, end,
|
||||
weekdayLabel(rule.getOpenWeekday()), rule.getOpenTime().format(TIME_FORMATTER));
|
||||
}
|
||||
return Availability.unavailable("本期预约已截止", start, end);
|
||||
return Availability.unavailableI18n(ErrorCodes.HARD_APPT_PERIOD_CLOSED, start, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -312,50 +315,50 @@ public class HardApptReservationServiceImpl implements HardApptReservationServic
|
||||
HardApptReserveModeEnum merchantMode = resolveMerchantMode(mchId);
|
||||
if (merchantMode == HardApptReserveModeEnum.WEEKLY_CYCLE) {
|
||||
if (apptRuleId == null) {
|
||||
throw new RuntimeException("周期预约规则不能为空");
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_CYCLE_RULE_REQUIRED);
|
||||
}
|
||||
return validateCycleReservation(mchId, apptRuleId, hourType, apptDate, now);
|
||||
}
|
||||
if (apptRuleId != null) {
|
||||
throw new RuntimeException("当前商户使用动态时间窗,不能提交周期预约规则");
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_CYCLE_NOT_ALLOWED);
|
||||
}
|
||||
if (ObjectUtil.isEmpty(apptId)) {
|
||||
throw new RuntimeException("动态预约餐段不能为空");
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_DYNAMIC_SLOT_EMPTY);
|
||||
}
|
||||
|
||||
HardApptEntity appt = hardApptService.getById(apptId);
|
||||
if (appt == null) {
|
||||
throw new RuntimeException("预约餐段不存在");
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_SLOT_MISSING);
|
||||
}
|
||||
if (ObjectUtil.notEqual(mchId, appt.getMchId())) {
|
||||
throw new RuntimeException("预约餐段与当前商户不匹配");
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_SLOT_MCH_MISMATCH);
|
||||
}
|
||||
if (ObjectUtil.notEqual(YesNoEnum.YES.getCode(), appt.getStatus())) {
|
||||
throw new RuntimeException("预约餐段已停用");
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_SLOT_DISABLED);
|
||||
}
|
||||
|
||||
HardApptReserveModeEnum reserveMode = resolveMode(appt);
|
||||
if (reserveMode != HardApptReserveModeEnum.TIME_WINDOW) {
|
||||
throw new RuntimeException("预约餐段与商户当前模式不匹配");
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_SLOT_MODE_MISMATCH);
|
||||
}
|
||||
|
||||
LocalDate targetDate = resolveLegacyApptDate(apptDate, legacyApptTimeType, now.toLocalDate());
|
||||
long dayOffset = ChronoUnit.DAYS.between(now.toLocalDate(), targetDate);
|
||||
HardApptTimeTypeEnum dateType = HardApptTimeTypeEnum.valueOfByDay((int) dayOffset);
|
||||
if (dateType == null || !HardApptTimeTypeEnum.isReservationDateType(dateType.getType())) {
|
||||
throw new RuntimeException("该预约日期不在可选范围内");
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_DATE_OUT_RANGE);
|
||||
}
|
||||
long mappingCount = hardApptTimeService.count(new LambdaQueryWrapper<HardApptTimeEntity>()
|
||||
.eq(HardApptTimeEntity::getMchId, mchId)
|
||||
.eq(HardApptTimeEntity::getApptId, apptId)
|
||||
.eq(HardApptTimeEntity::getType, dateType.getType()));
|
||||
if (mappingCount == 0) {
|
||||
throw new RuntimeException("该日期未配置此预约餐段");
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_DATE_NO_SLOT);
|
||||
}
|
||||
|
||||
Availability availability = evaluateAvailability(appt, targetDate, now);
|
||||
if (!availability.available()) {
|
||||
throw new RuntimeException(availability.unavailableReason());
|
||||
throwUnavailable(availability);
|
||||
}
|
||||
return new ReservationValidation(appt, appt.getHourType(), targetDate, null, availability.endDateTime(),
|
||||
resolveUsageEndDateTime(targetDate));
|
||||
@@ -363,19 +366,19 @@ public class HardApptReservationServiceImpl implements HardApptReservationServic
|
||||
|
||||
private ReservationValidation validateCycleReservation(Long mchId, Long apptRuleId, String hourType, LocalDate apptDate, LocalDateTime now) {
|
||||
if (apptDate == null || HardHourTypeEnum.valueOfByType(hourType) == null) {
|
||||
throw new RuntimeException("周期预约需要选择预约日期和餐端");
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_DATE_MEAL_REQUIRED);
|
||||
}
|
||||
List<HardApptCycleRuleVo> rules = cycleRuleService.listEnabledConfigurations(mchId);
|
||||
HardApptCycleRuleVo selected = rules.stream()
|
||||
.filter(rule -> ObjectUtil.equals(rule.getId(), apptRuleId))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new RuntimeException("周期预约规则不存在或已停用"));
|
||||
.orElseThrow(() -> new I18nBizException(ErrorCodes.HARD_APPT_CYCLE_MISSING));
|
||||
CycleMatch match = matchCycleRule(selected, hourType, apptDate, now);
|
||||
if (match == null) {
|
||||
throw new RuntimeException("该日期未配置此预约餐段");
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_DATE_NO_SLOT);
|
||||
}
|
||||
if (!match.availability().available()) {
|
||||
throw new RuntimeException(match.availability().unavailableReason());
|
||||
throwUnavailable(match.availability());
|
||||
}
|
||||
return new ReservationValidation(null, hourType, apptDate, selected.getId(), match.availability().endDateTime(),
|
||||
resolveUsageEndDateTime(apptDate));
|
||||
@@ -416,7 +419,7 @@ public class HardApptReservationServiceImpl implements HardApptReservationServic
|
||||
private HardApptOptionVo buildOption(HardApptEntity appt, Availability availability) {
|
||||
HardApptOptionVo option = BeanUtil.toBean(appt, HardApptOptionVo.class);
|
||||
option.setAvailable(availability.available());
|
||||
option.setUnavailableReason(availability.unavailableReason());
|
||||
option.setUnavailableReason(availability.resolvedUnavailableReason());
|
||||
option.setReserveStartDateTime(availability.startDateTime());
|
||||
option.setReserveEndDateTime(availability.endDateTime());
|
||||
return option;
|
||||
@@ -429,7 +432,7 @@ public class HardApptReservationServiceImpl implements HardApptReservationServic
|
||||
option.setHourTypeName(hourType.getDescription());
|
||||
option.setTitle(hourType.getDescription());
|
||||
option.setAvailable(availability.available());
|
||||
option.setUnavailableReason(availability.unavailableReason());
|
||||
option.setUnavailableReason(availability.resolvedUnavailableReason());
|
||||
option.setReserveStartDateTime(availability.startDateTime());
|
||||
option.setReserveEndDateTime(availability.endDateTime());
|
||||
return option;
|
||||
@@ -438,28 +441,28 @@ public class HardApptReservationServiceImpl implements HardApptReservationServic
|
||||
static Availability evaluateAvailability(HardApptEntity appt, LocalDate apptDate, LocalDateTime now) {
|
||||
HardApptReserveModeEnum reserveMode = HardApptReserveModeEnum.valueOfByType(appt.getReserveMode());
|
||||
if (reserveMode == null) {
|
||||
return Availability.unavailable("预约规则模式无效");
|
||||
return Availability.unavailableI18n(ErrorCodes.HARD_APPT_RULE_MODE_INVALID);
|
||||
}
|
||||
if (reserveMode == HardApptReserveModeEnum.WEEKLY_CYCLE) {
|
||||
return Availability.unavailable("周期预约规则配置不完整");
|
||||
return Availability.unavailableI18n(ErrorCodes.HARD_APPT_RULE_INCOMPLETE);
|
||||
}
|
||||
|
||||
HardApptTimeTypeEnum startType = HardApptTimeTypeEnum.valueOfByType(appt.getStartTimeType());
|
||||
HardApptTimeTypeEnum endType = HardApptTimeTypeEnum.valueOfByType(appt.getEndTimeType());
|
||||
if (startType == null || endType == null || appt.getStartTime() == null || appt.getEndTime() == null) {
|
||||
return Availability.unavailable("预约规则配置不完整");
|
||||
return Availability.unavailableI18n(ErrorCodes.HARD_APPT_RULE_INCOMPLETE);
|
||||
}
|
||||
|
||||
LocalDateTime startDateTime = apptDate.plusDays(startType.getDay()).atTime(appt.getStartTime());
|
||||
LocalDateTime endDateTime = apptDate.plusDays(endType.getDay()).atTime(appt.getEndTime());
|
||||
if (!endDateTime.isAfter(startDateTime)) {
|
||||
return Availability.unavailable("预约规则时间范围无效");
|
||||
return Availability.unavailableI18n(ErrorCodes.HARD_APPT_RULE_TIME_INVALID);
|
||||
}
|
||||
if (now.isBefore(startDateTime)) {
|
||||
return Availability.unavailable("预约尚未开放", startDateTime, endDateTime);
|
||||
return Availability.unavailableI18n(ErrorCodes.HARD_APPT_NOT_OPEN, startDateTime, endDateTime);
|
||||
}
|
||||
if (now.isAfter(endDateTime)) {
|
||||
return Availability.unavailable("预约已截止", startDateTime, endDateTime);
|
||||
return Availability.unavailableI18n(ErrorCodes.HARD_APPT_CLOSED, startDateTime, endDateTime);
|
||||
}
|
||||
// 业务要求开始和结束准点均可提交,因此使用闭区间 [start, end]。
|
||||
return Availability.available(startDateTime, endDateTime);
|
||||
@@ -471,7 +474,7 @@ public class HardApptReservationServiceImpl implements HardApptReservationServic
|
||||
}
|
||||
HardApptTimeTypeEnum legacyType = HardApptTimeTypeEnum.valueOfByTypeOrToday(legacyApptTimeType);
|
||||
if (legacyType == null || !HardApptTimeTypeEnum.isReservationDateType(legacyType.getType())) {
|
||||
throw new RuntimeException("预约日期类型无效");
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_DATE_TYPE_INVALID);
|
||||
}
|
||||
return today.plusDays(legacyType.getDay());
|
||||
}
|
||||
@@ -483,9 +486,8 @@ public class HardApptReservationServiceImpl implements HardApptReservationServic
|
||||
if (batch.open()) {
|
||||
return Availability.available(start, end);
|
||||
}
|
||||
String reason = "周" + weekdayLabel(rule.getOpenWeekday())
|
||||
+ rule.getOpenTime().format(TIME_FORMATTER) + "开放";
|
||||
return Availability.unavailable(reason, start, end);
|
||||
return Availability.unavailableI18n(ErrorCodes.HARD_APPT_CYCLE_OPEN_AT, start, end,
|
||||
weekdayLabel(rule.getOpenWeekday()), rule.getOpenTime().format(TIME_FORMATTER));
|
||||
}
|
||||
|
||||
private List<HardApptEntity> findEnabledAppts(Long mchId, HardApptReserveModeEnum reserveMode) {
|
||||
@@ -549,11 +551,20 @@ public class HardApptReservationServiceImpl implements HardApptReservationServic
|
||||
};
|
||||
}
|
||||
|
||||
private void throwUnavailable(Availability availability) {
|
||||
if (availability.unavailableCode() != null) {
|
||||
throw new I18nBizException(availability.unavailableCode(),
|
||||
availability.unavailableArgs() == null ? new Object[0] : availability.unavailableArgs());
|
||||
}
|
||||
throw new I18nBizException(ErrorCodes.HARD_APPT_CLOSED);
|
||||
}
|
||||
|
||||
record Availability(boolean available, String unavailableReason,
|
||||
String unavailableCode, Object[] unavailableArgs,
|
||||
LocalDateTime startDateTime, LocalDateTime endDateTime) {
|
||||
|
||||
static Availability available(LocalDateTime startDateTime, LocalDateTime endDateTime) {
|
||||
return new Availability(true, null, startDateTime, endDateTime);
|
||||
return new Availability(true, null, null, null, startDateTime, endDateTime);
|
||||
}
|
||||
|
||||
static Availability unavailable(String reason) {
|
||||
@@ -561,7 +572,23 @@ public class HardApptReservationServiceImpl implements HardApptReservationServic
|
||||
}
|
||||
|
||||
static Availability unavailable(String reason, LocalDateTime startDateTime, LocalDateTime endDateTime) {
|
||||
return new Availability(false, reason, startDateTime, endDateTime);
|
||||
return new Availability(false, reason, null, null, startDateTime, endDateTime);
|
||||
}
|
||||
|
||||
static Availability unavailableI18n(String code, LocalDateTime startDateTime, LocalDateTime endDateTime,
|
||||
Object... args) {
|
||||
return new Availability(false, null, code, args, startDateTime, endDateTime);
|
||||
}
|
||||
|
||||
static Availability unavailableI18n(String code, Object... args) {
|
||||
return new Availability(false, null, code, args, null, null);
|
||||
}
|
||||
|
||||
String resolvedUnavailableReason() {
|
||||
if (unavailableCode != null) {
|
||||
return MsgUtils.getMessage(unavailableCode, unavailableArgs == null ? new Object[0] : unavailableArgs);
|
||||
}
|
||||
return unavailableReason;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-3
@@ -1,5 +1,8 @@
|
||||
package com.bsd.pjcloud.hard.service.impl;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.hard.api.vo.order.app.HardTakeOutDeliveryTimeDayVO;
|
||||
import com.bsd.pjcloud.hard.api.vo.order.app.HardTakeOutDeliveryTimeOptionVO;
|
||||
@@ -31,12 +34,12 @@ public class HardTakeOutDeliveryTimeOptionServiceImpl implements HardTakeOutDeli
|
||||
@Override
|
||||
public R<HardTakeOutDeliveryTimeOptionVO> listDeliveryTimeSlots(Long merchantId, LocalDate expectDate, Integer days, Integer slotMinutes, Integer leadMinutes) {
|
||||
if (merchantId == null) {
|
||||
return R.failed("商户ID不能为空");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_ID_EMPTY));
|
||||
}
|
||||
LocalDate today = LocalDate.now();
|
||||
LocalDate startDate = expectDate != null ? expectDate : today;
|
||||
if (startDate.isBefore(today)) {
|
||||
return R.failed("不能选择过去的日期");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PAST_DATE_NOT_ALLOWED));
|
||||
}
|
||||
int dayCount = days == null || days < 1 ? DEFAULT_DAY_COUNT : Math.min(days, MAX_DAY_COUNT);
|
||||
int sm = slotMinutes == null || slotMinutes <= 0 ? DEFAULT_SLOT_MINUTES : Math.min(slotMinutes, MAX_SLOT_MINUTES);
|
||||
@@ -44,7 +47,7 @@ public class HardTakeOutDeliveryTimeOptionServiceImpl implements HardTakeOutDeli
|
||||
|
||||
R<MchManageVo> r = remoteMchService.getById(merchantId);
|
||||
if (r == null || !r.isOk() || r.getData() == null) {
|
||||
return R.failed("商户不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
}
|
||||
MchManageVo mch = r.getData();
|
||||
String jobTime = mch.getJobTime();
|
||||
|
||||
+6
-4
@@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.bsd.pjcloud.admin.api.dto.UserInfo;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.BeanUtils;
|
||||
import com.bsd.pjcloud.common.data.datascope.DataScope;
|
||||
import com.bsd.pjcloud.hard.api.dto.address.HardUserMapAddressDto;
|
||||
@@ -38,11 +40,11 @@ public class HardUserMapAddressServiceImpl extends ServiceImpl<HardUserMapAddres
|
||||
@Override
|
||||
public Long createOrUpdate(HardUserMapAddressDto dto) {
|
||||
if (ObjectUtil.isEmpty(dto.getUserId())) {
|
||||
throw new RuntimeException("用户ID不能为空");
|
||||
throw new I18nBizException(ErrorCodes.SYS_USER_ID_EMPTY);
|
||||
}
|
||||
UserInfo user = remoteUserService.getInnerByUserId(dto.getUserId()).getData();
|
||||
if (ObjectUtil.isEmpty(user)) {
|
||||
throw new RuntimeException("用户不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_USER_NOT_EXIST);
|
||||
}
|
||||
|
||||
if (ObjectUtil.isEmpty(dto.getId())) {
|
||||
@@ -54,7 +56,7 @@ public class HardUserMapAddressServiceImpl extends ServiceImpl<HardUserMapAddres
|
||||
.eq(HardUserMapAddressEntity::getUserId, dto.getUserId())
|
||||
);
|
||||
if (ObjectUtil.isEmpty(detail)) {
|
||||
throw new RuntimeException("地址记录不存在,无法修改");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_RECORD_UPDATE_MISSING);
|
||||
}
|
||||
HardUserMapAddressEntity updateObj = BeanUtils.toBean(dto, HardUserMapAddressEntity.class);
|
||||
baseMapper.updateById(updateObj);
|
||||
@@ -68,7 +70,7 @@ public class HardUserMapAddressServiceImpl extends ServiceImpl<HardUserMapAddres
|
||||
.eq(HardUserMapAddressEntity::getId, id)
|
||||
);
|
||||
if (count <= 0) {
|
||||
throw new RuntimeException("地址记录不存在,无法删除");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_RECORD_DELETE_MISSING);
|
||||
}
|
||||
baseMapper.deleteById(id);
|
||||
return id;
|
||||
|
||||
+89
-86
@@ -1,5 +1,8 @@
|
||||
package com.bsd.pjcloud.hard.service.impl.order;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
@@ -221,18 +224,18 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
validateAppOrderStateRefundable(order);
|
||||
validateAppOrderRefund(order.getId(), userId);
|
||||
if (!ObjectUtil.equals(dto.getWay(), "10")) {
|
||||
throw new RuntimeException("当前仅支持仅退款");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_REFUND_ONLY);
|
||||
}
|
||||
List<HardAfterSaleEntity> afterSales = listOrderAfterSales(order.getId());
|
||||
if (afterSales.stream().anyMatch(item -> ObjectUtil.equals(item.getStatus(), HardSaleStatusEnum.APPLY.getStatus()))) {
|
||||
throw new RuntimeException("当前订单已有退款申请待审核,请勿重复提交");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_PENDING_DUP);
|
||||
}
|
||||
|
||||
List<HardCarEntity> originalCars = getOriginalCars(order);
|
||||
List<HardAfterSaleCarEntity> refundCars;
|
||||
if (dto.getCarList() == null) {
|
||||
if (hasEffectiveRefund(afterSales)) {
|
||||
throw new RuntimeException("当前版本不支持部分退款后的继续申请,请升级应用后重试");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_PARTIAL_CONTINUE_UNSUPPORTED);
|
||||
}
|
||||
refundCars = buildLegacyWholeOrderRefundCars(order, originalCars);
|
||||
} else {
|
||||
@@ -242,7 +245,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
.mapToInt(Math::toIntExact).sum();
|
||||
int completedPrice = sumRefundPrice(afterSales, HardSaleStatusEnum.COMPLETE.getStatus());
|
||||
if (refundPrice <= 0 || completedPrice + refundPrice > safePrice(order.getPayPrice())) {
|
||||
throw new RuntimeException("本次退款金额超出订单剩余可退金额");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_AMOUNT_EXCEED);
|
||||
}
|
||||
|
||||
HardAfterSaleEntity afterSale = new HardAfterSaleEntity();
|
||||
@@ -282,12 +285,12 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
validateAppOrderRefund(orderId, userId);
|
||||
HardOrderEntity order = hardOrderService.getById(orderId);
|
||||
if (order == null) {
|
||||
throw new RuntimeException("订单不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
}
|
||||
validateOrderTypeRefundable(order);
|
||||
validateAppOrderStateRefundable(order);
|
||||
if (safePrice(order.getPayPrice()) <= 0) {
|
||||
throw new RuntimeException("订单实付金额异常");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_PAY_AMOUNT_INVALID);
|
||||
}
|
||||
List<HardCarEntity> originalCars = getOriginalCars(order);
|
||||
List<HardAfterSaleEntity> afterSales = listOrderAfterSales(orderId);
|
||||
@@ -392,7 +395,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
public void validateAppAfterSaleAccess(Long afterSaleId, Long viewerUserId) {
|
||||
HardAfterSaleEntity afterSale = baseMapper.selectById(afterSaleId);
|
||||
if (afterSale == null) {
|
||||
throw new RuntimeException("售后单不存在");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_NOT_FOUND);
|
||||
}
|
||||
hardOrderService.validateAppOrderView(afterSale.getOrderId(), viewerUserId);
|
||||
}
|
||||
@@ -404,7 +407,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
public void validateAppAfterSaleRefund(Long afterSaleId, Long viewerUserId) {
|
||||
HardAfterSaleEntity afterSale = baseMapper.selectById(afterSaleId);
|
||||
if (afterSale == null) {
|
||||
throw new RuntimeException("售后单不存在");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_NOT_FOUND);
|
||||
}
|
||||
hardOrderService.validateAppOrderRefund(afterSale.getOrderId(), viewerUserId);
|
||||
}
|
||||
@@ -416,18 +419,18 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
public void validateAppMerchantAfterSaleAccess(Long afterSaleId, Long viewerUserId) {
|
||||
HardAfterSaleEntity afterSale = baseMapper.selectById(afterSaleId);
|
||||
if (afterSale == null) {
|
||||
throw new RuntimeException("售后单不存在");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_NOT_FOUND);
|
||||
}
|
||||
HardOrderEntity order = hardOrderService.getById(afterSale.getOrderId());
|
||||
if (order == null) {
|
||||
throw new RuntimeException("订单不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
}
|
||||
boolean isCanteenReserveOrder = ObjectUtil.equals(order.getMerchantType(), MerchantTypeEnum.CANTEEN.getType())
|
||||
&& ObjectUtil.equals(order.getSysType(), HardTypeEnum.CANTEEN.getType())
|
||||
&& ObjectUtil.equals(order.getOrderType(), HardOrderTypeEnum.RESERVE.getType())
|
||||
&& (order.getApptId() != null || order.getApptRuleId() != null);
|
||||
if (!isCanteenReserveOrder) {
|
||||
throw new RuntimeException("当前 App 商户仅支持审核食堂预约订单");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_APP_MCH_SCOPE);
|
||||
}
|
||||
hardOrderService.validateAppMerchantReserveAccess(order.getId(), viewerUserId);
|
||||
}
|
||||
@@ -436,7 +439,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
public Boolean cancelAfterSale(Long userId, Long afterSaleId) {
|
||||
HardAfterSaleEntity current = baseMapper.selectById(afterSaleId);
|
||||
if (current == null) {
|
||||
throw new RuntimeException("售后单不存在");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_NOT_FOUND);
|
||||
}
|
||||
return withOrderRefundLock(current.getOrderId(), () -> getSelf().cancelAfterSaleInTransaction(userId, afterSaleId));
|
||||
}
|
||||
@@ -451,11 +454,11 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean cancelAfterSaleInTransaction(Long userId, Long afterSaleId) {
|
||||
HardAfterSaleEntity afterSale = baseMapper.selectById(afterSaleId);
|
||||
if (ObjectUtil.isEmpty(afterSale)) throw new RuntimeException("售后单不存在");
|
||||
if (ObjectUtil.isEmpty(afterSale)) throw new I18nBizException(ErrorCodes.AFTER_SALE_NOT_FOUND);
|
||||
HardOrderEntity order = hardOrderMapper.selectByIdForUpdate(afterSale.getOrderId());
|
||||
if (ObjectUtil.isEmpty(order)) throw new RuntimeException("订单不存在");
|
||||
if (ObjectUtil.isEmpty(order)) throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
if (!ObjectUtil.equals(HardSaleStatusEnum.APPLY.getStatus(), afterSale.getStatus())) {
|
||||
throw new RuntimeException("取消售后单失败,售后单状态不是【待审核】");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_CANCEL_STATUS_INVALID);
|
||||
}
|
||||
ensureNoAutoRefundTask(afterSaleId);
|
||||
// 更新售后单的状态为【已取消】
|
||||
@@ -613,9 +616,9 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
private HardOrderEntity refundInCurrentTransaction(Long afterSaleId, String prefixStr, Long autoRefundConfigId,
|
||||
String autoRefundTaskType) {
|
||||
HardAfterSaleEntity afterSale = baseMapper.selectById(afterSaleId);
|
||||
if (ObjectUtil.isEmpty(afterSale)) throw new RuntimeException("售后订单不存在");
|
||||
if (ObjectUtil.isEmpty(afterSale)) throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_NOT_FOUND);
|
||||
HardOrderEntity order = hardOrderMapper.selectByIdForUpdate(afterSale.getOrderId());
|
||||
if (order == null) throw new RuntimeException("订单不存在");
|
||||
if (order == null) throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
validateOrderTypeRefundable(order);
|
||||
// hard_after_sale.refund_time 的历史表定义带 CURRENT_TIMESTAMP 默认值,申请创建时就可能非空,
|
||||
// 不能用它判断渠道退款是否执行过;重复调用由售后状态、订单锁和售后单 ID 下游幂等共同兜底。
|
||||
@@ -630,7 +633,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
refundPrice = order.getPayPrice();
|
||||
}
|
||||
if (refundPrice == null || refundPrice <= 0) {
|
||||
throw new RuntimeException("退款金额必须大于0");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_AMOUNT_GT_ZERO);
|
||||
}
|
||||
// 审核同意会先把当前售后单更新为完成,累计校验必须排除当前单,否则首次整单退款也会被重复计算。
|
||||
int completedRefundPrice = listOrderAfterSales(order.getId()).stream()
|
||||
@@ -639,7 +642,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
.map(HardAfterSaleEntity::getRefundPrice).filter(Objects::nonNull).mapToInt(Integer::intValue).sum();
|
||||
if (completedRefundPrice > safePrice(order.getPayPrice())
|
||||
|| completedRefundPrice + refundPrice > safePrice(order.getPayPrice())) {
|
||||
throw new RuntimeException("退款总金额大于支付总金额");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_AMOUNT_GT_PAY);
|
||||
}
|
||||
HardOrderTypeEnum hardOrderType = HardOrderTypeEnum.valueOfByType(order.getOrderType());
|
||||
HardPayTypeEnum hardPayType = HardPayTypeEnum.valueOfByType(order.getPayType());
|
||||
@@ -661,7 +664,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
.price(refundPrice).autoRefundConfigId(autoRefundConfigId).autoRefundTaskType(autoRefundTaskType).build();
|
||||
R<WalletRechargeVo> walletRefundResult = walletRechargeService.refund(hardRefundDto);
|
||||
if (walletRefundResult == null || !walletRefundResult.isOk() || ObjectUtil.isEmpty(walletRefundResult.getData())) {
|
||||
throw new RuntimeException("钱包退款错误");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_WALLET_REFUND_FAIL);
|
||||
}
|
||||
WalletRechargeVo walletRefund = walletRefundResult.getData();
|
||||
HardOrderEntity updateObj = HardOrderEntity.builder()
|
||||
@@ -679,10 +682,10 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
refundDto.setBizType(payOrderBizType);
|
||||
R<String> refundRes = thirdAppPlusPayService.remoterRefund(refundDto);
|
||||
if (!refundRes.isOk()) {
|
||||
throw new RuntimeException("微信退款错误:" + refundRes.getMsg());
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_WX_REFUND_FAIL_MSG, refundRes.getMsg());
|
||||
}
|
||||
if (ObjectUtil.isEmpty(refundRes.getData())) {
|
||||
throw new RuntimeException("微信退款错误");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_WX_REFUND_FAIL);
|
||||
}
|
||||
hardOrderService.updateById(HardOrderEntity.builder().id(order.getId()).payRefundId(order.getId()).build());
|
||||
}
|
||||
@@ -695,14 +698,14 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
refundDto.setBizType(payOrderBizType);
|
||||
R<String> refundRes = thirdAppPlusPayService.remoterRefund(refundDto);
|
||||
if (!refundRes.isOk()) {
|
||||
throw new RuntimeException("支付宝退款错误:" + refundRes.getMsg());
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ALI_REFUND_FAIL_MSG, refundRes.getMsg());
|
||||
}
|
||||
if (ObjectUtil.isEmpty(refundRes.getData())) {
|
||||
throw new RuntimeException("支付宝退款错误");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ALI_REFUND_FAIL);
|
||||
}
|
||||
hardOrderService.updateById(HardOrderEntity.builder().id(order.getId()).payRefundId(order.getId()).build());
|
||||
} else {
|
||||
throw new RuntimeException("不支持的退款类型");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_UNSUPPORTED_TYPE);
|
||||
}
|
||||
baseMapper.updateById(HardAfterSaleEntity.builder().id(afterSaleId).refundTime(LocalDateTime.now()).build());
|
||||
return order;
|
||||
@@ -719,14 +722,14 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
public void completeAutoRefund(Long afterSaleId, Long autoRefundConfigId) {
|
||||
HardAfterSaleEntity afterSale = baseMapper.selectById(afterSaleId);
|
||||
if (afterSale == null) {
|
||||
throw new RuntimeException("售后单不存在");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_NOT_FOUND);
|
||||
}
|
||||
if (!ObjectUtil.equals(afterSale.getStatus(), HardSaleStatusEnum.APPLY.getStatus())) {
|
||||
throw new RuntimeException("自动退款售后状态不处于申请中");
|
||||
}
|
||||
HardOrderEntity order = hardOrderMapper.selectByIdForUpdate(afterSale.getOrderId());
|
||||
if (order == null) {
|
||||
throw new RuntimeException("订单不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
}
|
||||
if (!Objects.equals(order.getOrderType(), HardOrderTypeEnum.RESERVE.getType())
|
||||
|| !Objects.equals(order.getPayType(), HardPayTypeEnum.WALLET_DEFAULT.getType())
|
||||
@@ -791,7 +794,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
}
|
||||
HardOrderEntity order = hardOrderMapper.selectByIdForUpdate(task.getOrderId());
|
||||
if (order == null) {
|
||||
throw new RuntimeException("订单不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
}
|
||||
if (!isDailyMenuOrder(order) || !Objects.equals(order.getOrderType(), HardOrderTypeEnum.RESERVE.getType())
|
||||
|| !Objects.equals(order.getOrderStatus(), HardOrderStatusEnum.PAY.getType())
|
||||
@@ -849,7 +852,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
}
|
||||
HardOrderEntity order = hardOrderMapper.selectByIdForUpdate(task.getOrderId());
|
||||
if (order == null) {
|
||||
throw new RuntimeException("订单不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
}
|
||||
if (!isDailyMenuOrder(order) || !Objects.equals(order.getOrderType(), HardOrderTypeEnum.RESERVE.getType())
|
||||
|| !Objects.equals(order.getOrderStatus(), HardOrderStatusEnum.PAY.getType())
|
||||
@@ -888,7 +891,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
public Boolean agreeAfterSale(Long userId, Long id) {
|
||||
HardAfterSaleEntity current = baseMapper.selectById(id);
|
||||
if (current == null) {
|
||||
throw new RuntimeException("售后单不存在");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_NOT_FOUND);
|
||||
}
|
||||
return withOrderRefundLock(current.getOrderId(), () -> getSelf().agreeAfterSaleInTransaction(userId, id));
|
||||
}
|
||||
@@ -904,7 +907,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
public Boolean agreeAfterSaleInTransaction(Long userId, Long id) {
|
||||
HardAfterSaleEntity afterSale = validateAfterSaleAuditable(id);
|
||||
HardOrderEntity order = hardOrderMapper.selectByIdForUpdate(afterSale.getOrderId());
|
||||
if (order == null) throw new RuntimeException("设备订单不存在");
|
||||
if (order == null) throw new I18nBizException(ErrorCodes.AFTER_SALE_DEVICE_ORDER_MISSING);
|
||||
long returnReviewCount = countReturnToReviewOperations(id);
|
||||
// 更新售后单的状态
|
||||
HardAfterSaleEntity updateRefundObj = HardAfterSaleEntity.builder()
|
||||
@@ -935,7 +938,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
public Boolean returnToReview(Long userId, Long id) {
|
||||
HardAfterSaleEntity current = baseMapper.selectById(id);
|
||||
if (current == null) {
|
||||
throw new RuntimeException("售后单不存在");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_NOT_FOUND);
|
||||
}
|
||||
return withOrderRefundLock(current.getOrderId(), () -> getSelf().returnToReviewInTransaction(userId, id));
|
||||
}
|
||||
@@ -953,7 +956,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
public Boolean returnToReviewInTransaction(Long userId, Long id) {
|
||||
HardAfterSaleEntity afterSale = baseMapper.selectById(id);
|
||||
if (afterSale == null) {
|
||||
throw new RuntimeException("售后单不存在");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_NOT_FOUND);
|
||||
}
|
||||
ensureNoAutoRefundTask(id);
|
||||
long completedReturnCount = countReturnToReviewOperations(id);
|
||||
@@ -966,7 +969,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
|
||||
HardOrderEntity order = hardOrderMapper.selectByIdForUpdate(afterSale.getOrderId());
|
||||
if (order == null) {
|
||||
throw new RuntimeException("订单不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
}
|
||||
HardOrderTypeEnum orderType = HardOrderTypeEnum.valueOfByType(order.getOrderType());
|
||||
HardPayTypeEnum payType = HardPayTypeEnum.valueOfByType(order.getPayType());
|
||||
@@ -1033,7 +1036,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
public Boolean disagreeRefund(Long userId, HardDisagreeDto dto) {
|
||||
HardAfterSaleEntity current = baseMapper.selectById(dto.getId());
|
||||
if (current == null) {
|
||||
throw new RuntimeException("售后单不存在");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_NOT_FOUND);
|
||||
}
|
||||
return withOrderRefundLock(current.getOrderId(), () -> getSelf().disagreeRefundInTransaction(userId, dto));
|
||||
}
|
||||
@@ -1049,7 +1052,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
public Boolean disagreeRefundInTransaction(Long userId, HardDisagreeDto dto) {
|
||||
HardAfterSaleEntity afterSale = validateAfterSaleAuditable(dto.getId());
|
||||
HardOrderEntity order = hardOrderMapper.selectByIdForUpdate(afterSale.getOrderId());
|
||||
if (order == null) throw new RuntimeException("设备订单不存在");
|
||||
if (order == null) throw new I18nBizException(ErrorCodes.AFTER_SALE_DEVICE_ORDER_MISSING);
|
||||
// 更新售后单的状态
|
||||
HardAfterSaleEntity updateRefundObj = HardAfterSaleEntity.builder()
|
||||
.id(dto.getId())
|
||||
@@ -1068,7 +1071,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
// 校验订单是否可以退款
|
||||
public HardOrderVo validateOrderCanRefund(Long orderId) {
|
||||
HardOrderEntity order = hardOrderService.getById(orderId);
|
||||
if (ObjectUtil.isEmpty(order)) throw new RuntimeException("订单不存在");
|
||||
if (ObjectUtil.isEmpty(order)) throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
HardOrderVo orderVo = BeanUtils.toBean(order, HardOrderVo.class);
|
||||
validateOrderTypeRefundable(order);
|
||||
// 查询所有成功的退款
|
||||
@@ -1080,12 +1083,12 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
int totalPrice = afterList.stream().filter(v -> ObjectUtil.isNotEmpty(v.getRefundPrice())).map(HardAfterSaleEntity::getRefundPrice).reduce(0, Integer::sum);
|
||||
if (totalPrice >= safePrice(order.getPayPrice())) {
|
||||
if (totalPrice > safePrice(order.getPayPrice())) {
|
||||
throw new RuntimeException("退款总金额大于支付总金额");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_AMOUNT_GT_PAY);
|
||||
}
|
||||
throw new RuntimeException("订单已全部退款");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_FULLY_REFUNDED);
|
||||
}
|
||||
if (totalPrice < 0) {
|
||||
throw new RuntimeException("退款总金额大于支付总金额");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_AMOUNT_GT_PAY);
|
||||
}
|
||||
return orderVo;
|
||||
}
|
||||
@@ -1097,34 +1100,34 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
* @param refundCarList 本次选择的退款商品及数量
|
||||
*/
|
||||
public void validateOrderCarCanRefund(HardOrderEntity order, List<HardAfterSaleCarEntity> refundCarList) {
|
||||
if (ObjectUtil.isEmpty(refundCarList)) throw new RuntimeException("售后商品列表不能为空");
|
||||
if (ObjectUtil.isEmpty(refundCarList)) throw new I18nBizException(ErrorCodes.AFTER_SALE_PRODUCT_LIST_EMPTY);
|
||||
// 查询订单购物车
|
||||
List<HardCarEntity> orderCarList = hardCarService.getByParentCarId(order.getParentCarId());
|
||||
if (ObjectUtil.isEmpty(orderCarList)) throw new RuntimeException("订单购物车不存在");
|
||||
if (ObjectUtil.isEmpty(orderCarList)) throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_CART_MISSING);
|
||||
// 查询已退款商品
|
||||
List<HardAfterSaleCarEntity> refundSuccessCarList = hardAfterSaleCarService.getOccupiedByCarParentId(order.getParentCarId());
|
||||
Map<Long, Integer> requestedCountByProductId = new LinkedHashMap<>();
|
||||
for (HardAfterSaleCarEntity refundCar : refundCarList) {
|
||||
if (refundCar == null || (refundCar.getProductId() == null && refundCar.getId() == null)) {
|
||||
throw new RuntimeException("退款商品不能为空");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_REFUND_PRODUCT_EMPTY);
|
||||
}
|
||||
HardCarEntity orderCar = resolveRefundOrderCar(orderCarList, refundCar);
|
||||
if (orderCar == null) throw new RuntimeException("退款商品<" + refundCar.getProductName() + ">不存在");
|
||||
if (orderCar == null) throw new I18nBizException(ErrorCodes.AFTER_SALE_REFUND_PRODUCT_MISSING, refundCar.getProductName());
|
||||
// 后续金额、售后快照和库存恢复都以服务端商品 ID 为准,兼容后台历史提交的购物车行 ID。
|
||||
refundCar.setProductId(orderCar.getProductId());
|
||||
// 按数量商品必须提交有效份数;称重商品历史请求可能只提交重量,数量按零参与数量校验。
|
||||
if (HardProductNatureEnum.DEFAULT.getType().equals(orderCar.getProductNature())
|
||||
&& refundCar.getProductCount() == null) {
|
||||
throw new RuntimeException("退款商品<" + orderCar.getProductName() + ">数量不能为空");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_REFUND_QTY_EMPTY, orderCar.getProductName());
|
||||
}
|
||||
if (refundCar.getProductCount() != null && refundCar.getProductCount() < 0) {
|
||||
throw new RuntimeException("退款商品<" + orderCar.getProductName() + ">数量不能为负数");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_REFUND_QTY_NEGATIVE, orderCar.getProductName());
|
||||
}
|
||||
int requestCount = refundCar.getProductCount() == null ? 0 : refundCar.getProductCount();
|
||||
try {
|
||||
requestedCountByProductId.merge(orderCar.getProductId(), requestCount, Math::addExact);
|
||||
} catch (ArithmeticException exception) {
|
||||
throw new RuntimeException("退款商品<" + orderCar.getProductName() + ">数量异常");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_REFUND_QTY_INVALID, orderCar.getProductName());
|
||||
}
|
||||
}
|
||||
Map<Long, Integer> occupiedCountByProductId = refundSuccessCarList.stream()
|
||||
@@ -1135,7 +1138,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
try {
|
||||
return Math.addExact(left, right);
|
||||
} catch (ArithmeticException exception) {
|
||||
throw new RuntimeException("历史退款商品数量异常");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_HIST_QTY_INVALID);
|
||||
}
|
||||
}, LinkedHashMap::new));
|
||||
Map<Long, Integer> originalCountByProductId = orderCarList.stream()
|
||||
@@ -1146,7 +1149,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
try {
|
||||
return Math.addExact(left, right);
|
||||
} catch (ArithmeticException exception) {
|
||||
throw new RuntimeException("订单商品数量异常");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_QTY_INVALID);
|
||||
}
|
||||
}, LinkedHashMap::new));
|
||||
requestedCountByProductId.forEach((productId, requestedCount) -> {
|
||||
@@ -1156,13 +1159,13 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
try {
|
||||
totalRefundCount = Math.addExact(occupiedCount, requestedCount);
|
||||
} catch (ArithmeticException exception) {
|
||||
throw new RuntimeException("退款商品数量异常");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_REFUND_QTY_BAD);
|
||||
}
|
||||
if (totalRefundCount > originalCount) {
|
||||
HardCarEntity orderCar = orderCarList.stream()
|
||||
.filter(item -> ObjectUtil.equal(item.getProductId(), productId))
|
||||
.findFirst().orElse(null);
|
||||
throw new RuntimeException("退款商品<" + (orderCar == null ? productId : orderCar.getProductName()) + ">数量超出");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_REFUND_QTY_EXCEED, orderCar == null ? productId : orderCar.getProductName());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1210,7 +1213,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
public Boolean refreshOrderRefundStateInTransaction(Long orderId) {
|
||||
HardOrderEntity order = hardOrderMapper.selectByIdForUpdate(orderId);
|
||||
if (order == null) {
|
||||
throw new RuntimeException("订单不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
}
|
||||
recomputeOrderRefundState(orderId);
|
||||
return true;
|
||||
@@ -1225,11 +1228,11 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
private HardOrderEntity requireRefundableOrderForUpdate(Long orderId) {
|
||||
HardOrderEntity order = hardOrderMapper.selectByIdForUpdate(orderId);
|
||||
if (order == null) {
|
||||
throw new RuntimeException("订单不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
}
|
||||
validateOrderTypeRefundable(order);
|
||||
if (safePrice(order.getPayPrice()) <= 0) {
|
||||
throw new RuntimeException("订单实付金额异常");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_PAY_AMOUNT_INVALID);
|
||||
}
|
||||
return order;
|
||||
}
|
||||
@@ -1242,7 +1245,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
private void validateOrderTypeRefundable(HardOrderEntity order) {
|
||||
HardOrderTypeEnum orderTypeEnum = HardOrderTypeEnum.valueOfByType(order.getOrderType());
|
||||
if (!HardOrderTypeEnum.isRefund(orderTypeEnum)) {
|
||||
throw new RuntimeException("该订单类型不支持退款");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_TYPE_NO_REFUND);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1254,7 +1257,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
private void validateAppOrderStateRefundable(HardOrderEntity order) {
|
||||
if (List.of(HardOrderStatusEnum.CREATE.getType(), HardOrderStatusEnum.OFFLINE_CREATE.getType(),
|
||||
HardOrderStatusEnum.UNFOLLOW.getType()).contains(order.getOrderStatus())) {
|
||||
throw new RuntimeException("当前订单状态不支持退款");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_STATUS_NO_REFUND);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1303,7 +1306,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
*/
|
||||
private void ensureNoAutoRefundTask(Long afterSaleId) {
|
||||
if (hardAutoRefundTaskService.existsByAfterSaleId(afterSaleId)) {
|
||||
throw new RuntimeException("自动退款处理中,当前售后单不允许人工取消或审核");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_AUTO_REFUND_LOCK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1316,7 +1319,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
private List<HardCarEntity> getOriginalCars(HardOrderEntity order) {
|
||||
List<HardCarEntity> cars = hardCarService.getByParentCarId(order.getParentCarId());
|
||||
if (ObjectUtil.isEmpty(cars)) {
|
||||
throw new RuntimeException("订单购物车不存在");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_CART_MISSING);
|
||||
}
|
||||
return cars;
|
||||
}
|
||||
@@ -1395,31 +1398,31 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
List<HardAfterSaleCarEntity> result = new ArrayList<>();
|
||||
for (HardAppRefundItemDto requestItem : requestItems) {
|
||||
if (!selectedProductIds.add(requestItem.getProductId())) {
|
||||
throw new RuntimeException("同一商品不能重复提交");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_DUP_PRODUCT);
|
||||
}
|
||||
HardAppRefundProductVo product = allocations.get(requestItem.getProductId());
|
||||
if (product == null) {
|
||||
throw new RuntimeException("退款商品不属于当前订单");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_PRODUCT_NOT_IN_ORDER);
|
||||
}
|
||||
if (!ObjectUtil.equals(product.getProductNature(), HardProductNatureEnum.DEFAULT.getType())) {
|
||||
throw new RuntimeException("称重商品暂不支持在线逐份退款");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_WEIGHTED_NO_PARTIAL);
|
||||
}
|
||||
int requestCount = requestItem.getProductCount() == null ? 0 : requestItem.getProductCount();
|
||||
int occupiedCount = occupiedCounts.getOrDefault(product.getProductId(), 0);
|
||||
if (requestCount <= 0 || occupiedCount + requestCount > product.getOriginalCount()) {
|
||||
throw new RuntimeException("退款商品<" + product.getProductName() + ">数量超出可退范围");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_REFUND_QTY_OUT_RANGE, product.getProductName());
|
||||
}
|
||||
int beforePrice = cumulativeProductPrice(product, occupiedCount);
|
||||
int afterPrice = cumulativeProductPrice(product, occupiedCount + requestCount);
|
||||
int currentPrice = afterPrice - beforePrice;
|
||||
if (currentPrice < 0) {
|
||||
throw new RuntimeException("退款商品<" + product.getProductName() + ">退款金额异常");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_REFUND_AMOUNT_INVALID, product.getProductName());
|
||||
}
|
||||
// 赠品或全额优惠商品的分摊额可以为零;允许其与正金额商品一同申请,确保审核后仍能按所选份数恢复库存。
|
||||
result.add(toAfterSaleCar(product, requestCount, currentPrice));
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
throw new RuntimeException("请选择需要退款的商品");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_SELECT_PRODUCT);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1435,7 +1438,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
Map<Long, HardAppRefundProductVo> products = new TreeMap<>();
|
||||
for (HardCarEntity car : originalCars) {
|
||||
if (car.getProductId() == null) {
|
||||
throw new RuntimeException("订单商品数据异常");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_PRODUCT_BAD);
|
||||
}
|
||||
HardAppRefundProductVo product = products.computeIfAbsent(car.getProductId(), productId -> {
|
||||
HardAppRefundProductVo item = new HardAppRefundProductVo();
|
||||
@@ -1458,7 +1461,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
long snapshotTotal = products.values().stream().map(HardAppRefundProductVo::getOriginalTotalPrice)
|
||||
.filter(Objects::nonNull).mapToLong(Long::longValue).sum();
|
||||
if (snapshotTotal <= 0) {
|
||||
throw new RuntimeException("订单商品金额快照异常");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_AMOUNT_SNAPSHOT_BAD);
|
||||
}
|
||||
long cumulativeSnapshot = 0L;
|
||||
int previousAllocated = 0;
|
||||
@@ -1480,7 +1483,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
*/
|
||||
private int cumulativeProductPrice(HardAppRefundProductVo product, int cumulativeCount) {
|
||||
if (product.getOriginalCount() <= 0) {
|
||||
throw new RuntimeException("订单商品数量异常");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_QTY_INVALID);
|
||||
}
|
||||
int limitedCount = Math.min(Math.max(cumulativeCount, 0), product.getOriginalCount());
|
||||
return proportionalPrice(product.getAllocatedPrice(), limitedCount, product.getOriginalCount());
|
||||
@@ -1496,7 +1499,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
*/
|
||||
private int proportionalPrice(int totalPrice, long cumulativeWeight, long totalWeight) {
|
||||
if (totalWeight <= 0) {
|
||||
throw new RuntimeException("退款分摊权重异常");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ALLOC_WEIGHT_BAD);
|
||||
}
|
||||
return BigDecimal.valueOf(totalPrice).multiply(BigDecimal.valueOf(cumulativeWeight))
|
||||
.divide(BigDecimal.valueOf(totalWeight), 0, RoundingMode.HALF_UP).intValueExact();
|
||||
@@ -1584,7 +1587,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
private void recomputeOrderRefundState(Long orderId) {
|
||||
HardOrderEntity order = hardOrderService.getById(orderId);
|
||||
if (order == null) {
|
||||
throw new RuntimeException("订单不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
}
|
||||
List<HardAfterSaleEntity> afterSales = listOrderAfterSales(orderId);
|
||||
int completedPrice = sumRefundPrice(afterSales, HardSaleStatusEnum.COMPLETE.getStatus());
|
||||
@@ -1678,7 +1681,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
LockInfo lock = lockTemplate.lock(REFUND_ORDER_LOCK_PREFIX + orderId, REFUND_ORDER_LOCK_EXPIRE_MILLIS,
|
||||
REFUND_ORDER_LOCK_WAIT_MILLIS);
|
||||
if (lock == null) {
|
||||
throw new RuntimeException("订单退款正在处理中,请稍后重试");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_PROCESSING);
|
||||
}
|
||||
try {
|
||||
return action.get();
|
||||
@@ -1728,10 +1731,10 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
*/
|
||||
private HardAfterSaleEntity validateAfterSaleAuditable(Long id) {
|
||||
HardAfterSaleEntity afterSale = baseMapper.selectById(id);
|
||||
if (afterSale == null) throw new RuntimeException("售后单不存在");
|
||||
if (afterSale == null) throw new I18nBizException(ErrorCodes.AFTER_SALE_NOT_FOUND);
|
||||
ensureNoAutoRefundTask(id);
|
||||
if (ObjectUtil.notEqual(afterSale.getStatus(), HardSaleStatusEnum.APPLY.getStatus())) {
|
||||
throw new RuntimeException("审批失败,售后状态不处于审批中");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_APPROVE_STATUS_INVALID);
|
||||
}
|
||||
return afterSale;
|
||||
}
|
||||
@@ -1791,11 +1794,11 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
HardOrderVo order = validateOrderCanRefund(dto.getOrderId());
|
||||
List<HardAfterSaleEntity> afterSales = listOrderAfterSales(order.getId());
|
||||
if (afterSales.stream().anyMatch(item -> ObjectUtil.equals(item.getStatus(), HardSaleStatusEnum.APPLY.getStatus()))) {
|
||||
throw new RuntimeException("当前订单已有退款申请待审核,请先处理后再退款");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_PENDING_HANDLE_FIRST);
|
||||
}
|
||||
int remainingRefundPrice = safePrice(order.getPayPrice()) - sumRefundPrice(afterSales, HardSaleStatusEnum.COMPLETE.getStatus());
|
||||
if (remainingRefundPrice <= 0) {
|
||||
throw new RuntimeException("订单已全部退款");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_FULLY_REFUNDED);
|
||||
}
|
||||
HardPayTypeEnum payType = HardPayTypeEnum.valueOfByType(lockedOrder.getPayType());
|
||||
HardOrderTypeEnum orderType = HardOrderTypeEnum.valueOfByType(lockedOrder.getOrderType());
|
||||
@@ -1806,7 +1809,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
int remainingCarPrice = remainingCars.stream().map(HardAfterSaleCarEntity::getTotalPrice)
|
||||
.filter(Objects::nonNull).mapToInt(Math::toIntExact).sum();
|
||||
if (remainingCars.isEmpty() || remainingCarPrice != remainingRefundPrice) {
|
||||
throw new RuntimeException("历史退款商品明细不完整,请通过后台核对后处理");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_HIST_DETAIL_INCOMPLETE);
|
||||
}
|
||||
}
|
||||
// 添加售后订单
|
||||
@@ -1880,21 +1883,21 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
HardOrderVo order = validateOrderCanRefund(dto.getOrderId());
|
||||
if (listOrderAfterSales(order.getId()).stream()
|
||||
.anyMatch(item -> ObjectUtil.equals(item.getStatus(), HardSaleStatusEnum.APPLY.getStatus()))) {
|
||||
throw new RuntimeException("当前订单已有退款申请待审核,请先处理后再退款");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_PENDING_HANDLE_FIRST);
|
||||
}
|
||||
|
||||
// 判断是否快速支付
|
||||
HardPayTypeEnum hardPayType = HardPayTypeEnum.valueOfByType(order.getPayType());
|
||||
if (ObjectUtil.isEmpty(hardPayType)) throw new RuntimeException("订单类型错误");
|
||||
if (ObjectUtil.isEmpty(hardPayType)) throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_TYPE_ERROR);
|
||||
HardOrderTypeEnum orderType = HardOrderTypeEnum.valueOfByType(order.getOrderType());
|
||||
if (ObjectUtil.isEmpty(orderType)) throw new RuntimeException("订单类型错误");
|
||||
if (ObjectUtil.isEmpty(orderType)) throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_TYPE_ERROR);
|
||||
// 如果是简单支付(没有购物车)的支付方式就直接返回
|
||||
boolean isSimplePayList = HardPayTypeEnum.isSimplePayList.contains(hardPayType);
|
||||
if (!isSimplePayList) {
|
||||
isSimplePayList = HardOrderTypeEnum.isSimplePayList.contains(orderType);
|
||||
}
|
||||
if (!isSimplePayList) {
|
||||
if (ObjectUtil.isEmpty(dto.getCarList())) throw new RuntimeException("退款商品列表不能为空");
|
||||
if (ObjectUtil.isEmpty(dto.getCarList())) throw new I18nBizException(ErrorCodes.AFTER_SALE_REFUND_LIST_EMPTY);
|
||||
// 校验订单购物车是否支持退款
|
||||
validateOrderCarCanRefund(order, dto.getCarList());
|
||||
}
|
||||
@@ -1922,7 +1925,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
}
|
||||
}
|
||||
if (refundPrice <= 0) {
|
||||
throw new RuntimeException("退款金额必须大于0");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_AMOUNT_GT_ZERO);
|
||||
}
|
||||
|
||||
saveObj.setType(HardSaleTypeEnum.AFTER_SALE.getType());
|
||||
@@ -2086,7 +2089,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
private int calculateDailyMenuRefundPrice(HardOrderEntity order, List<HardAfterSaleCarEntity> refundCarList) {
|
||||
List<HardCarEntity> orderCarList = hardCarService.getByParentCarId(order.getParentCarId());
|
||||
if (ObjectUtil.isEmpty(orderCarList)) {
|
||||
throw new RuntimeException("订单购物车不存在");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_CART_MISSING);
|
||||
}
|
||||
Map<Long, Integer> refundCountByProductId = new LinkedHashMap<>();
|
||||
try {
|
||||
@@ -2149,7 +2152,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
List<HardAfterSaleCarEntity> refundCarList) {
|
||||
List<HardCarEntity> orderCarList = hardCarService.getByParentCarId(order.getParentCarId());
|
||||
if (ObjectUtil.isEmpty(orderCarList)) {
|
||||
throw new RuntimeException("订单购物车不存在");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_CART_MISSING);
|
||||
}
|
||||
Map<Long, HardCarEntity> orderCarMap = orderCarList.stream()
|
||||
.filter(item -> item.getProductId() != null)
|
||||
@@ -2253,15 +2256,15 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
HardOrderEntity order = requireRefundableOrderForUpdate(orderId);
|
||||
List<HardAfterSaleEntity> afterSales = listOrderAfterSales(orderId);
|
||||
if (afterSales.stream().anyMatch(item -> ObjectUtil.equals(item.getStatus(), HardSaleStatusEnum.APPLY.getStatus()))) {
|
||||
throw new RuntimeException("当前订单已有退款申请待审核,请先处理后再退款");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_PENDING_HANDLE_FIRST);
|
||||
}
|
||||
int remainingRefundPrice = safePrice(order.getPayPrice())
|
||||
- sumRefundPrice(afterSales, HardSaleStatusEnum.COMPLETE.getStatus());
|
||||
if (remainingRefundPrice <= 0) {
|
||||
throw new RuntimeException("订单已全部退款");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_ORDER_FULLY_REFUNDED);
|
||||
}
|
||||
if (checkTimeLimit && order.getPayTime() != null && order.getPayTime().plusHours(4).isBefore(LocalDateTime.now())) {
|
||||
throw new RuntimeException("订单已超过4个小时,不能退款");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_REFUND_TIME_EXCEEDED);
|
||||
}
|
||||
|
||||
HardPayTypeEnum payType = HardPayTypeEnum.valueOfByType(order.getPayType());
|
||||
@@ -2273,7 +2276,7 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
|
||||
int remainingCarPrice = remainingCars.stream().map(HardAfterSaleCarEntity::getTotalPrice)
|
||||
.filter(Objects::nonNull).mapToInt(Math::toIntExact).sum();
|
||||
if (remainingCars.isEmpty() || remainingCarPrice != remainingRefundPrice) {
|
||||
throw new RuntimeException("历史退款商品明细不完整,请通过后台核对后处理");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_HIST_DETAIL_INCOMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-15
@@ -1,5 +1,8 @@
|
||||
package com.bsd.pjcloud.hard.service.impl.order;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.baomidou.lock.annotation.Lock4j;
|
||||
@@ -270,11 +273,11 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
*/
|
||||
private List<Long> saveBatchCarts(HardCarBatchSaveOrUpdateDto dto, boolean useDailyMenuProducts) {
|
||||
if (dto == null || ObjectUtil.isEmpty(dto.getGroups())) {
|
||||
throw new RuntimeException("购物车分组不能为空");
|
||||
throw new I18nBizException(ErrorCodes.HARD_CAR_GROUP_EMPTY);
|
||||
}
|
||||
HardCarSaveOrUpdateDto firstGroup = dto.getGroups().get(0);
|
||||
if (firstGroup == null || !ObjectUtil.isAllNotEmpty(firstGroup.getUserId(), firstGroup.getMerchantId(), firstGroup.getHardType(), firstGroup.getOrderType())) {
|
||||
throw new RuntimeException("购物车业务信息不完整");
|
||||
throw new I18nBizException(ErrorCodes.HARD_CAR_BIZ_INCOMPLETE);
|
||||
}
|
||||
boolean containsDifferentOwner = dto.getGroups().stream().anyMatch(group -> group == null
|
||||
|| !Objects.equals(group.getUserId(), firstGroup.getUserId())
|
||||
@@ -282,7 +285,7 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
|| !Objects.equals(group.getHardType(), firstGroup.getHardType())
|
||||
|| !Objects.equals(group.getOrderType(), firstGroup.getOrderType()));
|
||||
if (containsDifferentOwner) {
|
||||
throw new RuntimeException("批量购物车必须属于同一用户、商户和业务类型");
|
||||
throw new I18nBizException(ErrorCodes.HARD_CAR_BATCH_SAME_USER_MCH);
|
||||
}
|
||||
clearUnorderedCreateCarts(firstGroup.getUserId(), firstGroup.getMerchantId(), firstGroup.getHardType(),
|
||||
useDailyMenuProducts ? DAILY_MENU_CART_SCENE : null);
|
||||
@@ -290,7 +293,7 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
for (int groupIndex = 0; groupIndex < dto.getGroups().size(); groupIndex++) {
|
||||
HardCarSaveOrUpdateDto group = dto.getGroups().get(groupIndex);
|
||||
if (ObjectUtil.isEmpty(group.getList())) {
|
||||
throw new RuntimeException("第" + (groupIndex + 1) + "组购物车不能为空");
|
||||
throw new I18nBizException(ErrorCodes.HARD_CAR_GROUP_ITEM_EMPTY, groupIndex + 1);
|
||||
}
|
||||
List<HardCreateCarDto> carList = group.getList().stream()
|
||||
.filter(Objects::nonNull)
|
||||
@@ -298,7 +301,7 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
.filter(item -> item.getProductCount() != null && item.getProductCount() > 0)
|
||||
.toList();
|
||||
if (carList.size() != group.getList().size()) {
|
||||
throw new RuntimeException("第" + (groupIndex + 1) + "组购物车商品信息不完整或数量无效");
|
||||
throw new I18nBizException(ErrorCodes.HARD_CAR_GROUP_ITEM_INCOMPLETE, groupIndex + 1);
|
||||
}
|
||||
HardProductSourceEnum groupProductSource = useDailyMenuProducts
|
||||
? HardProductSourceEnum.CANTEEN_DAILY_MENU
|
||||
@@ -312,7 +315,7 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
.takeOutSettingJson(group.getTakeOutSetting())
|
||||
.build();
|
||||
if (hardParentCarMapper.insert(parentCar) != 1) {
|
||||
throw new RuntimeException("第" + (groupIndex + 1) + "组父购物车创建失败");
|
||||
throw new I18nBizException(ErrorCodes.HARD_CAR_GROUP_PARENT_FAIL, groupIndex + 1);
|
||||
}
|
||||
if (useDailyMenuProducts) {
|
||||
createDailyMenuCartItems(parentCar.getId(), group.getMerchantId(), carList);
|
||||
@@ -320,7 +323,7 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
getSelf().appCreateCard(parentCar.getId(), group.getHardType(), group.getOrderType(), carList);
|
||||
}
|
||||
if (getByParentCarId(parentCar.getId()).size() != carList.size()) {
|
||||
throw new RuntimeException("第" + (groupIndex + 1) + "组存在无效商品");
|
||||
throw new I18nBizException(ErrorCodes.HARD_CAR_GROUP_ITEM_INVALID, groupIndex + 1);
|
||||
}
|
||||
parentCarIds.add(parentCar.getId());
|
||||
}
|
||||
@@ -338,8 +341,10 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
List<Long> productIds = productList.stream().map(HardCreateCarDto::getProductId).distinct().toList();
|
||||
R<List<CanteenSpuEntity>> response = canteenSpuService.getInnerSpuListByIds(productIds);
|
||||
if (response == null || !response.isOk() || response.getData() == null) {
|
||||
String message = response == null || response.getMsg() == null ? "查询每日菜谱商品失败" : response.getMsg();
|
||||
throw new RuntimeException(message);
|
||||
if (response != null && ObjectUtil.isNotEmpty(response.getMsg())) {
|
||||
throw new RuntimeException(response.getMsg());
|
||||
}
|
||||
throw new I18nBizException(ErrorCodes.HARD_DAILY_PRODUCT_QUERY_FAIL);
|
||||
}
|
||||
Map<Long, CanteenSpuEntity> productMap = new HashMap<>(response.getData().size());
|
||||
response.getData().stream()
|
||||
@@ -351,10 +356,10 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
for (HardCreateCarDto product : productList) {
|
||||
CanteenSpuEntity spu = productMap.get(product.getProductId());
|
||||
if (spu == null || !Objects.equals(spu.getMerchantId(), merchantId)) {
|
||||
throw new RuntimeException("每日菜谱商品不存在或不属于当前商户");
|
||||
throw new I18nBizException(ErrorCodes.HARD_DAILY_MENU_PRODUCT_BAD);
|
||||
}
|
||||
if (spu.getPrice() == null || spu.getPrice() < 0) {
|
||||
throw new RuntimeException(spu.getName() + "价格异常,请联系商户");
|
||||
throw new I18nBizException(ErrorCodes.HARD_PRODUCT_PRICE_BAD, spu.getName());
|
||||
}
|
||||
long totalPrice = Math.multiplyExact((long) spu.getPrice(), product.getProductCount().longValue());
|
||||
String productNature = ObjectUtil.isNotEmpty(product.getProductNature())
|
||||
@@ -524,7 +529,7 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
continue spu;
|
||||
}
|
||||
if (ObjectUtil.isEmpty(spu.getSkuList())) {
|
||||
throw new RuntimeException("共富商城商品无SKU信息商品名字:" + spu.getTitle() + "商品ID:" + spu.getId() + "请联系管理员");
|
||||
throw new I18nBizException(ErrorCodes.MALL_PRODUCT_SKU_MISSING, spu.getTitle(), spu.getId());
|
||||
}
|
||||
Integer price = sku.getPrice();
|
||||
if (ObjectUtil.isNotEmpty(v.getProductCount()) && !ObjectUtil.equals(v.getProductCount(), 0)) {
|
||||
@@ -757,7 +762,7 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
continue spu;
|
||||
}
|
||||
if (ObjectUtil.isEmpty(spu.getSkuList())) {
|
||||
throw new RuntimeException("共富商城商品无SKU信息商品名字:" + spu.getTitle() + "商品ID:" + spu.getId() + "请联系管理员");
|
||||
throw new I18nBizException(ErrorCodes.MALL_PRODUCT_SKU_MISSING, spu.getTitle(), spu.getId());
|
||||
}
|
||||
Integer price = sku.getPrice();
|
||||
int totalPrice = 0;
|
||||
@@ -798,7 +803,7 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
private void insertCartItemsInCurrentTransaction(List<HardCarEntity> cartItems) {
|
||||
for (HardCarEntity cartItem : cartItems) {
|
||||
if (baseMapper.insert(cartItem) != 1) {
|
||||
throw new RuntimeException("购物车商品保存失败");
|
||||
throw new I18nBizException(ErrorCodes.HARD_CAR_SAVE_FAIL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -860,7 +865,7 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
continue spu;
|
||||
}
|
||||
if (ObjectUtil.isEmpty(spu.getSkuList())) {
|
||||
throw new RuntimeException("共富商城商品无SKU信息商品名字:" + spu.getTitle() + "商品ID:" + spu.getId() + "请联系管理员");
|
||||
throw new I18nBizException(ErrorCodes.MALL_PRODUCT_SKU_MISSING, spu.getTitle(), spu.getId());
|
||||
}
|
||||
str.append(spu.getTitle()).append("/").append(sku.getSkuName()).append("x").append(v.getProductCount()).append(";");
|
||||
}
|
||||
|
||||
+232
-225
File diff suppressed because it is too large.
Load diff
+6
-4
@@ -6,7 +6,9 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.util.BeanUtils;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.supermarket.entity.ShopSpuEntity;
|
||||
import com.bsd.pjcloud.supermarket.entity.ShopSkuEntity;
|
||||
@@ -83,7 +85,7 @@ public class AppShopSpuController {
|
||||
@Operation(summary = "APP商品详情", description = "移动端商品详情")
|
||||
public R<ShopSpuDetailAppVo> detail(@PathVariable("id") Long id) {
|
||||
ShopSpuEntity spu = shopSpuService.getByIdDeep(id);
|
||||
if (spu == null) return R.failed("商品不存在");
|
||||
if (spu == null) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_NOT_FOUND));
|
||||
ShopSpuDetailAppVo vo = BeanUtils.toBean(spu, ShopSpuDetailAppVo.class);
|
||||
// 查询sku列表
|
||||
List<ShopSkuEntity> skuList = shopSkuService.list(Wrappers.<ShopSkuEntity>lambdaQuery().eq(ShopSkuEntity::getSpuId, id));
|
||||
@@ -111,16 +113,16 @@ public class AppShopSpuController {
|
||||
@Operation(summary = "批量增减库存", description = "正加负减,任一失败全失败")
|
||||
public R<Boolean> deductStock(@RequestBody SkuStockChangeDTO changes) {
|
||||
boolean result = shopSkuService.deductStockBatch(changes);
|
||||
return result ? R.ok(true) : R.failed("库存不足或扣减失败");
|
||||
return result ? R.ok(true) : R.failed(MsgUtils.getMessage(ErrorCodes.HARD_STOCK_DEDUCT_FAIL));
|
||||
}
|
||||
|
||||
@GetMapping("/checkSpuStock")
|
||||
@Operation(summary = "检查商品库存", description = "检查商品库存")
|
||||
public R<Boolean> checkSpuStock(@RequestParam(value ="skuId")Long skuId,@RequestParam("incrCount")Integer incrCount) {
|
||||
ShopSkuEntity shopSkuEntity = shopSkuService.getById(skuId);
|
||||
if (shopSkuEntity == null) return R.failed("商品sku不存在");
|
||||
if (shopSkuEntity == null) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_SKU_NOT_FOUND));
|
||||
if (shopSkuEntity.getStock()<Math.abs(incrCount)){
|
||||
return R.failed("库存不足");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_STOCK_LOW));
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
+35
-33
@@ -14,29 +14,31 @@ import com.bsd.pjcloud.admin.api.entity.SysRole;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteRoleService;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.BeanUtils;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.security.service.PjcloudUser;
|
||||
import com.bsd.pjcloud.common.security.util.SecurityUtils;
|
||||
import com.bsd.pjcloud.supermarket.dto.MallProductCreateDTO;
|
||||
import com.bsd.pjcloud.supermarket.dto.SkuStockChangeDTO;
|
||||
import com.bsd.pjcloud.supermarket.constant.MallConstants;
|
||||
import com.bsd.pjcloud.supermarket.entity.MallCategoryEntity;
|
||||
import com.bsd.pjcloud.supermarket.entity.MallMerchantEntity;
|
||||
import com.bsd.pjcloud.supermarket.entity.MallProductEntity;
|
||||
import com.bsd.pjcloud.supermarket.entity.MallProductSkuEntity;
|
||||
import com.bsd.pjcloud.supermarket.exception.BusinessException;
|
||||
import com.bsd.pjcloud.supermarket.service.MallCategoryService;
|
||||
import com.bsd.pjcloud.supermarket.service.MallMerchantService;
|
||||
import com.bsd.pjcloud.supermarket.service.MallMerchantUserService;
|
||||
import com.bsd.pjcloud.supermarket.service.MallProductService;
|
||||
import com.bsd.pjcloud.supermarket.service.MallProductSkuService;
|
||||
import com.bsd.pjcloud.supermarket.vo.mall.MallCategoryTreeVo;
|
||||
import com.bsd.pjcloud.supermarket.vo.mall.MallMchManageVo;
|
||||
import com.bsd.pjcloud.supermarket.vo.app.MallProductListAppVo;
|
||||
import com.bsd.pjcloud.supermarket.vo.app.MallProductDetailAppVo;
|
||||
import com.bsd.pjcloud.supermarket.vo.app.MallProductSkuAppVo;
|
||||
import com.bsd.pjcloud.supermarket.vo.app.MallMerchantListAppVo;
|
||||
import com.bsd.pjcloud.supermarket.dto.SkuStockChangeDTO;
|
||||
import com.bsd.pjcloud.supermarket.constant.MallConstants;
|
||||
import com.bsd.pjcloud.supermarket.vo.mall.MallMchManageVo;
|
||||
import com.bsd.pjcloud.wallet.api.dto.MchManageDto;
|
||||
import com.bsd.pjcloud.wallet.api.feign.RemoteMchService;
|
||||
import com.bsd.pjcloud.wallet.api.vo.MchManageVo;
|
||||
@@ -130,7 +132,7 @@ public class MallAppController {
|
||||
mchManageDto.setTypes(MerchantTypeEnum.FARMER.getType());
|
||||
R<List<MchManageVo>> listR = remoteMchService.list(mchManageDto);
|
||||
if (!listR.isOk()) {
|
||||
return R.failed("商户服务异常!");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_SERVICE_ERROR));
|
||||
}
|
||||
List<MchManageVo> merchants = listR.getData();
|
||||
if (CollectionUtils.isEmpty(merchants)) {
|
||||
@@ -247,11 +249,11 @@ public class MallAppController {
|
||||
public R<MallMchManageVo> getMerchantDetail(@PathVariable("id") Long id) {
|
||||
R<MchManageVo> mchManageVoR = remoteMchService.getById(id);
|
||||
if (!mchManageVoR.isOk()) {
|
||||
return R.failed("商户服务异常!");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_SERVICE_ERROR));
|
||||
}
|
||||
MchManageVo mchManageVo = mchManageVoR.getData();
|
||||
if (mchManageVo == null) {
|
||||
return R.failed("商户不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
}
|
||||
MallMchManageVo mallMchManageVo = new MallMchManageVo();
|
||||
mallMchManageVo.setId(mchManageVo.getId());
|
||||
@@ -335,7 +337,7 @@ public class MallAppController {
|
||||
public R<MallProductDetailAppVo> getProductDetail(@PathVariable("id") Long id) {
|
||||
MallProductEntity product = mallProductService.getById(id);
|
||||
if (product == null) {
|
||||
return R.failed("商品不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_NOT_FOUND));
|
||||
}
|
||||
|
||||
MallProductDetailAppVo vo = BeanUtils.toBean(product, MallProductDetailAppVo.class);
|
||||
@@ -400,10 +402,10 @@ public class MallAppController {
|
||||
if (success) {
|
||||
return R.ok("商品创建成功");
|
||||
} else {
|
||||
return R.failed("商品创建失败");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_PRODUCT_CREATE_FAIL));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return R.failed("商品创建失败:" + e.getMessage());
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_PRODUCT_CREATE_FAIL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,17 +425,17 @@ public class MallAppController {
|
||||
|
||||
// 验证商品ID
|
||||
if (productCreateDTO.getId() == null) {
|
||||
return R.failed("商品ID不能为空");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_PRODUCT_ID_EMPTY));
|
||||
}
|
||||
// 更新商品
|
||||
boolean success = mallProductService.updateProductWithSkus(productCreateDTO);
|
||||
if (success) {
|
||||
return R.ok("商品更新成功");
|
||||
} else {
|
||||
return R.failed("商品更新失败");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_PRODUCT_UPDATE_FAIL));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return R.failed("商品更新失败:" + e.getMessage());
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_PRODUCT_UPDATE_FAIL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,7 +448,7 @@ public class MallAppController {
|
||||
// 获取当前用户ID
|
||||
Long deptId = SecurityUtils.getUser().getDeptId();
|
||||
if (deptId == null) {
|
||||
throw new BusinessException("用户未登录");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_NOT_LOGIN);
|
||||
}
|
||||
|
||||
// Long merchantIdByUserId=null;
|
||||
@@ -458,7 +460,7 @@ public class MallAppController {
|
||||
return mchManageVo.getId();
|
||||
|
||||
} else {
|
||||
throw new BusinessException("该用户未分配共富商户");
|
||||
throw new I18nBizException(ErrorCodes.MALL_USER_NO_FARMER_MCH);
|
||||
}
|
||||
// R<List<SysRole>> mallMchUserLists = remoteRoleService.findRolesByCodes(Arrays.asList(MallConstants.RoleCode.MERCHANT_USER));
|
||||
// if (mallMchUserLists.isOk()) {
|
||||
@@ -487,10 +489,10 @@ public class MallAppController {
|
||||
|
||||
MallProductEntity mallProduct = mallProductService.getById(productId);
|
||||
if (mallProduct == null) {
|
||||
throw new BusinessException("商品不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_PRODUCT_NOT_FOUND);
|
||||
}
|
||||
if (!merchantId.equals(mallProduct.getMerchantId())) {
|
||||
throw new BusinessException("无权限处理此商品");
|
||||
throw new I18nBizException(ErrorCodes.MALL_NO_PRODUCT_PERM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,7 +560,7 @@ public class MallAppController {
|
||||
|
||||
return R.ok(voPage);
|
||||
} catch (Exception e) {
|
||||
return R.failed("获取商品列表失败:" + e.getMessage());
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_PRODUCT_LIST_FAIL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,10 +579,10 @@ public class MallAppController {
|
||||
if (success) {
|
||||
return R.ok("商品删除成功");
|
||||
} else {
|
||||
return R.failed("商品删除失败");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_PRODUCT_DELETE_FAIL));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return R.failed("商品删除失败:" + e.getMessage());
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_PRODUCT_DELETE_FAIL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,10 +605,10 @@ public class MallAppController {
|
||||
if (success) {
|
||||
return R.ok("商品分类创建成功");
|
||||
} else {
|
||||
return R.failed("商品分类创建失败");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_CATEGORY_CREATE_FAIL));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return R.failed("商品分类创建失败:" + e.getMessage());
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_CATEGORY_CREATE_FAIL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,7 +625,7 @@ public class MallAppController {
|
||||
|
||||
// 验证分类ID
|
||||
if (category.getId() == null) {
|
||||
return R.failed("分类ID不能为空");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_CATEGORY_ID_EMPTY));
|
||||
}
|
||||
|
||||
// 更新分类
|
||||
@@ -631,10 +633,10 @@ public class MallAppController {
|
||||
if (success) {
|
||||
return R.ok("分类更新成功");
|
||||
} else {
|
||||
return R.failed("分类更新失败");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_CATEGORY_UPDATE_FAIL));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return R.failed("分类更新失败:" + e.getMessage());
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_CATEGORY_UPDATE_FAIL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,10 +655,10 @@ public class MallAppController {
|
||||
if (success) {
|
||||
return R.ok("分类删除成功");
|
||||
} else {
|
||||
return R.failed("分类删除失败");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_CATEGORY_DELETE_FAIL));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return R.failed("分类删除失败:" + e.getMessage());
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_CATEGORY_DELETE_FAIL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -677,7 +679,7 @@ public class MallAppController {
|
||||
List<MallCategoryEntity> list = mallCategoryService.list(wrapper);
|
||||
return R.ok(list);
|
||||
} catch (Exception e) {
|
||||
return R.failed("获取分类列表失败:" + e.getMessage());
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.MALL_CATEGORY_LIST_FAIL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -687,10 +689,10 @@ public class MallAppController {
|
||||
private void validateCategoryPermission(Long categoryId, Long merchantId) {
|
||||
MallCategoryEntity category = mallCategoryService.getById(categoryId);
|
||||
if (category == null) {
|
||||
throw new BusinessException("分类不存在");
|
||||
throw new I18nBizException(ErrorCodes.MALL_CATEGORY_NOT_FOUND);
|
||||
}
|
||||
if (!merchantId.equals(category.getMerchantId())) {
|
||||
throw new BusinessException("无权限处理此分类");
|
||||
throw new I18nBizException(ErrorCodes.MALL_NO_CATEGORY_PERM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -703,7 +705,7 @@ public class MallAppController {
|
||||
@Operation(summary = "批量增减库存", description = "正加负减,任一失败全失败")
|
||||
public R<Boolean> deductStock(@RequestBody SkuStockChangeDTO changes) {
|
||||
boolean result = mallProductSkuService.deductStockBatch(changes);
|
||||
return result ? R.ok(true) : R.failed("库存不足或扣减失败");
|
||||
return result ? R.ok(true) : R.failed(MsgUtils.getMessage(ErrorCodes.HARD_STOCK_DEDUCT_FAIL));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -714,10 +716,10 @@ public class MallAppController {
|
||||
public R<Boolean> checkStock(@RequestParam("skuId") Long skuId, @RequestParam("incrCount") Integer incrCount) {
|
||||
MallProductSkuEntity sku = mallProductSkuService.getById(skuId);
|
||||
if (sku == null) {
|
||||
return R.failed("商品SKU不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_SKU_NOT_FOUND));
|
||||
}
|
||||
if (sku.getStock() < Math.abs(incrCount)) {
|
||||
return R.failed("库存不足");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_PRODUCT_STOCK_LOW));
|
||||
}
|
||||
return R.ok(true);
|
||||
}
|
||||
|
||||
+149
-24
@@ -6,6 +6,8 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.bsd.pjcloud.admin.api.dto.user.SysUserRelationRecipientQueryDto;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteUserRelationService;
|
||||
import com.bsd.pjcloud.admin.api.vo.user.SysUserRelationRecipientVo;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.thirdparty.constant.appmessage.AppMessageConstants;
|
||||
import com.bsd.pjcloud.thirdparty.constant.appmessage.AppMessageEventEnum;
|
||||
@@ -20,8 +22,11 @@ import com.bsd.pjcloud.thirdparty.service.appmessage.ThirdAppMessageSettingServi
|
||||
import com.bsd.pjcloud.thirdparty.service.appmessage.ThirdPushDeliveryService;
|
||||
import com.bsd.pjcloud.thirdparty.vo.appmessage.AppMessageVo;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -38,6 +43,7 @@ import java.util.Set;
|
||||
/**
|
||||
* App业务消息事件接入和收件箱实现。
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ThirdAppMessageServiceImpl implements ThirdAppMessageService {
|
||||
@@ -98,15 +104,16 @@ public class ThirdAppMessageServiceImpl implements ThirdAppMessageService {
|
||||
if (ownerMessageExists(dto.getEventId(), dto.getSubjectUserId())) {
|
||||
return true;
|
||||
}
|
||||
String mealName = StrUtil.blankToDefault(dto.getMealName(), "本次预约用餐");
|
||||
String mealName = StrUtil.blankToDefault(dto.getMealName(), MsgUtils.getMessage(ErrorCodes.APP_MSG_MEAL_DEFAULT_NAME));
|
||||
String payloadJson = serialize(Map.of(
|
||||
"orderId", dto.getOrderId(),
|
||||
"mealName", mealName));
|
||||
ThirdAppMessageEntity ownerMessage = buildBaseMessage(
|
||||
dto.getTenantId(), dto.getEventId(), event.getCode(), dto.getSubjectUserId(), dto.getSubjectUserId(),
|
||||
AppMessageConstants.RECIPIENT_OWNER, AppMessageConstants.SOURCE_HARDWARE, event.getCode(),
|
||||
String.valueOf(dto.getOrderId()), dto.getSourceMchId(), dto.getSourceMchName(), "用餐核销成功",
|
||||
mealName + "已核销,祝您用餐愉快。", payloadJson, dto.getOccurredTime());
|
||||
String.valueOf(dto.getOrderId()), dto.getSourceMchId(), dto.getSourceMchName(),
|
||||
MsgUtils.getMessage(ErrorCodes.APP_MSG_TITLE_MEAL_VERIFIED),
|
||||
MsgUtils.getMessage(ErrorCodes.APP_MSG_MEAL_CONTENT, mealName), payloadJson, dto.getOccurredTime());
|
||||
messageMapper.insert(ownerMessage);
|
||||
ThirdAppPushPolicyEntity policy = settingService.findPolicy(dto.getSourceMchId(), event.getCode());
|
||||
deliveryService.createDelivery(ownerMessage, ownerSkipReason(dto.getSourceMchId(), policy, dto.getSubjectUserId(), event.getCode()));
|
||||
@@ -231,13 +238,16 @@ public class ThirdAppMessageServiceImpl implements ThirdAppMessageService {
|
||||
createdRecipientIds.remove(relation.getRecipientUserId());
|
||||
continue;
|
||||
}
|
||||
String subjectName = StrUtil.blankToDefault(relation.getSubjectUserName(), "被监护人");
|
||||
String subjectName = StrUtil.blankToDefault(relation.getSubjectUserName(),
|
||||
MsgUtils.getMessage(ErrorCodes.APP_MSG_WARD_FALLBACK));
|
||||
ThirdAppMessageEntity relationMessage = buildBaseMessage(
|
||||
ownerMessage.getTenantId(), ownerMessage.getEventId(), ownerMessage.getEventCode(),
|
||||
relation.getRecipientUserId(), ownerMessage.getSubjectUserId(), AppMessageConstants.RECIPIENT_RELATION,
|
||||
ownerMessage.getSourceService(), ownerMessage.getSourceBizType(), ownerMessage.getSourceBizId(),
|
||||
ownerMessage.getSourceMchId(), ownerMessage.getSourceMchName(), subjectName + "的" + ownerMessage.getTitle(),
|
||||
subjectName + ":" + ownerMessage.getContent(), payloadJson, occurredTime);
|
||||
ownerMessage.getSourceMchId(), ownerMessage.getSourceMchName(),
|
||||
MsgUtils.getMessage(ErrorCodes.APP_MSG_RELATION_TITLE, subjectName, ownerMessage.getTitle()),
|
||||
MsgUtils.getMessage(ErrorCodes.APP_MSG_RELATION_CONTENT, subjectName, ownerMessage.getContent()),
|
||||
payloadJson, occurredTime);
|
||||
relationMessage.setRelationId(relation.getRelationId());
|
||||
relationMessage.setRelationCode(relation.getRelationCode());
|
||||
relationMessage.setRelationName(relation.getRelationName());
|
||||
@@ -367,18 +377,43 @@ public class ThirdAppMessageServiceImpl implements ThirdAppMessageService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回钱包事件本人标题。
|
||||
* 返回钱包事件本人标题(写入与按请求语言重渲染共用)。
|
||||
*
|
||||
* @param event 钱包事件
|
||||
* @return 固定模板标题
|
||||
* @return 当前语言下的固定模板标题
|
||||
*/
|
||||
private String ownerTitle(AppMessageEventEnum event) {
|
||||
return switch (event) {
|
||||
case WALLET_PAYMENT -> "下单成功,钱包已扣款";
|
||||
case WALLET_REFUND, WALLET_TRANSFER_REFUND -> "退款已到账";
|
||||
case WALLET_RECHARGE -> "充值已到账";
|
||||
case WALLET_RESET -> "钱包余额已重置";
|
||||
default -> event.getLabel();
|
||||
case WALLET_PAYMENT -> MsgUtils.getMessage(ErrorCodes.APP_MSG_TITLE_WALLET_PAYMENT);
|
||||
case WALLET_REFUND, WALLET_TRANSFER_REFUND -> MsgUtils.getMessage(ErrorCodes.APP_MSG_TITLE_WALLET_REFUND);
|
||||
case WALLET_RECHARGE -> MsgUtils.getMessage(ErrorCodes.APP_MSG_TITLE_WALLET_RECHARGE);
|
||||
case WALLET_RESET -> MsgUtils.getMessage(ErrorCodes.APP_MSG_TITLE_WALLET_RESET);
|
||||
case MEAL_VERIFIED -> MsgUtils.getMessage(ErrorCodes.APP_MSG_TITLE_MEAL_VERIFIED);
|
||||
default -> eventLabel(event);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回事件展示名称(正文前缀)。
|
||||
*
|
||||
* @param event 消息事件
|
||||
* @return 当前语言下的事件名称
|
||||
*/
|
||||
private String eventLabel(AppMessageEventEnum event) {
|
||||
if (event == null) {
|
||||
return "";
|
||||
}
|
||||
return switch (event) {
|
||||
case WALLET_UPDATE -> MsgUtils.getMessage(ErrorCodes.APP_MSG_EVENT_WALLET_UPDATE);
|
||||
case WALLET_BATCH -> MsgUtils.getMessage(ErrorCodes.APP_MSG_EVENT_WALLET_BATCH);
|
||||
case WALLET_RECHARGE -> MsgUtils.getMessage(ErrorCodes.APP_MSG_EVENT_WALLET_RECHARGE);
|
||||
case WALLET_PAYMENT -> MsgUtils.getMessage(ErrorCodes.APP_MSG_EVENT_WALLET_PAYMENT);
|
||||
case WALLET_REFUND -> MsgUtils.getMessage(ErrorCodes.APP_MSG_EVENT_WALLET_REFUND);
|
||||
case WALLET_TRANSFER -> MsgUtils.getMessage(ErrorCodes.APP_MSG_EVENT_WALLET_TRANSFER);
|
||||
case WALLET_TRANSFER_REFUND -> MsgUtils.getMessage(ErrorCodes.APP_MSG_EVENT_WALLET_TRANSFER_REFUND);
|
||||
case WALLET_RETURN_CANTEEN -> MsgUtils.getMessage(ErrorCodes.APP_MSG_EVENT_WALLET_RETURN_CANTEEN);
|
||||
case WALLET_RESET -> MsgUtils.getMessage(ErrorCodes.APP_MSG_EVENT_WALLET_RESET);
|
||||
case MEAL_VERIFIED -> MsgUtils.getMessage(ErrorCodes.APP_MSG_EVENT_MEAL_VERIFIED);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -387,23 +422,111 @@ public class ThirdAppMessageServiceImpl implements ThirdAppMessageService {
|
||||
*
|
||||
* @param event 钱包事件
|
||||
* @param details 同一业务操作的钱包明细
|
||||
* @return 固定模板正文
|
||||
* @return 当前语言下的模板正文
|
||||
*/
|
||||
private String walletContent(AppMessageEventEnum event, List<WalletMessageDetailDto> details) {
|
||||
StringBuilder content = new StringBuilder(event.getLabel()).append(":");
|
||||
String sep = MsgUtils.getMessage(ErrorCodes.APP_MSG_WALLET_DETAIL_SEP);
|
||||
StringBuilder detailsText = new StringBuilder();
|
||||
for (int index = 0; index < details.size(); index++) {
|
||||
WalletMessageDetailDto detail = details.get(index);
|
||||
if (index > 0) {
|
||||
content.append(";");
|
||||
detailsText.append(sep);
|
||||
}
|
||||
content.append(StrUtil.blankToDefault(detail.getWalletName(), "钱包"))
|
||||
.append(detail.getAmount() >= 0 ? "增加" : "减少")
|
||||
.append(formatFen(Math.abs(detail.getAmount())))
|
||||
.append("元,余额")
|
||||
.append(formatFen(detail.getBalance()))
|
||||
.append("元");
|
||||
String walletName = StrUtil.blankToDefault(detail.getWalletName(),
|
||||
MsgUtils.getMessage(ErrorCodes.APP_MSG_WALLET_DEFAULT_NAME));
|
||||
String amount = formatFen(Math.abs(detail.getAmount() == null ? 0 : detail.getAmount()));
|
||||
String balance = formatFen(detail.getBalance() == null ? 0 : detail.getBalance());
|
||||
String detailCode = detail.getAmount() != null && detail.getAmount() >= 0
|
||||
? ErrorCodes.APP_MSG_WALLET_DETAIL_INC
|
||||
: ErrorCodes.APP_MSG_WALLET_DETAIL_DEC;
|
||||
detailsText.append(MsgUtils.getMessage(detailCode, walletName, amount, balance));
|
||||
}
|
||||
return MsgUtils.getMessage(ErrorCodes.APP_MSG_WALLET_CONTENT, eventLabel(event), detailsText.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 按当前请求语言重渲染标题;payload 缺失时回退库中原文。
|
||||
*/
|
||||
private String resolveLocalizedTitle(ThirdAppMessageEntity entity, AppMessageEventEnum event) {
|
||||
if (event == null) {
|
||||
return entity.getTitle();
|
||||
}
|
||||
String ownerTitle = ownerTitle(event);
|
||||
if (AppMessageConstants.RECIPIENT_RELATION.equals(entity.getRecipientType())) {
|
||||
String subjectName = StrUtil.blankToDefault(entity.getSubjectUserName(),
|
||||
MsgUtils.getMessage(ErrorCodes.APP_MSG_WARD_FALLBACK));
|
||||
return MsgUtils.getMessage(ErrorCodes.APP_MSG_RELATION_TITLE, subjectName, ownerTitle);
|
||||
}
|
||||
return ownerTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按当前请求语言重渲染正文;无法从 payload 还原时回退库中原文。
|
||||
*/
|
||||
private String resolveLocalizedContent(ThirdAppMessageEntity entity, AppMessageEventEnum event) {
|
||||
if (event == null) {
|
||||
return entity.getContent();
|
||||
}
|
||||
String ownerContent;
|
||||
if (event == AppMessageEventEnum.MEAL_VERIFIED) {
|
||||
ownerContent = resolveMealContent(entity.getPayloadJson());
|
||||
} else if ("wallet".equals(event.getCategory())) {
|
||||
ownerContent = resolveWalletContent(event, entity.getPayloadJson());
|
||||
} else {
|
||||
ownerContent = null;
|
||||
}
|
||||
if (StrUtil.isBlank(ownerContent)) {
|
||||
return entity.getContent();
|
||||
}
|
||||
if (AppMessageConstants.RECIPIENT_RELATION.equals(entity.getRecipientType())) {
|
||||
String subjectName = StrUtil.blankToDefault(entity.getSubjectUserName(),
|
||||
MsgUtils.getMessage(ErrorCodes.APP_MSG_WARD_FALLBACK));
|
||||
return MsgUtils.getMessage(ErrorCodes.APP_MSG_RELATION_CONTENT, subjectName, ownerContent);
|
||||
}
|
||||
return ownerContent;
|
||||
}
|
||||
|
||||
private String resolveWalletContent(AppMessageEventEnum event, String payloadJson) {
|
||||
List<WalletMessageDetailDto> details = parseWalletDetails(payloadJson);
|
||||
if (details == null || details.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return walletContent(event, details);
|
||||
}
|
||||
|
||||
private String resolveMealContent(String payloadJson) {
|
||||
if (StrUtil.isBlank(payloadJson)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JsonNode root = objectMapper.readTree(payloadJson);
|
||||
String mealName = root.path("mealName").asText(null);
|
||||
if (StrUtil.isBlank(mealName)) {
|
||||
mealName = MsgUtils.getMessage(ErrorCodes.APP_MSG_MEAL_DEFAULT_NAME);
|
||||
}
|
||||
return MsgUtils.getMessage(ErrorCodes.APP_MSG_MEAL_CONTENT, mealName);
|
||||
} catch (Exception exception) {
|
||||
log.warn("解析用餐消息 payload 失败,回退库中正文", exception);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private List<WalletMessageDetailDto> parseWalletDetails(String payloadJson) {
|
||||
if (StrUtil.isBlank(payloadJson)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JsonNode root = objectMapper.readTree(payloadJson);
|
||||
JsonNode detailsNode = root.get("details");
|
||||
if (detailsNode == null || !detailsNode.isArray() || detailsNode.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return objectMapper.convertValue(detailsNode, new TypeReference<List<WalletMessageDetailDto>>() {
|
||||
});
|
||||
} catch (Exception exception) {
|
||||
log.warn("解析钱包消息 payload 失败,回退库中正文", exception);
|
||||
return null;
|
||||
}
|
||||
return content.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -463,7 +586,7 @@ public class ThirdAppMessageServiceImpl implements ThirdAppMessageService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将消息实体转换为App安全展示模型。
|
||||
* 将消息实体转换为App安全展示模型,并按请求语言重渲染 title/content。
|
||||
*
|
||||
* @param entity 消息实体
|
||||
* @return App消息模型
|
||||
@@ -474,6 +597,8 @@ public class ThirdAppMessageServiceImpl implements ThirdAppMessageService {
|
||||
AppMessageEventEnum event = AppMessageEventEnum.fromCode(entity.getEventCode());
|
||||
vo.setCategory(event == null ? null : event.getCategory());
|
||||
vo.setRead(AppMessageConstants.READ.equals(entity.getReadStatus()));
|
||||
vo.setTitle(resolveLocalizedTitle(entity, event));
|
||||
vo.setContent(resolveLocalizedContent(entity, event));
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
+14
-12
@@ -4,6 +4,8 @@ import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alipay.api.AlipayClient;
|
||||
@@ -109,7 +111,7 @@ public class ThirdAggregateAliPayServiceImpl implements ThirdAggregateAliPayServ
|
||||
@Override
|
||||
public ThirdAggregateAlipayOauthIdentity exchangeOauthCode(String authCode) {
|
||||
if (StrUtil.isBlank(authCode)) {
|
||||
throw new RuntimeException("支付宝授权码不能为空");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALIPAY_AUTH_CODE_EMPTY);
|
||||
}
|
||||
AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
|
||||
request.setGrantType(OAUTH_GRANT_TYPE);
|
||||
@@ -119,18 +121,18 @@ public class ThirdAggregateAliPayServiceImpl implements ThirdAggregateAliPayServ
|
||||
if (response == null || !response.isSuccess()) {
|
||||
String errorCode = response == null ? "EMPTY_RESPONSE" : StrUtil.firstNonBlank(response.getSubCode(), response.getCode(), "UNKNOWN");
|
||||
log.warn("|{}|支付宝用户授权失败,errorCode:{}", TAG, errorCode);
|
||||
throw new RuntimeException("支付宝用户授权失败,请重新扫码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALIPAY_OAUTH_FAIL);
|
||||
}
|
||||
ThirdAggregateAlipayOauthIdentity identity = new ThirdAggregateAlipayOauthIdentity(response.getOpenId(), response.getUserId());
|
||||
if (StrUtil.isBlank(identity.getStableIdentity())) {
|
||||
throw new RuntimeException("支付宝用户授权未返回付款人标识");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALIPAY_OAUTH_NO_PAYER);
|
||||
}
|
||||
return identity;
|
||||
} catch (RuntimeException exception) {
|
||||
throw exception;
|
||||
} catch (Exception exception) {
|
||||
log.warn("|{}|支付宝用户授权异常,exceptionType:{}", TAG, exception.getClass().getSimpleName());
|
||||
throw new RuntimeException("支付宝用户授权失败,请重新扫码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALIPAY_OAUTH_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,13 +184,13 @@ public class ThirdAggregateAliPayServiceImpl implements ThirdAggregateAliPayServ
|
||||
} catch (Exception exception) {
|
||||
saveFailedOrder(payOrder, "SDK_EXCEPTION", exception.getClass().getSimpleName());
|
||||
log.warn("|{}|支付宝JSAPI子订单创建异常,payNo:{},exceptionType:{}", TAG, context.getPayNo(), exception.getClass().getSimpleName());
|
||||
throw new RuntimeException("创建支付宝支付订单失败,请重新扫码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALIPAY_JSAPI_CREATE_FAIL);
|
||||
}
|
||||
if (response == null || !response.isSuccess() || StrUtil.isBlank(response.getTradeNo())) {
|
||||
String errorCode = response == null ? "EMPTY_RESPONSE" : StrUtil.firstNonBlank(response.getSubCode(), response.getCode(), "EMPTY_TRADE_NO");
|
||||
saveFailedOrder(payOrder, errorCode, null);
|
||||
log.warn("|{}|支付宝JSAPI子订单创建失败,payNo:{},errorCode:{}", TAG, context.getPayNo(), errorCode);
|
||||
throw new RuntimeException("创建支付宝支付订单失败,请重新扫码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALIPAY_JSAPI_CREATE_FAIL);
|
||||
}
|
||||
|
||||
Map<String, Object> payParams = new LinkedHashMap<>();
|
||||
@@ -199,12 +201,12 @@ public class ThirdAggregateAliPayServiceImpl implements ThirdAggregateAliPayServ
|
||||
.set("launchParams", payParams).toString());
|
||||
try {
|
||||
if (!thirdPayOrderService.save(payOrder)) {
|
||||
throw new RuntimeException("聚合支付子订单保存失败");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_AGGREGATE_SUB_ORDER_SAVE_FAIL);
|
||||
}
|
||||
} catch (RuntimeException exception) {
|
||||
thirdAppPlusAliPayService.cancel(context.getPayNo(), JSONUtil.toJsonStr(paySetting));
|
||||
log.error("|{}|支付宝JSAPI子订单保存失败,已执行最佳努力撤销,payNo:{}", TAG, context.getPayNo());
|
||||
throw new RuntimeException("创建支付宝支付订单失败,请重新扫码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALIPAY_JSAPI_CREATE_FAIL);
|
||||
}
|
||||
return new ThirdAggregateCashierLaunch(AppPlusPlatformTypeEnum.ALI_PAY, context.getPayNo(), payParams);
|
||||
}
|
||||
@@ -252,7 +254,7 @@ public class ThirdAggregateAliPayServiceImpl implements ThirdAggregateAliPayServ
|
||||
sdkConfig.setSignType("RSA2");
|
||||
alipayClient = new DefaultAlipayClient(sdkConfig);
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException("支付宝客户端初始化失败");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALIPAY_CLIENT_INIT_FAIL);
|
||||
}
|
||||
}
|
||||
return alipayClient;
|
||||
@@ -323,11 +325,11 @@ public class ThirdAggregateAliPayServiceImpl implements ThirdAggregateAliPayServ
|
||||
*/
|
||||
private MchPaySettingEntity.AliPaySetting parseAliPaySetting(MchPaySettingVo paySetting) {
|
||||
if (paySetting == null || StrUtil.isBlank(paySetting.getSettingJson())) {
|
||||
throw new RuntimeException("商户支付宝支付配置不完整");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_ALIPAY_CONFIG_INCOMPLETE);
|
||||
}
|
||||
MchPaySettingEntity.AliPaySetting setting = JSONUtil.toBean(paySetting.getSettingJson(), MchPaySettingEntity.AliPaySetting.class);
|
||||
if (setting == null || StrUtil.isBlank(setting.getSubMchid())) {
|
||||
throw new RuntimeException("商户支付宝直付通二级商户标识未配置");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_ALIPAY_SUB_MCH_MISSING);
|
||||
}
|
||||
return setting;
|
||||
}
|
||||
@@ -338,7 +340,7 @@ public class ThirdAggregateAliPayServiceImpl implements ThirdAggregateAliPayServ
|
||||
return;
|
||||
}
|
||||
if (mchFzRelationService == null) {
|
||||
throw new RuntimeException("支付宝平台分佣关系服务不可用");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_FZ_RELATION_UNAVAILABLE);
|
||||
}
|
||||
mchFzRelationService.requirePaymentRelation(context.getFzRelationId(), paySetting);
|
||||
}
|
||||
|
||||
+16
-14
@@ -1,6 +1,8 @@
|
||||
package com.bsd.pjcloud.thirdparty.service.impl.appplus;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.json.JSONObject;
|
||||
@@ -107,7 +109,7 @@ public class ThirdAggregateWechatPayServiceImpl implements ThirdAggregateWechatP
|
||||
AppPlusPayConfig.WechatConfig wechatConfig = appPlusPayConfig.getWechatConfig();
|
||||
if (StrUtil.isBlank(authCode) || wechatConfig == null
|
||||
|| StrUtil.hasBlank(wechatConfig.getGzhAppId(), wechatConfig.getGzhAppSecret())) {
|
||||
throw new RuntimeException("微信用户授权参数不完整");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_OAUTH_INCOMPLETE);
|
||||
}
|
||||
Map<String, Object> form = new LinkedHashMap<>();
|
||||
form.put("appid", wechatConfig.getGzhAppId());
|
||||
@@ -120,20 +122,20 @@ public class ThirdAggregateWechatPayServiceImpl implements ThirdAggregateWechatP
|
||||
.execute()) {
|
||||
if (!response.isOk()) {
|
||||
log.warn("|{}|微信用户授权HTTP失败,httpStatus:{}", TAG, response.getStatus());
|
||||
throw new RuntimeException("微信用户授权失败,请重新扫码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_OAUTH_FAIL);
|
||||
}
|
||||
JSONObject body = JSONUtil.parseObj(response.body());
|
||||
String spOpenId = body.getStr("openid");
|
||||
if (StrUtil.isBlank(spOpenId)) {
|
||||
log.warn("|{}|微信用户授权业务失败,errorCode:{}", TAG, body.getStr("errcode"));
|
||||
throw new RuntimeException("微信用户授权失败,请重新扫码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_OAUTH_FAIL);
|
||||
}
|
||||
return spOpenId;
|
||||
} catch (RuntimeException exception) {
|
||||
throw exception;
|
||||
} catch (Exception exception) {
|
||||
log.warn("|{}|微信用户授权异常,exceptionType:{}", TAG, exception.getClass().getSimpleName());
|
||||
throw new RuntimeException("微信用户授权失败,请重新扫码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_OAUTH_FAIL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +174,7 @@ public class ThirdAggregateWechatPayServiceImpl implements ThirdAggregateWechatP
|
||||
boolean enableFz = context.getFzRelationId() != null;
|
||||
if (enableFz) {
|
||||
if (mchFzRelationService == null) {
|
||||
throw new RuntimeException("微信平台分佣关系服务不可用");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_FZ_RELATION_UNAVAILABLE);
|
||||
}
|
||||
mchFzRelationService.requirePaymentRelation(context.getFzRelationId(), paySetting);
|
||||
}
|
||||
@@ -187,15 +189,15 @@ public class ThirdAggregateWechatPayServiceImpl implements ThirdAggregateWechatP
|
||||
String errorCode = StrUtil.blankToDefault(exception.getErrorCode(), "UNKNOWN");
|
||||
saveFailedOrder(payOrder, errorCode, exception.getClass().getSimpleName());
|
||||
log.warn("|{}|微信JSAPI子订单创建失败,payNo:{},errorCode:{}", TAG, context.getPayNo(), errorCode);
|
||||
throw new RuntimeException("创建微信支付订单失败,请重新扫码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_JSAPI_CREATE_FAIL);
|
||||
} catch (Exception exception) {
|
||||
saveFailedOrder(payOrder, "SDK_EXCEPTION", exception.getClass().getSimpleName());
|
||||
log.warn("|{}|微信JSAPI子订单创建异常,payNo:{},exceptionType:{}", TAG, context.getPayNo(), exception.getClass().getSimpleName());
|
||||
throw new RuntimeException("创建微信支付订单失败,请重新扫码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_JSAPI_CREATE_FAIL);
|
||||
}
|
||||
if (!isCompleteResponse(response)) {
|
||||
saveFailedOrder(payOrder, "INCOMPLETE_RESPONSE", null);
|
||||
throw new RuntimeException("创建微信支付订单失败,请重新扫码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_JSAPI_CREATE_FAIL);
|
||||
}
|
||||
|
||||
Map<String, Object> payParams = new LinkedHashMap<>();
|
||||
@@ -208,12 +210,12 @@ public class ThirdAggregateWechatPayServiceImpl implements ThirdAggregateWechatP
|
||||
payOrder.setPayRes(JSONUtil.createObj().set("aggregatePay", true).set("launchParams", payParams).toString());
|
||||
try {
|
||||
if (!thirdPayOrderService.save(payOrder)) {
|
||||
throw new RuntimeException("聚合支付子订单保存失败");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_AGGREGATE_SUB_ORDER_SAVE_FAIL);
|
||||
}
|
||||
} catch (RuntimeException exception) {
|
||||
close(context.getPayNo(), JSONUtil.toJsonStr(paySetting));
|
||||
log.error("|{}|微信JSAPI子订单保存失败,已执行最佳努力关单,payNo:{}", TAG, context.getPayNo());
|
||||
throw new RuntimeException("创建微信支付订单失败,请重新扫码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_JSAPI_CREATE_FAIL);
|
||||
}
|
||||
return new ThirdAggregateCashierLaunch(AppPlusPlatformTypeEnum.WECHAT, context.getPayNo(), payParams);
|
||||
}
|
||||
@@ -339,11 +341,11 @@ public class ThirdAggregateWechatPayServiceImpl implements ThirdAggregateWechatP
|
||||
*/
|
||||
private MchPaySettingEntity.WechatPaySetting parseWechatPaySetting(MchPaySettingVo paySetting) {
|
||||
if (paySetting == null || StrUtil.isBlank(paySetting.getSettingJson())) {
|
||||
throw new RuntimeException("商户微信支付配置不完整");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_WECHAT_CONFIG_INCOMPLETE);
|
||||
}
|
||||
MchPaySettingEntity.WechatPaySetting setting = JSONUtil.toBean(paySetting.getSettingJson(), MchPaySettingEntity.WechatPaySetting.class);
|
||||
if (setting == null || StrUtil.isBlank(setting.getSubMchid())) {
|
||||
throw new RuntimeException("商户微信子商户号未配置");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_WECHAT_SUB_MCH_MISSING);
|
||||
}
|
||||
return setting;
|
||||
}
|
||||
@@ -356,11 +358,11 @@ public class ThirdAggregateWechatPayServiceImpl implements ThirdAggregateWechatP
|
||||
*/
|
||||
private MchPaySettingEntity.WechatPaySetting parseWechatPaySettingSnapshot(String settingJson) {
|
||||
if (StrUtil.isBlank(settingJson)) {
|
||||
throw new RuntimeException("支付订单缺少商户配置快照");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PAY_ORDER_SNAPSHOT_MISSING);
|
||||
}
|
||||
MchPaySettingEntity snapshot = JSONUtil.toBean(settingJson, MchPaySettingEntity.class);
|
||||
if (snapshot == null || StrUtil.isBlank(snapshot.getSettingJson())) {
|
||||
throw new RuntimeException("支付订单商户配置快照无效");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PAY_ORDER_SNAPSHOT_INVALID);
|
||||
}
|
||||
MchPaySettingVo setting = new MchPaySettingVo();
|
||||
setting.setSettingJson(snapshot.getSettingJson());
|
||||
|
||||
+10
-9
@@ -48,6 +48,8 @@ import com.alipay.api.response.AlipayTradeSettleConfirmResponse;
|
||||
import com.alipay.api.response.AlipayTradeOrderSettleResponse;
|
||||
import com.alipay.api.response.AlipayTradeOrderSettleQueryResponse;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.thirdparty.config.AppPlusPayConfig;
|
||||
import com.bsd.pjcloud.thirdparty.constant.fz.ThirdMchFzRelationStatusEnum;
|
||||
import com.bsd.pjcloud.thirdparty.constant.miniplatform.AppPlusPlatformTypeEnum;
|
||||
@@ -207,7 +209,7 @@ public class ThirdAppPlusAliPayServiceImpl implements ThirdAppPlusAliPayService
|
||||
alipayClient = new DefaultAlipayClient(getAlipayConfig());
|
||||
} catch (Exception e) {
|
||||
log.error("初始化支付宝客户端失败", e);
|
||||
throw new RuntimeException("支付宝客户端初始化失败");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALIPAY_CLIENT_INIT_FAIL);
|
||||
}
|
||||
}
|
||||
return alipayClient;
|
||||
@@ -371,20 +373,19 @@ public class ThirdAppPlusAliPayServiceImpl implements ThirdAppPlusAliPayService
|
||||
payOrder.setPayRes(buildExceptionSnapshot(exception).toString());
|
||||
thirdPayOrderService.save(payOrder);
|
||||
log.error("|{}|支付宝订单码预创建异常,payNo:{},exceptionType:{}", TAG, dto.getOutTradeNo(), exception.getClass().getSimpleName());
|
||||
throw new RuntimeException("创建支付宝订单码失败,请稍后重试");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALI_QR_CREATE_FAIL);
|
||||
}
|
||||
|
||||
payOrder.setPayRes(buildPrecreateResponseSnapshot(response).toString());
|
||||
if (response == null || !response.isSuccess()) {
|
||||
payOrder.setStatus(ThirdPayOrderStatusEnum.PAY_FAILED.getType());
|
||||
thirdPayOrderService.save(payOrder);
|
||||
String errorCode = response == null ? "EMPTY_RESPONSE" : StrUtil.firstNonBlank(response.getSubCode(), response.getCode(), "UNKNOWN");
|
||||
throw new RuntimeException("创建支付宝订单码失败,支付宝错误码:" + errorCode);
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALI_QR_CREATE_FAIL);
|
||||
}
|
||||
if (StrUtil.isBlank(response.getQrCode())) {
|
||||
payOrder.setStatus(ThirdPayOrderStatusEnum.PAY_FAILED.getType());
|
||||
thirdPayOrderService.save(payOrder);
|
||||
throw new RuntimeException("创建支付宝订单码失败,支付宝未返回二维码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALI_QR_CREATE_FAIL);
|
||||
}
|
||||
|
||||
thirdPayOrderService.save(payOrder);
|
||||
@@ -449,12 +450,12 @@ public class ThirdAppPlusAliPayServiceImpl implements ThirdAppPlusAliPayService
|
||||
payOrder.setFzRelationId(dto.getFzRelationId());
|
||||
validateFzRatioAndRelation(dto, setting);
|
||||
if (dto.getAmount() == null || dto.getAmount() <= 0) {
|
||||
throw new RuntimeException("支付宝支付金额必须大于0分");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALI_AMOUNT_INVALID);
|
||||
}
|
||||
boolean enableFz = dto.getFzRelationId() != null;
|
||||
if (enableFz) {
|
||||
if (dto.getAmount() <= 10) {
|
||||
throw new RuntimeException("支付宝直付通支付金额必须大于10分");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALI_ZT_AMOUNT_MIN);
|
||||
}
|
||||
// 上层通常已经通过 requireBound 解析关系;底层再次核对是为了防止内部调用者伪造
|
||||
// fzRelationId,把其他商户、其他 smid 或尚未绑定的关系带入支付宝支付请求。
|
||||
@@ -539,7 +540,7 @@ public class ThirdAppPlusAliPayServiceImpl implements ThirdAppPlusAliPayService
|
||||
}
|
||||
if (refundFee == null || refundFee <= 0 || thirdPayOrder.getPrice() == null
|
||||
|| refundFee > thirdPayOrder.getPrice()) {
|
||||
throw new RuntimeException("支付宝退款金额必须大于0且不能超过订单金额");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALI_REFUND_AMOUNT_BAD);
|
||||
}
|
||||
|
||||
ThirdPayOrderEntity updateObj = new ThirdPayOrderEntity();
|
||||
@@ -1811,7 +1812,7 @@ public class ThirdAppPlusAliPayServiceImpl implements ThirdAppPlusAliPayService
|
||||
*/
|
||||
private MchPaySettingEntity.AliPaySetting parseAliPaySetting(MchPaySettingVo setting) {
|
||||
if (setting == null || StrUtil.isBlank(setting.getSettingJson())) {
|
||||
throw new RuntimeException("商户支付宝支付配置不完整");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_ALIPAY_CONFIG_INCOMPLETE);
|
||||
}
|
||||
MchPaySettingEntity.AliPaySetting aliPaySetting = JSONUtil.toBean(setting.getSettingJson(), MchPaySettingEntity.AliPaySetting.class);
|
||||
if (aliPaySetting == null || StrUtil.isBlank(aliPaySetting.getSubMchid())) {
|
||||
|
||||
+64
-62
@@ -23,6 +23,8 @@ import com.bsd.pjcloud.app.api.dto.AppUserInfo;
|
||||
import com.bsd.pjcloud.app.api.feign.RemoteAppUserService;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.hard.api.dto.order.remote.HardUpdateShopStatusDto;
|
||||
import com.bsd.pjcloud.hard.api.entity.order.HardOrderEntity;
|
||||
@@ -350,16 +352,16 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
try {
|
||||
bizId = Long.valueOf(dto.getBizId());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("充值业务id解析错误");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_RECHARGE_BIZ_ID_INVALID);
|
||||
}
|
||||
// 查询充值配置
|
||||
WalletRechargePackageEntity walletPackage = remoteWalletRechargePackageService.remoteGetById(bizId).getData();
|
||||
if (ObjectUtil.isEmpty(walletPackage)) {
|
||||
throw new RuntimeException("错误的充值配置");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PACKAGE_NOT_FOUND);
|
||||
}
|
||||
int price = walletPackage.getPayPrice();
|
||||
if (price <= 0) {
|
||||
throw new RuntimeException("错误的充值配置");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PACKAGE_AMOUNT_INVALID);
|
||||
}
|
||||
dto.setAmount(price);
|
||||
mchManage = getUserMerchant(userId);
|
||||
@@ -369,14 +371,14 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
try {
|
||||
rechargeId = Long.valueOf(dto.getBizId());
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException("代充值业务id解析错误");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PROXY_RECHARGE_BIZ_ID_INVALID);
|
||||
}
|
||||
// 类型 40 仍走统一 App 支付,只从待支付充值记录解析可信金额和目标饭卡。
|
||||
R<WalletRechargeEntity> rechargeResult = remoteWalletRechargeService.getRechargeById(rechargeId);
|
||||
WalletRechargeEntity recharge = rechargeResult == null || !rechargeResult.isOk() ? null : rechargeResult.getData();
|
||||
if (recharge == null || recharge.getWalletId() == null || recharge.getPackageId() == null || !Boolean.FALSE.equals(recharge.getPayStatus())
|
||||
|| recharge.getPayPrice() == null || recharge.getPayPrice() <= 0) {
|
||||
throw new RuntimeException("代充值记录不存在或金额无效");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PROXY_RECHARGE_INVALID);
|
||||
}
|
||||
R<com.bsd.pjcloud.wallet.api.vo.WalletManageVo> walletResult = remoteWalletService.getWalletById(recharge.getWalletId());
|
||||
WalletManageEntity wallet = walletResult == null || !walletResult.isOk() ? null : walletResult.getData();
|
||||
@@ -387,30 +389,30 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
|| ObjectUtil.equals(wallet.getStatus(), WalleCardStatusEnum.NONE_ACTIVE.getCode())
|
||||
|| ObjectUtil.equals(wallet.getStatus(), WalleCardStatusEnum.ACTIVE.getCode()));
|
||||
if (!walletSupportsRecharge) {
|
||||
throw new RuntimeException("目标饭卡当前不可充值");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WARD_WALLET_NO_RECHARGE);
|
||||
}
|
||||
R<List<Long>> relationResult = remoteUserRelationService.listActiveGuardianWardUserIds(userId);
|
||||
if (relationResult == null || !relationResult.isOk() || relationResult.getData() == null || !relationResult.getData().contains(wallet.getUserId())) {
|
||||
throw new RuntimeException("无权操作该被监护人");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_NO_WARD_PERM);
|
||||
}
|
||||
R<MchManageVo> merchantResult = remoteMchService.getViewsMchByDeptId(wallet.getDeptId(), List.of(MerchantTypeEnum.FARMER, MerchantTypeEnum.CANTEEN));
|
||||
mchManage = merchantResult == null || !merchantResult.isOk() ? null : merchantResult.getData();
|
||||
if (ObjectUtil.isEmpty(mchManage)) {
|
||||
throw new RuntimeException("饭卡所属食堂不存在");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_CARD_CANTEEN_MISSING);
|
||||
}
|
||||
// 支付创建时再次读取目标用户身份,防止待支付记录创建后商户身份配置变化导致越权充值。
|
||||
validateTopUpIdentity(mchManage, wallet.getUserId());
|
||||
dto.setAmount(recharge.getPayPrice());
|
||||
} else if (ObjectUtil.equals(dto.getBizType(), ThirdPayOrderBizTypeEnum.APP_SHOP_PAY)) {
|
||||
if (dto.getAmount() == null || dto.getAmount() <= 0) {
|
||||
throw new RuntimeException("支付金额不能小于等于0");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PAY_AMOUNT_GT_ZERO);
|
||||
}
|
||||
mchManage = resolveShopPayMerchant(userId, dto);
|
||||
} else {
|
||||
throw new RuntimeException("不支持的支付类型");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_UNSUPPORTED_PAY_TYPE);
|
||||
}
|
||||
if (ObjectUtil.isEmpty(mchManage) || ObjectUtil.isEmpty(mchManage.getPaySettingList())) {
|
||||
throw new RuntimeException("商户未配置支付参数");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PAY_METHOD_MISSING);
|
||||
}
|
||||
validateMerchantForPayment(mchManage);
|
||||
List<MchPaySettingVo> paySettingList = mchManage.getPaySettingList();
|
||||
@@ -441,7 +443,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
pollingCoordinator.wakePaymentCompensationPolling();
|
||||
}
|
||||
if (ObjectUtil.isEmpty(appPlusPayParams)) {
|
||||
throw new RuntimeException("创建微信支付错误");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WECHAT_PAY_CREATE_FAIL);
|
||||
}
|
||||
result.setAppPlusPayParams(appPlusPayParams);
|
||||
}
|
||||
@@ -457,7 +459,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
pollingCoordinator.wakePaymentCompensationPolling();
|
||||
}
|
||||
if (ObjectUtil.isEmpty(orderStr)) {
|
||||
throw new RuntimeException("创建支付宝支付错误");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALIPAY_PAY_CREATE_FAIL);
|
||||
}
|
||||
HashMap<String, Object> aliPayParams = new HashMap<String, Object>();
|
||||
aliPayParams.put("orderInfo", orderStr);
|
||||
@@ -465,7 +467,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
}
|
||||
// 不支持的支付类型
|
||||
else {
|
||||
throw new RuntimeException("不支持的支付类型");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_UNSUPPORTED_PAY_TYPE);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -477,12 +479,12 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
R<UserInfo> userResult = remoteUserService.getByUserId(userId);
|
||||
UserInfo userInfo = userResult == null || !userResult.isOk() ? null : userResult.getData();
|
||||
if (ObjectUtil.isEmpty(userInfo)) {
|
||||
throw new RuntimeException("用户不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_USER_NOT_EXIST);
|
||||
}
|
||||
R<MchManageVo> merchantResult = remoteMchService.getViewsMchByDeptId(userInfo.getSysUser().getDeptId(), List.of(MerchantTypeEnum.FARMER, MerchantTypeEnum.CANTEEN));
|
||||
MchManageVo merchant = merchantResult == null || !merchantResult.isOk() ? null : merchantResult.getData();
|
||||
if (ObjectUtil.isEmpty(merchant)) {
|
||||
throw new RuntimeException("用户不属于任何食堂或者商城");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_USER_NO_MCH);
|
||||
}
|
||||
return merchant;
|
||||
}
|
||||
@@ -510,10 +512,10 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
try {
|
||||
userResult = remoteUserService.getUserDeptByIds(List.of(targetUserId));
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException("查询充值用户身份失败", exception);
|
||||
throw new I18nBizException(ErrorCodes.WALLET_IDENTITY_QUERY_FAIL);
|
||||
}
|
||||
if (userResult == null || !userResult.isOk() || userResult.getData() == null || userResult.getData().isEmpty()) {
|
||||
throw new RuntimeException("查询充值用户身份失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_IDENTITY_QUERY_FAIL);
|
||||
}
|
||||
UserVO targetUser = userResult.getData().get(0);
|
||||
boolean allowed = targetUser.getIdentityTypes() != null && targetUser.getIdentityTypes().stream()
|
||||
@@ -521,7 +523,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
.map(String::trim)
|
||||
.anyMatch(allowedIdentityTypes::contains);
|
||||
if (!allowed) {
|
||||
throw new RuntimeException("当前人员身份不支持钱包充值");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_IDENTITY_NO_RECHARGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,13 +537,13 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
*/
|
||||
private MchManageVo resolveShopPayMerchant(Long userId, ThirdMiniAppPayDto dto) {
|
||||
if (!(dto instanceof ThirdMiniRemotePayDto remotePayDto) || remotePayDto.getMchId() == null) {
|
||||
throw new RuntimeException("商城支付缺少可信商户信息");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_SHOP_PAY_MCH_MISSING);
|
||||
}
|
||||
Long orderId;
|
||||
try {
|
||||
orderId = Long.valueOf(dto.getBizId());
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException("商城订单业务id解析错误");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_SHOP_ORDER_BIZ_ID_INVALID);
|
||||
}
|
||||
R<List<HardOrderEntity>> orderResult = remoteHardOrderService.getByIds(List.of(orderId));
|
||||
List<HardOrderEntity> orders = orderResult == null || !orderResult.isOk() ? null : orderResult.getData();
|
||||
@@ -549,17 +551,17 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
.filter(item -> item != null && ObjectUtil.equals(item.getId(), orderId))
|
||||
.findFirst().orElse(null);
|
||||
if (order == null || order.getMerchantId() == null || !ObjectUtil.equals(order.getUserId(), userId)) {
|
||||
throw new RuntimeException("商城订单不存在或无权支付");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_SHOP_ORDER_NO_PAY);
|
||||
}
|
||||
if (order.getPayPrice() == null || order.getPayPrice() <= 0 || ObjectUtil.notEqual(order.getPayPrice(), dto.getAmount())) {
|
||||
throw new RuntimeException("商城订单支付金额不一致");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_SHOP_ORDER_AMOUNT_MISMATCH);
|
||||
}
|
||||
if (!ObjectUtil.equals(order.getMerchantId(), remotePayDto.getMchId())) {
|
||||
throw new RuntimeException("商城订单收款商户不一致");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_SHOP_ORDER_MCH_MISMATCH);
|
||||
}
|
||||
MchManageVo merchant = getMerchantById(order.getMerchantId());
|
||||
if (merchant == null) {
|
||||
throw new RuntimeException("商城订单收款商户不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_MCH_NOT_FOUND);
|
||||
}
|
||||
return merchant;
|
||||
}
|
||||
@@ -571,10 +573,10 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
*/
|
||||
private void validateMerchantForPayment(MchManageVo merchant) {
|
||||
if (merchant == null || merchant.getId() == null) {
|
||||
throw new RuntimeException("收款商户不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_MCH_NOT_FOUND);
|
||||
}
|
||||
if (ObjectUtil.equals(merchant.getCooperationStatus(), YesNoEnum.NO.getCode())) {
|
||||
throw new RuntimeException("收款商户已停用");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_PAY_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,17 +605,17 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
if (ObjectUtil.equals(dto.getMiniPlatformType(), AppPlusPlatformTypeEnum.ZAX_APP_WALLET)) {
|
||||
UserInfo userInfo = remoteUserService.getByUserId(dto.getUserId()).getData();
|
||||
if (ObjectUtil.isEmpty(userInfo)) {
|
||||
throw new RuntimeException("用户不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_USER_NOT_EXIST);
|
||||
}
|
||||
mchManage = remoteMchService.getViewsCanteenMchByDeptId(userInfo.getSysUser().getDeptId()).getData();
|
||||
} else {
|
||||
mchManage = remoteMchService.getById(dto.getMchId()).getData();
|
||||
}
|
||||
if (ObjectUtil.isEmpty(mchManage)) {
|
||||
throw new RuntimeException("用户不属于任何食堂");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_USER_NO_CANTEEN);
|
||||
}
|
||||
if (ObjectUtil.isEmpty(mchManage.getPaySettingList())) {
|
||||
throw new RuntimeException("商户未配置支付参数");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PAY_METHOD_MISSING);
|
||||
}
|
||||
|
||||
List<MchPaySettingVo> paySettingList = mchManage.getPaySettingList();
|
||||
@@ -622,7 +624,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
}
|
||||
// 不支持的类型
|
||||
else {
|
||||
throw new RuntimeException("不支持的支付类型");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_UNSUPPORTED_PAY_TYPE);
|
||||
}
|
||||
|
||||
ThirdAppPlusPayDto appPlusPayDto = new ThirdAppPlusPayDto();
|
||||
@@ -644,7 +646,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), AppPlusPlatformTypeEnum.WECHAT.getType())) {
|
||||
MchPaySettingVo paySetting = paySettingList.stream().filter(item -> ObjectUtil.equals(item.getPlatformType(), AppPlusPlatformPayType.WECHAT.getType())).findFirst().orElse(null);
|
||||
if (ObjectUtil.isEmpty(paySetting)) {
|
||||
throw new RuntimeException("商户未配置微信支付参数");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_WECHAT_PAY_CONFIG_MISSING);
|
||||
}
|
||||
paySetting = applyDefaultPaymentRelation(paySetting, appPlusPayDto);
|
||||
|
||||
@@ -657,13 +659,13 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
else if (ObjectUtil.equals(dto.getMiniPlatformType().getType(), AppPlusPlatformTypeEnum.ALI_PAY.getType())) {
|
||||
MchPaySettingVo paySetting = paySettingList.stream().filter(item -> ObjectUtil.equals(item.getPlatformType(), AppPlusPlatformPayType.ALI_PAY.getType())).findFirst().orElse(null);
|
||||
if (ObjectUtil.isEmpty(paySetting)) {
|
||||
throw new RuntimeException("商户未配置微信支付参数");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_ALIPAY_PAY_CONFIG_MISSING);
|
||||
}
|
||||
applyDefaultPaymentRelation(paySetting, appPlusPayDto);
|
||||
}
|
||||
// 不支持的支付类型
|
||||
else {
|
||||
throw new RuntimeException("不支持的支付类型");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_UNSUPPORTED_PAY_TYPE);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -681,7 +683,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
String lockToken = UUID.randomUUID().toString();
|
||||
Boolean lockAcquired = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, lockToken, ORDER_CODE_LOCK_TTL);
|
||||
if (!Boolean.TRUE.equals(lockAcquired)) {
|
||||
throw new RuntimeException("订单码支付正在处理中,请勿重复提交");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ORDER_CODE_PROCESSING);
|
||||
}
|
||||
try {
|
||||
ThirdOrderCodePayVo result = createOrReuseOrderCodePay(dto);
|
||||
@@ -698,13 +700,13 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
@Override
|
||||
public ThirdOrderCodePayStatusVo getOrderCodePayStatus(String payNo) {
|
||||
if (StrUtil.isBlank(payNo)) {
|
||||
throw new RuntimeException("支付订单号不能为空");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PAY_NO_EMPTY);
|
||||
}
|
||||
ThirdPayOrderEntity payOrder = thirdPayOrderService.getByPayNo(payNo);
|
||||
if (payOrder == null
|
||||
|| ObjectUtil.notEqual(payOrder.getBizType(), ThirdPayOrderBizTypeEnum.YXFJ_PAY.getType())
|
||||
|| !isSupportedOrderCodePlatform(payOrder.getPayPlatformType())) {
|
||||
throw new RuntimeException("订单码支付订单不存在");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ORDER_CODE_NOT_FOUND);
|
||||
}
|
||||
ThirdOrderCodePayStatusVo result = new ThirdOrderCodePayStatusVo();
|
||||
result.setPayNo(payOrder.getPayNo());
|
||||
@@ -742,19 +744,19 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
private ThirdOrderCodePayVo createOrReuseOrderCodePay(ThirdOrderCodePayDto dto) {
|
||||
thirdAggregateOrderPayService.assertNoBlockingAggregateSession(dto.getBizType(), dto.getBizId());
|
||||
if (hasSuccessfulOrderCodePay(dto.getBizType(), dto.getBizId())) {
|
||||
throw new RuntimeException("该业务订单已支付,请勿重复下单");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ORDER_ALREADY_PAID);
|
||||
}
|
||||
ThirdPayOrderEntity latestOrder = getLatestOrderCodePay(dto.getBizType(), dto.getBizId());
|
||||
if (latestOrder != null) {
|
||||
if (ObjectUtil.equals(latestOrder.getStatus(), ThirdPayOrderStatusEnum.PAY_SUCCESS.getType())) {
|
||||
throw new RuntimeException("该业务订单已支付,请勿重复下单");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ORDER_ALREADY_PAID);
|
||||
}
|
||||
if (ObjectUtil.equals(latestOrder.getStatus(), ThirdPayOrderStatusEnum.PAY_UNPAID.getType())) {
|
||||
validateReusableOrder(latestOrder, dto);
|
||||
String qrCode = getOrderCodeQrCode(latestOrder);
|
||||
if (latestOrder.getExpireTime() != null && latestOrder.getExpireTime().isAfter(LocalDateTime.now()) && StrUtil.isNotBlank(qrCode)) {
|
||||
if (ObjectUtil.notEqual(latestOrder.getPayPlatformType(), dto.getMiniPlatformType().getType())) {
|
||||
throw new RuntimeException("该业务订单已有其他平台的待支付订单码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ORDER_CODE_OTHER_PLATFORM);
|
||||
}
|
||||
return buildOrderCodePayVo(latestOrder, qrCode);
|
||||
}
|
||||
@@ -763,13 +765,13 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
queryPayResult(latestOrder);
|
||||
latestOrder = thirdPayOrderService.getById(latestOrder.getId());
|
||||
if (latestOrder != null && ObjectUtil.equals(latestOrder.getStatus(), ThirdPayOrderStatusEnum.PAY_SUCCESS.getType())) {
|
||||
throw new RuntimeException("该业务订单已支付,请勿重复下单");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ORDER_ALREADY_PAID);
|
||||
}
|
||||
if (latestOrder != null && ObjectUtil.equals(latestOrder.getStatus(), ThirdPayOrderStatusEnum.PAY_UNPAID.getType())) {
|
||||
if (latestOrder.getExpireTime() != null && latestOrder.getExpireTime().isAfter(LocalDateTime.now())) {
|
||||
throw new RuntimeException("订单码数据异常,请稍后重试");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ORDER_CODE_DATA_ERROR);
|
||||
}
|
||||
throw new RuntimeException("上一笔订单正在确认关闭,请稍后重试");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ORDER_CLOSING);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -830,22 +832,22 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
*/
|
||||
private void validateOrderCodePayRequest(ThirdOrderCodePayDto dto) {
|
||||
if (dto == null) {
|
||||
throw new RuntimeException("订单码支付参数不能为空");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ORDER_CODE_PARAM_EMPTY);
|
||||
}
|
||||
if (ObjectUtil.notEqual(dto.getBizType(), ThirdPayOrderBizTypeEnum.YXFJ_PAY)) {
|
||||
throw new RuntimeException("订单码支付仅支持云消费机支付业务");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ORDER_CODE_BIZ_ONLY);
|
||||
}
|
||||
if (dto.getMiniPlatformType() == null || !isSupportedOrderCodePlatform(dto.getMiniPlatformType().getType())) {
|
||||
throw new RuntimeException("订单码支付仅支持支付宝或微信");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ORDER_CODE_PLATFORM_ONLY);
|
||||
}
|
||||
if (StrUtil.isBlank(dto.getBizId())) {
|
||||
throw new RuntimeException("支付业务id不能为空");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PAY_BIZ_ID_EMPTY);
|
||||
}
|
||||
if (dto.getMchId() == null) {
|
||||
throw new RuntimeException("商户id不能为空");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_MCH_ID_EMPTY);
|
||||
}
|
||||
if (dto.getAmount() == null || dto.getAmount() <= 0) {
|
||||
throw new RuntimeException("支付金额必须大于0");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PAY_AMOUNT_GT_ZERO);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -882,7 +884,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
*/
|
||||
private void validateReusableOrder(ThirdPayOrderEntity payOrder, ThirdOrderCodePayDto dto) {
|
||||
if (ObjectUtil.notEqual(payOrder.getMchId(), dto.getMchId()) || ObjectUtil.notEqual(payOrder.getPrice(), dto.getAmount())) {
|
||||
throw new RuntimeException("该业务订单已有不同金额或商户的待支付订单");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ORDER_PENDING_MISMATCH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -919,13 +921,13 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
R<MchManageVo> merchantResult = remoteMchService.getById(mchId);
|
||||
MchManageVo merchant = merchantResult == null || !merchantResult.isOk() ? null : merchantResult.getData();
|
||||
if (merchant == null) {
|
||||
throw new RuntimeException("收款商户不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_MCH_NOT_FOUND);
|
||||
}
|
||||
if (merchant.getId() == null || ObjectUtil.notEqual(merchant.getId(), mchId)) {
|
||||
throw new RuntimeException("收款商户信息不一致");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_INFO_MISMATCH);
|
||||
}
|
||||
if (ObjectUtil.isEmpty(merchant.getPaySettingList())) {
|
||||
throw new RuntimeException("商户未配置支付参数");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PAY_METHOD_MISSING);
|
||||
}
|
||||
return merchant;
|
||||
}
|
||||
@@ -946,7 +948,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (paySetting == null) {
|
||||
throw new RuntimeException("商户未启用支付宝支付配置");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_ALIPAY_CONFIG_DISABLED);
|
||||
}
|
||||
return paySetting;
|
||||
}
|
||||
@@ -961,7 +963,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (paySetting == null) {
|
||||
throw new RuntimeException("商户未启用微信支付配置");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_WECHAT_CONFIG_DISABLED);
|
||||
}
|
||||
return paySetting;
|
||||
}
|
||||
@@ -973,7 +975,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
AppPlusPayConfig.AliPayConfig config = appPlusPayConfig.getAliPayConfig();
|
||||
if (config == null || StrUtil.hasBlank(config.getAppId(), config.getAppPrivateKey(), config.getAlipayPublicKey(),
|
||||
config.getBaseCallbackUrl(), config.getPayCallbackUrl())) {
|
||||
throw new RuntimeException("支付宝应用支付配置不完整");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_ALIPAY_APP_CONFIG_INCOMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -985,7 +987,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
if (config == null || StrUtil.hasBlank(config.getAppPlatformAppId(), config.getMerchantId(),
|
||||
config.getMchPrivatePath(), config.getMerchantSerialNumber(), config.getApiV3Key(),
|
||||
config.getBaseCallbackUrl(), config.getPayCallbackUrl())) {
|
||||
throw new RuntimeException("微信服务商支付配置不完整");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WECHAT_APP_CONFIG_INCOMPLETE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1037,7 +1039,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
ThirdPayOrderEntity thirdPayOrder = thirdPayOrderService.getByPayNo(dto.getPayNo());
|
||||
if (ObjectUtil.isEmpty(thirdPayOrder)) {
|
||||
log.error("|{}|小程序退款错误,订单不存在dto:|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
throw new RuntimeException("订单不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
}
|
||||
try {
|
||||
// 微信小程序
|
||||
@@ -1054,7 +1056,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
}
|
||||
// 不支持的支付类型
|
||||
else {
|
||||
throw new RuntimeException("不支持的支付类型");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_UNSUPPORTED_PAY_TYPE);
|
||||
}
|
||||
} finally {
|
||||
pollingCoordinator.wakePaymentCompensationPolling();
|
||||
@@ -1071,7 +1073,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
ThirdPayOrderEntity thirdPayOrder = thirdPayOrderService.getByBiz(dto.getBizType(), String.valueOf(dto.getOrderId()));
|
||||
if (ObjectUtil.isEmpty(thirdPayOrder)) {
|
||||
log.error("|{}|远程退款,订单不存在dto:|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
throw new RuntimeException("订单不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_ORDER_NOT_FOUND);
|
||||
}
|
||||
|
||||
String expectedRefundNo = dto.getAfterSaleId() == null ? "refund_" + thirdPayOrder.getPayNo()
|
||||
@@ -1081,7 +1083,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
if (ObjectUtil.equals(thirdPayOrder.getRefundNo(), expectedRefundNo)) {
|
||||
return thirdPayOrder.getRefundNo();
|
||||
}
|
||||
throw new RuntimeException("上一笔退款仍在处理中,请稍后重试");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_REFUND_PROCESSING);
|
||||
}
|
||||
// 同一售后单的远程重试直接返回原退款号,避免渠道重复受理同一笔金额。
|
||||
if (ObjectUtil.equals(thirdPayOrder.getStatus(), ThirdPayOrderStatusEnum.REFUND_SUCCESS.getType())
|
||||
@@ -1113,7 +1115,7 @@ public class ThirdAppPlusServiceImpl implements ThirdAppPlusService {
|
||||
}
|
||||
// 不支持的支付类型
|
||||
else {
|
||||
throw new RuntimeException("不支持的支付类型");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_UNSUPPORTED_PAY_TYPE);
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
|
||||
+10
-8
@@ -1,6 +1,8 @@
|
||||
package com.bsd.pjcloud.thirdparty.service.impl.appplus;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.bsd.pjcloud.thirdparty.config.AppPlusPayConfig;
|
||||
@@ -110,7 +112,7 @@ public class ThirdAppPlusWechatNativePayServiceImpl implements ThirdAppPlusWecha
|
||||
boolean enableFz = dto.getFzRelationId() != null;
|
||||
if (enableFz) {
|
||||
if (mchFzRelationService == null) {
|
||||
throw new RuntimeException("微信平台分佣关系服务不可用");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_FZ_RELATION_UNAVAILABLE);
|
||||
}
|
||||
mchFzRelationService.requirePaymentRelation(dto.getFzRelationId(), setting);
|
||||
}
|
||||
@@ -125,16 +127,16 @@ public class ThirdAppPlusWechatNativePayServiceImpl implements ThirdAppPlusWecha
|
||||
String errorCode = StrUtil.blankToDefault(exception.getErrorCode(), "UNKNOWN");
|
||||
saveFailedOrder(payOrder, errorCode, exception.getClass().getSimpleName());
|
||||
log.error("|{}|创建微信订单码失败,payNo:{},errorCode:{}", TAG, dto.getOutTradeNo(), errorCode);
|
||||
throw new RuntimeException("创建微信订单码失败,微信错误码:" + errorCode);
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_NATIVE_CREATE_FAIL_CODE, errorCode);
|
||||
} catch (Exception exception) {
|
||||
saveFailedOrder(payOrder, "SDK_EXCEPTION", exception.getClass().getSimpleName());
|
||||
log.error("|{}|创建微信订单码异常,payNo:{},exceptionType:{}", TAG, dto.getOutTradeNo(), exception.getClass().getSimpleName());
|
||||
throw new RuntimeException("创建微信订单码失败,请稍后重试");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_NATIVE_CREATE_FAIL);
|
||||
}
|
||||
|
||||
if (response == null || StrUtil.isBlank(response.getCodeUrl())) {
|
||||
saveFailedOrder(payOrder, response == null ? "EMPTY_RESPONSE" : "EMPTY_CODE_URL", null);
|
||||
throw new RuntimeException("创建微信订单码失败,微信未返回二维码");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_NATIVE_NO_QR);
|
||||
}
|
||||
|
||||
JSONObject responseSnapshot = JSONUtil.createObj().set("qrCode", response.getCodeUrl());
|
||||
@@ -251,11 +253,11 @@ public class ThirdAppPlusWechatNativePayServiceImpl implements ThirdAppPlusWecha
|
||||
*/
|
||||
private MchPaySettingEntity.WechatPaySetting parseWechatPaySetting(MchPaySettingVo setting) {
|
||||
if (setting == null || StrUtil.isBlank(setting.getSettingJson())) {
|
||||
throw new RuntimeException("商户微信支付配置不完整");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_WECHAT_CONFIG_INCOMPLETE);
|
||||
}
|
||||
MchPaySettingEntity.WechatPaySetting wechatPaySetting = JSONUtil.toBean(setting.getSettingJson(), MchPaySettingEntity.WechatPaySetting.class);
|
||||
if (wechatPaySetting == null || StrUtil.isBlank(wechatPaySetting.getSubMchid())) {
|
||||
throw new RuntimeException("商户微信子商户号未配置");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_WECHAT_SUB_MCH_MISSING);
|
||||
}
|
||||
return wechatPaySetting;
|
||||
}
|
||||
@@ -268,11 +270,11 @@ public class ThirdAppPlusWechatNativePayServiceImpl implements ThirdAppPlusWecha
|
||||
*/
|
||||
private MchPaySettingEntity.WechatPaySetting parseWechatPaySettingSnapshot(String settingJson) {
|
||||
if (StrUtil.isBlank(settingJson)) {
|
||||
throw new RuntimeException("支付订单缺少商户配置快照");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PAY_ORDER_SNAPSHOT_MISSING);
|
||||
}
|
||||
MchPaySettingEntity settingSnapshot = JSONUtil.toBean(settingJson, MchPaySettingEntity.class);
|
||||
if (settingSnapshot == null) {
|
||||
throw new RuntimeException("支付订单商户配置快照无效");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PAY_ORDER_SNAPSHOT_INVALID);
|
||||
}
|
||||
MchPaySettingVo setting = new MchPaySettingVo();
|
||||
setting.setSettingJson(settingSnapshot.getSettingJson());
|
||||
|
||||
+13
-11
@@ -12,6 +12,8 @@ import cn.hutool.core.util.XmlUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.thirdparty.config.AppPlusPayConfig;
|
||||
import com.bsd.pjcloud.thirdparty.constant.miniplatform.AppPlusPlatformTypeEnum;
|
||||
import com.bsd.pjcloud.thirdparty.constant.pay.ThirdPayOrderBizTypeEnum;
|
||||
@@ -190,22 +192,22 @@ public class ThirdAppPlusWechatServiceImpl implements ThirdAppPlusWechatService
|
||||
private MchPaySettingEntity.WechatPaySetting validateWechatAppPaySetting(ThirdAppPlusPayDto dto,
|
||||
MchPaySettingVo setting) {
|
||||
if (dto == null || dto.getAmount() == null || dto.getAmount() <= 0) {
|
||||
throw new RuntimeException("微信支付金额必须大于0");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PAY_AMOUNT_GT_ZERO);
|
||||
}
|
||||
if (setting == null || StrUtil.isBlank(setting.getSettingJson())) {
|
||||
throw new RuntimeException("商户微信支付配置不完整");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_WECHAT_CONFIG_INCOMPLETE);
|
||||
}
|
||||
MchPaySettingEntity.WechatPaySetting wechatPaySetting = JSONUtil.toBean(
|
||||
setting.getSettingJson(), MchPaySettingEntity.WechatPaySetting.class);
|
||||
if (wechatPaySetting == null || StrUtil.isBlank(wechatPaySetting.getSubMchid())) {
|
||||
throw new RuntimeException("微信支付子商户号未配置");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_MCH_WECHAT_SUB_MCH_MISSING);
|
||||
}
|
||||
if (dto.getFzRelationId() == null) {
|
||||
return wechatPaySetting;
|
||||
}
|
||||
ThirdMchFzRelationEntity relation = mchFzRelationService.requirePaymentRelation(dto.getFzRelationId(), setting);
|
||||
if (dto.getAmount() <= 10) {
|
||||
throw new RuntimeException("微信分账支付金额必须大于10分");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_PROFIT_AMOUNT_MIN);
|
||||
}
|
||||
long fzAmount = BigDecimal.valueOf(dto.getAmount())
|
||||
.multiply(BigDecimal.valueOf(relation.getFzRatio()))
|
||||
@@ -213,7 +215,7 @@ public class ThirdAppPlusWechatServiceImpl implements ThirdAppPlusWechatService
|
||||
// 微信分账单笔金额至少1分,低比例向下取整为0时按1分提交。
|
||||
fzAmount = Math.max(1L, fzAmount);
|
||||
if (fzAmount > dto.getAmount()) {
|
||||
throw new RuntimeException("微信平台抽佣金额必须不少于1分且不能超过订单金额");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_PROFIT_AMOUNT_RANGE);
|
||||
}
|
||||
return wechatPaySetting;
|
||||
}
|
||||
@@ -325,13 +327,13 @@ public class ThirdAppPlusWechatServiceImpl implements ThirdAppPlusWechatService
|
||||
AppPlusPayConfig.WechatConfig wechatConfig = appPlusPayConfig.getWechatConfig();
|
||||
|
||||
if (ObjectUtil.isEmpty(thirdPayOrder.getMchPaySettingJson())) {
|
||||
throw new RuntimeException("支付配置不存在");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PAY_CONFIG_MISSING);
|
||||
}
|
||||
|
||||
MchPaySettingEntity wechatPaySettingEntity = JSONUtil.toBean(thirdPayOrder.getMchPaySettingJson(), MchPaySettingEntity.class);
|
||||
MchPaySettingEntity.WechatPaySetting wechatPaySetting = JSONUtil.toBean(wechatPaySettingEntity.getSettingJson(), MchPaySettingEntity.WechatPaySetting.class);
|
||||
if (wechatPaySetting == null || StrUtil.isBlank(wechatPaySetting.getSubMchid())) {
|
||||
throw new RuntimeException("微信支付配置快照无效");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PAY_ORDER_SNAPSHOT_INVALID);
|
||||
}
|
||||
|
||||
ThirdPayOrderEntity updateObj = new ThirdPayOrderEntity();
|
||||
@@ -349,7 +351,7 @@ public class ThirdAppPlusWechatServiceImpl implements ThirdAppPlusWechatService
|
||||
}
|
||||
if (refundFee == null || refundFee <= 0 || thirdPayOrder.getPrice() == null
|
||||
|| refundFee > thirdPayOrder.getPrice()) {
|
||||
throw new RuntimeException("微信退款金额必须大于0且不能超过订单金额");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_REFUND_AMOUNT_BAD);
|
||||
}
|
||||
String refundNo = dto.getAfterSaleId() == null ? "refund_" + thirdPayOrder.getPayNo()
|
||||
: "refund_" + dto.getAfterSaleId();
|
||||
@@ -383,7 +385,7 @@ public class ThirdAppPlusWechatServiceImpl implements ThirdAppPlusWechatService
|
||||
|| ObjectUtil.equals(latest.getStatus(), ThirdPayOrderStatusEnum.REFUND_SUCCESS.getType()))) {
|
||||
return latest;
|
||||
}
|
||||
throw new RuntimeException("支付订单当前状态不允许退款");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PAY_ORDER_STATUS_NO_REFUND);
|
||||
}
|
||||
|
||||
// 先持久化普通退款请求,再使用稳定分账退款号发起退分账;两条链路均可由数据库轮询恢复。
|
||||
@@ -393,12 +395,12 @@ public class ThirdAppPlusWechatServiceImpl implements ThirdAppPlusWechatService
|
||||
try {
|
||||
Refund refund = refundService.create(createRequest);
|
||||
if (ObjectUtil.isEmpty(refund)) {
|
||||
throw new RuntimeException("微信退款申请错误异常");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_REFUND_APPLY_ERROR);
|
||||
}
|
||||
saveWechatRefundResponse(thirdPayOrder.getId(), refundNo, refund);
|
||||
} catch (Exception e) {
|
||||
log.error("|{}|AP申请退款,异常", TAG, e);
|
||||
throw new RuntimeException("微信退款请求已进入补偿队列,请稍后查询结果");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_WX_REFUND_QUEUED);
|
||||
} finally {
|
||||
// 退款订单已先原子推进到 REFUNDING,渠道异常也必须留下稳定退款号对应的查单任务。
|
||||
if (paymentTaskEnqueuer != null) {
|
||||
|
||||
+3
-1
@@ -3,6 +3,8 @@ import com.bsd.pjcloud.common.api.encrypt.annotation.crypto.ApiCryptoAes;
|
||||
|
||||
import com.bsd.pjcloud.admin.api.dto.UserDTO;
|
||||
import com.bsd.pjcloud.admin.service.SysUserService;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.log.annotation.SysLog;
|
||||
import com.bsd.pjcloud.common.security.annotation.Inner;
|
||||
@@ -46,7 +48,7 @@ public class RegisterController {
|
||||
@SysLog("注册用户")
|
||||
@PostMapping("/default-user")
|
||||
public R<Boolean> registerDefaultUser(@RequestBody UserDTO userDto) {
|
||||
return R.failed("暂时停止注册!");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_REGISTER_SUSPENDED));
|
||||
|
||||
// return R.ok(userService.registerDefaultUser(userDto));
|
||||
}
|
||||
|
||||
+7
-5
@@ -13,6 +13,8 @@ import com.bsd.pjcloud.admin.service.SysDeptBuildingService;
|
||||
import com.bsd.pjcloud.admin.service.SysDeptBuildingUnitService;
|
||||
import com.bsd.pjcloud.admin.service.SysDeptService;
|
||||
import com.bsd.pjcloud.admin.service.SysUserAddressService;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.log.annotation.SysLog;
|
||||
import com.bsd.pjcloud.common.security.annotation.Inner;
|
||||
@@ -78,10 +80,10 @@ public class SysUserAddressController {
|
||||
Long deptId = SecurityUtils.getUser().getDeptId();
|
||||
SysDeptBuildingEntity building = sysDeptBuildingService.getById(buildingId);
|
||||
if (building == null) {
|
||||
return R.failed("楼栋不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ADDRESS_BUILDING_NOT_FOUND));
|
||||
}
|
||||
if (!Objects.equals(building.getDeptId(), deptId)) {
|
||||
return R.failed("无权访问该楼栋");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ADDRESS_BUILDING_NO_ACCESS));
|
||||
}
|
||||
List<SysDeptBuildingUnitEntity> list = sysDeptBuildingUnitService.listByBuildingId(buildingId);
|
||||
List<SimpleOptionVo> options = list == null ? List.of() : list.stream()
|
||||
@@ -98,14 +100,14 @@ public class SysUserAddressController {
|
||||
Long deptId = SecurityUtils.getUser().getDeptId();
|
||||
SysDeptBuildingUnitEntity unit = sysDeptBuildingUnitService.getById(unitId);
|
||||
if (unit == null) {
|
||||
return R.failed("单元不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ADDRESS_UNIT_NOT_FOUND));
|
||||
}
|
||||
SysDeptBuildingEntity building = sysDeptBuildingService.getById(unit.getBuildingId());
|
||||
if (building == null) {
|
||||
return R.failed("楼栋不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ADDRESS_BUILDING_NOT_FOUND));
|
||||
}
|
||||
if (!Objects.equals(building.getDeptId(), deptId)) {
|
||||
return R.failed("无权访问该单元");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.ADDRESS_UNIT_NO_ACCESS));
|
||||
}
|
||||
List<SysDeptBuildingRoomEntity> list = sysDeptBuildingRoomService.listByUnitId(unitId);
|
||||
List<SimpleOptionVo> options = list == null ? List.of() : list.stream()
|
||||
|
||||
+3
-1
@@ -10,6 +10,8 @@ import com.bsd.pjcloud.admin.mapper.SysSocialDetailsMapper;
|
||||
import com.bsd.pjcloud.admin.service.SysUserService;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.LoginTypeEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.CheckedException;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -32,7 +34,7 @@ public class AppleLoginHandler extends AbstractLoginHandler {
|
||||
condition.setType(LoginTypeEnum.APPLE.getType());
|
||||
SysSocialDetails socialDetails = sysSocialDetailsMapper.selectOne(new QueryWrapper<>(condition));
|
||||
if (socialDetails == null) {
|
||||
throw new CheckedException("未配置Apple登录");
|
||||
throw new CheckedException(MsgUtils.getMessage(ErrorCodes.AUTH_APPLE_NOT_CONFIGURED));
|
||||
}
|
||||
String sub = AppleIdentityTokenVerifier.verifyAndGetSubject(identityToken, socialDetails.getAppId());
|
||||
log.debug("Apple identityToken 校验通过, sub={}", sub);
|
||||
|
||||
+3
-1
@@ -30,6 +30,8 @@ import com.bsd.pjcloud.admin.service.SysUserService;
|
||||
import com.bsd.pjcloud.common.core.constant.SecurityConstants;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.LoginTypeEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.CheckedException;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -71,7 +73,7 @@ public class MiniAppLoginHandler extends AbstractLoginHandler {
|
||||
|
||||
if (resultJsonObj.containsKey("errcode")) {
|
||||
log.error("微信小程序登录失败:{}", result);
|
||||
throw new CheckedException("微信小程序登录失败");
|
||||
throw new CheckedException(MsgUtils.getMessage(ErrorCodes.AUTH_MINI_APP_LOGIN_FAIL));
|
||||
}
|
||||
|
||||
Object obj = resultJsonObj.get("openid");
|
||||
|
||||
+4
-2
@@ -30,6 +30,8 @@ import com.bsd.pjcloud.admin.service.SysUserService;
|
||||
import com.bsd.pjcloud.common.core.constant.SecurityConstants;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.LoginTypeEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.CheckedException;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -69,13 +71,13 @@ public class WeChatLoginHandler extends AbstractLoginHandler {
|
||||
if (resultJsonObj.containsKey("errcode")) {
|
||||
log.error("微信授权失败:{}", result);
|
||||
String errMsg = resultJsonObj.getStr("errmsg", "微信授权失败");
|
||||
throw new CheckedException("微信授权失败:" + errMsg);
|
||||
throw new CheckedException(MsgUtils.getMessage(ErrorCodes.AUTH_WX_AUTH_FAIL, errMsg));
|
||||
}
|
||||
|
||||
Object obj = resultJsonObj.get("openid");
|
||||
if (obj == null) {
|
||||
log.error("微信响应缺少openid:{}", result);
|
||||
throw new CheckedException("微信授权失败,未获取到用户标识");
|
||||
throw new CheckedException(MsgUtils.getMessage(ErrorCodes.AUTH_WX_OPENID_MISSING));
|
||||
}
|
||||
return obj.toString();
|
||||
}
|
||||
|
||||
+3
-1
@@ -7,6 +7,8 @@ import com.bsd.pjcloud.admin.api.entity.SysUser;
|
||||
import com.bsd.pjcloud.admin.service.SysUserService;
|
||||
import com.bsd.pjcloud.common.core.constant.CacheConstants;
|
||||
import com.bsd.pjcloud.common.core.exception.CheckedException;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
@@ -39,7 +41,7 @@ public class WxTicketLoginHandler implements LoginHandler {
|
||||
public String identify(String ticket) {
|
||||
String openid = redisTemplate.opsForValue().get(ticketKey(ticket));
|
||||
if (StrUtil.isBlank(openid)) {
|
||||
throw new CheckedException("微信授权已过期,请重新授权");
|
||||
throw new CheckedException(MsgUtils.getMessage(ErrorCodes.AUTH_WX_AUTH_EXPIRED));
|
||||
}
|
||||
redisTemplate.delete(ticketKey(ticket));
|
||||
return openid;
|
||||
|
||||
+1
-1
@@ -292,7 +292,7 @@ public class SysMessageServiceImpl extends ServiceImpl<SysMessageMapper, SysMess
|
||||
} catch (Exception e) {
|
||||
redisTemplate.delete(redisKey);
|
||||
log.error("发送短信验证码失败: mobile={}", mobile, e);
|
||||
return R.failed("短信验证码发送失败,请稍后重试");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_APP_SMS_SEND_FAIL));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-2
@@ -31,6 +31,9 @@ import com.bsd.pjcloud.admin.mapper.SysUserMapper;
|
||||
import com.bsd.pjcloud.admin.service.SysSocialDetailsService;
|
||||
import com.bsd.pjcloud.common.core.constant.CacheConstants;
|
||||
import com.bsd.pjcloud.common.core.exception.CheckedException;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.security.util.SecurityUtils;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -108,7 +111,7 @@ public class SysSocialDetailsServiceImpl extends ServiceImpl<SysSocialDetailsMap
|
||||
public Boolean bindSocialByTicket(String type, String ticket) {
|
||||
String openid = redisTemplate.opsForValue().get(wxTicketKey(type, ticket));
|
||||
if (StrUtil.isBlank(openid)) {
|
||||
throw new CheckedException("授权已过期,请重新授权");
|
||||
throw new I18nBizException(ErrorCodes.AUTH_SOCIAL_AUTH_EXPIRED);
|
||||
}
|
||||
LoginHandler loginHandler = loginHandlerMap.get(type);
|
||||
SysUser sysUser = sysUserMapper.selectById(SecurityUtils.getUser().getId());
|
||||
@@ -135,7 +138,7 @@ public class SysSocialDetailsServiceImpl extends ServiceImpl<SysSocialDetailsMap
|
||||
public WxSocialResolveVO resolveAppleIdentityToken(String identityToken) {
|
||||
LoginHandler appleHandler = loginHandlerMap.get("APPLE");
|
||||
if (appleHandler == null) {
|
||||
throw new CheckedException("未启用Apple登录");
|
||||
throw new I18nBizException(ErrorCodes.AUTH_APPLE_NOT_ENABLED);
|
||||
}
|
||||
String openid = appleHandler.identify(identityToken);
|
||||
UserInfo userInfo = appleHandler.info(openid);
|
||||
|
||||
+14
-12
@@ -36,6 +36,8 @@ import com.bsd.pjcloud.common.core.constant.CommonConstants;
|
||||
import com.bsd.pjcloud.common.core.constant.CommonRoleConstant;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.CheckedException;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.CollectionUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.data.datascope.DataScope;
|
||||
@@ -153,7 +155,7 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long create(SysUserFaceEntity sysUserFace) {
|
||||
if (isExceedMax(sysUserFace.getUserId())) {
|
||||
throw new RuntimeException("最多只能上传3张人脸图片");
|
||||
throw new I18nBizException(ErrorCodes.SYS_FACE_MAX_COUNT);
|
||||
}
|
||||
PjcloudUser applyUser = SecurityUtils.getUser();
|
||||
boolean needFaceApproval = needFaceApproval(applyUser.getId());
|
||||
@@ -188,19 +190,19 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
|
||||
public List<Long> createGuardianWardFaces(SysUserFaceGuardianWardCreateDto dto) {
|
||||
PjcloudUser loginUser = SecurityUtils.getUser();
|
||||
if (new HashSet<>(dto.getFaceImgs()).size() != dto.getFaceImgs().size()) {
|
||||
throw new RuntimeException("请勿重复提交同一张人脸图片");
|
||||
throw new I18nBizException(ErrorCodes.SYS_FACE_DUP_IMAGE);
|
||||
}
|
||||
SysUser applyUser = sysUserService.getById(loginUser.getId());
|
||||
if (applyUser == null) {
|
||||
throw new RuntimeException("当前用户不存在");
|
||||
throw new I18nBizException(ErrorCodes.SYS_USER_NOT_FOUND);
|
||||
}
|
||||
if (sysUserService.getById(dto.getWardUserId()) == null) {
|
||||
throw new RuntimeException("目标用户不存在");
|
||||
throw new I18nBizException(ErrorCodes.SYS_USER_NOT_FOUND);
|
||||
}
|
||||
validateSelfOrGuardianWardUser(loginUser.getId(), dto.getWardUserId());
|
||||
boolean needFaceApproval = needFaceApproval(loginUser.getId());
|
||||
if (needFaceApproval && sysDeptService.getById(applyUser.getDeptId()) == null) {
|
||||
throw new RuntimeException("当前用户所属部门不存在,无法发起人脸审核");
|
||||
throw new I18nBizException(ErrorCodes.SYS_FACE_DEPT_MISSING);
|
||||
}
|
||||
validateAppRelationFaceLimit(dto.getWardUserId(), dto.getFaceImgs().size());
|
||||
|
||||
@@ -406,7 +408,7 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
|
||||
public SysUserFaceVo getGuardianWardFaceDetail(Long id) {
|
||||
SysUserFaceVo detail = baseMapper.join(id);
|
||||
if (detail == null) {
|
||||
throw new RuntimeException("人脸审核记录不存在");
|
||||
throw new I18nBizException(ErrorCodes.SYS_FACE_RECORD_MISSING);
|
||||
}
|
||||
validateSelfOrGuardianWardUser(SecurityUtils.getUser().getId(), detail.getUserId());
|
||||
return detail;
|
||||
@@ -423,11 +425,11 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
|
||||
public SysUserFaceGuardianWardWithdrawVo cancelGuardianWardFace(Long id) {
|
||||
SysUserFaceVo detail = baseMapper.join(id);
|
||||
if (detail == null) {
|
||||
throw new RuntimeException("人脸审核记录不存在");
|
||||
throw new I18nBizException(ErrorCodes.SYS_FACE_RECORD_MISSING);
|
||||
}
|
||||
validateSelfOrGuardianWardUser(SecurityUtils.getUser().getId(), detail.getUserId());
|
||||
if (!ObjectUtil.equals(detail.getProcessStatus(), TaskCheckStatusEnum.PADDING.getCode())) {
|
||||
throw new RuntimeException("只有审核中的人脸记录可以撤销");
|
||||
throw new I18nBizException(ErrorCodes.SYS_FACE_REVOKE_STATUS);
|
||||
}
|
||||
boolean deleted = update(new LambdaUpdateWrapper<SysUserFaceEntity>()
|
||||
.eq(SysUserFaceEntity::getId, detail.getId())
|
||||
@@ -435,7 +437,7 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
|
||||
.set(SysUserFaceEntity::getDelFlag, CommonConstants.STATUS_DEL)
|
||||
.set(SysUserFaceEntity::getUpdateTime, LocalDateTime.now()));
|
||||
if (!deleted) {
|
||||
throw new RuntimeException("人脸审核状态已发生变化,请刷新后重试");
|
||||
throw new I18nBizException(ErrorCodes.SYS_FACE_STATUS_CHANGED);
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(detail.getProcessId())) {
|
||||
TaskParamDto taskParam = new TaskParamDto();
|
||||
@@ -465,7 +467,7 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
|
||||
return;
|
||||
}
|
||||
if (!sysUserRelationService.hasActiveGuardianWardRelation(loginUserId, targetUserId)) {
|
||||
throw new RuntimeException("仅可查看或操作本人及有效被监护人的人脸审核记录");
|
||||
throw new I18nBizException(ErrorCodes.SYS_FACE_WARD_ONLY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,7 +566,7 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
|
||||
.in(SysUserFaceEntity::getProcessStatus,
|
||||
TaskCheckStatusEnum.PADDING.getCode(), TaskCheckStatusEnum.RESULT.getCode()));
|
||||
if (count + uploadCount > 3) {
|
||||
throw new RuntimeException("审核中和已通过的人脸合计最多只能保留3张");
|
||||
throw new I18nBizException(ErrorCodes.SYS_FACE_MAX_ACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,7 +603,7 @@ public class SysUserFaceServiceImpl extends ServiceImpl<SysUserFaceMapper, SysUs
|
||||
public Boolean editGlobalFace(SysUserFaceDto dto) {
|
||||
SysUser user = sysUserService.getById(dto.getUserId());
|
||||
if (ObjectUtil.isEmpty(user)) {
|
||||
throw new RuntimeException("用户不存在");
|
||||
throw new I18nBizException(ErrorCodes.SYS_USER_NOT_FOUND);
|
||||
}
|
||||
SysUser updateObj = new SysUser();
|
||||
updateObj.setUserId(dto.getUserId());
|
||||
|
||||
+12
-11
@@ -67,6 +67,7 @@ import com.bsd.pjcloud.common.core.constant.CommonRoleConstant;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.LoginTypeEnum;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.CollectionUtils;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
@@ -175,10 +176,10 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
public Boolean applyCloseAccount(Long userId) {
|
||||
SysUser sysUser = baseMapper.selectById(userId);
|
||||
if (ObjectUtil.isEmpty(sysUser)) {
|
||||
throw new RuntimeException("用户不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_USER_NOT_EXIST);
|
||||
}
|
||||
if (ObjectUtil.equals(sysUser.getCloseAccountFlag(), YesNoEnum.YES.getCode())) {
|
||||
throw new RuntimeException("您已注销");
|
||||
throw new I18nBizException(ErrorCodes.SYS_USER_CANCELLED);
|
||||
}
|
||||
SysUser updateObj = new SysUser();
|
||||
updateObj.setUserId(userId);
|
||||
@@ -938,7 +939,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
public R changePassword(UserDTO userDto) {
|
||||
SysUser user = baseMapper.selectById(SecurityUtils.getUser().getId());
|
||||
if (StrUtil.isEmpty(userDto.getPassword())) {
|
||||
return R.failed("原密码不能为空");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_PASSWORD_OLD_EMPTY));
|
||||
}
|
||||
|
||||
if (!ENCODER.matches(userDto.getPassword(), user.getPassword())) {
|
||||
@@ -947,7 +948,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
}
|
||||
|
||||
if (StrUtil.isEmpty(userDto.getNewpassword1())) {
|
||||
return R.failed("新密码不能为空");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_PASSWORD_NEW_EMPTY));
|
||||
}
|
||||
String weakPasswordMsg = validatePasswordStrength(userDto.getNewpassword1());
|
||||
if (StrUtil.isNotBlank(weakPasswordMsg)) {
|
||||
@@ -981,7 +982,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
wrapper = Wrappers.<SysUser>lambdaUpdate().set(SysUser::getWxDingUserid, null).eq(SysUser::getUserId, user.getId());
|
||||
}
|
||||
if (wrapper == null) {
|
||||
return R.failed("解绑账号类型不存在");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_UNBIND_TYPE_INVALID));
|
||||
}
|
||||
this.update(wrapper);
|
||||
return R.ok();
|
||||
@@ -995,7 +996,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
|
||||
if (!ENCODER.matches(password, sysUser.getPassword())) {
|
||||
log.info("原密码错误");
|
||||
return R.failed("密码输入错误");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_UPDATE_PASSWORDERROR));
|
||||
} else {
|
||||
return R.ok();
|
||||
}
|
||||
@@ -1018,7 +1019,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
|
||||
// 新密码校验
|
||||
if (StrUtil.equals(userDto.getPassword(), userDto.getNewpassword1())) {
|
||||
return R.failed("新旧密码不能相同");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_PASSWORD_SAME));
|
||||
}
|
||||
String weakPasswordMsg = validatePasswordStrength(userDto.getNewpassword1());
|
||||
if (StrUtil.isNotBlank(weakPasswordMsg)) {
|
||||
@@ -1041,7 +1042,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
String cacheKey = CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + forgotPasswordDTO.getMobile();
|
||||
String cacheCode = redisTemplate.opsForValue().get(cacheKey);
|
||||
if (StrUtil.isBlank(cacheCode) || !StrUtil.equals(cacheCode, forgotPasswordDTO.getSmsCode())) {
|
||||
return R.failed("短信验证码错误或已过期");
|
||||
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_APP_SMS_CODE_INVALID));
|
||||
}
|
||||
String weakPasswordMsg = validatePasswordStrength(forgotPasswordDTO.getNewPassword());
|
||||
if (StrUtil.isNotBlank(weakPasswordMsg)) {
|
||||
@@ -1065,7 +1066,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
|
||||
private String validatePasswordStrength(String password) {
|
||||
if (StrUtil.length(password) < 8 || StrUtil.length(password) > 20) {
|
||||
return "密码长度需为8-20位";
|
||||
return MsgUtils.getMessage(ErrorCodes.SYS_USER_PASSWORD_LENGTH);
|
||||
}
|
||||
boolean hasLetter = false;
|
||||
boolean hasDigit = false;
|
||||
@@ -1075,11 +1076,11 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
|
||||
} else if (Character.isDigit(c)) {
|
||||
hasDigit = true;
|
||||
} else {
|
||||
return "密码只能包含字母和数字";
|
||||
return MsgUtils.getMessage(ErrorCodes.SYS_USER_PASSWORD_CHARS_ONLY);
|
||||
}
|
||||
}
|
||||
if (!(hasLetter && hasDigit)) {
|
||||
return "密码需同时包含字母和数字";
|
||||
return MsgUtils.getMessage(ErrorCodes.SYS_USER_PASSWORD_LETTER_DIGIT);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+17
-15
@@ -17,6 +17,8 @@ import com.bsd.pjcloud.admin.service.SysDeptBuildingUnitService;
|
||||
import com.bsd.pjcloud.admin.service.SysDeptService;
|
||||
import com.bsd.pjcloud.admin.service.SysUserAddressService;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -90,11 +92,11 @@ public class SysUserAddressServiceImpl extends ServiceImpl<SysUserAddressMapper,
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateForUser(Long userId, SysUserAddressDto dto) {
|
||||
if (dto.getId() == null) {
|
||||
throw new IllegalArgumentException("地址ID不能为空");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_ID_EMPTY);
|
||||
}
|
||||
SysUserAddressEntity old = getById(dto.getId());
|
||||
if (old == null || !userId.equals(old.getUserId())) {
|
||||
throw new IllegalArgumentException("地址不存在");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_NOT_FOUND);
|
||||
}
|
||||
validateBinding(dto);
|
||||
dto.setUserId(userId);
|
||||
@@ -112,7 +114,7 @@ public class SysUserAddressServiceImpl extends ServiceImpl<SysUserAddressMapper,
|
||||
public void removeForUser(Long userId, Long addressId) {
|
||||
SysUserAddressEntity old = getById(addressId);
|
||||
if (old == null || !userId.equals(old.getUserId())) {
|
||||
throw new IllegalArgumentException("地址不存在");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_NOT_FOUND);
|
||||
}
|
||||
removeById(addressId);
|
||||
if (YesNoEnum.YES.getCode().equals(old.getIsDefault())) {
|
||||
@@ -132,7 +134,7 @@ public class SysUserAddressServiceImpl extends ServiceImpl<SysUserAddressMapper,
|
||||
public void setDefault(Long userId, Long addressId) {
|
||||
SysUserAddressEntity entity = getById(addressId);
|
||||
if (entity == null || !userId.equals(entity.getUserId())) {
|
||||
throw new IllegalArgumentException("地址不存在");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_NOT_FOUND);
|
||||
}
|
||||
clearDefault(userId);
|
||||
entity.setIsDefault(YesNoEnum.YES.getCode());
|
||||
@@ -151,39 +153,39 @@ public class SysUserAddressServiceImpl extends ServiceImpl<SysUserAddressMapper,
|
||||
|
||||
private void validateBinding(SysUserAddressDto dto) {
|
||||
if (dto.getDeptId() == null || dto.getBuildingId() == null) {
|
||||
throw new IllegalArgumentException("单位与楼栋不能为空");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_DEPT_BUILDING_REQUIRED);
|
||||
}
|
||||
if (dto.getUnitId() == null) {
|
||||
throw new IllegalArgumentException("单元不能为空");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_UNIT_REQUIRED);
|
||||
}
|
||||
if (dto.getRoomId() == null) {
|
||||
throw new IllegalArgumentException("房间不能为空");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_ROOM_REQUIRED);
|
||||
}
|
||||
if (sysDeptService.getById(dto.getDeptId()) == null) {
|
||||
throw new IllegalArgumentException("单位不存在");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_DEPT_NOT_FOUND);
|
||||
}
|
||||
SysDeptBuildingEntity building = sysDeptBuildingService.getById(dto.getBuildingId());
|
||||
if (building == null) {
|
||||
throw new IllegalArgumentException("楼栋不存在");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_BUILDING_NOT_FOUND);
|
||||
}
|
||||
if (!building.getDeptId().equals(dto.getDeptId())) {
|
||||
throw new IllegalArgumentException("所选楼栋不属于该单位");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_BUILDING_DEPT_MISMATCH);
|
||||
}
|
||||
|
||||
SysDeptBuildingUnitEntity unit = sysDeptBuildingUnitService.getById(dto.getUnitId());
|
||||
if (unit == null) {
|
||||
throw new IllegalArgumentException("单元不存在");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_UNIT_NOT_FOUND);
|
||||
}
|
||||
if (!unit.getBuildingId().equals(dto.getBuildingId())) {
|
||||
throw new IllegalArgumentException("所选单元不属于该楼栋");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_UNIT_BUILDING_MISMATCH);
|
||||
}
|
||||
|
||||
SysDeptBuildingRoomEntity room = sysDeptBuildingRoomService.getById(dto.getRoomId());
|
||||
if (room == null) {
|
||||
throw new IllegalArgumentException("房间不存在");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_ROOM_NOT_FOUND);
|
||||
}
|
||||
if (!room.getUnitId().equals(dto.getUnitId()) || !room.getBuildingId().equals(dto.getBuildingId())) {
|
||||
throw new IllegalArgumentException("所选房间不属于该单元/楼栋");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_ROOM_UNIT_MISMATCH);
|
||||
}
|
||||
|
||||
// 回填快照字段(展示/机器人定位)
|
||||
@@ -191,7 +193,7 @@ public class SysUserAddressServiceImpl extends ServiceImpl<SysUserAddressMapper,
|
||||
dto.setFloorNo(room.getFloorNo());
|
||||
dto.setRoomNo(room.getRoomNo());
|
||||
if (StrUtil.isBlank(dto.getRoomNo())) {
|
||||
throw new IllegalArgumentException("房间号不能为空");
|
||||
throw new I18nBizException(ErrorCodes.ADDRESS_ROOM_NO_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -22,6 +22,8 @@ import com.bsd.pjcloud.admin.service.SysUserService;
|
||||
import com.bsd.pjcloud.admin.utils.flow.FlowUtil;
|
||||
import com.bsd.pjcloud.admin.utils.flow.dto.UserCarFlowDto;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.CollectionUtils;
|
||||
import com.bsd.pjcloud.common.data.datascope.DataScope;
|
||||
import com.bsd.pjcloud.common.data.tenant.TenantContextHolder;
|
||||
@@ -65,7 +67,7 @@ public class SysUserCarServiceImpl extends ServiceImpl<SysUserCarMapper, SysUser
|
||||
@Override
|
||||
public Long create(SysUserCarDto sysUserCar) {
|
||||
if (existName(sysUserCar)) {
|
||||
throw new RuntimeException("车牌号不能重复");
|
||||
throw new I18nBizException(ErrorCodes.SYS_CAR_PLATE_DUP);
|
||||
}
|
||||
if (ObjectUtil.isEmpty(sysUserCar.getEnableStatus())) {
|
||||
sysUserCar.setEnableStatus(YesNoEnum.YES.getCode());
|
||||
@@ -81,7 +83,7 @@ public class SysUserCarServiceImpl extends ServiceImpl<SysUserCarMapper, SysUser
|
||||
@Override
|
||||
public void edit(SysUserCarDto sysUserCar) {
|
||||
if (existName(sysUserCar)) {
|
||||
throw new RuntimeException("车牌号不能重复");
|
||||
throw new I18nBizException(ErrorCodes.SYS_CAR_PLATE_DUP);
|
||||
}
|
||||
baseMapper.updateById(sysUserCar);
|
||||
}
|
||||
@@ -93,7 +95,7 @@ public class SysUserCarServiceImpl extends ServiceImpl<SysUserCarMapper, SysUser
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void appCreateCar(SysUserCarDto dto) {
|
||||
if (existName(dto)) {
|
||||
throw new RuntimeException("车牌号不能重复");
|
||||
throw new I18nBizException(ErrorCodes.SYS_CAR_PLATE_DUP);
|
||||
}
|
||||
if (ObjectUtil.isEmpty(dto.getEnableStatus())) {
|
||||
dto.setEnableStatus(YesNoEnum.YES.getCode());
|
||||
|
||||
+5
-2
@@ -1,4 +1,7 @@
|
||||
package com.bsd.pjcloud.wallet.controller;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.api.encrypt.annotation.crypto.ApiCryptoAes;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
@@ -57,10 +60,10 @@ public class WalletFreezeController {
|
||||
@Operation(summary = "申请冻结")
|
||||
public R<Object> appApplyFreeze(@RequestBody WalletFreezeDto dto) {
|
||||
if (ObjectUtil.isEmpty(dto.getWalletTypeId())) {
|
||||
throw new RuntimeException("钱包类型id不能为空");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TYPE_ID_EMPTY);
|
||||
}
|
||||
if (ObjectUtil.isEmpty(dto.getRemark())) {
|
||||
throw new RuntimeException("备注不能为空");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_REMARK_EMPTY);
|
||||
}
|
||||
PjcloudUser user = SecurityUtils.getUser();
|
||||
dto.setUserId(user.getId());
|
||||
|
||||
+4
-2
@@ -4,6 +4,8 @@ import com.bsd.pjcloud.common.api.encrypt.annotation.crypto.ApiCryptoAes;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.idempotent.annotation.Idempotent;
|
||||
import com.bsd.pjcloud.common.log.annotation.SysLog;
|
||||
@@ -58,8 +60,8 @@ public class ActCancelItemController {
|
||||
@PostMapping("/app/get")
|
||||
@Idempotent(expireTime = 2, key = "'/act/cancel/app/get/' + #dto.getReceiverUserId()", info = "正在领取中,请勿重复操作")
|
||||
public R<Long> appGet(@RequestBody ActCancelItemDto dto) {
|
||||
if (ObjectUtil.isEmpty(dto.getActId())) throw new RuntimeException("活动id不能为空");
|
||||
if (ObjectUtil.isEmpty(dto.getMchId())) throw new RuntimeException("商户id不能为空");
|
||||
if (ObjectUtil.isEmpty(dto.getActId())) throw new I18nBizException(ErrorCodes.ACT_ID_EMPTY);
|
||||
if (ObjectUtil.isEmpty(dto.getMchId())) throw new I18nBizException(ErrorCodes.COMMON_MCH_ID_EMPTY);
|
||||
PjcloudUser user = SecurityUtils.getUser();
|
||||
return R.ok(actCancelItemService.appGet(user, dto));
|
||||
}
|
||||
|
||||
+14
-12
@@ -14,6 +14,8 @@ import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.common.api.encrypt.annotation.encrypt.ApiEncryptAes;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.data.datascope.DataScope;
|
||||
import com.bsd.pjcloud.common.log.annotation.SysLog;
|
||||
@@ -74,7 +76,7 @@ public class MchManageController {
|
||||
@GetMapping("/get-by-types")
|
||||
public R<List<MchManageVo>> getByTypes(@RequestParam List<String> types) {
|
||||
List<MchManageVo> list = mchManageService.list(MchManageDto.builder().typesList(types).build());
|
||||
if (ObjectUtil.isEmpty(list)) return R.failed("商户不存在");
|
||||
if (ObjectUtil.isEmpty(list)) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
@@ -82,7 +84,7 @@ public class MchManageController {
|
||||
@GetMapping("/get-by-id")
|
||||
public R<MchManageVo> getById(@RequestParam Long id) {
|
||||
MchManageVo mchManageVo = mchManageService.join(id);
|
||||
if (ObjectUtil.isEmpty(mchManageVo)) return R.failed("商户不存在");
|
||||
if (ObjectUtil.isEmpty(mchManageVo)) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
return R.ok(mchManageVo);
|
||||
}
|
||||
|
||||
@@ -100,7 +102,7 @@ public class MchManageController {
|
||||
@GetMapping("/get-by-ids")
|
||||
public R<List<MchManageVo>> getByIds(@RequestParam List<Long> ids) {
|
||||
List<MchManageVo> list = mchManageService.list(MchManageDto.builder().ids(ids).build());
|
||||
if (ObjectUtil.isEmpty(list)) return R.failed("商户不存在");
|
||||
if (ObjectUtil.isEmpty(list)) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
@@ -108,7 +110,7 @@ public class MchManageController {
|
||||
@GetMapping("/get-by-dept-id")
|
||||
public R<MchManageVo> getByDeptId(@RequestParam("deptId") Long deptId, MerchantTypeEnum type) {
|
||||
MchManageVo mchManage = mchManageService.getByDeptId(deptId, type);
|
||||
if (ObjectUtil.isEmpty(mchManage)) return R.failed("商户不存在");
|
||||
if (ObjectUtil.isEmpty(mchManage)) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
return R.ok(mchManage);
|
||||
}
|
||||
|
||||
@@ -116,7 +118,7 @@ public class MchManageController {
|
||||
@GetMapping("/get-by-dept-ids")
|
||||
public R<List<MchManageVo>> getByDeptIds(@RequestParam List<Long> deptIds) {
|
||||
List<MchManageVo> list = mchManageService.list(MchManageDto.builder().deptIds(deptIds).build());
|
||||
if (ObjectUtil.isEmpty(list)) return R.failed("商户不存在");
|
||||
if (ObjectUtil.isEmpty(list)) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
@@ -124,7 +126,7 @@ public class MchManageController {
|
||||
@GetMapping("/get-first-mch")
|
||||
public R<MchManageVo> getFirstMch(@RequestParam List<Long> deptIds, @RequestParam MerchantTypeEnum mchType) {
|
||||
MchManageVo mchManage = mchManageService.getFirstMch(deptIds, List.of(mchType));
|
||||
if (ObjectUtil.isEmpty(mchManage)) return R.failed("商户不存在");
|
||||
if (ObjectUtil.isEmpty(mchManage)) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
return R.ok(mchManage);
|
||||
}
|
||||
|
||||
@@ -132,7 +134,7 @@ public class MchManageController {
|
||||
@GetMapping("/get-first-mch-by-dept-id")
|
||||
public R<MchManageVo> getFirstMchByDeptId(@RequestParam Long deptId, @RequestParam MerchantTypeEnum mchType) {
|
||||
MchManageVo mchManage = mchManageService.getFirstMchByDeptId(deptId, List.of(mchType));
|
||||
if (ObjectUtil.isEmpty(mchManage)) return R.failed("商户不存在");
|
||||
if (ObjectUtil.isEmpty(mchManage)) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
return R.ok(mchManage);
|
||||
}
|
||||
|
||||
@@ -140,7 +142,7 @@ public class MchManageController {
|
||||
@GetMapping("/get-views-canteen-mch-by-dept-id")
|
||||
public R<MchManageVo> getViewsCanteenMchByDeptId(@RequestParam Long deptId) {
|
||||
MchManageVo mchManage = mchManageService.getViewsCanteenMchByDeptId(deptId);
|
||||
if (ObjectUtil.isEmpty(mchManage)) return R.failed("商户不存在");
|
||||
if (ObjectUtil.isEmpty(mchManage)) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
return R.ok(mchManage);
|
||||
}
|
||||
|
||||
@@ -148,7 +150,7 @@ public class MchManageController {
|
||||
@GetMapping("/get-views-mch-by-dept-id")
|
||||
public R<MchManageVo> getViewsMchByDeptId(@RequestParam Long deptId, @RequestParam List<MerchantTypeEnum> mchTypeList) {
|
||||
MchManageVo mchManage = mchManageService.getViewsCanteenMch(deptId, mchTypeList);
|
||||
if (ObjectUtil.isEmpty(mchManage)) return R.failed("商户不存在");
|
||||
if (ObjectUtil.isEmpty(mchManage)) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
return R.ok(mchManage);
|
||||
}
|
||||
|
||||
@@ -156,7 +158,7 @@ public class MchManageController {
|
||||
@GetMapping("/get-self-canteen-user-dept-id-list")
|
||||
public R<List<Long>> getSelfCanteenUserDeptIdList(@RequestParam Long mchId) {
|
||||
List<Long> userDeptIdList = mchManageService.getSelfCanteenUserDeptIdList(mchId);
|
||||
if (ObjectUtil.isEmpty(userDeptIdList)) return R.failed("商户不存在");
|
||||
if (ObjectUtil.isEmpty(userDeptIdList)) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
return R.ok(userDeptIdList);
|
||||
}
|
||||
|
||||
@@ -172,7 +174,7 @@ public class MchManageController {
|
||||
public R<List<Long>> getSelfMchUserDeptIdListByUserId(@RequestParam Long userId,
|
||||
@RequestParam List<MerchantTypeEnum> mchTypeList) {
|
||||
List<Long> userDeptIdList = mchManageService.getSelfMchUserDeptIdListByUserId(userId, mchTypeList);
|
||||
if (ObjectUtil.isEmpty(userDeptIdList)) return R.failed("商户不存在");
|
||||
if (ObjectUtil.isEmpty(userDeptIdList)) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
return R.ok(userDeptIdList);
|
||||
}
|
||||
|
||||
@@ -180,7 +182,7 @@ public class MchManageController {
|
||||
@GetMapping("/get-self-mch-id-list")
|
||||
public R<List<Long>> getSelfMchIdList(@RequestParam Long userId, @RequestParam List<MerchantTypeEnum> mchTypeList) {
|
||||
List<Long> userDeptIdList = mchManageService.getSelfMchIdList(userId, mchTypeList);
|
||||
if (ObjectUtil.isEmpty(userDeptIdList)) return R.failed("商户不存在");
|
||||
if (ObjectUtil.isEmpty(userDeptIdList)) return R.failed(MsgUtils.getMessage(ErrorCodes.COMMON_MCH_NOT_FOUND));
|
||||
return R.ok(userDeptIdList);
|
||||
}
|
||||
|
||||
|
||||
+12
-9
@@ -1,5 +1,8 @@
|
||||
package com.bsd.pjcloud.wallet.service.impl;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
@@ -132,18 +135,18 @@ public class WalletActiveServiceImpl extends ServiceImpl<WalletActiveMapper, Wal
|
||||
public WalletActiveEntity bindCard(WalletActiveBindCardDto dto) {
|
||||
WalletActiveEntity walletActive = getByCardNumber(dto.getCardNumber());
|
||||
if (ObjectUtil.isEmpty(walletActive)) {
|
||||
throw new RuntimeException("卡号不存在");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_CARD_NOT_FOUND);
|
||||
}
|
||||
WalletManageEntity wallet = walletManageService.getWallet(dto.getCardNumber());
|
||||
if (ObjectUtil.isNotEmpty(wallet)) {
|
||||
throw new RuntimeException("该卡号已经绑定用户");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_CARD_ALREADY_BOUND);
|
||||
}
|
||||
WalletManageEntity selfWallet = walletManageService.getWallet(dto.getWalletId());
|
||||
if (ObjectUtil.isEmpty(selfWallet)) {
|
||||
throw new RuntimeException("饭卡钱包不存在");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_MEAL_CARD_NOT_FOUND);
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(selfWallet) && ObjectUtil.isNotEmpty(selfWallet.getCardNumber())) {
|
||||
throw new RuntimeException("用户已绑定饭卡");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_USER_ALREADY_BOUND);
|
||||
}
|
||||
// 前置查询只能用于友好提示,必须以未绑定条件原子抢占饭卡,防止并发请求相互覆盖。
|
||||
WalletActiveEntity walletActiveObj = WalletActiveEntity.builder().id(walletActive.getId()).userId(dto.getUserId()).walletId(selfWallet.getId()).walletTypeId(selfWallet.getWalletTypeId()).build();
|
||||
@@ -152,7 +155,7 @@ public class WalletActiveServiceImpl extends ServiceImpl<WalletActiveMapper, Wal
|
||||
.isNull(WalletActiveEntity::getUserId)
|
||||
.isNull(WalletActiveEntity::getWalletId));
|
||||
if (activeUpdateCount == 0) {
|
||||
throw new RuntimeException("该卡号已经绑定用户");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_CARD_ALREADY_BOUND);
|
||||
}
|
||||
// 历史未绑定钱包的卡号同时存在 NULL 和空字符串,原子更新必须兼容两种值;失败时由事务回滚饭卡抢占。
|
||||
WalletManageEntity walletObj = WalletManageEntity.builder().id(selfWallet.getId()).cardNumber(walletActive.getCardNumber()).status(WalleCardStatusEnum.ACTIVE.getCode()).activeBindTime(LocalDateTime.now()).build();
|
||||
@@ -162,7 +165,7 @@ public class WalletActiveServiceImpl extends ServiceImpl<WalletActiveMapper, Wal
|
||||
.or()
|
||||
.eq(WalletManageEntity::getCardNumber, "")));
|
||||
if (!walletUpdateSuccess) {
|
||||
throw new RuntimeException("用户已绑定饭卡");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_USER_ALREADY_BOUND);
|
||||
}
|
||||
return baseMapper.selectById(walletActiveObj.getId());
|
||||
}
|
||||
@@ -172,7 +175,7 @@ public class WalletActiveServiceImpl extends ServiceImpl<WalletActiveMapper, Wal
|
||||
// 查询饭卡钱包
|
||||
WalletManageEntity wallet = walletManageService.getWallet(dto.getUserId(), WalletTypeEnum.EAT);
|
||||
if (ObjectUtil.isEmpty(wallet)) {
|
||||
throw new RuntimeException("饭卡钱包不存在");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_MEAL_CARD_NOT_FOUND);
|
||||
}
|
||||
dto.setWalletId(wallet.getId());
|
||||
return getSelf().bindCard(dto);
|
||||
@@ -223,11 +226,11 @@ public class WalletActiveServiceImpl extends ServiceImpl<WalletActiveMapper, Wal
|
||||
public Boolean cancelAdminBindCard(Long activeId) {
|
||||
WalletActiveEntity walletActive = getById(activeId);
|
||||
if (ObjectUtil.isEmpty(walletActive)) {
|
||||
throw new RuntimeException("卡号不存在");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_CARD_NOT_FOUND);
|
||||
}
|
||||
WalletManageEntity wallet = walletManageService.getWallet(walletActive.getWalletId());
|
||||
if (ObjectUtil.isEmpty(wallet)) {
|
||||
throw new RuntimeException("改饭卡没有绑定用户");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_CARD_NO_USER);
|
||||
}
|
||||
// 更新开卡记录
|
||||
LambdaUpdateWrapper<WalletActiveEntity> walletActiveUpdateWrapper = new LambdaUpdateWrapper<WalletActiveEntity>()
|
||||
|
||||
+3
-1
@@ -13,6 +13,8 @@ import com.bsd.pjcloud.admin.api.entity.SysUser;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteDeptService;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.admin.api.utils.DataUtil;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.CollectionUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.security.util.SecurityUtils;
|
||||
@@ -75,7 +77,7 @@ public class WalletForeignServiceImpl extends ServiceImpl<WalletForeignMapper, W
|
||||
SysDept dept = deptService.getDeptByDeptId(dto.getDeptId()).getData();
|
||||
if (ObjectUtil.isEmpty(dept)) throw new RuntimeException("发起人部门不存在");
|
||||
// 判断之前有没有在审核的
|
||||
if (isCheckData(dto.getUserId())) throw new RuntimeException("已提交申请,请勿重复提交");
|
||||
if (isCheckData(dto.getUserId())) throw new I18nBizException(ErrorCodes.WALLET_APPLY_DUP_SUBMIT);
|
||||
baseMapper.insert(dto);
|
||||
// 发起审批
|
||||
WalletForeignApplyFlowDto flowDto = new WalletForeignApplyFlowDto();
|
||||
|
||||
+5
-2
@@ -1,5 +1,8 @@
|
||||
package com.bsd.pjcloud.wallet.service.impl;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
@@ -123,9 +126,9 @@ public class WalletFreezeServiceImpl extends ServiceImpl<WalletFreezeMapper, Wal
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void applyFreeze(WalletFreezeDto dto, PjcloudUser user) {
|
||||
WalletManageEntity wallet = walletManageService.getWallet(dto.getUserId(), dto.getWalletTypeId());
|
||||
if (ObjectUtil.isEmpty(wallet)) throw new RuntimeException("钱包不存在");
|
||||
if (ObjectUtil.isEmpty(wallet)) throw new I18nBizException(ErrorCodes.WALLET_NOT_FOUND);
|
||||
// 判断之前有没有在审核的
|
||||
if (isCheckData(dto.getUserId())) throw new RuntimeException("已提交申请,请勿重复提交");
|
||||
if (isCheckData(dto.getUserId())) throw new I18nBizException(ErrorCodes.WALLET_FREEZE_DUP);
|
||||
// 查询发起人
|
||||
UserInfo userData = userService.getInnerByUserId(user.getId()).getData();
|
||||
// 查询部门
|
||||
|
||||
+4
-1
@@ -1,5 +1,8 @@
|
||||
package com.bsd.pjcloud.wallet.service.impl;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
@@ -249,7 +252,7 @@ public class WalletManageServiceImpl extends ServiceImpl<WalletManageMapper, Wal
|
||||
@Override
|
||||
public String getQrCode(Long walletId) {
|
||||
WalletCodeUseEntity walletCodeUse = walletCodeUseService.generateWallet(walletId);
|
||||
if (ObjectUtil.isEmpty(walletCodeUse)) throw new RuntimeException("钱包二维码生成错误");
|
||||
if (ObjectUtil.isEmpty(walletCodeUse)) throw new I18nBizException(ErrorCodes.WALLET_QR_GEN_FAIL);
|
||||
return walletCodeUse.getShortCode();
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -13,6 +13,8 @@ import com.bsd.pjcloud.admin.api.entity.SysUser;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteDeptService;
|
||||
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.admin.api.utils.DataUtil;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.CollectionUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.security.util.SecurityUtils;
|
||||
@@ -83,7 +85,7 @@ public class WalletStrideServiceImpl extends ServiceImpl<WalletStrideMapper, Wal
|
||||
if (ObjectUtil.isEmpty(dept)) throw new RuntimeException("发起人部门不存在");
|
||||
// 判断之前有没有在审核的
|
||||
if (isCheckData(dto.getUserId())) {
|
||||
throw new RuntimeException("已提交申请,请勿重复提交");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_APPLY_DUP_SUBMIT);
|
||||
}
|
||||
baseMapper.insert(dto);
|
||||
// 发起审批
|
||||
|
||||
+41
-38
@@ -1,5 +1,8 @@
|
||||
package com.bsd.pjcloud.wallet.service.impl;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.io.resource.ResourceUtil;
|
||||
@@ -255,12 +258,12 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
WalletManageEntity wallet = walletManageService.getById(walletId);
|
||||
if (ObjectUtil.isEmpty(wallet)) {
|
||||
log.error("|{}|,用户钱包id({})不存在.", TAG, walletId);
|
||||
throw new RuntimeException("扣款失败,用户钱包不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_WALLET_NOT_FOUND);
|
||||
}
|
||||
int updateCounts = walletManageMapper.updateWhenConsumption(wallet.getId(), price, force);
|
||||
if (updateCounts == 0) {
|
||||
log.error("|{}|,用户钱包id({})余额不足.", TAG, walletId);
|
||||
throw new RuntimeException("钱包余额不足");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_WALLET_BALANCE_INSUFFICIENT);
|
||||
}
|
||||
Integer afterBalance = wallet.getBalance() - price;
|
||||
WalletTransactionEntity insetObj = new WalletTransactionEntity();
|
||||
@@ -287,17 +290,17 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
}
|
||||
WalletManageEntity wallet = walletManageMapper.selectByIdForUpdate(walletId);
|
||||
if (ObjectUtil.isEmpty(wallet)) {
|
||||
throw new RuntimeException("扣款失败,用户钱包不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_WALLET_NOT_FOUND);
|
||||
}
|
||||
WalletTransactionEntity existing = findBizTransaction(walletId, bizId, bizType);
|
||||
if (existing != null) {
|
||||
if (!ObjectUtil.equals(existing.getPrice(), -price)) {
|
||||
throw new RuntimeException("重复业务扣款金额不一致");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_DEDUCT_AMOUNT_MISMATCH);
|
||||
}
|
||||
return existing;
|
||||
}
|
||||
if (walletManageMapper.updateWhenConsumption(walletId, price, force) == 0) {
|
||||
throw new RuntimeException("钱包余额不足");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_WALLET_BALANCE_INSUFFICIENT);
|
||||
}
|
||||
WalletTransactionEntity transaction = buildWalletTransaction(wallet, walletId, -price, wallet.getBalance() - price, bizId, bizType);
|
||||
save(transaction);
|
||||
@@ -317,7 +320,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
List<WalletBalanceTransactionDto> payments = validatePaymentBatch(dtoList);
|
||||
acquirePaymentOperationLocks(payments, new ArrayList<>());
|
||||
if (payments.stream().anyMatch(this::isPaymentCancelled)) {
|
||||
throw new RuntimeException("订单支付已经取消,不能继续扣款");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_ORDER_PAYMENT_CANCELLED);
|
||||
}
|
||||
Map<Long, WalletManageEntity> lockedWalletMap = lockBatchWallets(payments);
|
||||
Map<Long, Integer> pendingPriceMap = new LinkedHashMap<>();
|
||||
@@ -326,12 +329,12 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
for (WalletBalanceTransactionDto payment : payments) {
|
||||
WalletTransactionEntity compensated = findBizTransaction(payment.getWalletId(), payment.getBizId(), WalletBizEnum.REFUND);
|
||||
if (compensated != null) {
|
||||
throw new RuntimeException("订单支付已经补偿,不能重复扣款");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_ORDER_PAYMENT_COMPENSATED);
|
||||
}
|
||||
WalletTransactionEntity existing = findBizTransaction(payment.getWalletId(), payment.getBizId(), WalletBizEnum.PAYMENT);
|
||||
if (existing != null) {
|
||||
if (!ObjectUtil.equals(existing.getPrice(), -payment.getPrice())) {
|
||||
throw new RuntimeException("重复业务扣款金额不一致");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_DEDUCT_AMOUNT_MISMATCH);
|
||||
}
|
||||
existingPaymentMap.put(paymentBatchKey(payment), existing);
|
||||
continue;
|
||||
@@ -342,12 +345,12 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
pendingPriceMap.forEach((walletId, totalPrice) -> {
|
||||
WalletManageEntity wallet = lockedWalletMap.get(walletId);
|
||||
if (wallet.getBalance() == null || wallet.getBalance() < totalPrice) {
|
||||
throw new RuntimeException("钱包余额不足");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_WALLET_BALANCE_INSUFFICIENT);
|
||||
}
|
||||
});
|
||||
pendingPriceMap.forEach((walletId, totalPrice) -> {
|
||||
if (walletManageMapper.updateWhenConsumption(walletId, totalPrice, false) != 1) {
|
||||
throw new RuntimeException("钱包余额不足");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_WALLET_BALANCE_INSUFFICIENT);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -367,7 +370,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
-payment.getPrice(), afterBalance, payment.getBizId(), WalletBizEnum.PAYMENT);
|
||||
transaction.setTags(payment.getTags());
|
||||
if (!save(transaction)) {
|
||||
throw new RuntimeException("保存钱包支付流水失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_PAYMENT_SAVE_FAIL);
|
||||
}
|
||||
results.add(transaction);
|
||||
}
|
||||
@@ -382,12 +385,12 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
public Boolean compensatePayment(Long walletId, Integer price, String bizId) {
|
||||
WalletManageEntity wallet = walletManageMapper.selectByIdForUpdate(walletId);
|
||||
if (ObjectUtil.isEmpty(wallet)) {
|
||||
throw new RuntimeException("退款失败,用户钱包不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_WALLET_NOT_FOUND);
|
||||
}
|
||||
WalletTransactionEntity existingRefund = findBizTransaction(walletId, bizId, WalletBizEnum.REFUND);
|
||||
if (existingRefund != null) {
|
||||
if (!ObjectUtil.equals(existingRefund.getPrice(), price)) {
|
||||
throw new RuntimeException("重复业务退款金额不一致");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_REFUND_AMOUNT_MISMATCH);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -396,10 +399,10 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
return true;
|
||||
}
|
||||
if (!ObjectUtil.equals(payment.getPrice(), -price)) {
|
||||
throw new RuntimeException("支付流水金额与补偿金额不一致");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_PAYMENT_AMOUNT_MISMATCH);
|
||||
}
|
||||
if (walletManageMapper.updateWhenConsumptionRefund(walletId, price) == 0) {
|
||||
throw new RuntimeException("钱包补偿失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_COMPENSATE_FAIL);
|
||||
}
|
||||
WalletTransactionEntity refund = buildWalletTransaction(wallet, walletId, price, wallet.getBalance() + price, bizId, WalletBizEnum.REFUND);
|
||||
save(refund);
|
||||
@@ -427,7 +430,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
WalletTransactionEntity existingRefund = findBizTransaction(payment.getWalletId(), payment.getBizId(), WalletBizEnum.REFUND);
|
||||
if (existingRefund != null) {
|
||||
if (!ObjectUtil.equals(existingRefund.getPrice(), payment.getPrice())) {
|
||||
throw new RuntimeException("重复业务退款金额不一致");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_REFUND_AMOUNT_MISMATCH);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -436,7 +439,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
continue;
|
||||
}
|
||||
if (!ObjectUtil.equals(existingPayment.getPrice(), -payment.getPrice())) {
|
||||
throw new RuntimeException("支付流水金额与补偿金额不一致");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_PAYMENT_AMOUNT_MISMATCH);
|
||||
}
|
||||
needRefundKeys.add(paymentBatchKey(payment));
|
||||
refundPriceMap.merge(payment.getWalletId(), payment.getPrice(), Math::addExact);
|
||||
@@ -444,7 +447,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
|
||||
refundPriceMap.forEach((walletId, totalPrice) -> {
|
||||
if (walletManageMapper.updateWhenConsumptionRefund(walletId, totalPrice) != 1) {
|
||||
throw new RuntimeException("钱包批量补偿失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_BATCH_COMPENSATE_FAIL);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -460,7 +463,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
WalletTransactionEntity refund = buildWalletTransaction(wallet, payment.getWalletId(), payment.getPrice(),
|
||||
afterBalance, payment.getBizId(), WalletBizEnum.REFUND);
|
||||
if (!save(refund)) {
|
||||
throw new RuntimeException("保存钱包补偿流水失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_REFUND_SAVE_FAIL);
|
||||
}
|
||||
}
|
||||
// 即使 PAYMENT 尚未到达也记录订单取消终态;该标记不会伪造 REFUND,仅阻止迟到请求继续扣款。
|
||||
@@ -476,19 +479,19 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
*/
|
||||
private List<WalletBalanceTransactionDto> validatePaymentBatch(List<WalletBalanceTransactionDto> dtoList) {
|
||||
if (ObjectUtil.isEmpty(dtoList) || dtoList.stream().anyMatch(Objects::isNull)) {
|
||||
throw new RuntimeException("钱包批量交易明细不能为空");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_BATCH_EMPTY);
|
||||
}
|
||||
Set<String> businessKeys = new HashSet<>();
|
||||
for (WalletBalanceTransactionDto dto : dtoList) {
|
||||
if (dto.getWalletId() == null || dto.getPrice() == null || dto.getPrice() <= 0
|
||||
|| dto.getBizId() == null || dto.getBizId().isBlank()) {
|
||||
throw new RuntimeException("钱包批量交易明细不完整");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_BATCH_INCOMPLETE);
|
||||
}
|
||||
if (!Objects.equals(dto.getBizType(), WalletBizEnum.PAYMENT) || Boolean.TRUE.equals(dto.getForce())) {
|
||||
throw new RuntimeException("钱包批量交易仅支持非透支支付");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_BATCH_NON_FORCE_ONLY);
|
||||
}
|
||||
if (!businessKeys.add(paymentBatchKey(dto))) {
|
||||
throw new RuntimeException("请勿重复提交同一钱包业务号");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_BATCH_DUP_BIZ);
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(dtoList);
|
||||
@@ -505,7 +508,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
payments.stream().map(WalletBalanceTransactionDto::getWalletId).distinct().sorted().forEach(walletId -> {
|
||||
WalletManageEntity wallet = walletManageMapper.selectByIdForUpdate(walletId);
|
||||
if (wallet == null) {
|
||||
throw new RuntimeException("扣款失败,用户钱包不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_WALLET_NOT_FOUND);
|
||||
}
|
||||
walletMap.put(walletId, wallet);
|
||||
});
|
||||
@@ -535,7 +538,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
for (String businessKey : payments.stream().map(this::paymentBatchKey).distinct().sorted().toList()) {
|
||||
RLock lock = redisson.getLock(PAYMENT_OPERATION_LOCK_PREFIX + businessKey);
|
||||
if (!lock.tryLock(PAYMENT_OPERATION_LOCK_WAIT_SECONDS, TimeUnit.SECONDS)) {
|
||||
throw new RuntimeException("订单钱包交易正在处理中,请稍后重试");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_PROCESSING);
|
||||
}
|
||||
locks.add(lock);
|
||||
}
|
||||
@@ -543,7 +546,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
} catch (InterruptedException exception) {
|
||||
Thread.currentThread().interrupt();
|
||||
releasePaymentOperationLocks(locks);
|
||||
throw new RuntimeException("订单钱包交易等待已中断,请稍后重试", exception);
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_LOCK_INTERRUPTED);
|
||||
} catch (RuntimeException exception) {
|
||||
releasePaymentOperationLocks(locks);
|
||||
throw exception;
|
||||
@@ -558,7 +561,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
*/
|
||||
private void registerPaymentOperationLockRelease(List<RLock> locks, List<String> rollbackMarkerKeys) {
|
||||
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||
throw new RuntimeException("钱包批量交易事务状态异常,请稍后重试");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_TX_STATE_BAD);
|
||||
}
|
||||
List<RLock> transactionLocks = List.copyOf(locks);
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||
@@ -690,12 +693,12 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
public WalletTransactionEntity addWalletBalanceIdempotent(Long walletId, Integer price, String bizId, WalletBizEnum bizType) {
|
||||
WalletManageEntity wallet = walletManageMapper.selectByIdForUpdate(walletId);
|
||||
if (ObjectUtil.isEmpty(wallet)) {
|
||||
throw new RuntimeException("增加余额失败,用户钱包不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_WALLET_NOT_FOUND);
|
||||
}
|
||||
WalletTransactionEntity existing = findBizTransaction(walletId, bizId, bizType);
|
||||
if (existing != null) {
|
||||
if (!ObjectUtil.equals(existing.getPrice(), price)) {
|
||||
throw new RuntimeException("重复业务入账金额不一致");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_CREDIT_AMOUNT_MISMATCH);
|
||||
}
|
||||
return existing;
|
||||
}
|
||||
@@ -743,7 +746,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
WalletManageEntity wallet = walletManageService.getById(walletId);
|
||||
if (ObjectUtil.isEmpty(wallet)) {
|
||||
log.error("|{}|,用户钱包id({})不存在.", TAG, walletId);
|
||||
throw new RuntimeException("扣款失败,用户钱包不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_WALLET_NOT_FOUND);
|
||||
}
|
||||
switch (bizType) {
|
||||
case UPDATE:
|
||||
@@ -796,7 +799,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
.set(WalletTransactionEntity::getRemark, remark));
|
||||
// 部分 MySQL affected-row 配置会把“值未变化”返回为 0,仅在记录也查不到时才判定失败。
|
||||
if (updated == 0 && baseMapper.selectById(dto.getId()) == null) {
|
||||
throw new RuntimeException("钱包流水不存在或已删除");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TX_NOT_FOUND);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -810,7 +813,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
}
|
||||
if (wallet == null) {
|
||||
log.error("|{}|,updateReqVO({}) 用户钱包不存在.", TAG, JSON.toJSONString(dto));
|
||||
throw new RuntimeException("用户钱包不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_WALLET_NOT_FOUND);
|
||||
}
|
||||
// 更新钱包余额
|
||||
WalletTransactionEntity result = getSelf().addWalletBalance(wallet.getId(), dto.getBalance(), String.valueOf(dto.getUserId()), WalletBizEnum.UPDATE, dto.getTags(), dto.getRemark());
|
||||
@@ -849,7 +852,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
WalletManageEntity wallet = walletManageService.getById(walletId);
|
||||
if (ObjectUtil.isEmpty(wallet)) {
|
||||
log.error("|{}|重置余额,用户钱包id({})不存在.", TAG, walletId);
|
||||
throw new RuntimeException("扣款失败,用户钱包不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_WALLET_NOT_FOUND);
|
||||
}
|
||||
if (ObjectUtil.equals(wallet.getBalance(), 0)) {
|
||||
return true;
|
||||
@@ -857,7 +860,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
int updateCounts = walletManageMapper.resetWhenRecharge(wallet.getId());
|
||||
if (updateCounts == 0) {
|
||||
log.error("|{}|重置余额失败walletId:{}", TAG, walletId);
|
||||
throw new RuntimeException("重置余额失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_RESET_BALANCE_FAIL);
|
||||
}
|
||||
WalletTransactionEntity insetObj = new WalletTransactionEntity();
|
||||
insetObj.setUserId(wallet.getUserId());
|
||||
@@ -955,7 +958,7 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
*/
|
||||
private void validateSelfOrGuardianWardUser(Long loginUserId, Long targetUserId) {
|
||||
if (targetUserId == null) {
|
||||
throw new RuntimeException("缺少目标用户信息");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TARGET_USER_MISSING);
|
||||
}
|
||||
if (Objects.equals(loginUserId, targetUserId)) {
|
||||
return;
|
||||
@@ -964,13 +967,13 @@ public class WalletTransactionServiceImpl extends ServiceImpl<WalletTransactionM
|
||||
try {
|
||||
result = remoteUserRelationService.listActiveGuardianWardUserIds(loginUserId);
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException("查询监护关系失败", exception);
|
||||
throw new I18nBizException(ErrorCodes.WALLET_GUARDIAN_RELATION_FAIL);
|
||||
}
|
||||
if (result == null || !result.isOk() || result.getData() == null) {
|
||||
throw new RuntimeException("查询监护关系失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_GUARDIAN_RELATION_FAIL);
|
||||
}
|
||||
if (!result.getData().contains(targetUserId)) {
|
||||
throw new RuntimeException("无权查看该被监护人的钱包流水");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_NO_WARD_TX_PERM);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-15
@@ -10,8 +10,11 @@ import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.admin.api.vo.UserVO;
|
||||
import com.bsd.pjcloud.common.core.constant.CommonRoleConstant;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.BeanUtils;
|
||||
import com.bsd.pjcloud.common.core.util.CollectionUtils;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.security.service.PjcloudUser;
|
||||
import com.bsd.pjcloud.wallet.api.constant.WalletTypeEnum;
|
||||
import com.bsd.pjcloud.wallet.api.constant.act.ActCancelStatusEnum;
|
||||
@@ -145,32 +148,32 @@ public class ActCancelItemServiceImpl extends ServiceImpl<ActCancelItemMapper, A
|
||||
public Long appGet(PjcloudUser user, ActCancelItemDto dto) {
|
||||
// 查询活动
|
||||
ActCancelEntity act = actCancelMapper.selectById(dto.getActId());
|
||||
if (ObjectUtil.isEmpty(act)) throw new RuntimeException("核销活动不存在");
|
||||
if (ObjectUtil.isEmpty(act)) throw new I18nBizException(ErrorCodes.ACT_CANCEL_NOT_FOUND);
|
||||
if (ObjectUtil.equals(act.getActStatus(), ActStatusEnum.ACT_CANCEL.getCode())) {
|
||||
throw new RuntimeException("核销活动已关闭");
|
||||
throw new I18nBizException(ErrorCodes.ACT_CANCEL_CLOSED);
|
||||
}
|
||||
|
||||
// 判断是否在时间内
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
if (act.getExpireTime().isBefore(LocalDateTime.now())) {
|
||||
throw new RuntimeException("核销失败,活动已结束");
|
||||
throw new I18nBizException(ErrorCodes.HARD_ACT_ENDED);
|
||||
}
|
||||
if (act.getStartTime().isAfter(LocalDateTime.now())) {
|
||||
throw new RuntimeException("核销失败,活动未开始");
|
||||
throw new I18nBizException(ErrorCodes.HARD_ACT_NOT_STARTED);
|
||||
}
|
||||
|
||||
// 获取商户
|
||||
MchManageEntity actMch = mchManageService.getById(dto.getMchId());
|
||||
if (ObjectUtil.isEmpty(actMch)) throw new RuntimeException("核销活动商户不存在");
|
||||
if (ObjectUtil.isEmpty(actMch)) throw new I18nBizException(ErrorCodes.ACT_CANCEL_MCH_MISSING);
|
||||
|
||||
// 判断是否已经领取
|
||||
if (existAct(user.getId(), dto.getActId())) throw new RuntimeException("您已经领,请勿重复领取");
|
||||
if (existAct(user.getId(), dto.getActId())) throw new I18nBizException(ErrorCodes.ACT_CANCEL_ALREADY_RECEIVED);
|
||||
|
||||
// 查询余是否大于核销价格
|
||||
WalletManageEntity wallet = walletManageService.getWallet(user.getId(), WalletTypeEnum.PAY);
|
||||
String cancelPrice = new BigDecimal(act.getActiveCancelPrice()).divide(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP).toString();
|
||||
if (wallet.getBalance() < act.getActiveCancelPrice()) {
|
||||
throw new RuntimeException("消费钱包余额不足" + cancelPrice + "元,无法领取");
|
||||
throw new I18nBizException(ErrorCodes.ACT_CANCEL_BALANCE_LOW, cancelPrice);
|
||||
}
|
||||
|
||||
LocalDateTime expireTime = act.getExpireTime();
|
||||
@@ -194,7 +197,7 @@ public class ActCancelItemServiceImpl extends ServiceImpl<ActCancelItemMapper, A
|
||||
public ActCancelItemVo appFindUnique(Long actId, PjcloudUser user) {
|
||||
// 查询活动
|
||||
ActCancelEntity act = actCancelMapper.selectById(actId);
|
||||
if (ObjectUtil.isEmpty(act)) throw new RuntimeException("核销活动不存在");
|
||||
if (ObjectUtil.isEmpty(act)) throw new I18nBizException(ErrorCodes.ACT_CANCEL_NOT_FOUND);
|
||||
ActCancelItemEntity detail = baseMapper.selectOne(new LambdaQueryWrapper<ActCancelItemEntity>()
|
||||
.eq(ActCancelItemEntity::getActId, actId)
|
||||
.eq(ActCancelItemEntity::getReceiverUserId, user.getId())
|
||||
@@ -202,7 +205,7 @@ public class ActCancelItemServiceImpl extends ServiceImpl<ActCancelItemMapper, A
|
||||
if (ObjectUtil.isEmpty(detail)) return null;
|
||||
if (ObjectUtil.isNotEmpty(detail.getExpireTime())) {
|
||||
if (detail.getExpireTime().isBefore(LocalDateTime.now())) {
|
||||
throw new RuntimeException("您领取的优惠券已过期");
|
||||
throw new I18nBizException(ErrorCodes.ACT_CANCEL_COUPON_EXPIRED);
|
||||
}
|
||||
}
|
||||
ActCancelItemVo result = BeanUtil.toBean(detail, ActCancelItemVo.class);
|
||||
@@ -250,15 +253,15 @@ public class ActCancelItemServiceImpl extends ServiceImpl<ActCancelItemMapper, A
|
||||
UserInfo userDetail = remoteUserService.getInnerByUserId(dto.getCancelUserId()).getData();
|
||||
if (ObjectUtil.isEmpty(userDetail)) {
|
||||
log.error("|{}|核销失败,核销用户不存在", TAG);
|
||||
throw new RuntimeException("核销失败,核销用户不存在");
|
||||
throw new I18nBizException(ErrorCodes.HARD_ACT_VERIFY_USER_MISSING);
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(detail.getExpireTime())) {
|
||||
if (detail.getExpireTime().isBefore(LocalDateTime.now())) {
|
||||
throw new RuntimeException("核销失败,您领取的优惠券已过期");
|
||||
throw new I18nBizException(ErrorCodes.ACT_CANCEL_COUPON_EXPIRED);
|
||||
}
|
||||
}
|
||||
if (ObjectUtil.equals(detail.getActStatus(), ActCancelStatusEnum.CANCEL_SUCCESS.getCode())) {
|
||||
throw new RuntimeException("核销失败,您领取的优惠券已核销");
|
||||
throw new I18nBizException(ErrorCodes.HARD_ACT_COUPON_USED);
|
||||
}
|
||||
ActCancelItemEntity updateObj = new ActCancelItemEntity();
|
||||
updateObj.setId(detail.getId());
|
||||
@@ -307,15 +310,15 @@ public class ActCancelItemServiceImpl extends ServiceImpl<ActCancelItemMapper, A
|
||||
// 查询核销用户
|
||||
UserInfo userDetail = remoteUserService.getInnerByUserId(dto.getCancelUserId()).getData();
|
||||
if (ObjectUtil.isEmpty(userDetail)) {
|
||||
return "核销失败,核销用户不存在";
|
||||
return MsgUtils.getMessage(ErrorCodes.HARD_ACT_VERIFY_USER_MISSING);
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(detail.getExpireTime())) {
|
||||
if (detail.getExpireTime().isBefore(LocalDateTime.now())) {
|
||||
return "核销失败,您领取的优惠券已过期";
|
||||
return MsgUtils.getMessage(ErrorCodes.ACT_CANCEL_COUPON_EXPIRED);
|
||||
}
|
||||
}
|
||||
if (ObjectUtil.equals(detail.getActStatus(), ActCancelStatusEnum.CANCEL_SUCCESS.getCode())) {
|
||||
return "核销失败,您领取的优惠券已核销";
|
||||
return MsgUtils.getMessage(ErrorCodes.HARD_ACT_COUPON_USED);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+8
-6
@@ -13,6 +13,8 @@ import com.bsd.pjcloud.admin.api.utils.DataUtil;
|
||||
import com.bsd.pjcloud.admin.api.vo.UserVO;
|
||||
import com.bsd.pjcloud.common.core.constant.CommonRoleConstant;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.exception.ServiceException;
|
||||
import com.bsd.pjcloud.common.core.util.CollectionUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
@@ -102,7 +104,7 @@ public class ActCouponRecordServiceImpl extends ServiceImpl<ActCouponRecordMappe
|
||||
// 1. 获取当前用户
|
||||
UserInfo userInfo = remoteUserService.getByUserId(dto.getReceiveUserId()).getData();
|
||||
if (ObjectUtil.isEmpty(userInfo)) {
|
||||
throw new ServiceException("用户不存在");
|
||||
throw new I18nBizException(ErrorCodes.SYS_USER_NOT_FOUND);
|
||||
}
|
||||
SysUser sysUser = userInfo.getSysUser();
|
||||
// 2. 预处理
|
||||
@@ -134,22 +136,22 @@ public class ActCouponRecordServiceImpl extends ServiceImpl<ActCouponRecordMappe
|
||||
// 1. 获取当前用户
|
||||
UserInfo userInfo = remoteUserService.getInnerByUserId(dto.getUserId()).getData();
|
||||
if (ObjectUtil.isEmpty(userInfo)) {
|
||||
throw new ServiceException("用户不存在");
|
||||
throw new I18nBizException(ErrorCodes.SYS_USER_NOT_FOUND);
|
||||
}
|
||||
SysUser sysUser = userInfo.getSysUser();
|
||||
ActCouponRecordEntity record = getDetail(dto.getId(), dto.getUserId());
|
||||
if (ObjectUtil.isEmpty(record)) {
|
||||
throw new ServiceException("优惠券不存在");
|
||||
throw new I18nBizException(ErrorCodes.ACT_COUPON_NOT_FOUND);
|
||||
}
|
||||
// 2. 查询活动
|
||||
ActCouponEntity actCouponEntity = actCouponService.getById(record.getCouponId());
|
||||
if (ObjectUtil.isEmpty(actCouponEntity)) {
|
||||
throw new ServiceException("活动不存在");
|
||||
throw new I18nBizException(ErrorCodes.ACT_NOT_FOUND);
|
||||
}
|
||||
// 3. 预处理
|
||||
ActCouponRecordEntity actCouponRecordEntity = actCouponComUtilService.preCancel(record);
|
||||
if (ObjectUtil.isEmpty(actCouponRecordEntity)) {
|
||||
throw new ServiceException("优惠券不存在");
|
||||
throw new I18nBizException(ErrorCodes.ACT_COUPON_NOT_FOUND);
|
||||
}
|
||||
// 4. 执行核销逻辑
|
||||
actCouponComUtilService.doCancel(actCouponRecordEntity.getId(), orderId, useAmountPrice);
|
||||
@@ -180,7 +182,7 @@ public class ActCouponRecordServiceImpl extends ServiceImpl<ActCouponRecordMappe
|
||||
if (ObjectUtil.isEmpty(actAdExtraJson) || ObjectUtil.isEmpty(actAdExtraJson.getIntegralNum())) return;
|
||||
IntegralTransactionEntity integralTransaction = integralTransactionService.reduceIntegral(sysUser.getUserId(), actAdExtraJson.getIntegralNum(), WalletIntegralBizEnum.EXCHANGE, String.valueOf(record.getId()), false);
|
||||
if (ObjectUtil.isEmpty(integralTransaction)) {
|
||||
throw new RuntimeException("扣减积分错误");
|
||||
throw new I18nBizException(ErrorCodes.ACT_COUPON_POINTS_DEDUCT_FAIL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-7
@@ -1,5 +1,8 @@
|
||||
package com.bsd.pjcloud.wallet.service.impl.recharge;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
@@ -103,7 +106,7 @@ public class WalletRechargePackageServiceImpl extends ServiceImpl<WalletRecharge
|
||||
update.setPayTime(LocalDateTime.now());
|
||||
if (walletRechargeMapper.updateById(update) == 0) {
|
||||
// 状态未落库时必须回滚同一事务中的余额变更,否则重试回调会再次入账。
|
||||
throw new RuntimeException("更新代充值到账状态失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PROXY_PAY_STATUS_FAIL);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -145,7 +148,7 @@ public class WalletRechargePackageServiceImpl extends ServiceImpl<WalletRecharge
|
||||
return true;
|
||||
}
|
||||
if (!Boolean.TRUE.equals(guardianRecharge.getPayStatus())) {
|
||||
throw new RuntimeException("代充值尚未到账,不能退款");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PROXY_REFUND_NOT_PAID);
|
||||
}
|
||||
topupWallet = walletManageService.getWallet(guardianRecharge.getWalletId());
|
||||
totalPrice = guardianRecharge.getTotalPrice();
|
||||
@@ -174,7 +177,7 @@ public class WalletRechargePackageServiceImpl extends ServiceImpl<WalletRecharge
|
||||
update.setRefundTime(LocalDateTime.now());
|
||||
if (walletRechargeMapper.updateById(update) == 0) {
|
||||
// 状态未落库时必须回滚扣款,确保退款通知重试不会重复扣减目标饭卡。
|
||||
throw new RuntimeException("更新代充值退款状态失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PROXY_REFUND_STATUS_FAIL);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -191,11 +194,11 @@ public class WalletRechargePackageServiceImpl extends ServiceImpl<WalletRecharge
|
||||
try {
|
||||
rechargeId = Long.valueOf(bizId);
|
||||
} catch (Exception exception) {
|
||||
throw new RuntimeException("代充值业务ID无效");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PROXY_RECHARGE_BIZ_ID_INVALID);
|
||||
}
|
||||
WalletRechargeEntity recharge = walletRechargeMapper.selectByIdForUpdate(rechargeId);
|
||||
if (recharge == null || recharge.getWalletId() == null || recharge.getPackageId() == null || recharge.getTotalPrice() == null || recharge.getTotalPrice() <= 0) {
|
||||
throw new RuntimeException("代充值记录不存在或金额无效");
|
||||
throw new I18nBizException(ErrorCodes.THIRD_PROXY_RECHARGE_INVALID);
|
||||
}
|
||||
return recharge;
|
||||
}
|
||||
@@ -210,10 +213,10 @@ public class WalletRechargePackageServiceImpl extends ServiceImpl<WalletRecharge
|
||||
public WalletRechargePackageEntity validEffective(Long packageId) {
|
||||
WalletRechargePackageEntity packageEntity = baseMapper.selectById(packageId);
|
||||
if (ObjectUtil.isEmpty(packageEntity)) {
|
||||
throw new RuntimeException("钱包充值套餐不存在");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PACKAGE_NOT_FOUND);
|
||||
}
|
||||
if (ObjectUtil.equals(packageEntity.getStatus(), YesNoEnum.NO.getCode())) {
|
||||
throw new RuntimeException("钱包充值套餐已禁用");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PACKAGE_DISABLED);
|
||||
}
|
||||
return packageEntity;
|
||||
}
|
||||
|
||||
+47
-24
@@ -1,5 +1,8 @@
|
||||
package com.bsd.pjcloud.wallet.service.impl.recharge;
|
||||
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -13,6 +16,7 @@ import com.bsd.pjcloud.admin.api.vo.SysUserFaceStatusCountVo;
|
||||
import com.bsd.pjcloud.admin.api.vo.UserVO;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.util.BeanUtils;
|
||||
import com.bsd.pjcloud.common.core.util.MsgUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.hard.api.constant.refund.HardRefundStatusEnum;
|
||||
import com.bsd.pjcloud.hard.api.feign.RemoteHardOrderService;
|
||||
@@ -182,7 +186,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
throw new RuntimeException("查询关系人信息失败", exception);
|
||||
}
|
||||
if (userResult == null || !userResult.isOk() || userResult.getData() == null) {
|
||||
throw new RuntimeException("查询关系人信息失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_RELATION_QUERY_FAIL);
|
||||
}
|
||||
Map<Long, UserVO> userMap = new LinkedHashMap<>();
|
||||
userResult.getData().forEach(user -> userMap.put(user.getUserId(), user));
|
||||
@@ -226,7 +230,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
WalletManageEntity wallet = requireRechargeableWallet(dto.getWardUserId(), ward);
|
||||
WalletRechargePackageEntity rechargePackage = walletRechargePackageService.validEffective(dto.getPackageId());
|
||||
if (rechargePackage.getPayPrice() == null || rechargePackage.getPayPrice() <= 0) {
|
||||
throw new RuntimeException("充值套餐金额无效");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PACKAGE_AMOUNT_INVALID);
|
||||
}
|
||||
// 创建待支付记录前先确认目标食堂存在可用支付配置,避免产生无法继续支付的孤立记录。
|
||||
resolvePaymentPlatformTypes(wallet);
|
||||
@@ -253,7 +257,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
WalletRechargeEntity recharge = requireRecharge(rechargeId);
|
||||
WalletManageEntity wallet = walletManageService.getWallet(recharge.getWalletId());
|
||||
if (wallet == null) {
|
||||
throw new RuntimeException("目标饭卡不存在");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TARGET_CARD_MISSING);
|
||||
}
|
||||
UserVO ward = requireActiveWard(guardianUserId, wallet.getUserId());
|
||||
GuardianWardRechargeResultVo result = new GuardianWardRechargeResultVo();
|
||||
@@ -288,7 +292,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
mchAutoRefundConfigService.lockForUpdate(dto.getAutoRefundConfigId());
|
||||
}
|
||||
WalletManageEntity wallet = walletManageMapper.selectByIdForUpdate(dto.getWalletId());
|
||||
if (ObjectUtil.isEmpty(wallet)) throw new RuntimeException("用户钱包不存在");
|
||||
if (ObjectUtil.isEmpty(wallet)) throw new I18nBizException(ErrorCodes.COMMON_WALLET_NOT_FOUND);
|
||||
// 每次部分退款以售后单 ID 幂等;重复调用返回原退款单,不再次增加钱包余额。
|
||||
WalletRechargeEntity refund = getByRefundId(dto.getAfterSaleId());
|
||||
if (ObjectUtil.isNotEmpty(refund)) {
|
||||
@@ -415,7 +419,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
WalletTransactionEntity rollbackTransaction = walletTransactionService.reduceWalletBalance(wallet.getId(),
|
||||
refundPrice, REFUND_ROLLBACK_BIZ_PREFIX + afterSaleId, WalletBizEnum.REFUND, true);
|
||||
if (rollbackTransaction == null) {
|
||||
throw new RuntimeException("钱包退款金额扣回失败");
|
||||
throw new I18nBizException(ErrorCodes.AFTER_SALE_WALLET_CLAWBACK_FAIL);
|
||||
}
|
||||
WalletRechargeEntity update = WalletRechargeEntity.builder().id(refund.getId())
|
||||
.refundStatus(HardRefundStatusEnum.NONE.getStatus()).build();
|
||||
@@ -470,7 +474,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
throw new RuntimeException("查询监护关系失败", exception);
|
||||
}
|
||||
if (result == null || !result.isOk() || result.getData() == null) {
|
||||
throw new RuntimeException("查询监护关系失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_GUARDIAN_RELATION_FAIL);
|
||||
}
|
||||
return result.getData().stream().filter(Objects::nonNull).distinct().toList();
|
||||
}
|
||||
@@ -489,7 +493,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
throw new RuntimeException("查询用户关系失败", exception);
|
||||
}
|
||||
if (result == null || !result.isOk() || result.getData() == null) {
|
||||
throw new RuntimeException("查询用户关系失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_USER_RELATION_FAIL);
|
||||
}
|
||||
return result.getData().stream().filter(Objects::nonNull).distinct().toList();
|
||||
}
|
||||
@@ -508,7 +512,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
throw new RuntimeException("查询用户人脸情况失败", exception);
|
||||
}
|
||||
if (result == null || !result.isOk() || result.getData() == null) {
|
||||
throw new RuntimeException("查询用户人脸情况失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_FACE_QUERY_FAIL);
|
||||
}
|
||||
Map<Long, SysUserFaceStatusCountVo> countMap = new LinkedHashMap<>();
|
||||
result.getData().stream().filter(Objects::nonNull).filter(item -> item.getUserId() != null).forEach(item -> countMap.put(item.getUserId(), item));
|
||||
@@ -529,7 +533,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
throw new RuntimeException("查询用户待核销预约失败", exception);
|
||||
}
|
||||
if (result == null || !result.isOk() || result.getData() == null) {
|
||||
throw new RuntimeException("查询用户待核销预约失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PENDING_APPT_FAIL);
|
||||
}
|
||||
Map<Long, HardPendingReservationCountVo> countMap = new LinkedHashMap<>();
|
||||
result.getData().stream().filter(Objects::nonNull).filter(item -> item.getUserId() != null).forEach(item -> countMap.put(item.getUserId(), item));
|
||||
@@ -541,7 +545,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
*/
|
||||
private UserVO requireActiveWard(Long guardianUserId, Long wardUserId) {
|
||||
if (wardUserId == null || !listActiveWardUserIds(guardianUserId).contains(wardUserId)) {
|
||||
throw new RuntimeException("无权操作该被监护人");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_NO_WARD_PERM);
|
||||
}
|
||||
R<List<UserVO>> result;
|
||||
try {
|
||||
@@ -551,7 +555,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
throw new RuntimeException("查询被监护人信息失败", exception);
|
||||
}
|
||||
if (result == null || !result.isOk() || CollUtil.isEmpty(result.getData())) {
|
||||
throw new RuntimeException("被监护人不存在");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_WARD_NOT_FOUND);
|
||||
}
|
||||
return result.getData().get(0);
|
||||
}
|
||||
@@ -563,7 +567,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
WalletManageEntity wallet = walletManageService.getWallet(wardUserId, WalletTypeEnum.EAT);
|
||||
GuardianWardRechargeItemVo item = buildWardItem(ward, wallet);
|
||||
if (!Boolean.TRUE.equals(item.getRechargeEnabled())) {
|
||||
throw new RuntimeException(item.getDisabledReason());
|
||||
throwRechargeDisabled(wallet, item.getIdentityTypes());
|
||||
}
|
||||
return wallet;
|
||||
}
|
||||
@@ -575,7 +579,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
*/
|
||||
private void requireTopUpIdentityAllowed(WalletManageEntity wallet) {
|
||||
if (wallet == null || wallet.getUserId() == null) {
|
||||
throw new RuntimeException("用户钱包不存在");
|
||||
throw new I18nBizException(ErrorCodes.COMMON_WALLET_NOT_FOUND);
|
||||
}
|
||||
R<List<UserVO>> userResult;
|
||||
try {
|
||||
@@ -584,14 +588,14 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
throw new RuntimeException("查询充值用户身份失败", exception);
|
||||
}
|
||||
if (userResult == null || !userResult.isOk() || CollUtil.isEmpty(userResult.getData())) {
|
||||
throw new RuntimeException("查询充值用户身份失败");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_IDENTITY_QUERY_FAIL);
|
||||
}
|
||||
MchManageVo merchant = mchManageService.getViewsCanteenMchByDeptId(wallet.getDeptId());
|
||||
if (merchant == null) {
|
||||
throw new RuntimeException("钱包所属食堂不存在");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_CANTEEN_MISSING);
|
||||
}
|
||||
if (!mchManageService.isTopUpIdentityAllowed(merchant, userResult.getData().get(0).getIdentityTypes())) {
|
||||
throw new RuntimeException("当前人员身份不支持钱包充值");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_IDENTITY_NO_RECHARGE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,7 +613,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
item.setBalance(0);
|
||||
item.setCardStatusName("未开通");
|
||||
item.setRechargeEnabled(false);
|
||||
item.setDisabledReason("未开通饭卡");
|
||||
item.setDisabledReason(MsgUtils.getMessage(ErrorCodes.WALLET_MEAL_CARD_NOT_OPEN));
|
||||
return item;
|
||||
}
|
||||
item.setWalletOpened(true);
|
||||
@@ -625,6 +629,25 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
return item;
|
||||
}
|
||||
|
||||
private void throwRechargeDisabled(WalletManageEntity wallet, List<String> identityTypes) {
|
||||
if (ObjectUtil.equals(wallet.getIsFreeze(), YesNoEnum.YES.getCode())) {
|
||||
throw new I18nBizException(ErrorCodes.WALLET_MEAL_CARD_FROZEN);
|
||||
}
|
||||
boolean cardStatusSupportsRecharge = StrUtil.isBlank(wallet.getStatus())
|
||||
|| ObjectUtil.equals(wallet.getStatus(), WalleCardStatusEnum.NONE_ACTIVE.getCode())
|
||||
|| ObjectUtil.equals(wallet.getStatus(), WalleCardStatusEnum.ACTIVE.getCode());
|
||||
if (!cardStatusSupportsRecharge) {
|
||||
throw new I18nBizException(ErrorCodes.WALLET_CARD_STATUS_NO_RECHARGE, cardStatusName(wallet.getStatus()));
|
||||
}
|
||||
MchManageVo merchant = mchManageService.getViewsCanteenMchByDeptId(wallet.getDeptId());
|
||||
if (merchant == null) {
|
||||
throw new I18nBizException(ErrorCodes.WALLET_CARD_CANTEEN_MISSING);
|
||||
}
|
||||
if (!mchManageService.isTopUpIdentityAllowed(merchant, identityTypes)) {
|
||||
throw new I18nBizException(ErrorCodes.WALLET_IDENTITY_NO_RECHARGE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回余额钱包的充值禁用原因。未绑定或未激活实体饭卡不影响余额充值,只有冻结、挂失、锁卡、
|
||||
* 销卡、异常状态、商户异常或人员身份不匹配时才禁止充值,页面无需自行推断状态编码。
|
||||
@@ -635,22 +658,22 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
*/
|
||||
private String rechargeDisabledReason(WalletManageEntity wallet, List<String> identityTypes) {
|
||||
if (ObjectUtil.equals(wallet.getIsFreeze(), YesNoEnum.YES.getCode())) {
|
||||
return "饭卡已冻结";
|
||||
return MsgUtils.getMessage(ErrorCodes.WALLET_MEAL_CARD_FROZEN);
|
||||
}
|
||||
// 新建但尚未绑定实体卡的钱包可能没有写入绑定状态,空状态与“未激活”均表示可接收余额充值。
|
||||
boolean cardStatusSupportsRecharge = StrUtil.isBlank(wallet.getStatus())
|
||||
|| ObjectUtil.equals(wallet.getStatus(), WalleCardStatusEnum.NONE_ACTIVE.getCode())
|
||||
|| ObjectUtil.equals(wallet.getStatus(), WalleCardStatusEnum.ACTIVE.getCode());
|
||||
if (!cardStatusSupportsRecharge) {
|
||||
return cardStatusName(wallet.getStatus()) + ",暂不可充值";
|
||||
return MsgUtils.getMessage(ErrorCodes.WALLET_CARD_STATUS_NO_RECHARGE, cardStatusName(wallet.getStatus()));
|
||||
}
|
||||
MchManageVo merchant = mchManageService.getViewsCanteenMchByDeptId(wallet.getDeptId());
|
||||
if (merchant == null) {
|
||||
return "饭卡所属食堂不存在";
|
||||
return MsgUtils.getMessage(ErrorCodes.WALLET_CARD_CANTEEN_MISSING);
|
||||
}
|
||||
// 商户未配置身份限制时保持历史行为;配置非空时要求目标用户至少命中一种身份。
|
||||
if (!mchManageService.isTopUpIdentityAllowed(merchant, identityTypes)) {
|
||||
return "当前人员身份不支持钱包充值";
|
||||
return MsgUtils.getMessage(ErrorCodes.WALLET_IDENTITY_NO_RECHARGE);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -708,7 +731,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
private List<String> resolvePaymentPlatformTypes(WalletManageEntity wallet) {
|
||||
MchManageVo merchant = mchManageService.getViewsCanteenMchByDeptId(wallet.getDeptId());
|
||||
if (merchant == null) {
|
||||
throw new RuntimeException("饭卡所属食堂不存在");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_CARD_CANTEEN_MISSING);
|
||||
}
|
||||
List<String> platformTypes = merchant.getPaySettingList() == null ? List.of() : merchant.getPaySettingList().stream()
|
||||
.map(item -> item.getPlatformType())
|
||||
@@ -716,7 +739,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
.distinct()
|
||||
.toList();
|
||||
if (CollUtil.isEmpty(platformTypes)) {
|
||||
throw new RuntimeException("饭卡所属食堂暂未配置支付方式");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PAY_METHOD_MISSING);
|
||||
}
|
||||
return platformTypes;
|
||||
}
|
||||
@@ -727,7 +750,7 @@ public class WalletRechargeServiceImpl extends ServiceImpl<WalletRechargeMapper,
|
||||
private WalletRechargeEntity requireRecharge(Long rechargeId) {
|
||||
WalletRechargeEntity recharge = getById(rechargeId);
|
||||
if (recharge == null || recharge.getWalletId() == null || recharge.getPackageId() == null) {
|
||||
throw new RuntimeException("代充值记录不存在");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_PROXY_RECORD_MISSING);
|
||||
}
|
||||
return recharge;
|
||||
}
|
||||
|
||||
+7
-5
@@ -7,6 +7,8 @@ import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
|
||||
import com.bsd.pjcloud.admin.api.utils.DataUtil;
|
||||
import com.bsd.pjcloud.admin.api.vo.UserVO;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.exception.ErrorCodes;
|
||||
import com.bsd.pjcloud.common.core.exception.I18nBizException;
|
||||
import com.bsd.pjcloud.common.core.util.CollectionUtils;
|
||||
import com.bsd.pjcloud.common.data.datascope.DataScope;
|
||||
import com.bsd.pjcloud.wallet.api.constant.WalletBizEnum;
|
||||
@@ -130,7 +132,7 @@ public class WalletRuleTransactionServiceImpl extends ServiceImpl<WalletRuleTran
|
||||
WalletRuleTransactionEntity entity = new WalletRuleTransactionEntity();
|
||||
int price = userConfig.getSourceWalletBalance() - body.getBalance();
|
||||
if (price < 0) {
|
||||
throw new RuntimeException("源钱包" + userConfig.getSourceWalletTypeName() + "余额不足");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TRANSFER_SOURCE_LOW, userConfig.getSourceWalletTypeName());
|
||||
}
|
||||
// 查询源饭卡
|
||||
if (ObjectUtil.equals(userConfig.getSourceWalletUniqueCode(), WalletTypeEnum.EAT.getCode())) {
|
||||
@@ -144,7 +146,7 @@ public class WalletRuleTransactionServiceImpl extends ServiceImpl<WalletRuleTran
|
||||
// 是否已经超过最大限制
|
||||
long cuurentTotalTransferBalance = userConfig.getTotalTransferBalance() + body.getBalance();
|
||||
if (cuurentTotalTransferBalance > userConfig.getMaxTransferBalance()) {
|
||||
throw new RuntimeException("已经超过最大转账金额限制");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TRANSFER_LIMIT_EXCEEDED);
|
||||
}
|
||||
entity.setBizType(WalletRuleTransationTypeEnum.USER_CHANGE.getCode());
|
||||
entity.setSourceWalletId(userConfig.getSourceWalletId());
|
||||
@@ -170,15 +172,15 @@ public class WalletRuleTransactionServiceImpl extends ServiceImpl<WalletRuleTran
|
||||
public void refund(Long id) {
|
||||
// 判断是否已退回
|
||||
WalletRuleTransactionEntity detail = baseMapper.selectById(id);
|
||||
if (ObjectUtil.isEmpty(detail)) throw new RuntimeException("查询不到转账记录");
|
||||
if (ObjectUtil.isEmpty(detail)) throw new I18nBizException(ErrorCodes.WALLET_TRANSFER_NOT_FOUND);
|
||||
if (ObjectUtil.equals(detail.getIsRefund(), YesNoEnum.YES.getCode())) {
|
||||
throw new RuntimeException("已退回请勿重复操作");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TRANSFER_REFUND_DUP);
|
||||
}
|
||||
// 判断源钱包余额是否够
|
||||
WalletManageVo tragetWallet = walletManageService.join(detail.getTargetWalletId());
|
||||
int price = tragetWallet.getBalance() - detail.getBalance();
|
||||
if (price < 0) {
|
||||
throw new RuntimeException("源钱包" + tragetWallet.getWalletTypeName() + "余额不足,无法退回");
|
||||
throw new I18nBizException(ErrorCodes.WALLET_TRANSFER_REFUND_SOURCE_LOW, tragetWallet.getWalletTypeName());
|
||||
}
|
||||
// 源头钱包增加
|
||||
walletTransactionService.addWalletBalance(detail.getSourceWalletId(), detail.getBalance(), String.valueOf(detail.getId()), WalletBizEnum.TRANSFER_ACCOUNTS_REFUND);
|
||||
|
||||
Reference in new issue
Block a user