package com.dy.pipIrrSell.virtualCard; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.dy.common.aop.SsoAop; import com.dy.common.webUtil.BaseResponse; import com.dy.common.webUtil.BaseResponseUtils; import com.dy.common.webUtil.ResultCodeMsg; import com.dy.pipIrrGlobal.pojoSe.SeVcRefund; import com.dy.pipIrrGlobal.pojoSe.SeVcRefundItem; import com.dy.pipIrrGlobal.pojoSe.SeVirtualCard; import com.dy.pipIrrSell.result.SellResultCode; import com.dy.pipIrrSell.util.PayHelper; import com.dy.pipIrrSell.virtualCard.dto.DtoAudit; import com.dy.pipIrrSell.virtualCard.dto.DtoRefund; import com.dy.pipIrrSell.virtualCard.enums.LastOperateENUM; import com.dy.pipIrrSell.virtualCard.enums.RefundItemStateENUM; import com.dy.pipIrrSell.virtualCard.enums.RefundStateENUM; import com.dy.pipIrrSell.wechatpay.dto.Refund; import com.dy.pipIrrSell.wechatpay.dto.ToRefund; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.MediaType; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.BindingResult; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.crypto.NoSuchPaddingException; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; import java.util.Date; import java.util.List; import java.util.Objects; /** * @author ZhuBaoMin * @date 2024-03-06 8:40 * @LastEditTime 2024-03-06 8:40 * @Description */ @Slf4j @Tag(name = "虚拟卡管理", description = "虚拟卡管理") @RestController @RequestMapping(path="virtual_card") @RequiredArgsConstructor @Validated public class VirtualCardCtrl { private final VirtualCardSv virtualCardSv; private final PayHelper payHelper; /** * 虚拟卡账号注册 * @param clientId * @return */ @Operation(summary = "注册虚拟卡", description = "注册虚拟卡") @ApiResponses(value = { @ApiResponse( responseCode = ResultCodeMsg.RsCode.SUCCESS_CODE, description = "操作结果:true:成功,false:失败(BaseResponse.content)", content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = Boolean.class))} ) }) @PostMapping(path = "add_vc") @SsoAop() public BaseResponse addWallet(@RequestParam("clientId") @NotNull(message = "农户编号不能为空") Long clientId){ if(clientId == null || clientId < 0) { return BaseResponseUtils.buildFail(SellResultCode.CLIENT_ID_CANNOT_BE_NULL.getMessage()); } SeVirtualCard seVirtualCard = new SeVirtualCard(); seVirtualCard.setClientId(clientId); seVirtualCard.setMoney(0d); seVirtualCard.setLastOperate(LastOperateENUM.OPEN_ACCOUNT.getCode()); seVirtualCard.setLastOperateTime(new Date()); seVirtualCard.setCreateTime(new Date()); Long rec = virtualCardSv.insertVirtualCard(seVirtualCard); if(rec == null) { return BaseResponseUtils.buildFail(SellResultCode.WALLET_OPEN_ACCOUNT_FAIL.getMessage()); } return BaseResponseUtils.buildSuccess(true) ; } /** * 用户申请退款 * @param po * @param bindingResult * @return */ @Operation(summary = "虚拟卡申请退款", description = "虚拟卡申请退款") @ApiResponses(value = { @ApiResponse( responseCode = ResultCodeMsg.RsCode.SUCCESS_CODE, description = "操作结果:true:成功,false:失败(BaseResponse.content)", content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = Boolean.class))} ) }) @PostMapping(path = "add_refund", consumes = MediaType.APPLICATION_JSON_VALUE) @Transactional(rollbackFor = Exception.class) @SsoAop() public BaseResponse addRefund(@RequestBody @Valid DtoRefund po, BindingResult bindingResult){ if(bindingResult != null && bindingResult.hasErrors()){ return BaseResponseUtils.buildFail(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage()); } Long virtualId = po.getVirtualId(); Integer refundAmount = po.getRefundAmount(); // 根据虚拟卡ID获取虚拟卡对象 SeVirtualCard seVirtualCard = virtualCardSv.selectVirtuCardById(virtualId); if(seVirtualCard == null) { return BaseResponseUtils.buildFail(SellResultCode.VIRTUAL_CARD_NOT_EXIST.getMessage()); } Long clientId = seVirtualCard.getClientId(); Double money = seVirtualCard.getMoney(); // 验证退款金额是否大于余额 if(refundAmount > money) { return BaseResponseUtils.buildFail(SellResultCode.REFUND_AMOUNT_CANNOT_GREATER_THAN_MONEY.getMessage()); } // 计算消费后余额 Double afterRefund = money - refundAmount; SeVcRefund seVcRefund = new SeVcRefund(); seVcRefund.setVcId(virtualId); seVcRefund.setClientId(clientId); seVcRefund.setMoney(money); seVcRefund.setRefundAmount(refundAmount); seVcRefund.setAfterRefund(afterRefund); seVcRefund.setApplicationTime(new Date()); seVcRefund.setRefundStatus(RefundStateENUM.TO_AUDIT.getCode()); Long rec = virtualCardSv.addRefund(seVcRefund); if(rec == 0) { return BaseResponseUtils.buildFail(SellResultCode.APPLICATION_REFUND_FAIL.getMessage()); } return BaseResponseUtils.buildSuccess(true) ; } /** * 审核退款申请 * @param po * @param bindingResult * @return */ @Operation(summary = "审核退款申请", description = "审核退款申请") @ApiResponses(value = { @ApiResponse( responseCode = ResultCodeMsg.RsCode.SUCCESS_CODE, description = "操作结果:true:成功,false:失败(BaseResponse.content)", content = {@Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = Boolean.class))} ) }) @PostMapping(path = "audit_refund", consumes = MediaType.APPLICATION_JSON_VALUE) @Transactional(rollbackFor = Exception.class) @SsoAop() public BaseResponse auditRefund(@RequestBody @Valid DtoAudit po, BindingResult bindingResult) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, IOException, SignatureException, InvalidKeyException { if(bindingResult != null && bindingResult.hasErrors()){ return BaseResponseUtils.buildFail(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage()); } // 根据退款ID获取退款对象,并更新审核人、审核时间、审核备注、退款状态字段 SeVcRefund seVcRefund = virtualCardSv.selectRefundByRefundId(po.getRefundId()); Long virtualId = seVcRefund.getVcId(); Integer refundAmount = seVcRefund.getRefundAmount(); seVcRefund.setAuditor(po.getAuditor()); seVcRefund.setAuditTime(new Date()); seVcRefund.setRemarks(po.getRemarks()); seVcRefund.setRefundStatus(RefundStateENUM.TO_REFUND.getCode()); Integer rec = virtualCardSv.updateRefund(seVcRefund); if(rec == 0) { return BaseResponseUtils.buildFail(SellResultCode.AUDIT_REFUND_FAIL.getMessage()); } // 完成审核后获取待退款订单列表 List list_ToRefund = payHelper.getToRefunds(virtualId, refundAmount); if(list_ToRefund == null || list_ToRefund.size() <=0) return BaseResponseUtils.buildFail(SellResultCode.NOT_SUFFICIENT_FUNDS.getMessage()); //遍历待退款列表 JSONArray array_ToRefund = (JSONArray) JSON.toJSON(list_ToRefund); for(int i = 0; i < array_ToRefund.size(); i++) { JSONObject job_ToRefund = array_ToRefund.getJSONObject(i); String orderNumber_ToRefund = job_ToRefund.getString("orderNumber"); Integer refundAmount_ToRefund = job_ToRefund.getInteger("refundAmount"); // 生成退款分项记录 SeVcRefundItem seVcRefundItem = new SeVcRefundItem(); seVcRefundItem.setRefundId(po.getRefundId()); seVcRefundItem.setOrderNumber(orderNumber_ToRefund); String refundNumber = virtualCardSv.generateRefundNumber(orderNumber_ToRefund); seVcRefundItem.setRefundNumber(refundNumber); seVcRefundItem.setRefundAmount(refundAmount_ToRefund); seVcRefundItem.setCreateTime(new Date()); seVcRefundItem.setRefundStatus(RefundItemStateENUM.NO_REFUND.getCode()); Long refundItemId = virtualCardSv.addRefundItem(seVcRefundItem); // 调用微信退款申请接口 Refund refund = new Refund(); refund.setTradeNo(orderNumber_ToRefund); refund.setRefundNo(refundNumber); refund.setRefund(refundAmount_ToRefund); BaseResponse rep = payHelper.refunds(refund); } return BaseResponseUtils.buildSuccess(true) ; } }