111
This commit is contained in:
1 parent
97ff8289e2
commit
a5a28f0990
25 files changed
+332
-169
No files matched your search
+5
@@ -5,6 +5,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 开门类型
|
||||
@@ -19,6 +20,10 @@ public enum HardDoorOpenTypeEnum {
|
||||
private final String type;
|
||||
private final String description;
|
||||
|
||||
public static List<String> getMaintenanceListCodes() {
|
||||
return List.of(MAINTENANCE_UNLOCK.getType(), MAINTENANCE_LOCK.getType());
|
||||
}
|
||||
|
||||
public static HardDoorOpenTypeEnum valueOfByType(String type) {
|
||||
if (ObjectUtil.isEmpty(type)) return null;
|
||||
return Arrays.stream(values()).filter(v -> ObjectUtil.equals(type, v.getType())).findFirst().get();
|
||||
|
||||
+7
@@ -121,6 +121,7 @@ public class HardDoorFlowEntity extends Model<HardDoorFlowEntity> {
|
||||
@Schema(description = "视频回调时间")
|
||||
private LocalDateTime videoCallbackTime;
|
||||
|
||||
|
||||
/**
|
||||
* sku识别提交参数
|
||||
*/
|
||||
@@ -133,6 +134,12 @@ public class HardDoorFlowEntity extends Model<HardDoorFlowEntity> {
|
||||
@Schema(description = "sku识别提交结果")
|
||||
private String skuSubmitVo;
|
||||
|
||||
/**
|
||||
* sku识别提交id(用于查询)
|
||||
*/
|
||||
@Schema(description = "sku识别提交id(用于查询)")
|
||||
private String skuSubmitRecogId;
|
||||
|
||||
/**
|
||||
* sku识别提交时间
|
||||
*/
|
||||
|
||||
-6
@@ -36,12 +36,6 @@ public class HardSpuRepertoryEntity extends Model<HardSpuRepertoryEntity> {
|
||||
@Schema(description = "用户id")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 设备id
|
||||
*/
|
||||
@Schema(description = "设备id")
|
||||
private Long hardId;
|
||||
|
||||
/**
|
||||
* 商品id
|
||||
*/
|
||||
|
||||
+1
-9
@@ -2,12 +2,11 @@ package com.bsd.pjcloud.hard.api.vo.spu;
|
||||
|
||||
import com.bsd.pjcloud.admin.api.vo.base.BaseUserInterface;
|
||||
import com.bsd.pjcloud.hard.api.entity.spu.HardSpuRepertoryEntity;
|
||||
import com.bsd.pjcloud.hard.api.vo.base.BaseHardInterface;
|
||||
import com.bsd.pjcloud.wallet.api.vo.base.BaseMchInterface;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class HardSpuRepertoryVo extends HardSpuRepertoryEntity implements BaseMchInterface, BaseHardInterface, BaseUserInterface {
|
||||
public class HardSpuRepertoryVo extends HardSpuRepertoryEntity implements BaseMchInterface, BaseUserInterface {
|
||||
|
||||
/**
|
||||
* 商品相关
|
||||
@@ -34,13 +33,6 @@ public class HardSpuRepertoryVo extends HardSpuRepertoryEntity implements BaseMc
|
||||
|
||||
private String logoPic;
|
||||
|
||||
/**
|
||||
* 设备相关
|
||||
*/
|
||||
private String hardName;
|
||||
|
||||
private String hardType;
|
||||
|
||||
/**
|
||||
* 用户相关
|
||||
*/
|
||||
|
||||
+1
-11
@@ -31,27 +31,17 @@ public interface HardCarService extends IService<HardCarEntity> {
|
||||
|
||||
/**
|
||||
* 新增或者更新购物车
|
||||
*
|
||||
* @param dto
|
||||
*/
|
||||
void saveOrUpload(HardCarSaveOrUpdateDto dto);
|
||||
|
||||
/**
|
||||
* @param userId 用户id
|
||||
* @param merchantId 商户id
|
||||
* @param sysType 硬件设备类型
|
||||
* @param list g购物车类表
|
||||
* @return 父购物车id
|
||||
* 创建购物车
|
||||
*/
|
||||
Long createCard(Long userId, Long merchantId, HardTypeEnum sysType, HardOrderTypeEnum orderTYpe, List<HardCreateCarDto> list);
|
||||
|
||||
|
||||
/**
|
||||
* 生成购买商品的描述
|
||||
*
|
||||
* @param sysType 订单类型
|
||||
* @param list 购物车列表
|
||||
* @return
|
||||
*/
|
||||
String computerCarSubject(HardTypeEnum sysType, HardOrderTypeEnum orderType, List<HardCreateCarDto> list);
|
||||
}
|
||||
+5
-4
@@ -38,15 +38,16 @@ public interface HardDoorFlowService extends IService<HardDoorFlowEntity> {
|
||||
*/
|
||||
void disposeLocakCallback(DoorOpenCallbackDto dto);
|
||||
|
||||
/**
|
||||
* 处理柜子状态回调
|
||||
*/
|
||||
void disposeStatusCallback(DoorStatusCallbackDto dto);
|
||||
|
||||
/**
|
||||
* 处理视频回调
|
||||
*/
|
||||
void disposeVideoCallback(DoorVideoCallbackDto dto);
|
||||
|
||||
/**
|
||||
* 处理柜子状态回调
|
||||
*/
|
||||
void disposeStatusCallback(DoorStatusCallbackDto dto);
|
||||
|
||||
/**
|
||||
* 处理旷世识别回调
|
||||
|
||||
+7
@@ -7,10 +7,12 @@ import com.bsd.pjcloud.common.data.datascope.DataScope;
|
||||
import com.bsd.pjcloud.common.security.service.PjcloudUser;
|
||||
import com.bsd.pjcloud.hard.api.dto.hard.HandCancelCodeDto;
|
||||
import com.bsd.pjcloud.hard.api.dto.hard.HardCreateOrderDto;
|
||||
import com.bsd.pjcloud.hard.api.dto.order.HardCreateCarDto;
|
||||
import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto;
|
||||
import com.bsd.pjcloud.hard.api.dto.order.app.HardAppCreateOrderDto;
|
||||
import com.bsd.pjcloud.hard.api.entity.order.HardOrderEntity;
|
||||
import com.bsd.pjcloud.hard.api.vo.order.HardOrderVo;
|
||||
import com.bsd.pjcloud.thirdparty.dto.ks.KsRecognitionCallbackDto;
|
||||
import jakarta.validation.Valid;
|
||||
|
||||
import java.util.List;
|
||||
@@ -47,6 +49,11 @@ public interface HardOrderService extends IService<HardOrderEntity> {
|
||||
*/
|
||||
Long createHardDoorOrder(Long userId, Long hardId);
|
||||
|
||||
/**
|
||||
* 结算智能柜订单
|
||||
*/
|
||||
Long payHardDoorOrder(HardOrderEntity dto, List<KsRecognitionCallbackDto.ResultSku> ksSpuList);
|
||||
|
||||
/**
|
||||
* 快速扣款,离线订单使用
|
||||
*/
|
||||
|
||||
+9
@@ -20,6 +20,10 @@ public interface HardSpuService extends IService<HardSpuEntity> {
|
||||
*/
|
||||
Page<HardSpuVo> scopPageJoin(Page page, HardSpuDto dto, DataScope dataScope);
|
||||
|
||||
List<HardSpuEntity> get(List<String> ksSpuIds);
|
||||
|
||||
List<HardSpuEntity> getByIds(List<Long> spuIds);
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
@@ -54,4 +58,9 @@ public interface HardSpuService extends IService<HardSpuEntity> {
|
||||
* 拉取旷世商品
|
||||
*/
|
||||
void asyncAll();
|
||||
|
||||
/**
|
||||
* 拉取旷世商品
|
||||
*/
|
||||
HardSpuEntity validateSpu(Long hardSpuId);
|
||||
}
|
||||
+96
-56
@@ -5,15 +5,18 @@ import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.bsd.pjcloud.common.core.constant.enums.YesNoEnum;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.hard.api.constant.HardDoorFlowEnum;
|
||||
import com.bsd.pjcloud.hard.api.constant.HardDoorOpenTypeEnum;
|
||||
import com.bsd.pjcloud.hard.api.dto.HardDoorFlowOpenDto;
|
||||
import com.bsd.pjcloud.hard.api.entity.HardAuthEntity;
|
||||
import com.bsd.pjcloud.hard.api.dto.order.HardCreateCarDto;
|
||||
import com.bsd.pjcloud.hard.api.entity.HardDoorFlowEntity;
|
||||
import com.bsd.pjcloud.hard.api.entity.manager.HardDoorManagerEntity;
|
||||
import com.bsd.pjcloud.hard.api.entity.order.HardOrderEntity;
|
||||
import com.bsd.pjcloud.hard.api.entity.spu.HardSpuEntity;
|
||||
import com.bsd.pjcloud.hard.api.vo.manager.HardDoorManagerVo;
|
||||
import com.bsd.pjcloud.hard.api.vo.manager.HardManagerVo;
|
||||
import com.bsd.pjcloud.hard.api.vo.spu.HardSpuJoinVo;
|
||||
import com.bsd.pjcloud.hard.mapper.HardAuthMapper;
|
||||
import com.bsd.pjcloud.hard.mapper.HardDoorFlowMapper;
|
||||
@@ -23,10 +26,8 @@ import com.bsd.pjcloud.thirdparty.api.feign.RemoterThirdKsService;
|
||||
import com.bsd.pjcloud.thirdparty.dto.door.*;
|
||||
import com.bsd.pjcloud.thirdparty.dto.ks.KsRecognitionCallbackDto;
|
||||
import com.bsd.pjcloud.thirdparty.dto.ks.KsRecognitionDto;
|
||||
import com.bsd.pjcloud.thirdparty.dto.ks.KsSkuSubmitDto;
|
||||
import com.bsd.pjcloud.thirdparty.vo.door.DoorOpenVo;
|
||||
import com.bsd.pjcloud.thirdparty.vo.ks.KsRecognitionVo;
|
||||
import com.bsd.pjcloud.thirdparty.vo.ks.KsSkuSubmitVo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -54,6 +55,7 @@ public class HardDoorFlowServiceImpl extends ServiceImpl<HardDoorFlowMapper, Har
|
||||
private final HardDoorManagerService hardDoorManagerService;
|
||||
private final HardDoorCabinetService hardDoorCabinetService;
|
||||
private final HardSpuJoinService hardSpuJoinService;
|
||||
private final HardSpuService hardSpuService;
|
||||
private final HardOrderService hardOrderService;
|
||||
|
||||
private final HardAuthMapper hardAuthMapper;
|
||||
@@ -61,6 +63,15 @@ public class HardDoorFlowServiceImpl extends ServiceImpl<HardDoorFlowMapper, Har
|
||||
private final RemoterThirdDoorApiService thirdDoorApiService;
|
||||
private final RemoterThirdKsService thirdKsService;
|
||||
|
||||
/**
|
||||
* 根据旷世识别id查询
|
||||
*/
|
||||
public HardDoorFlowEntity get(String ksRecogId) {
|
||||
return baseMapper.selectOne(new LambdaQueryWrapper<HardDoorFlowEntity>()
|
||||
.eq(HardDoorFlowEntity::getSkuSubmitRecogId, ksRecogId)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开门
|
||||
*/
|
||||
@@ -79,7 +90,14 @@ public class HardDoorFlowServiceImpl extends ServiceImpl<HardDoorFlowMapper, Har
|
||||
openDto.setEventType(Integer.valueOf(dto.getOpenType().getType()));
|
||||
DoorOpenVo openVo = thirdDoorApiService.open(openDto).getData();
|
||||
if (ObjectUtil.isEmpty(openVo) || !openVo.isSuccess()) throw new RuntimeException(openVo.getMessage());
|
||||
HardDoorFlowEntity updateObj = HardDoorFlowEntity.builder().id(saveObj.getId()).requestOpenDto(JSONUtil.toJsonStr(openDto)).requestOpenVo(JSONUtil.toJsonStr(openVo)).requestOpenTime(LocalDateTime.now()).build();
|
||||
HardDoorFlowEntity updateObj = HardDoorFlowEntity.builder()
|
||||
.id(saveObj.getId())
|
||||
.hardId(hardDoorStatus.getHardId())
|
||||
.hardDoorId(dto.getHardDoorId())
|
||||
.cabinetNo(dto.getCabinetNo())
|
||||
.requestOpenDto(JSONUtil.toJsonStr(openDto))
|
||||
.requestOpenVo(JSONUtil.toJsonStr(openVo))
|
||||
.requestOpenTime(LocalDateTime.now()).build();
|
||||
// 是否开门成功
|
||||
updateObj.setIsOpen(YesNoEnum.YES.getCode());
|
||||
baseMapper.updateById(updateObj);
|
||||
@@ -127,23 +145,7 @@ public class HardDoorFlowServiceImpl extends ServiceImpl<HardDoorFlowMapper, Har
|
||||
// 查询货柜是否配置spu信息
|
||||
List<HardSpuJoinVo> spuList = hardSpuJoinService.getSpuList(hardDoorDetail.getId(), dto.getCabinetNo());
|
||||
if (ObjectUtil.isEmpty(spuList) || spuList.isEmpty()) throw new RuntimeException("货柜商品信息为空,请上架");
|
||||
DoorOpenDto openDto = new DoorOpenDto();
|
||||
openDto.setDeviceCode(hardDoorDetail.getDeviceCode());
|
||||
openDto.setCabinetNo(dto.getCabinetNo());
|
||||
openDto.setOutOpenNo(String.valueOf(dto.getHardDoorFlowId()));
|
||||
DoorOpenVo openVo = thirdDoorApiService.open(openDto).getData();
|
||||
if (ObjectUtil.isEmpty(openVo) || !openVo.isSuccess()) {
|
||||
throw new RuntimeException("开门失败");
|
||||
}
|
||||
HardDoorFlowEntity updateObj = HardDoorFlowEntity.builder()
|
||||
.id(dto.getHardDoorFlowId())
|
||||
.hardId(hardDoorDetail.getHardId())
|
||||
.hardDoorId(dto.getHardDoorId())
|
||||
.cabinetNo(dto.getCabinetNo())
|
||||
.requestOpenDto(JSONUtil.toJsonStr(dto))
|
||||
.requestOpenVo(JSONUtil.toJsonStr(openVo))
|
||||
.build();
|
||||
baseMapper.updateById(updateObj);
|
||||
getSelf().openDoor(dto, hardDoorDetail);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,46 +162,84 @@ public class HardDoorFlowServiceImpl extends ServiceImpl<HardDoorFlowMapper, Har
|
||||
@Override
|
||||
public void disposeLocakCallback(DoorOpenCallbackDto dto) {
|
||||
if (ObjectUtil.isEmpty(dto) || ObjectUtil.isEmpty(dto.getType())) {
|
||||
log.info("|{}|disposeLocakCallback 参数错误dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
log.info("|{}|disposeLocakCallback 意外的错误,参数错误dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
if (ObjectUtil.equals(dto.getResultCode(), "FAIL")) {
|
||||
log.info("|{}|disposeLocakCallback 关门回调直接返回dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
log.info("|{}|disposeLocakCallback 意外的错误,关门回调直接返回dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
// 查询流程
|
||||
HardDoorFlowEntity flowDetail = baseMapper.selectById(dto.getOutOpenNo());
|
||||
if (ObjectUtil.isEmpty(flowDetail)) {
|
||||
log.info("|{}|disposeLocakCallback 流程不存在dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
log.info("|{}|disposeLocakCallback 意外的错误,流程不存在dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
// 维修开锁不处理
|
||||
List<String> maintenanceList = HardDoorOpenTypeEnum.getMaintenanceListCodes();
|
||||
if (maintenanceList.contains(String.valueOf(dto.getEventType()))) {
|
||||
hardDoorManagerService.refresh(dto.getDeviceCode());
|
||||
return;
|
||||
}
|
||||
// 创建订单
|
||||
Long orderId = hardOrderService.createHardDoorOrder(flowDetail.getUserId(), flowDetail.getHardId());
|
||||
// 更新流程
|
||||
boolean isOpenDoor = ObjectUtil.equals(dto.getType(), "OPEN");
|
||||
HardDoorFlowEntity updateObj = HardDoorFlowEntity.builder()
|
||||
.id(flowDetail.getId())
|
||||
.orderId(orderId)
|
||||
.isOpen(isOpenDoor ? YesNoEnum.YES.getCode() : YesNoEnum.NO.getCode())
|
||||
.openCallbackTime(LocalDateTime.now())
|
||||
.openCallbackVo(JSONUtil.toJsonStr(dto))
|
||||
.build();
|
||||
// 如果是购买的话
|
||||
if (ObjectUtil.equals(flowDetail.getBizType(), HardDoorFlowEnum.PAY_OPEN.getType())) {
|
||||
// 创建订单
|
||||
Long orderId = hardOrderService.createHardDoorOrder(flowDetail.getUserId(), flowDetail.getHardId());
|
||||
updateObj.setOrderId(orderId);
|
||||
}
|
||||
baseMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理柜子状态回调
|
||||
*/
|
||||
@Override
|
||||
public void disposeStatusCallback(DoorStatusCallbackDto dto) {
|
||||
if (ObjectUtil.isEmpty(dto)) {
|
||||
log.error("|{}|disposeStatusCallback 意外的错误,参数错误dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
HardDoorManagerVo hardDoorDetail = hardDoorManagerService.getByDeviceCode(dto.getDeviceCode());
|
||||
if (ObjectUtil.isEmpty(hardDoorDetail)) {
|
||||
log.error("|{}|disposeStatusCallback 意外的错误,设备不存在dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
hardDoorCabinetService.saveOrUpdate(hardDoorDetail.getId(), dto.getCabinetList());
|
||||
} catch (Exception e) {
|
||||
log.error("|{}|disposeStatusCallback 更新柜子状态失败dto|{}|", TAG, JSONUtil.toJsonStr(dto), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理视频回调
|
||||
*/
|
||||
@Override
|
||||
public void disposeVideoCallback(DoorVideoCallbackDto dto) {
|
||||
if (ObjectUtil.isEmpty(dto) || ObjectUtil.isEmpty(dto.getVideoList())) {
|
||||
log.info("|{}|disposeVideoCallback 参数错误dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
log.info("|{}|disposeVideoCallback 意外的错误,参数错误dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
if (ObjectUtil.equals(dto.getResultCode(), "FAIL")) {
|
||||
log.info("|{}|disposeVideoCallback 意外的错误,关门回调直接返回dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
// 查询流程
|
||||
HardDoorFlowEntity flowDetail = baseMapper.selectById(dto.getOutOpenNo());
|
||||
if (ObjectUtil.isEmpty(flowDetail)) {
|
||||
log.info("|{}|disposeVideoCallback 流程不存在dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
log.info("|{}|disposeVideoCallback 意外的错误,流程不存在dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
// 判断是否已提交
|
||||
if (ObjectUtil.isNotEmpty(flowDetail.getSkuSubmitTime())) {
|
||||
log.info("|{}|disposeVideoCallback 该流程已经提交识别|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
// 提交视频
|
||||
@@ -223,9 +263,10 @@ public class HardDoorFlowServiceImpl extends ServiceImpl<HardDoorFlowMapper, Har
|
||||
// 提交识别
|
||||
KsRecognitionDto ksRecognitionDto = new KsRecognitionDto();
|
||||
ksRecognitionDto.setRecog_id(String.valueOf(flowDetail.getId()));
|
||||
ksRecognitionDto.setExtra_params(JSONUtil.toJsonStr(ksMap));
|
||||
ksRecognitionDto.setExtra_params(ksMap);
|
||||
ksRecognitionDto.setResource_type("1");
|
||||
ksRecognitionDto.setResource_urls(JSONUtil.toJsonStr(videoList));
|
||||
ksRecognitionDto.setContainer_id(String.valueOf(flowDetail.getHardDoorId()));
|
||||
ksRecognitionDto.setResource_urls(videoList);
|
||||
// third服务生成
|
||||
ksRecognitionDto.setNotify_url("");
|
||||
ksRecognitionDto.setSub_mch_id(String.valueOf(flowDetail.getOrderId()));
|
||||
@@ -235,31 +276,10 @@ public class HardDoorFlowServiceImpl extends ServiceImpl<HardDoorFlowMapper, Har
|
||||
return;
|
||||
}
|
||||
// 更新流程
|
||||
HardDoorFlowEntity ksSubmitUpdateObj = HardDoorFlowEntity.builder().id(flowDetail.getId()).skuSubmitDto(JSONUtil.toJsonStr(ksRecognitionDto)).skuSubmitVo(JSONUtil.toJsonStr(ksRecognitionVo)).skuSubmitTime(LocalDateTime.now()).build();
|
||||
HardDoorFlowEntity ksSubmitUpdateObj = HardDoorFlowEntity.builder().id(flowDetail.getId()).skuSubmitDto(JSONUtil.toJsonStr(ksRecognitionDto)).skuSubmitVo(JSONUtil.toJsonStr(ksRecognitionVo)).skuSubmitRecogId(ksRecognitionVo.getKs_recog_id()).skuSubmitTime(LocalDateTime.now()).build();
|
||||
baseMapper.updateById(ksSubmitUpdateObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理柜子状态回调
|
||||
*/
|
||||
@Override
|
||||
public void disposeStatusCallback(DoorStatusCallbackDto dto) {
|
||||
if (ObjectUtil.isEmpty(dto)) {
|
||||
log.error("|{}|disposeStatusCallback 参数错误dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
HardDoorManagerVo hardDoorDetail = hardDoorManagerService.getByDeviceCode(dto.getDeviceCode());
|
||||
if (ObjectUtil.isEmpty(hardDoorDetail)) {
|
||||
log.error("|{}|disposeStatusCallback 设备不存在dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
hardDoorCabinetService.saveOrUpdate(hardDoorDetail.getId(), dto.getCabinetList());
|
||||
} catch (Exception e) {
|
||||
log.error("|{}|disposeStatusCallback 更新柜子状态失败dto|{}|", TAG, JSONUtil.toJsonStr(dto), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理旷世识别回调
|
||||
*/
|
||||
@@ -269,6 +289,26 @@ public class HardDoorFlowServiceImpl extends ServiceImpl<HardDoorFlowMapper, Har
|
||||
log.error("|{}|disposeRecognitionCallback 参数错误dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
// 更新流程
|
||||
HardDoorFlowEntity flowDetail = get(dto.getKs_recog_id());
|
||||
if (ObjectUtil.isEmpty(flowDetail)) {
|
||||
log.error("|{}|disposeRecognitionCallback 意外的错误,流程不存在dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
// 查询订单
|
||||
HardOrderEntity orderDetail = hardOrderService.getById(flowDetail.getOrderId());
|
||||
if (ObjectUtil.isEmpty(orderDetail)) {
|
||||
log.error("|{}|disposeRecognitionCallback 意外的错误,订单不存在dto|{}|", TAG, JSONUtil.toJsonStr(dto));
|
||||
return;
|
||||
}
|
||||
KsRecognitionCallbackDto.Result result = dto.getResult();
|
||||
List<KsRecognitionCallbackDto.ResultSku> resultSkuList = result.getResult();
|
||||
if (ObjectUtil.isNotEmpty(resultSkuList)) {
|
||||
Long orderId = hardOrderService.payHardDoorOrder(orderDetail, resultSkuList);
|
||||
if (ObjectUtil.isNotEmpty(orderId)) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private HardDoorFlowServiceImpl getSelf() {
|
||||
|
||||
+64
@@ -20,11 +20,13 @@ import com.bsd.pjcloud.hard.api.dto.order.HardCreateCarDto;
|
||||
import com.bsd.pjcloud.hard.api.entity.order.HardCarEntity;
|
||||
import com.bsd.pjcloud.hard.api.entity.order.HardParentCarEntity;
|
||||
import com.bsd.pjcloud.hard.api.entity.order.HardOrderEntity;
|
||||
import com.bsd.pjcloud.hard.api.entity.spu.HardSpuEntity;
|
||||
import com.bsd.pjcloud.hard.api.vo.order.HardCarVo;
|
||||
import com.bsd.pjcloud.hard.mapper.order.HardCarMapper;
|
||||
import com.bsd.pjcloud.hard.mapper.order.HardOrderMapper;
|
||||
import com.bsd.pjcloud.hard.mapper.order.HardParentCarMapper;
|
||||
import com.bsd.pjcloud.hard.service.HardCarService;
|
||||
import com.bsd.pjcloud.hard.service.HardSpuService;
|
||||
import com.bsd.pjcloud.supermarket.api.feign.RemoteSupermarketUnitSkuService;
|
||||
import com.bsd.pjcloud.supermarket.vo.erp.SmErpUnitWithSpuVo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -53,6 +55,7 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
|
||||
private final HardOrderMapper hardCarMapper;
|
||||
private final HardParentCarMapper hardParentCarMapper;
|
||||
private final HardSpuService hardSpuService;
|
||||
|
||||
private final RemoteOnlineCanteenSpuService onlineCanteenSpuService;
|
||||
private final RemoteCanteenSpuService canteenSpuService;
|
||||
@@ -180,6 +183,27 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
}
|
||||
yield supermarketTotalPrice.get();
|
||||
}
|
||||
case DOOR -> {
|
||||
AtomicInteger doorTotalPrice = new AtomicInteger();
|
||||
// 查询智能柜
|
||||
List<HardSpuEntity> supList = hardSpuService.getByIds(productIds);
|
||||
for (HardCreateCarDto v : list) {
|
||||
supList.stream().filter(i -> ObjectUtil.equals(i.getId(), v.getProductId())).findFirst().ifPresent(spu -> {
|
||||
Integer price = spu.getPrice();
|
||||
if (ObjectUtil.isNotEmpty(v.getProductCount()) && !ObjectUtil.equals(v.getProductCount(), 0)) {
|
||||
// 按数量
|
||||
int itemTotalPrice = v.getProductCount() * price;
|
||||
doorTotalPrice.addAndGet(itemTotalPrice);
|
||||
} else if (ObjectUtil.isNotEmpty(v.getProductWeight()) && v.getProductWeight().compareTo(BigDecimal.valueOf(0)) != 0) {
|
||||
// 按重量
|
||||
// 向上取整
|
||||
int itemTotalPrice = v.getProductWeight().multiply(BigDecimal.valueOf(price)).setScale(0, RoundingMode.CEILING).intValue();
|
||||
doorTotalPrice.addAndGet(itemTotalPrice);
|
||||
}
|
||||
});
|
||||
}
|
||||
yield doorTotalPrice.get();
|
||||
}
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
@@ -272,6 +296,37 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
baseMapper.insert(carObjectList);
|
||||
return;
|
||||
}
|
||||
// 智能柜
|
||||
if (ObjectUtil.equals(sysType, HardTypeEnum.DOOR)) {
|
||||
List<HardCarEntity> carObjectList = new ArrayList<>();
|
||||
List<HardSpuEntity> supList = hardSpuService.getByIds(productIds);
|
||||
for (HardCreateCarDto v : productList) {
|
||||
HardCarEntity item = HardCarEntity.builder().parentCarId(parentCarId).build();
|
||||
supList.stream().filter(i -> ObjectUtil.equals(i.getId(), v.getProductId())).findFirst().ifPresent(spu -> {
|
||||
Integer price = spu.getPrice();
|
||||
int totalPrice = 0;
|
||||
// 按重量
|
||||
if (ObjectUtil.isNotEmpty(v.getProductCount()) && !ObjectUtil.equals(v.getProductCount(), 0)) {
|
||||
// 按数量
|
||||
totalPrice = v.getProductCount() * price;
|
||||
} else if (ObjectUtil.isNotEmpty(v.getProductWeight()) && v.getProductWeight().compareTo(BigDecimal.valueOf(0)) != 0) {
|
||||
// 按重量
|
||||
totalPrice = v.getProductWeight().multiply(BigDecimal.valueOf(price)).setScale(0, RoundingMode.CEILING).intValue();
|
||||
}
|
||||
item.setProductId(spu.getId());
|
||||
item.setProductName(spu.getName());
|
||||
item.setProductPrice(price);
|
||||
item.setProductPic(spu.getCover());
|
||||
item.setTotalPrice((long) totalPrice);
|
||||
// item.setProductNature(v.getProductNature().getType());
|
||||
item.setProductCount(v.getProductCount());
|
||||
item.setProductWeight(v.getProductWeight());
|
||||
carObjectList.add(item);
|
||||
});
|
||||
}
|
||||
baseMapper.insert(carObjectList);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -308,6 +363,15 @@ public class HardCarServiceImpl extends ServiceImpl<HardCarMapper, HardCarEntity
|
||||
});
|
||||
}
|
||||
}
|
||||
// 智能柜
|
||||
if (ObjectUtil.equals(sysType, HardTypeEnum.DOOR)) {
|
||||
List<HardSpuEntity> supList = hardSpuService.getByIds(productIds);
|
||||
for (HardCreateCarDto v : list) {
|
||||
supList.stream().filter(i -> ObjectUtil.equals(i.getId(), v.getProductId())).findFirst().ifPresent(spu -> {
|
||||
str.append(spu.getName()).append("x").append(v.getProductCount()).append(";");
|
||||
});
|
||||
}
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
|
||||
+58
@@ -2,6 +2,7 @@ package com.bsd.pjcloud.hard.service.impl.order;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
@@ -19,6 +20,7 @@ import com.bsd.pjcloud.common.core.util.CollectionUtils;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.data.datascope.DataScope;
|
||||
import com.bsd.pjcloud.common.security.service.PjcloudUser;
|
||||
import com.bsd.pjcloud.hard.api.constant.HardProductNatureEnum;
|
||||
import com.bsd.pjcloud.hard.api.constant.HardTypeEnum;
|
||||
import com.bsd.pjcloud.hard.api.constant.order.HardOrderStatusEnum;
|
||||
import com.bsd.pjcloud.hard.api.constant.order.HardOrderTypeEnum;
|
||||
@@ -33,6 +35,7 @@ import com.bsd.pjcloud.hard.api.entity.manager.HardManagerEntity;
|
||||
import com.bsd.pjcloud.hard.api.entity.order.HardCarEntity;
|
||||
import com.bsd.pjcloud.hard.api.entity.order.HardOrderEntity;
|
||||
import com.bsd.pjcloud.hard.api.entity.order.HardParentCarEntity;
|
||||
import com.bsd.pjcloud.hard.api.entity.spu.HardSpuEntity;
|
||||
import com.bsd.pjcloud.hard.api.utils.HardUtil;
|
||||
import com.bsd.pjcloud.hard.api.vo.manager.HardManagerVo;
|
||||
import com.bsd.pjcloud.hard.api.vo.order.HardCarVo;
|
||||
@@ -42,6 +45,7 @@ import com.bsd.pjcloud.hard.mapper.order.HardOrderMapper;
|
||||
import com.bsd.pjcloud.hard.service.*;
|
||||
import com.bsd.pjcloud.supermarket.api.feign.RemoteSupermarketSpuService;
|
||||
import com.bsd.pjcloud.supermarket.dto.SupermarketSpuUpdateStockReqDTO;
|
||||
import com.bsd.pjcloud.thirdparty.dto.ks.KsRecognitionCallbackDto;
|
||||
import com.bsd.pjcloud.wallet.api.constant.WalletBizEnum;
|
||||
import com.bsd.pjcloud.wallet.api.constant.WalletCodeBizEnum;
|
||||
import com.bsd.pjcloud.wallet.api.constant.WalletTypeEnum;
|
||||
@@ -89,6 +93,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
|
||||
@Lazy
|
||||
private final HardInvoiceService hardInvoiceService;
|
||||
private final HardBroadcastService hardBroadcastService;
|
||||
private final HardSpuService hardSpuService;
|
||||
|
||||
private final RemoteMchService remoteMchService;
|
||||
private final RemoteCodeUseService remoteCodeUseService;
|
||||
@@ -423,6 +428,9 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
|
||||
.orderStatus(HardOrderStatusEnum.CREATE.getType())
|
||||
.orderType(HardOrderTypeEnum.BELOW.getType())
|
||||
.payType(HardPayTypeEnum.HARD_DOOR_FREE_PAY.getType())
|
||||
.totalPrice(0)
|
||||
.extraPrice(0)
|
||||
.payPrice(0)
|
||||
.isOfflineOrder(YesNoEnum.NO.getCode())
|
||||
.productDesc("智能柜商品*?")
|
||||
.build();
|
||||
@@ -430,6 +438,56 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
|
||||
return orderObj.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 结算智能柜订单
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long payHardDoorOrder(HardOrderEntity dto, List<KsRecognitionCallbackDto.ResultSku> ksSpuList) {
|
||||
if (ObjectUtil.isEmpty(dto) || ObjectUtil.isEmpty(ksSpuList)) return null;
|
||||
// 创建购物车
|
||||
List<String> ksSpuIds = ksSpuList.stream().map(KsRecognitionCallbackDto.ResultSku::getKs_sku_id).toList();
|
||||
List<HardSpuEntity> hardSpuList = hardSpuService.get(ksSpuIds);
|
||||
if (ObjectUtil.isEmpty(hardSpuList)) {
|
||||
log.error("|{}|智能柜订单结算,商品不存在dto|{}|ksSpuList|{}|", TAG, JSONUtil.toJsonStr(dto), JSONUtil.toJsonStr(ksSpuList));
|
||||
return null;
|
||||
}
|
||||
List<HardCreateCarDto> carListDto = new ArrayList<>();
|
||||
for (KsRecognitionCallbackDto.ResultSku v : ksSpuList) {
|
||||
hardSpuList.stream().filter(i -> ObjectUtil.equals(i.getKsSkuId(), v.getKs_sku_id())).findFirst().ifPresent(hardSpu -> {
|
||||
HardCreateCarDto entity = new HardCreateCarDto();
|
||||
entity.setProductId(hardSpu.getId());
|
||||
entity.setProductNature(HardProductNatureEnum.DEFAULT);
|
||||
entity.setProductCount(Integer.parseInt(v.getSku_num()));
|
||||
carListDto.add(entity);
|
||||
});
|
||||
}
|
||||
HardTypeEnum hardType = HardTypeEnum.valueOfByType(dto.getSysType());
|
||||
HardOrderTypeEnum orderType = HardOrderTypeEnum.valueOfByType(dto.getOrderType());
|
||||
// 获取商品价格
|
||||
Integer totalPrice = hardCarService.computerCarTotalPrice(hardType, orderType, carListDto);
|
||||
// 添加购物车
|
||||
Long parentCarId = hardCarService.createCard(dto.getUserId(), dto.getMerchantId(), hardType, orderType, carListDto);
|
||||
// 获取商品描述
|
||||
String subject = hardCarService.computerCarSubject(hardType, orderType, carListDto);
|
||||
// 更新订单信息
|
||||
HardOrderEntity updateObj = HardOrderEntity.builder()
|
||||
.id(dto.getId())
|
||||
.parentCarId(parentCarId)
|
||||
.totalPrice(totalPrice)
|
||||
.payPrice(totalPrice)
|
||||
.extraPrice(0)
|
||||
.productDesc(subject)
|
||||
.build();
|
||||
baseMapper.updateById(updateObj);
|
||||
HardOrderEntity orderObj = baseMapper.selectById(updateObj.getId());
|
||||
// 扣减库存
|
||||
getSelf().fastenerInventory(orderObj, YesNoEnum.YES);
|
||||
// 钱包扣款
|
||||
getSelf().fastReduceBalance(orderObj);
|
||||
return orderObj.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void fastReduceBalance(HardOrderEntity order) {
|
||||
|
||||
+1
@@ -59,6 +59,7 @@ public class HardSpuJoinServiceImpl extends ServiceImpl<HardSpuJoinMapper, HardS
|
||||
HardSpuJoinDto queryDto = new HardSpuJoinDto();
|
||||
queryDto.setHardDoorId(hardDoorId);
|
||||
queryDto.setCabinetNo(String.valueOf(cabinetNo));
|
||||
queryDto.setIsSpu(true);
|
||||
return scopeList(queryDto);
|
||||
}
|
||||
}
|
||||
+6
-11
@@ -69,13 +69,18 @@ public class HardSpuRepertoryServiceImpl extends ServiceImpl<HardSpuRepertoryMap
|
||||
if (ObjectUtil.isEmpty(spuDetail)) {
|
||||
throw new RuntimeException("商品不存在");
|
||||
}
|
||||
if (ObjectUtil.isEmpty(spuDetail.getSpuCategoryId())) {
|
||||
throw new RuntimeException("商品分类不能为空");
|
||||
}
|
||||
if (ObjectUtil.equals(spuDetail.getPrice(), 0)) {
|
||||
throw new RuntimeException("商品价格不能为0");
|
||||
}
|
||||
Integer beforeCount = 0;
|
||||
if (ObjectUtil.isNotEmpty(spuDetail.getRepertoryCount())) {
|
||||
beforeCount = spuDetail.getRepertoryCount();
|
||||
}
|
||||
entity.setBeforeCount(beforeCount);
|
||||
entity.setUserId(user.getId());
|
||||
entity.setHardId(entity.getHardId());
|
||||
entity.setBizType(HardSpuRepertoryTypeEnum.HANDLER.getType());
|
||||
baseMapper.insert(entity);
|
||||
// 更新商品库存
|
||||
@@ -154,16 +159,6 @@ public class HardSpuRepertoryServiceImpl extends ServiceImpl<HardSpuRepertoryMap
|
||||
WalletDataUtil.convertMchList(list, CollectionUtils.convertMap(mchList, MchManageVo::getId));
|
||||
}
|
||||
}
|
||||
// 设备
|
||||
List<Long> hardIds = list.stream().map(HardSpuRepertoryVo::getHardId).filter(ObjectUtil::isNotEmpty).distinct().toList();
|
||||
if (ObjectUtil.isNotEmpty(hardIds)) {
|
||||
HardManagerDto hardManagerDto = new HardManagerDto();
|
||||
hardManagerDto.setIds(hardIds);
|
||||
List<HardManagerEntity> hardList = hardManagerMapper.list(hardManagerDto);
|
||||
if (ObjectUtil.isNotEmpty(hardList)) {
|
||||
HardUtil.convertHardList(list, CollectionUtils.convertMap(hardList, HardManagerEntity::getId));
|
||||
}
|
||||
}
|
||||
// 用户
|
||||
List<Long> userIds = list.stream().map(HardSpuRepertoryVo::getUserId).distinct().toList();
|
||||
R<List<SysUser>> userList = remoteUserService.getUserById(new ArrayList<>(userIds));
|
||||
|
||||
+32
-18
@@ -66,14 +66,24 @@ public class HardSpuServiceImpl extends ServiceImpl<HardSpuMapper, HardSpuEntity
|
||||
return pageList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HardSpuEntity> get(List<String> ksSpuIds) {
|
||||
return baseMapper.selectList(new LambdaQueryWrapper<HardSpuEntity>().in(HardSpuEntity::getKsSkuId, ksSpuIds));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<HardSpuEntity> getByIds(List<Long> spuIds) {
|
||||
return baseMapper.selectList(new LambdaQueryWrapper<HardSpuEntity>().in(HardSpuEntity::getId, spuIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*/
|
||||
@Override
|
||||
public Long create(HardSpuEntity entity) {
|
||||
if (existName(entity)) {
|
||||
throw new RuntimeException("商品名不能重复");
|
||||
}
|
||||
// if (existName(entity)) {
|
||||
// throw new RuntimeException("商品名不能重复");
|
||||
// }
|
||||
entity.setSkuType(HardKsSkuTypeEnum.SELF.getType());
|
||||
baseMapper.insert(entity);
|
||||
// 发起审核
|
||||
@@ -86,9 +96,9 @@ public class HardSpuServiceImpl extends ServiceImpl<HardSpuMapper, HardSpuEntity
|
||||
*/
|
||||
@Override
|
||||
public Long edit(HardSpuEntity entity) {
|
||||
if (existName(entity)) {
|
||||
throw new RuntimeException("商品名不能重复");
|
||||
}
|
||||
// if (existName(entity)) {
|
||||
// throw new RuntimeException("商品名不能重复");
|
||||
// }
|
||||
baseMapper.updateById(entity);
|
||||
return entity.getId();
|
||||
}
|
||||
@@ -207,6 +217,22 @@ public class HardSpuServiceImpl extends ServiceImpl<HardSpuMapper, HardSpuEntity
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验商品
|
||||
*/
|
||||
@Override
|
||||
public HardSpuEntity validateSpu(Long hardSpuId) {
|
||||
HardSpuEntity spuDetail = baseMapper.selectById(hardSpuId);
|
||||
if (ObjectUtil.isEmpty(spuDetail)) throw new RuntimeException("商品不存在");
|
||||
if (ObjectUtil.equals(spuDetail.getPrice(), 0)) {
|
||||
throw new RuntimeException("商品价格不能为0");
|
||||
}
|
||||
if (spuDetail.getRepertoryCount() <= 0) {
|
||||
throw new RuntimeException("商品库存不能小于0");
|
||||
}
|
||||
return spuDetail;
|
||||
}
|
||||
|
||||
public boolean asyncAllGroup(KsBarcodeLikeDto likeDto) {
|
||||
KsBarcodeLikeVo data = remoterThirdKsService.barcodeSkuLike(likeDto).getData();
|
||||
if (ObjectUtil.isEmpty(data) || !data.isSuccess() || ObjectUtil.isEmpty(data.getResultList())) return false;
|
||||
@@ -295,18 +321,6 @@ public class HardSpuServiceImpl extends ServiceImpl<HardSpuMapper, HardSpuEntity
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验商品
|
||||
*/
|
||||
private HardSpuEntity validateSpu(Long hardSpuId) {
|
||||
HardSpuEntity spuDetail = baseMapper.selectById(hardSpuId);
|
||||
if (ObjectUtil.isEmpty(spuDetail)) throw new RuntimeException("商品不存在");
|
||||
if (ObjectUtil.equals(spuDetail.getPrice(), 0)) {
|
||||
throw new RuntimeException("商品价格不能为0");
|
||||
}
|
||||
return spuDetail;
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品是否重复
|
||||
*/
|
||||
|
||||
-7
@@ -5,7 +5,6 @@
|
||||
<resultMap id="hardSpuRepertoryMap" type="com.bsd.pjcloud.hard.api.entity.spu.HardSpuRepertoryEntity">
|
||||
<id property="id" column="id"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="hardId" column="hard_id"/>
|
||||
<result property="spuId" column="spu_id"/>
|
||||
<result property="beforeCount" column="before_count"/>
|
||||
<result property="count" column="count"/>
|
||||
@@ -21,7 +20,6 @@
|
||||
<sql id="selectA">
|
||||
select a.id,
|
||||
a.user_id,
|
||||
a.hard_id,
|
||||
a.spu_id,
|
||||
a.before_count,
|
||||
a.count,
|
||||
@@ -36,9 +34,6 @@
|
||||
|
||||
<sql id="whereA">
|
||||
a.del_flag = '0'
|
||||
<if test="dto.hardId != null and dto.hardId != '' ">
|
||||
and a.hard_id = #{dto.hardId}
|
||||
</if>
|
||||
<if test="dto.spuId != null and dto.spuId != '' ">
|
||||
and a.spu_id = #{dto.spuId}
|
||||
</if>
|
||||
@@ -60,8 +55,6 @@
|
||||
<include refid="selectA"/>
|
||||
s.name as spuName,
|
||||
s.spu_category_id,
|
||||
s.hard_door_number,
|
||||
s.mch_id as spuMchId,
|
||||
c.name as spuCategoryName
|
||||
from hard_spu_repertory a
|
||||
left join hard_spu s on s.id = a.spu_id
|
||||
|
||||
Reference in new issue
Block a user