超市优化
This commit is contained in:
@ -114,6 +114,7 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode STORE_ORDER_NOT_EXISTS = new ErrorCode(1_007_904_005, "商品订单不存在");
|
ErrorCode STORE_ORDER_NOT_EXISTS = new ErrorCode(1_007_904_005, "商品订单不存在");
|
||||||
|
|
||||||
ErrorCode AMOUNT_NOT_ENOUGH = new ErrorCode(1_007_904_008, "金额不足");
|
ErrorCode AMOUNT_NOT_ENOUGH = new ErrorCode(1_007_904_008, "金额不足");
|
||||||
|
ErrorCode CODE_NOT_TIME = new ErrorCode(1_007_904_008, "二维码过期");
|
||||||
ErrorCode STATUS_ERROR = new ErrorCode(1_007_904_007, "订单已完成或已退款");
|
ErrorCode STATUS_ERROR = new ErrorCode(1_007_904_007, "订单已完成或已退款");
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package cn.iocoder.yudao.module.member.controller.app.store;
|
package cn.iocoder.yudao.module.member.controller.app.store;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.StoreResult;
|
import cn.iocoder.yudao.framework.common.pojo.StoreResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
|
import cn.iocoder.yudao.module.member.controller.admin.storegoodsinventory.vo.AddReqVO;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.store.dto.FacePayDto;
|
import cn.iocoder.yudao.module.member.controller.app.store.dto.FacePayDto;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.store.dto.StoreOrderDto;
|
import cn.iocoder.yudao.module.member.controller.app.store.dto.StoreOrderDto;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.store.dto.StoreOrderUploadDto;
|
import cn.iocoder.yudao.module.member.controller.app.store.dto.StoreOrderUploadDto;
|
||||||
@ -19,6 +19,7 @@ import cn.iocoder.yudao.module.member.dal.dataobject.storegoods.StoreGoodsDO;
|
|||||||
import cn.iocoder.yudao.module.member.dal.dataobject.storegoodstype.StoreGoodsTypeDO;
|
import cn.iocoder.yudao.module.member.dal.dataobject.storegoodstype.StoreGoodsTypeDO;
|
||||||
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
|
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
|
||||||
import cn.iocoder.yudao.module.member.enums.StoreOrderStatusEnum;
|
import cn.iocoder.yudao.module.member.enums.StoreOrderStatusEnum;
|
||||||
|
import cn.iocoder.yudao.module.member.service.async.MemberAsyncService;
|
||||||
import cn.iocoder.yudao.module.member.service.storegoods.StoreGoodsService;
|
import cn.iocoder.yudao.module.member.service.storegoods.StoreGoodsService;
|
||||||
import cn.iocoder.yudao.module.member.service.storegoodstype.StoreGoodsTypeService;
|
import cn.iocoder.yudao.module.member.service.storegoodstype.StoreGoodsTypeService;
|
||||||
import cn.iocoder.yudao.module.member.service.storeorder.StoreOrderService;
|
import cn.iocoder.yudao.module.member.service.storeorder.StoreOrderService;
|
||||||
@ -59,6 +60,8 @@ public class AppStoreController {
|
|||||||
private StoreOrderService orderService;
|
private StoreOrderService orderService;
|
||||||
@Resource
|
@Resource
|
||||||
private StoreOrderDetailService orderDetailService;
|
private StoreOrderDetailService orderDetailService;
|
||||||
|
@Resource
|
||||||
|
private MemberAsyncService memberAsyncService;
|
||||||
|
|
||||||
@GetMapping("/mgcr/memberUser/getMenberTwoList")
|
@GetMapping("/mgcr/memberUser/getMenberTwoList")
|
||||||
@Operation(summary = "获取用户关联信息")
|
@Operation(summary = "获取用户关联信息")
|
||||||
@ -180,14 +183,10 @@ public class AppStoreController {
|
|||||||
@PostMapping("/mgcr/order/payByCodeOrder")
|
@PostMapping("/mgcr/order/payByCodeOrder")
|
||||||
@Operation(summary = "添加二维码订单")
|
@Operation(summary = "添加二维码订单")
|
||||||
public String payByCodeOrder(@RequestBody StoreOrderDto dto) {
|
public String payByCodeOrder(@RequestBody StoreOrderDto dto) {
|
||||||
|
AddReqVO addReqVO = orderService.codePay(dto);
|
||||||
|
memberAsyncService.batchRecord(addReqVO);
|
||||||
|
return JsonUtils.toJsonString(StoreResult.success(null));
|
||||||
|
|
||||||
String s = orderService.codePay(dto);
|
|
||||||
|
|
||||||
if(StrUtil.isNotBlank(s)){
|
|
||||||
return JsonUtils.toJsonString(StoreResult.fail(s));
|
|
||||||
}else {
|
|
||||||
return JsonUtils.toJsonString(StoreResult.success(null));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String reverseHexAndConvert(String hexStr) {
|
public String reverseHexAndConvert(String hexStr) {
|
||||||
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.member.controller.admin.storegoodsinventory.vo.Ad
|
|||||||
import cn.iocoder.yudao.module.member.controller.admin.storeorder.vo.StoreOrderPageReqVO;
|
import cn.iocoder.yudao.module.member.controller.admin.storeorder.vo.StoreOrderPageReqVO;
|
||||||
import cn.iocoder.yudao.module.member.controller.admin.storeorder.vo.StoreOrderRespVO;
|
import cn.iocoder.yudao.module.member.controller.admin.storeorder.vo.StoreOrderRespVO;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.AppStoreOrderDetailVo;
|
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.AppStoreOrderDetailVo;
|
||||||
|
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.AppStoreOrderVO;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.CardDto;
|
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.CardDto;
|
||||||
import cn.iocoder.yudao.module.member.dal.dataobject.storeorder.StoreOrderDO;
|
import cn.iocoder.yudao.module.member.dal.dataobject.storeorder.StoreOrderDO;
|
||||||
import cn.iocoder.yudao.module.member.service.async.MemberAsyncService;
|
import cn.iocoder.yudao.module.member.service.async.MemberAsyncService;
|
||||||
@ -73,6 +74,12 @@ public class AppStoreOrderController {
|
|||||||
return success(storeOrderService.code(orderId));
|
return success(storeOrderService.code(orderId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/info")
|
||||||
|
@Operation(summary = "二维码商品信息")
|
||||||
|
public CommonResult<AppStoreOrderVO> info(String code) {
|
||||||
|
return success(storeOrderService.info(code));
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/complete")
|
@GetMapping("/complete")
|
||||||
@Operation(summary = "核销")
|
@Operation(summary = "核销")
|
||||||
public CommonResult<Boolean> complete(Integer orderId) {
|
public CommonResult<Boolean> complete(Integer orderId) {
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
package cn.iocoder.yudao.module.member.controller.app.storeorder.vo;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.module.member.dal.dataobject.storeorderdetail.StoreOrderDetailDO;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zt
|
||||||
|
* @description <description class purpose>
|
||||||
|
* @since 2024/11/13
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class AppStoreOrderVO {
|
||||||
|
|
||||||
|
private Integer orderId;
|
||||||
|
/**
|
||||||
|
* 读取卡号
|
||||||
|
*/
|
||||||
|
private String cardNumber;
|
||||||
|
/**
|
||||||
|
* 人脸
|
||||||
|
*/
|
||||||
|
private String openId;
|
||||||
|
/**
|
||||||
|
* 数量
|
||||||
|
*/
|
||||||
|
private Integer number;
|
||||||
|
/**
|
||||||
|
* 设备ID
|
||||||
|
*/
|
||||||
|
private String equipmentCode;
|
||||||
|
/**
|
||||||
|
* 离线缓存ID
|
||||||
|
*/
|
||||||
|
private String uuid;
|
||||||
|
/**
|
||||||
|
* 总价钱
|
||||||
|
*/
|
||||||
|
private Double totalPrice;
|
||||||
|
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 减免金额
|
||||||
|
*/
|
||||||
|
private Double reductionPrice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 门店ID
|
||||||
|
*/
|
||||||
|
private Long carteenId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (1-已支付,2-已完成,3-已取消,4-已退款)
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
|
||||||
|
@Schema(description = "商品详情")
|
||||||
|
private List<StoreOrderDetailDO> goodsList;
|
||||||
|
}
|
@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.member.controller.app.store.dto.FacePayDto;
|
|||||||
import cn.iocoder.yudao.module.member.controller.app.store.dto.StoreOrderDto;
|
import cn.iocoder.yudao.module.member.controller.app.store.dto.StoreOrderDto;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.store.dto.StoreOrderUploadDto;
|
import cn.iocoder.yudao.module.member.controller.app.store.dto.StoreOrderUploadDto;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.store.vo.UserInfoVo;
|
import cn.iocoder.yudao.module.member.controller.app.store.vo.UserInfoVo;
|
||||||
|
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.AppStoreOrderVO;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.CardDto;
|
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.CardDto;
|
||||||
import cn.iocoder.yudao.module.member.dal.dataobject.storeorder.StoreOrderDO;
|
import cn.iocoder.yudao.module.member.dal.dataobject.storeorder.StoreOrderDO;
|
||||||
|
|
||||||
@ -67,7 +68,7 @@ public interface StoreOrderService {
|
|||||||
|
|
||||||
String cardPay(StoreOrderDto dto);
|
String cardPay(StoreOrderDto dto);
|
||||||
|
|
||||||
String codePay(StoreOrderDto dto);
|
AddReqVO codePay(StoreOrderDto dto);
|
||||||
|
|
||||||
void batchCacheOrder(StoreOrderUploadDto dto);
|
void batchCacheOrder(StoreOrderUploadDto dto);
|
||||||
|
|
||||||
@ -83,6 +84,8 @@ public interface StoreOrderService {
|
|||||||
|
|
||||||
String code(Integer orderId);
|
String code(Integer orderId);
|
||||||
|
|
||||||
|
AppStoreOrderVO info(String code);
|
||||||
|
|
||||||
Boolean complete(Integer orderId);
|
Boolean complete(Integer orderId);
|
||||||
|
|
||||||
AddReqVO cancel(Integer orderId);
|
AddReqVO cancel(Integer orderId);
|
||||||
|
@ -19,6 +19,7 @@ import cn.iocoder.yudao.module.member.controller.app.store.dto.StoreOrderDto;
|
|||||||
import cn.iocoder.yudao.module.member.controller.app.store.dto.StoreOrderUploadDto;
|
import cn.iocoder.yudao.module.member.controller.app.store.dto.StoreOrderUploadDto;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.store.vo.UserInfoVo;
|
import cn.iocoder.yudao.module.member.controller.app.store.vo.UserInfoVo;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.AppStoreGoodsDetail;
|
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.AppStoreGoodsDetail;
|
||||||
|
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.AppStoreOrderVO;
|
||||||
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.CardDto;
|
import cn.iocoder.yudao.module.member.controller.app.storeorder.vo.CardDto;
|
||||||
import cn.iocoder.yudao.module.member.dal.dataobject.storeorder.StoreOrderDO;
|
import cn.iocoder.yudao.module.member.dal.dataobject.storeorder.StoreOrderDO;
|
||||||
import cn.iocoder.yudao.module.member.dal.dataobject.storeorderdetail.StoreOrderDetailDO;
|
import cn.iocoder.yudao.module.member.dal.dataobject.storeorderdetail.StoreOrderDetailDO;
|
||||||
@ -203,25 +204,42 @@ public class StoreOrderServiceImpl implements StoreOrderService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public String codePay(StoreOrderDto dto) {
|
public AddReqVO codePay(StoreOrderDto dto) {
|
||||||
|
|
||||||
String s = storeOrderRedisTemplate.opsForValue().get(dto.getJwt());
|
String s = storeOrderRedisTemplate.opsForValue().get(dto.getJwt());
|
||||||
if (StrUtil.isBlank(s)) {
|
if (StrUtil.isBlank(s)) {
|
||||||
return "二维码过期";
|
throw exception(CODE_NOT_TIME);
|
||||||
}
|
}
|
||||||
|
Long storeId = cashregisterinfoApi.getStoreId(dto.getEquipmentCode());
|
||||||
|
|
||||||
|
|
||||||
List<StoreGoodsDto> equipmentGoodsCustoms = dto.getEquipmentGoodsCustoms();
|
List<StoreGoodsDto> equipmentGoodsCustoms = dto.getEquipmentGoodsCustoms();
|
||||||
double sum = equipmentGoodsCustoms.stream()
|
double sum = equipmentGoodsCustoms.stream()
|
||||||
.mapToDouble(StoreGoodsDto::getTotalPrice)
|
.mapToDouble(StoreGoodsDto::getTotalPrice)
|
||||||
.sum();
|
.sum();
|
||||||
BigDecimal totalMoney = BigDecimal.valueOf(sum);
|
BigDecimal totalMoney = BigDecimal.valueOf(sum);
|
||||||
// BigDecimal amount = amountService.getAmount(dto.getUserId());
|
|
||||||
|
|
||||||
MemberUserDO user = userService.getUser(Long.valueOf(s));
|
MemberUserDO user = userService.getUser(Long.valueOf(s));
|
||||||
dto.setUserId(user.getId());
|
dto.setUserId(user.getId());
|
||||||
if(user.getMoney().compareTo(totalMoney) < 0){
|
if(user.getMoney().compareTo(totalMoney) < 0){
|
||||||
return "金额不足";
|
throw exception(AMOUNT_NOT_ENOUGH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//库存处理,扣除库存
|
||||||
|
AddReqVO addReqVO = new AddReqVO();
|
||||||
|
addReqVO.setType(InventoryTypeEnum.OUT.getCode());
|
||||||
|
addReqVO.setOutType(OutTypeEnum.SELL.getCode());
|
||||||
|
List<GoodsInfoReqVO> infos = new ArrayList<>();
|
||||||
|
for (StoreGoodsDto detail : dto.getEquipmentGoodsCustoms()){
|
||||||
|
GoodsInfoReqVO vo = new GoodsInfoReqVO();
|
||||||
|
BeanUtil.copyProperties(detail,vo);
|
||||||
|
vo.setCarteenId(storeId);
|
||||||
|
vo.setWeight(0d);
|
||||||
|
infos.add(vo);
|
||||||
|
}
|
||||||
|
addReqVO.setList(infos);
|
||||||
|
storeGoodsInventoryService.createStoreGoodsInventory(addReqVO);
|
||||||
|
|
||||||
StoreOrderDO order = createOrder(dto,StoreOrderStatusEnum.COMPLETE.getCode());
|
StoreOrderDO order = createOrder(dto,StoreOrderStatusEnum.COMPLETE.getCode());
|
||||||
Double totalPrice = order.getTotalPrice();
|
Double totalPrice = order.getTotalPrice();
|
||||||
BigDecimal total = BigDecimal.valueOf(totalPrice).setScale(2, RoundingMode.HALF_UP);
|
BigDecimal total = BigDecimal.valueOf(totalPrice).setScale(2, RoundingMode.HALF_UP);
|
||||||
@ -230,7 +248,7 @@ public class StoreOrderServiceImpl implements StoreOrderService {
|
|||||||
if (compute.compareTo(BigDecimal.ZERO) < 0) {
|
if (compute.compareTo(BigDecimal.ZERO) < 0) {
|
||||||
storeOrderMapper.deleteById(order.getOrderId());
|
storeOrderMapper.deleteById(order.getOrderId());
|
||||||
orderDetailService.deleteByOrderNo(order.getOrderId());
|
orderDetailService.deleteByOrderNo(order.getOrderId());
|
||||||
return "金额不足";
|
throw exception(AMOUNT_NOT_ENOUGH);
|
||||||
}
|
}
|
||||||
//营业数据
|
//营业数据
|
||||||
StatisticsVo statisticsVo = new StatisticsVo();
|
StatisticsVo statisticsVo = new StatisticsVo();
|
||||||
@ -241,7 +259,7 @@ public class StoreOrderServiceImpl implements StoreOrderService {
|
|||||||
statisticsVo.setOrderId(order.getOrderId().longValue());
|
statisticsVo.setOrderId(order.getOrderId().longValue());
|
||||||
storeBusinessService.updateStatistics(statisticsVo);
|
storeBusinessService.updateStatistics(statisticsVo);
|
||||||
|
|
||||||
return null;
|
return addReqVO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -408,7 +426,19 @@ public class StoreOrderServiceImpl implements StoreOrderService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String code(Integer orderId) {
|
public String code(Integer orderId) {
|
||||||
return QRCodeWithJWTUtil.generateQRCode(orderId.toString(), 350, 350, null);// 生
|
return QRCodeWithJWTUtil.generateQRCode(QRCodeWithJWTUtil.QR_PREFIX_HX+orderId.toString(), 350, 350, null);// 生
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AppStoreOrderVO info(String code) {
|
||||||
|
code = code.replace(QRCodeWithJWTUtil.QR_PREFIX_HX,"");
|
||||||
|
Integer orderId = Integer.valueOf(code);
|
||||||
|
StoreOrderDO storeOrderDO = storeOrderMapper.selectById(orderId);
|
||||||
|
AppStoreOrderVO vo = new AppStoreOrderVO();
|
||||||
|
BeanUtil.copyProperties(storeOrderDO,vo);
|
||||||
|
List<StoreOrderDetailDO> listByOrderId = orderDetailService.getListByOrderId(orderId);
|
||||||
|
vo.setGoodsList(listByOrderId);
|
||||||
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -921,6 +921,7 @@ public class MemberUserServiceImpl implements MemberUserService {
|
|||||||
// return url;
|
// return url;
|
||||||
// }
|
// }
|
||||||
String encode = DigestUtil.md5Hex(userId.toString()+System.currentTimeMillis());
|
String encode = DigestUtil.md5Hex(userId.toString()+System.currentTimeMillis());
|
||||||
|
encode = QRCodeWithJWTUtil.QR_PREFIX_ZF+encode;
|
||||||
String fileName = "QRCode_" + userId + ".png";
|
String fileName = "QRCode_" + userId + ".png";
|
||||||
String path = QRCodeWithJWTUtil.BASE_PATH+fileName;
|
String path = QRCodeWithJWTUtil.BASE_PATH+fileName;
|
||||||
String s = QRCodeWithJWTUtil.generateQRCode(encode, 350, 350, path);// 生
|
String s = QRCodeWithJWTUtil.generateQRCode(encode, 350, 350, path);// 生
|
||||||
|
@ -1,20 +1,14 @@
|
|||||||
package cn.iocoder.yudao.module.member.util;
|
package cn.iocoder.yudao.module.member.util;
|
||||||
|
|
||||||
import cn.hutool.core.io.FileUtil;
|
|
||||||
import cn.hutool.crypto.digest.DigestUtil;
|
import cn.hutool.crypto.digest.DigestUtil;
|
||||||
import cn.hutool.extra.qrcode.QrCodeUtil;
|
import cn.hutool.extra.qrcode.QrCodeUtil;
|
||||||
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONObject;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
|
|
||||||
import cn.hutool.jwt.JWTUtil;
|
import cn.hutool.jwt.JWTUtil;
|
||||||
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -24,7 +18,8 @@ import java.util.concurrent.TimeUnit;
|
|||||||
public class QRCodeWithJWTUtil {
|
public class QRCodeWithJWTUtil {
|
||||||
private static final String SECRET_KEY = "your_secret_key"; // 使用HS256算法生成秘钥
|
private static final String SECRET_KEY = "your_secret_key"; // 使用HS256算法生成秘钥
|
||||||
public static final String BASE_PATH = "qrCodes/";
|
public static final String BASE_PATH = "qrCodes/";
|
||||||
public static final String QR_PREFIX = "QRCODE_";
|
public static final String QR_PREFIX_ZF = "ZF_";
|
||||||
|
public static final String QR_PREFIX_HX = "HX_";
|
||||||
// public static void main(String[] args) throws WriterException, IOException {
|
// public static void main(String[] args) throws WriterException, IOException {
|
||||||
// // 用户ID
|
// // 用户ID
|
||||||
// Long userId = 123L;
|
// Long userId = 123L;
|
||||||
|
Reference in New Issue
Block a user