xiongzhu 5 роки тому
батько
коміт
d6dcc5cc7a

+ 4 - 0
src/main/java/com/izouma/zhumj/domain/UserMoneyWithdrawApply.java

@@ -2,6 +2,7 @@ package com.izouma.zhumj.domain;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.izouma.zhumj.enums.WithdrawApplyStatus;
+import com.izouma.zhumj.enums.WithdrawMethod;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
@@ -50,4 +51,7 @@ public class UserMoneyWithdrawApply extends BaseEntity {
     @NotFound(action = NotFoundAction.IGNORE)
     @JsonIgnore
     private User user;
+
+    @Enumerated(EnumType.STRING)
+    private WithdrawMethod method;
 }

+ 2 - 1
src/main/java/com/izouma/zhumj/enums/DepositRefundType.java

@@ -6,7 +6,8 @@ package com.izouma.zhumj.enums;
 public enum DepositRefundType {
     PAID("原路退还"),
     BANK("银行卡"),
-    ENT_PAY("微信零钱");
+    ENT_PAY("微信零钱"),
+    ALI_ENT_PAY("支付宝转账");
 
     private final String description;
 

+ 16 - 0
src/main/java/com/izouma/zhumj/enums/WithdrawMethod.java

@@ -0,0 +1,16 @@
+package com.izouma.zhumj.enums;
+
+public enum WithdrawMethod {
+    WECHAT("微信"),
+    ALIPAY("支付宝");
+
+    private final String description;
+
+    WithdrawMethod(String description) {
+        this.description = description;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+}

+ 36 - 20
src/main/java/com/izouma/zhumj/service/UserMoneyWithdrawApplyService.java

@@ -1,5 +1,6 @@
 package com.izouma.zhumj.service;
 
+import com.alipay.api.AlipayClient;
 import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
 import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
 import com.github.binarywang.wxpay.exception.WxPayException;
@@ -9,6 +10,7 @@ import com.izouma.zhumj.domain.MemberInfo;
 import com.izouma.zhumj.domain.User;
 import com.izouma.zhumj.domain.UserMoneyWithdrawApply;
 import com.izouma.zhumj.enums.WithdrawApplyStatus;
+import com.izouma.zhumj.enums.WithdrawMethod;
 import com.izouma.zhumj.exception.BusinessException;
 import com.izouma.zhumj.repo.CheckinInfoRepo;
 import com.izouma.zhumj.repo.MemberRepo;
@@ -36,8 +38,9 @@ public class UserMoneyWithdrawApplyService {
     private WxPayService               wxPayService;
     private CheckinInfoRepo            checkinInfoRepo;
     private MemberRepo                 memberRepo;
+    private AlipayClient               alipayClient;
 
-    public UserMoneyWithdrawApply apply(Long userId) {
+    public UserMoneyWithdrawApply apply(Long userId, WithdrawMethod method) {
         User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
         MemberInfo memberInfo = memberRepo.findById(user.getIdNo()).orElseThrow(new BusinessException("无住客信息"));
         if (Optional.ofNullable(memberInfo.getMoney()).orElse(BigDecimal.ZERO).compareTo(BigDecimal.ZERO) <= 0) {
@@ -47,6 +50,7 @@ public class UserMoneyWithdrawApplyService {
                 .userId(userId)
                 .amount(memberInfo.getMoney())
                 .status(WithdrawApplyStatus.APPLY)
+                .method(method)
                 .build();
         if (StringUtils.isNotBlank(user.getIdNo())) {
             checkinInfoRepo.findFirstByIdNoOrderByCheckinTimeDescCreatedAtDesc(user.getIdNo())
@@ -72,28 +76,40 @@ public class UserMoneyWithdrawApplyService {
             userMoneyWithdrawApplyRepo.saveAndFlush(apply);
         }
         CheckinInfo checkinInfo = checkinInfoRepo.findFirstByIdNo(user.getIdNo());
-        try {
-            EntPayRequest request = new EntPayRequest();
-            request.setPartnerTradeNo(apply.getTradeNo());
-            request.setAmount(apply.getAmount().multiply(BigDecimal.valueOf(100)).intValue());
-            request.setOpenid(user.getOpenId());
-            request.setCheckName("NO_CHECK");
-            request.setDescription(checkinInfo.getStoreInfo().getStoreName()+","+
-                    checkinInfo.getRoomInfo().getRoomName()+","
-                    +checkinInfo.getRoomInfo().getRoomName()
-                    +"余额提现");
-            request.setSpbillCreateIp("192.168.31.12");
-            EntPayResult result = wxPayService.getEntPayService().entPay(request);
-            result.checkResult(wxPayService, "MD5", true);
-        } catch (WxPayException e) {
-            log.error("余额提现失败", e);
-            throw new BusinessException(e.getMessage());
+        String body = checkinInfo.getStoreInfo().getStoreName() + "," +
+                checkinInfo.getRoomInfo().getRoomName() + ","
+                + checkinInfo.getBedInfo().getBedName()
+                + "余额提现";
+
+        switch (apply.getMethod()) {
+            case WECHAT:
+                try {
+                    EntPayRequest request = new EntPayRequest();
+                    request.setPartnerTradeNo(apply.getTradeNo());
+                    request.setAmount(apply.getAmount().multiply(BigDecimal.valueOf(100)).intValue());
+                    request.setOpenid(user.getOpenId());
+                    request.setCheckName("NO_CHECK");
+                    request.setDescription(body);
+                    request.setSpbillCreateIp("192.168.31.12");
+                    EntPayResult result = wxPayService.getEntPayService().entPay(request);
+                    result.checkResult(wxPayService, "MD5", true);
+                } catch (WxPayException e) {
+                    log.error("余额提现失败", e);
+                    throw new BusinessException(e.getMessage());
+                }
+                break;
+            case ALIPAY:
+                break;
+            default:
+                throw new BusinessException("不支持此提现方式");
         }
 
+
         apply.setStatus(WithdrawApplyStatus.SUCCESS);
         apply.setTransferTime(LocalDateTime.now());
 
-        memberInfo.setMoney(Optional.ofNullable(memberInfo.getMoney()).orElse(BigDecimal.ZERO).subtract(apply.getAmount()));
+        memberInfo.setMoney(Optional.ofNullable(memberInfo.getMoney()).orElse(BigDecimal.ZERO)
+                .subtract(apply.getAmount()));
         memberRepo.save(memberInfo);
 
         userMoneyRecordService.saveWithdrawRecord(user.getId(), user.getIdNo(), apply.getAmount(), apply.getId());
@@ -106,11 +122,11 @@ public class UserMoneyWithdrawApplyService {
         userMoneyWithdrawApplyRepo.save(apply);
     }
 
-    public void applyAndPass(Long userId) {
+    public void applyAndPass(Long userId, WithdrawMethod method) {
         if (SecurityUtils.getAuthenticatedUser().isTemporal()) {
             throw new BusinessException("扫码进入无法提现");
         }
-        UserMoneyWithdrawApply apply = apply(userId);
+        UserMoneyWithdrawApply apply = apply(userId, method);
         try {
             pass(apply.getId());
         } catch (BusinessException e) {

+ 2 - 2
src/main/java/com/izouma/zhumj/service/client/ClientRoomInfoService.java

@@ -188,7 +188,7 @@ public class ClientRoomInfoService {
                         .build());
                 if (Arrays.stream(environment.getActiveProfiles()).noneMatch(s -> s.equals("prod"))) {
                     // 测试环境设为1分
-                    model.setTotalAmount("0.01");
+//                    model.setTotalAmount("0.01");
                 }
 
                 alipayRequest.setNotifyUrl(aliNotifyUrl);
@@ -286,7 +286,7 @@ public class ClientRoomInfoService {
                         .build());
                 if (Arrays.stream(environment.getActiveProfiles()).noneMatch(s -> s.equals("prod"))) {
                     // 测试环境设为1分
-                    model.setTotalAmount("0.01");
+//                    model.setTotalAmount("0.01");
                 }
 
                 alipayRequest.setNotifyUrl(aliNotifyUrl);

+ 54 - 19
src/main/java/com/izouma/zhumj/service/client/DepositRefundApplyService.java

@@ -1,5 +1,10 @@
 package com.izouma.zhumj.service.client;
 
+import com.alipay.api.AlipayApiException;
+import com.alipay.api.AlipayClient;
+import com.alipay.api.domain.AlipayTradeRefundModel;
+import com.alipay.api.request.AlipayTradeRefundRequest;
+import com.alipay.api.response.AlipayTradeRefundResponse;
 import com.github.binarywang.wxpay.bean.entpay.EntPayBankRequest;
 import com.github.binarywang.wxpay.bean.entpay.EntPayRequest;
 import com.github.binarywang.wxpay.bean.entpay.EntPayResult;
@@ -56,6 +61,8 @@ public class DepositRefundApplyService {
     private UserRepo               userRepo;
     @Autowired
     private MemberRepo             memberRepo;
+    @Autowired
+    private AlipayClient           alipayClient;
 
     public Page<DepositRefundApply> getDepositRefundApply(Long storeId, String search, DepositRefundStatus status, DepositRefundType depositRefundType, Pageable pageable) {
         return depositRefundApplyRepo
@@ -198,8 +205,8 @@ public class DepositRefundApplyService {
                     case ENT_PAY:
                         refundEntPay(checkinInfo, apply, user.getOpenId());
                         break;
-                    case BANK:
-                        throw new BusinessException("暂不支持退回银行卡");
+                    default:
+                        throw new BusinessException("暂不支持");
                         // refundBank(checkinInfo, apply, user);
                         // break;
                 }
@@ -216,24 +223,52 @@ public class DepositRefundApplyService {
     }
 
     private void refund(CheckinInfo checkinInfo, DepositRefundApply apply) {
-        apply.setStatus(DepositRefundStatus.REFUNDING);
-        try {
-            apply.setRefundId(checkinInfo.getDepositRecord().getTransactionId());
-            WxPayRefundRequest req = WxPayRefundRequest.newBuilder()
-                    .outRefundNo(apply.getRefundId())
-                    .transactionId(checkinInfo.getDepositRecord().getTransactionId())
-                    .totalFee(checkinInfo.getDepositAmount()
-                            .multiply(BigDecimal.valueOf(100)).intValue())
-                    .refundFee(apply.getAmount()
-                            .multiply(BigDecimal.valueOf(100)).intValue())
-                    .notifyUrl(refundNotifyUrl)
-                    .build();
-            wxPayService.refund(req);
-        } catch (WxPayException e) {
-            log.error("微信退款失败", e);
-            throw new BusinessException(e.getMessage());
+        switch (checkinInfo.getDepositRecord().getPayMethod()) {
+            case WEIXIN:
+                apply.setStatus(DepositRefundStatus.REFUNDING);
+                try {
+                    apply.setRefundId(checkinInfo.getDepositRecord().getTransactionId());
+                    WxPayRefundRequest req = WxPayRefundRequest.newBuilder()
+                            .outRefundNo(apply.getRefundId())
+                            .transactionId(checkinInfo.getDepositRecord().getTransactionId())
+                            .totalFee(checkinInfo.getDepositAmount()
+                                    .multiply(BigDecimal.valueOf(100)).intValue())
+                            .refundFee(apply.getAmount()
+                                    .multiply(BigDecimal.valueOf(100)).intValue())
+                            .notifyUrl(refundNotifyUrl)
+                            .build();
+                    wxPayService.refund(req);
+                } catch (WxPayException e) {
+                    log.error("微信退款失败", e);
+                    throw new BusinessException(e.getMessage());
+                }
+                depositRecordRepo.save(apply.getCheckinInfo().getDepositRecord());
+                return;
+            case ALIPAY:
+                AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
+                AlipayTradeRefundModel model = new AlipayTradeRefundModel();
+                model.setTradeNo(checkinInfo.getDepositRecord().getTransactionId());
+                model.setRefundAmount(apply.getAmount().toString());
+                request.setBizModel(model);
+                AlipayTradeRefundResponse response = null;
+                try {
+                    response = alipayClient.execute(request);
+                    log.info("支付宝请求 {}", response.toString());
+                    if (response.isSuccess() && "10000".equals(response.getCode())) {
+                        apply.setStatus(DepositRefundStatus.SUCCESS);
+                        apply.setRefundTime(LocalDateTime.now());
+                        depositRefundApplyRepo.save(apply);
+                        checkinInfo.setDepositStatus(DepositStatus.REFUNDED);
+                    } else {
+                        throw new BusinessException("支付宝退款失败");
+                    }
+                } catch (AlipayApiException e) {
+                    e.printStackTrace();
+                    log.error("支付宝退款失败", e);
+                    throw new BusinessException(e.getMessage());
+                }
+                break;
         }
-        depositRecordRepo.save(apply.getCheckinInfo().getDepositRecord());
     }
 
     private void refundEntPay(CheckinInfo checkinInfo, DepositRefundApply apply, String openId) {

+ 3 - 2
src/main/java/com/izouma/zhumj/web/UserMoneyWithdrawApplyController.java

@@ -2,6 +2,7 @@ package com.izouma.zhumj.web;
 
 import com.izouma.zhumj.domain.UserMoneyWithdrawApply;
 import com.izouma.zhumj.dto.PageQuery;
+import com.izouma.zhumj.enums.WithdrawMethod;
 import com.izouma.zhumj.exception.BusinessException;
 import com.izouma.zhumj.repo.UserMoneyWithdrawApplyRepo;
 import com.izouma.zhumj.service.UserMoneyWithdrawApplyService;
@@ -70,8 +71,8 @@ public class UserMoneyWithdrawApplyController extends BaseController {
     }
 
     @PostMapping("/applyAndPass")
-    public void applyAndPass() {
-        userMoneyWithdrawApplyService.applyAndPass(SecurityUtils.getAuthenticatedUser().getId());
+    public void applyAndPass(@RequestParam(defaultValue = "WECHAT") WithdrawMethod method) {
+        userMoneyWithdrawApplyService.applyAndPass(SecurityUtils.getAuthenticatedUser().getId(), method);
     }
 }
 

+ 2 - 1
src/main/vue/src/views/DepositRefundApplyList.vue

@@ -124,7 +124,8 @@ export default {
                 { label: '原路退回', value: 'PAID' },
                 { label: '红包', value: 'RED_PACK' },
                 { label: '银行卡转账', value: 'BANK' },
-                { label: '微信零钱', value: 'ENT_PAY' }
+                { label: '微信零钱', value: 'ENT_PAY' },
+                { label: '支付宝转账', value: 'ALI_ENT_PAY' }
             ],
             depositRefundType: ''
         };

BIN
src/main/zmj_mp/src/assets/ali_logo.png


+ 35 - 32
src/main/zmj_mp/src/views/User.vue

@@ -187,38 +187,41 @@ export default {
             this.$router.push(route);
         },
         withdraw() {
-            this.$alert(
-                {
-                    type: 'info',
-                    showCancel: true,
-                    cancelText: '确认提现',
-                    confirmText: '取消',
-                    content: '是否确认提现?'
-                },
-                _ => {},
-                () => {
-                    this.$toast.loading({ duration: 0, message: '加载中' });
-                    this.$http
-                        .post('/userMoneyWithdrawApply/applyAndPass')
-                        .then(res => {
-                            this.$toast.clear();
-                            this.$router.push({
-                                name: 'result',
-                                params: {
-                                    title: '申请成功',
-                                    type: 'success',
-                                    desc: '您已成功申请提现,钱款稍后会发放至您的微信钱包,请注意查收',
-                                    showBack: true
-                                }
-                            });
-                        })
-                        .catch(e => {
-                            console.log(e);
-                            this.$toast.clear();
-                            this.$toast(e.error);
-                        });
-                }
-            );
+            this.$router.push({
+                path: '/withdraw'
+            });
+            // this.$alert(
+            //     {
+            //         type: 'info',
+            //         showCancel: true,
+            //         cancelText: '确认提现',
+            //         confirmText: '取消',
+            //         content: '是否确认提现?'
+            //     },
+            //     _ => {},
+            //     () => {
+            //         this.$toast.loading({ duration: 0, message: '加载中' });
+            //         this.$http
+            //             .post('/userMoneyWithdrawApply/applyAndPass')
+            //             .then(res => {
+            //                 this.$toast.clear();
+            //                 this.$router.push({
+            //                     name: 'result',
+            //                     params: {
+            //                         title: '申请成功',
+            //                         type: 'success',
+            //                         desc: '您已成功申请提现,钱款稍后会发放至您的微信钱包,请注意查收',
+            //                         showBack: true
+            //                     }
+            //                 });
+            //             })
+            //             .catch(e => {
+            //                 console.log(e);
+            //                 this.$toast.clear();
+            //                 this.$toast(e.error);
+            //             });
+            //     }
+            // );
         }
     }
 };

+ 41 - 9
src/main/zmj_mp/src/views/Withdraw.vue

@@ -1,16 +1,27 @@
 <template>
     <div>
         <div class="head">
-            <div class="title">房间预存余额</div>
-            <div class="money">¥{{ roomInfo.balance }}</div>
+            <div class="title">个人余额</div>
+            <div class="money">¥{{ roomInfo.money }}</div>
             <div class="btn" @click="$router.push('/withdrawRecord')">提现明细</div>
         </div>
 
         <div class="cell">
             <div class="label">提现金额</div>
-            <input placeholder="请输入提现金额" v-model="money" type="number" />
+            <input placeholder="请输入提现金额" v-model="money" type="number" disabled />
             <div class="suffix">元</div>
         </div>
+        <template v-if="$store.state.app">
+            <div class="tip">当前提现仅支持提现到支付宝账号,请输入信息</div>
+            <div class="cell">
+                <div class="label">支付宝姓名</div>
+                <input placeholder="请输入支付宝姓名" v-model="name" />
+            </div>
+            <div class="cell">
+                <div class="label">支付宝账号</div>
+                <input placeholder="请输入支付宝账号" v-model="account" />
+            </div>
+        </template>
         <div class="btn-round-large" :class="{ disabled: !moneyValid }" @click="withdraw">立即提现</div>
     </div>
 </template>
@@ -23,14 +34,19 @@ export default {
     },
     data() {
         return {
-            money: ''
+            money: '',
+            account: '',
+            name: ''
         };
     },
+    created() {
+        this.money = this.$store.state.roomInfo.money;
+    },
     computed: {
-        ...mapState(['roomInfo']),
+        ...mapState(['roomInfo', 'roomInfo']),
         moneyValid() {
             if (/((^[1-9]\d*)|^0)(\.\d{0,2}){0,1}$/.test(this.money)) {
-                return Number(this.money) <= this.roomInfo.balance;
+                return Number(this.money) <= this.roomInfo.money;
             }
             return false;
         }
@@ -38,13 +54,23 @@ export default {
     methods: {
         withdraw() {
             if (!this.moneyValid) {
+                this.$toast('请输入正确的金额');
                 return;
             }
+            if (this.$store.state.app) {
+                if (!this.name) {
+                    this.$toast('请输入支付宝姓名');
+                    return;
+                }
+                if (!this.account) {
+                    this.$toast('请输入支付宝账号');
+                    return;
+                }
+            }
             this.$toast.loading({ duration: 0, message: '加载中' });
             this.$http
-                .post('/roomMoneyWithdrawApply/apply', {
-                    roomId: this.roomInfo.roomId,
-                    amount: this.money
+                .post('/userMoneyWithdrawApply/applyAndPass', {
+                    method: this.$store.state.app ? 'ALPAY' : 'WECHAT'
                 })
                 .then(res => {
                     this.$toast.clear();
@@ -132,4 +158,10 @@ export default {
         border-left: 1px solid rgba(227, 229, 230, 1);
     }
 }
+.tip {
+    margin: 30px 15px 0 15px;
+    color: #f7931d;
+    font-size: 13px;
+    font-weight: bold;
+}
 </style>

+ 5 - 2
src/test/java/com/izouma/zhumj/repo/UserRepoTest.java

@@ -14,7 +14,10 @@ import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
 import org.springframework.test.context.junit4.SpringRunner;
 
+import java.time.LocalDate;
+import java.time.ZoneOffset;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -58,8 +61,8 @@ public class UserRepoTest {
     @Test
     public void getToken() {
         final UserDetails userDetails = userDetailsService
-                .loadUserByUsername(userRepo.findById(409427L).get().getUsername());
-        String token = jwtTokenUtil.generateToken(userDetails);
+                .loadUserByUsername(userRepo.findById(121655L).get().getUsername());
+        String token = jwtTokenUtil.generateToken(userDetails, Date.from(LocalDate.of(2022,12,12).atStartOfDay().toInstant(ZoneOffset.ofHours(8))));
         System.out.println(token);
     }