瀏覽代碼

用户退房业务开发

wangzhengliang 3 年之前
父節點
當前提交
ed839ca0ef

+ 55 - 27
src/main/java/com/chuanghai/ihotel/component/DoorLockComponent.java

@@ -19,6 +19,9 @@ import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
 import org.springframework.web.client.RestTemplate;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * 门锁服务
  */
@@ -27,6 +30,7 @@ import org.springframework.web.client.RestTemplate;
 public class DoorLockComponent {
 
     private String sign;
+    private ObjectMapper objectMapper = new ObjectMapper();
 
     @Autowired
     private DoorLockConfig doorLockConfig;
@@ -38,34 +42,10 @@ public class DoorLockComponent {
      * @throws JsonProcessingException
      */
     public DoorLockAddPasswordDataDTO addPassword(DoorLockAddPasswordRequestDTO addPasswordDTO) {
+        String uri = "open/api/v2/lock/addPassword";
+        addPasswordDTO.setCategoryId(doorLockConfig.getCategoryId());
         try {
-            String uri = "open/api/v2/lock/addPassword";
-            String url = doorLockConfig.getServiceHost() + uri;
-
-            addPasswordDTO.setCategoryId(doorLockConfig.getCategoryId());
-            ObjectMapper objectMapper = new ObjectMapper();
-            String encrypt = DoorLockAESUtil.encrypt(objectMapper.writeValueAsString(addPasswordDTO), doorLockConfig.getAppSecret());
-
-            RestTemplate restTemplate = new RestTemplate();
-            HttpHeaders headers = new HttpHeaders();
-            headers.add("Content-Type", "application/json");
-            headers.add("appId", doorLockConfig.getAppId());
-            headers.add("sign", getSign());
-            HttpEntity<String> formEntity = new HttpEntity<>(encrypt, headers);
-            ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, formEntity, String.class);
-            String body = responseEntity.getBody();
-
-            // {"result":1,"message":"successful operation",
-            // "data":{"id":"e4252cbabb884d5dba99d3a0fef24667","name":"test","usertype":4,
-            // "lockId":"bb725cba35484034b08f4d6e3f90b584","temporaryPassword":"B07CF12E3A1E2FC184D0DA2548FF0943",
-            // "starttime":1659420000000,"endtime":1659499200000,"enable":1,"taskId":null,"status":0,"password":"386327"}}
-            JsonNode jsonNode = objectMapper.readTree(body);
-            String result = jsonNode.get("result").asText();
-            if (!"1".equals(result)) {
-                throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "请求结果状态不为1");
-            }
-
-            String dataJsonStr = jsonNode.get("data").toString();
+            String dataJsonStr = doRequest(uri, addPasswordDTO);
             DoorLockAddPasswordDataDTO dto = objectMapper.readValue(dataJsonStr, DoorLockAddPasswordDataDTO.class);
             return dto;
         } catch (Exception e) {
@@ -73,6 +53,54 @@ public class DoorLockComponent {
         }
     }
 
+    /**
+     * 删除锁用户
+     * @param lockId
+     * @param lockUserId
+     */
+    public void deleteLockUser(String lockId, String lockUserId) {
+        String uri = "open/api/v2/lock/deleteLockUser";
+        Map<String, String> param = new HashMap<>();
+        param.put("categoryId", doorLockConfig.getCategoryId());
+        param.put("luid", lockId);
+        param.put("id", lockUserId);
+        try {
+            doRequest(uri, param);
+        } catch (Exception e) {
+            throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "门锁服务-删除用户密码失败-" + e.getMessage());
+        }
+    }
+
+    /**
+     * 发送请求
+     * @param uri 请求地址
+     * @param param 参数
+     * @throws JsonProcessingException
+     * @return
+     */
+    private String doRequest(String uri, Object param) throws JsonProcessingException {
+        String url = doorLockConfig.getServiceHost() + uri;
+        String encrypt = DoorLockAESUtil.encrypt(objectMapper.writeValueAsString(param), doorLockConfig.getAppSecret());
+
+        RestTemplate restTemplate = new RestTemplate();
+        HttpHeaders headers = new HttpHeaders();
+        headers.add("Content-Type", "application/json");
+        headers.add("appId", doorLockConfig.getAppId());
+        headers.add("sign", getSign());
+        HttpEntity<String> formEntity = new HttpEntity<>(encrypt, headers);
+        ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, formEntity, String.class);
+        String body = responseEntity.getBody();
+        log.info("门锁服务请求结果【{}】", body);
+        JsonNode jsonNode = objectMapper.readTree(body);
+        String result = jsonNode.get("result").asText();
+        if (!"1".equals(result)) {
+            throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "门锁服务-请求结果状态不为1");
+        }
+
+        String dataJsonStr = jsonNode.get("data").toString();
+        return dataJsonStr;
+    }
+
     private String getSign() {
         if (StringUtils.hasText(sign)) {
             return sign;

+ 14 - 4
src/main/java/com/chuanghai/ihotel/controller/HotelOrderController.java

@@ -19,6 +19,7 @@ import com.chuanghai.ihotel.service.HotelOrderService;
 import com.chuanghai.ihotel.util.CommonUtil;
 import com.chuanghai.ihotel.vo.ConfirmOrderVO;
 import com.chuanghai.ihotel.vo.LoginUserVO;
+import com.chuanghai.ihotel.vo.OrderBillHandleVO;
 import com.chuanghai.ihotel.vo.OrderSubmitTokenVO;
 import com.chuanghai.ihotel.vo.OrderSubmitVO;
 import com.chuanghai.ihotel.vo.UserOrderDetailVO;
@@ -219,12 +220,21 @@ public class HotelOrderController {
         return CommonResult.ok();
     }
 
-
+    /**
+     * 办理退房
+     * @param userToken 用户token
+     * @param orderId 订单id
+     * @return
+     */
+    @UserLoginCheck
+    @PutMapping("user/order/return/{orderId}")
+    public CommonResult<String> userReturnOrder(@RequestHeader("user_token") String userToken,
+                                              @PathVariable("orderId") Long orderId) {
+        OrderBillHandleVO orderBillHandleVO = hotelOrderService.userReturnOrder(orderId);
+        return CommonResult.ok().setResult(orderBillHandleVO);
+    }
 
     // 办理续住
-    // 退房 -> 订单结算、水电、门锁
-
-
 
 
     /**

+ 6 - 2
src/main/java/com/chuanghai/ihotel/controller/TestController.java

@@ -3,7 +3,6 @@ package com.chuanghai.ihotel.controller;
 import com.chuanghai.ihotel.component.DoorLockComponent;
 import com.chuanghai.ihotel.component.WaterElectricComponent;
 import com.chuanghai.ihotel.dto.DoorLockAddPasswordRequestDTO;
-import com.fasterxml.jackson.core.JsonProcessingException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -42,7 +41,7 @@ public class TestController {
     }
 
     @GetMapping("test5")
-    public void test5() throws JsonProcessingException {
+    public void test5() {
         LocalDateTime startTime = LocalDateTime.of(2022, 8, 2, 14, 0);
         LocalDateTime endTime = LocalDateTime.of(2022, 8, 3, 12, 0);
 
@@ -57,4 +56,9 @@ public class TestController {
                 .build();
         doorLockComponent.addPassword(dto);
     }
+
+    @GetMapping("test6")
+    public void test6() {
+        doorLockComponent.deleteLockUser("80A036D93CFB", "c7e634f560954849811f1001b6174e29");
+    }
 }

+ 29 - 0
src/main/java/com/chuanghai/ihotel/dto/BillHandleResultDTO.java

@@ -0,0 +1,29 @@
+package com.chuanghai.ihotel.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 结账单处理结果
+ */
+@Data
+public class BillHandleResultDTO {
+
+    /**
+     * 结账单id
+     */
+    private Long billId;
+    /**
+     * 结果标识 1待退款、2待补缴
+     */
+    private String resultFlag;
+    /**
+     * 待退款金额
+     */
+    private BigDecimal returnFee;
+    /**
+     * 待补缴金额
+     */
+    private BigDecimal realFee;
+}

+ 1 - 1
src/main/java/com/chuanghai/ihotel/entity/HotelOrderBillEntity.java

@@ -75,7 +75,7 @@ public class HotelOrderBillEntity implements Serializable {
 	 */
 	private BigDecimal realFree;
 	/**
-	 * 状态 1待处理、2完成
+	 * 状态 1待处理、2计算完成、3处理完成
 	 */
 	private String statu;
 	/**

+ 8 - 0
src/main/java/com/chuanghai/ihotel/service/HotelOrderBillService.java

@@ -3,6 +3,7 @@ package com.chuanghai.ihotel.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.chuanghai.ihotel.common.utils.PageUtils;
 import com.chuanghai.ihotel.common.utils.PageParam;
+import com.chuanghai.ihotel.dto.BillHandleResultDTO;
 import com.chuanghai.ihotel.entity.HotelOrderBillEntity;
 
 /**
@@ -24,5 +25,12 @@ public interface HotelOrderBillService extends IService<HotelOrderBillEntity> {
      * @param roomId 房间id
      */
     void generateBill(Long orderId, Long roomId);
+
+    /**
+     * 计算订单
+     * @param orderId
+     * @return
+     */
+    BillHandleResultDTO calcBill(Long orderId);
 }
 

+ 8 - 0
src/main/java/com/chuanghai/ihotel/service/HotelOrderService.java

@@ -9,6 +9,7 @@ import com.chuanghai.ihotel.controller.request.SubmitOrderRequest;
 import com.chuanghai.ihotel.dto.EventMessageDTO;
 import com.chuanghai.ihotel.entity.HotelOrderEntity;
 import com.chuanghai.ihotel.vo.ConfirmOrderVO;
+import com.chuanghai.ihotel.vo.OrderBillHandleVO;
 import com.chuanghai.ihotel.vo.OrderSubmitVO;
 import com.chuanghai.ihotel.vo.UserOrderDetailVO;
 
@@ -108,5 +109,12 @@ public interface HotelOrderService extends IService<HotelOrderEntity> {
      * @param orderId
      */
     void userHoldOrder(Long orderId);
+
+    /**
+     * 用户退房
+     * @param orderId
+     * @return
+     */
+    OrderBillHandleVO userReturnOrder(Long orderId);
 }
 

+ 2 - 0
src/main/java/com/chuanghai/ihotel/service/RoomDoorLockDataService.java

@@ -19,6 +19,8 @@ public interface RoomDoorLockDataService extends IService<RoomDoorLockDataEntity
 
     RoomDoorLockDataEntity queryByOrderId(Long orderId);
 
+    void deleteByOrderId(Long orderId);
+
     /**
      * 生成密码
      * @param order

+ 98 - 13
src/main/java/com/chuanghai/ihotel/service/impl/HotelOrderBillServiceImpl.java

@@ -3,6 +3,7 @@ package com.chuanghai.ihotel.service.impl;
 import com.chuanghai.ihotel.common.exception.BizCodeEnume;
 import com.chuanghai.ihotel.common.exception.RRException;
 import com.chuanghai.ihotel.component.WaterElectricComponent;
+import com.chuanghai.ihotel.dto.BillHandleResultDTO;
 import com.chuanghai.ihotel.entity.RoomThirdSettingEntity;
 import com.chuanghai.ihotel.entity.SystemSettingEntity;
 import com.chuanghai.ihotel.service.RoomThirdSettingService;
@@ -22,6 +23,9 @@ import com.chuanghai.ihotel.service.HotelOrderBillService;
 import org.springframework.util.StringUtils;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
 
 
 @Service("hotelOrderBillService")
@@ -58,19 +62,9 @@ public class HotelOrderBillServiceImpl extends ServiceImpl<HotelOrderBillDao, Ho
         SystemSettingEntity systemSetting = systemSettingService.get();
 
         // 水电抄表
-        RoomThirdSettingEntity waterElectricEntity = roomWaterElectricService.findByRoomId(roomId);
-        if (waterElectricEntity == null) {
-            throw new RRException(BizCodeEnume.PERMISSION_DENIED, "房间水电表数据读取失败");
-        }
-
-        String electricData = waterElectricComponent.queryPowerRealTimeData(waterElectricEntity.getElectricId());
-        if (!StringUtils.hasText(electricData)) {
-            throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "读取电表数据异常");
-        }
-        String waterData = waterElectricComponent.queryLastHistoryCumulantInfo(waterElectricEntity.getWaterId());
-        if (!StringUtils.hasText(waterData)) {
-            throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "读取电表数据异常");
-        }
+        Map<String, String> returnParam = readWaterElectricData(roomId);
+        String electricData = returnParam.get("electricData");
+        String waterData = returnParam.get("waterData");
 
         // 生成结账单
         HotelOrderBillEntity orderBill = new HotelOrderBillEntity();
@@ -89,4 +83,95 @@ public class HotelOrderBillServiceImpl extends ServiceImpl<HotelOrderBillDao, Ho
         this.save(orderBill);
     }
 
+    @Override
+    public BillHandleResultDTO calcBill(Long orderId) {
+        // 系统设置
+        SystemSettingEntity systemSetting = systemSettingService.get();
+        HotelOrderBillEntity orderBill = findByOrderId(orderId);
+        if (orderBill == null) {
+            throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "订单账单信息不存在");
+        }
+        Map<String, String> returnParam = readWaterElectricData(orderBill.getRoomId());
+        String electricData = returnParam.get("electricData");
+        String waterData = returnParam.get("waterData");
+
+        orderBill.setEndOfElectric(electricData);
+        orderBill.setEndOfWater(waterData);
+
+        // 订单结算
+        // 水用量
+        BigDecimal useOfWater = new BigDecimal(orderBill.getEndOfWater()).subtract(new BigDecimal(orderBill.getStartOfWater()));
+        // 电用量
+        BigDecimal useOfElectric = new BigDecimal(orderBill.getEndOfElectric()).subtract(new BigDecimal(orderBill.getStartOfElectric()));
+        // 水费
+        BigDecimal waterFee = useOfWater.multiply(new BigDecimal(orderBill.getPriceOfWater()));
+        // 电费
+        BigDecimal electricFee = useOfElectric.multiply(new BigDecimal(orderBill.getPriceOfElectric()));
+        // 总费用 【实际花费】
+        BigDecimal totalFee = waterFee.add(electricFee);
+        // 应缴费用 【总费用-减免费用】
+        BigDecimal shouldFee = totalFee.subtract(orderBill.getDiscountFree());
+        if (shouldFee.doubleValue() < 0) {
+            shouldFee = new BigDecimal("0");
+        }
+
+        // 补缴费用 【应缴费用-预缴费用】
+        BigDecimal realFee = shouldFee.subtract(systemSetting.getFreeTotal());
+        if (realFee.doubleValue() < 0.01) {
+            realFee = new BigDecimal("0");
+        }
+
+        orderBill.setTotalFree(totalFee);
+        orderBill.setShouldFree(shouldFee);
+        orderBill.setRealFree(realFee);
+
+        BillHandleResultDTO dto = new BillHandleResultDTO();
+        dto.setBillId(orderBill.getId());
+        if (orderBill.getRealFree().doubleValue() <= 0) {
+            // 自动完成结账
+            orderBill.setStatu("3");
+            orderBill.setFinishTime(LocalDateTime.now());
+
+            dto.setResultFlag("1");
+            dto.setReturnFee(systemSetting.getDeposit().subtract(shouldFee));
+        } else {
+            orderBill.setStatu("2");
+
+            // 发起缴费
+            dto.setResultFlag("2");
+            dto.setRealFee(realFee);
+        }
+
+        this.updateById(orderBill);
+
+        return dto;
+    }
+
+    /**
+     * 读取水电表数据
+     * @param roomId 房间号
+     * @return
+     */
+    private Map<String, String> readWaterElectricData(Long roomId) {
+        // 水电抄表
+        RoomThirdSettingEntity waterElectricEntity = roomWaterElectricService.findByRoomId(roomId);
+        if (waterElectricEntity == null) {
+            throw new RRException(BizCodeEnume.PERMISSION_DENIED, "房间水电表计信息读取失败");
+        }
+
+        String electricData = waterElectricComponent.queryPowerRealTimeData(waterElectricEntity.getElectricId());
+        if (!StringUtils.hasText(electricData)) {
+            throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "读取电表数据异常");
+        }
+        String waterData = waterElectricComponent.queryLastHistoryCumulantInfo(waterElectricEntity.getWaterId());
+        if (!StringUtils.hasText(waterData)) {
+            throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "读取电表数据异常");
+        }
+
+        Map<String, String> param = new HashMap<>();
+        param.put("electricData", electricData);
+        param.put("waterData", waterData);
+        return param;
+    }
+
 }

+ 36 - 0
src/main/java/com/chuanghai/ihotel/service/impl/HotelOrderServiceImpl.java

@@ -19,6 +19,7 @@ import com.chuanghai.ihotel.controller.request.ConfrimOrderRequest;
 import com.chuanghai.ihotel.controller.request.OrderQueryRequest;
 import com.chuanghai.ihotel.controller.request.SubmitOrderRequest;
 import com.chuanghai.ihotel.dao.HotelOrderDao;
+import com.chuanghai.ihotel.dto.BillHandleResultDTO;
 import com.chuanghai.ihotel.dto.EventMessageDTO;
 import com.chuanghai.ihotel.dto.LockRoomDTO;
 import com.chuanghai.ihotel.entity.HotelOrderBillEntity;
@@ -43,6 +44,7 @@ import com.chuanghai.ihotel.service.SystemSettingService;
 import com.chuanghai.ihotel.util.CommonUtil;
 import com.chuanghai.ihotel.vo.ConfirmOrderVO;
 import com.chuanghai.ihotel.vo.LoginUserVO;
+import com.chuanghai.ihotel.vo.OrderBillHandleVO;
 import com.chuanghai.ihotel.vo.OrderSubmitVO;
 import com.chuanghai.ihotel.vo.UserOrderDetailVO;
 import com.chuanghai.ihotel.vo.UserOrderIndexVO;
@@ -502,6 +504,40 @@ public class HotelOrderServiceImpl extends ServiceImpl<HotelOrderDao, HotelOrder
         this.update(null, updateWrapper);
     }
 
+    @Override
+    public OrderBillHandleVO userReturnOrder(Long orderId) {
+        HotelOrderEntity order = userGetOrderById(orderId);
+        // 入住状态的订单才可以办理退房
+        if (!OrderStatuEnum.HOLD_ON.getCode().equalsIgnoreCase(order.getOrderStatu())) {
+            throw new RRException(BizCodeEnume.PERMISSION_DENIED, "订单状态异常");
+        }
+
+        // 结算订单
+        BillHandleResultDTO billHandleResult = orderBillService.calcBill(orderId);
+        if ("1".equals(billHandleResult.getResultFlag()) && billHandleResult.getReturnFee().doubleValue() > 0) {
+            // TODO 发起退款
+        }
+
+        // 密码锁密码删除
+        roomDoorLockDataService.deleteByOrderId(orderId);
+
+        // 更新订单状态
+        UpdateWrapper<HotelOrderEntity> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.eq("id", orderId);
+        updateWrapper.set("order_statu", OrderStatuEnum.WAIT_BILL.getCode());
+        updateWrapper.last("limit 1");
+        this.update(null, updateWrapper);
+
+        OrderBillHandleVO vo = new OrderBillHandleVO();
+        vo.setOrderId(orderId);
+        vo.setBillId(billHandleResult.getBillId());
+        vo.setFlag(billHandleResult.getResultFlag());
+        vo.setRefundFee(billHandleResult.getReturnFee());
+        vo.setSupperFee(billHandleResult.getRealFee());
+
+        return vo;
+    }
+
     /**
      * 用户根据订单id获取订单
      * @param orderId

+ 18 - 0
src/main/java/com/chuanghai/ihotel/service/impl/RoomDoorLockDataServiceImpl.java

@@ -52,6 +52,24 @@ public class RoomDoorLockDataServiceImpl extends ServiceImpl<RoomDoorLockDataDao
     }
 
     @Override
+    public void deleteByOrderId(Long orderId) {
+        RoomDoorLockDataEntity lockData = this.queryByOrderId(orderId);
+        if (lockData != null) {
+            // 删除远程锁
+            RoomThirdSettingEntity roomThirdSettingEntity = roomThirdSettingService.findByRoomId(lockData.getRoomId());
+            if (roomThirdSettingEntity == null) {
+                throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "门锁不存在");
+            }
+            try {
+                doorLockComponent.deleteLockUser(roomThirdSettingEntity.getLockId(), lockData.getLockId());
+            } catch (Exception e) {}
+
+            // 删除锁
+            this.removeById(lockData);
+        }
+    }
+
+    @Override
     public void generatePassword(HotelOrderEntity order) {
         Long roomId = order.getRoomId();
         RoomThirdSettingEntity roomThirdSettingEntity = roomThirdSettingService.findByRoomId(roomId);

+ 37 - 0
src/main/java/com/chuanghai/ihotel/vo/OrderBillHandleVO.java

@@ -0,0 +1,37 @@
+package com.chuanghai.ihotel.vo;
+
+import com.chuanghai.ihotel.util.BigDecimalSerializer;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 订单账单处理vo
+ */
+@Data
+public class OrderBillHandleVO {
+
+    /**
+     * 订单id
+     */
+    private Long orderId;
+    /**
+     * 账单id
+     */
+    private Long billId;
+    /**
+     * 处理标识 1待退款、2待补缴
+     */
+    private String flag;
+    /**
+     * 待退款金额
+     */
+    @JsonSerialize(using = BigDecimalSerializer.class)
+    private BigDecimal refundFee;
+    /**
+     * 待补缴金额
+     */
+    @JsonSerialize(using = BigDecimalSerializer.class)
+    private BigDecimal supperFee;
+}