3 files added
13 files modified
| | |
| | | } |
| | | |
| | | /** |
| | | * 订单列表-确认收款 |
| | | * |
| | | * @param id |
| | | * @return |
| | | */ |
| | | @GetMapping("insurePay/{id}") |
| | | @ControllerEndpoint(operation = "订单列表-确认收款", exceptionMessage = "操作失败") |
| | | public FebsResponse insurePay(@NotNull(message = "{required}") @PathVariable Long id) { |
| | | return adminMallOrderService.insurePay(id); |
| | | } |
| | | |
| | | /** |
| | | * 订单列表-取消发货 |
| | | * |
| | | * @param id |
| | |
| | | return new FebsResponse().success().message("保存成功"); |
| | | } |
| | | |
| | | @PostMapping(value = "/payLink") |
| | | @ControllerEndpoint(operation = "保存付款链接配置") |
| | | public FebsResponse payLink(PayLinkDto dto) { |
| | | if (StrUtil.isBlank(dto.getXtLink())) { |
| | | return new FebsResponse().fail().message("付款链接不能为空"); |
| | | } |
| | | if (StrUtil.isBlank(dto.getXtLinkImg())) { |
| | | return new FebsResponse().fail().message("付款链接图片不能为空"); |
| | | } |
| | | commonService.addDataDic("PAY_LINK", "XT_LINK", dto.getXtLink(), "付款链接", false); |
| | | commonService.addDataDic("PAY_LINK", "XT_LINK_IMG", dto.getXtLinkImg(), "付款链接图片", false); |
| | | return new FebsResponse().success().message("保存成功"); |
| | | } |
| | | |
| | | @GetMapping(value = "/moneyChangeList") |
| | | public FebsResponse moneyChangeList() { |
| | | List<DataDictionaryCustom> list = dataDictionaryCustomMapper.selectDicByType("MONEY_CHANGE"); |
| | |
| | | public String moneyChange() { |
| | | return FebsUtil.view("modules/system/moneyChange"); |
| | | } |
| | | |
| | | @GetMapping("payLink") |
| | | @RequiresPermissions("payLink:update") |
| | | public String payLink(Model model) { |
| | | PayLinkDto dto = new PayLinkDto(); |
| | | DataDictionaryCustom xtLink = dataDictionaryCustomMapper.selectDicDataByTypeAndCode("PAY_LINK", "XT_LINK"); |
| | | DataDictionaryCustom xtLinkImg = dataDictionaryCustomMapper.selectDicDataByTypeAndCode("PAY_LINK", "XT_LINK_IMG"); |
| | | if (xtLink != null) dto.setXtLink(xtLink.getValue()); |
| | | if (xtLinkImg != null) dto.setXtLinkImg(xtLinkImg.getValue()); |
| | | model.addAttribute("payLink", dto); |
| | | return FebsUtil.view("modules/system/payLink"); |
| | | } |
| | | } |
| | |
| | | return new FebsResponse().success().data(iXcxPayService.getTemplateId()); |
| | | } |
| | | |
| | | // ==================== XT 支付 ==================== |
| | | |
| | | /** |
| | | * 创建订单并通过 XT 支付 |
| | | * <p> |
| | | * 流程:创建订单 → 通过 XT 支付链接 |
| | | * <p> |
| | | */ |
| | | @ApiOperation(value = "创建订单-XT支付", notes = "创建订单并返回XT支付") |
| | | @PostMapping(value = "/createOrderByXtPay") |
| | | @Limit(key = "createOrderByXtPay", period = 1, count = 1, name = "XT下单", prefix = "limit", limitType = LimitType.IP) |
| | | public FebsResponse createOrderByXtPay(@RequestBody @Validated XtPayCreateOrderDto lwPayDto) { |
| | | // 1. 创建订单 |
| | | AddOrderDto addOrderDto = lwPayDto.getOrder(); |
| | | Long orderId = mallOrderInfoService.createOrder(addOrderDto); |
| | | |
| | | // 2. 获取订单详情 |
| | | MallOrderInfo order = mallOrderInfoService.getById(orderId); |
| | | if (order != null |
| | | && OrderStatusEnum.WAIT_PAY.getValue() == order.getStatus() |
| | | ){ |
| | | return mallOrderInfoService.createOrderByXtPay(); |
| | | } |
| | | return new FebsResponse().fail().message("Payment channel exception"); |
| | | } |
| | | |
| | | @ApiOperation(value = "XT支付", notes = "XT支付") |
| | | @PostMapping(value = "/payOrderByXtPay", produces = "application/json") |
| | | public FebsResponse payOrderByXtPay(@RequestBody @Validated ApiOrderPayDto payDto) { |
| | | |
| | | Long orderId = payDto.getOrderId(); |
| | | Integer payType = payDto.getPayType(); |
| | | // 2. 获取订单详情 |
| | | MallOrderInfo order = mallOrderInfoService.getById(orderId); |
| | | if (order != null |
| | | && OrderConstants.PAY_TYPE_XT == payType |
| | | && OrderStatusEnum.WAIT_PAY.getValue() == order.getStatus() |
| | | ){ |
| | | return mallOrderInfoService.createOrderByXtPay(); |
| | | } |
| | | return new FebsResponse().fail().message("Payment channel exception"); |
| | | } |
| | | |
| | | // ==================== LWPAY 支付 ==================== |
| | | |
| | | /** |
| | |
| | | result.put("orderNo", order.getOrderNo()); |
| | | result.put("amount", order.getAmount()); |
| | | result.put("payUrl", payUrl); |
| | | return new FebsResponse().success().data(result).message("下单成功"); |
| | | return new FebsResponse().success().data(result).message("success"); |
| | | } catch (Exception e) { |
| | | log.error("LWPAY 代收下单失败: orderId={}", orderId, e); |
| | | return new FebsResponse().fail().message("Payment channel exception: " + e.getMessage()); |
| | |
| | | public static final String ORDER_STATE = "order_state"; |
| | | |
| | | /** |
| | | * 支付方式 1-微信 2-支付宝 3-USDT |
| | | * 支付方式 1-微信 2-支付宝 3-USDT 4-LWPAY支付 5-XT支付 |
| | | */ |
| | | public static final Integer PAY_TYPE_WECHAT = 1; |
| | | public static final Integer PAY_TYPE_ALIPAY = 2; |
| | | public static final Integer PAY_TYPE_USDT = 3; |
| | | public static final Integer PAY_TYPE_SYSTEM = 4; |
| | | public static final Integer PAY_TYPE_XT = 5; |
| | | public static final String ORDER_PAY_TYPE = "order_pay_type"; |
| | | |
| | | public static final String TRC20_SYSTEM_ADDRESS = "pay.trc20.address"; |
| | |
| | | private Long orderId; |
| | | |
| | | @NotNull(message = "支付方式不能为空") |
| | | @ApiModelProperty(value = "支付方式 1-微信 2-支付宝 3-USDT 4-LwPAY", example = "you_ke_*****") |
| | | @ApiModelProperty(value = "支付方式 1-微信 2-支付宝 3-USDT 4-LwPAY 5-XTPAY", example = "you_ke_*****") |
| | | private Integer payType; |
| | | } |
| New file |
| | |
| | | package cc.mrbird.febs.mall.dto; |
| | | |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * 付款链接配置 DTO |
| | | * 对应 data_dictionary_custom 表 type='PAY_LINK' |
| | | * |
| | | * @author auto-generated |
| | | */ |
| | | @Data |
| | | public class PayLinkDto { |
| | | /** 付款链接 */ |
| | | private String xtLink; |
| | | /** 付款链接图片 */ |
| | | private String xtLinkImg; |
| | | } |
| | |
| | | @ApiModel(value = "RegisterDto", description = "用户注册参数接收类") |
| | | public class RegisterDto { |
| | | |
| | | @NotBlank(message = "The First Name cannot be empty") |
| | | @ApiModelProperty(value = "First Name", example = "15773001234") |
| | | private String firstName; |
| | | |
| | | @NotBlank(message = "The LastName cannot be empty") |
| | | @ApiModelProperty(value = "LastName", example = "15773001234") |
| | | private String lastName; |
| | | // @NotBlank(message = "The First Name cannot be empty") |
| | | // @ApiModelProperty(value = "First Name", example = "15773001234") |
| | | // private String firstName; |
| | | // |
| | | // @NotBlank(message = "The LastName cannot be empty") |
| | | // @ApiModelProperty(value = "LastName", example = "15773001234") |
| | | // private String lastName; |
| | | |
| | | @NotBlank(message = "The Email Address cannot be empty") |
| | | @ApiModelProperty(value = "Email Address", example = "15773001234") |
| | | private String account; |
| | | |
| | | @NotBlank(message = "The Phone Number cannot be empty") |
| | | @ApiModelProperty(value = "Phone Number", example = "15773001234") |
| | | private String phoneNumber; |
| | | // |
| | | // @NotBlank(message = "The Phone Number cannot be empty") |
| | | // @ApiModelProperty(value = "Phone Number", example = "15773001234") |
| | | // private String phoneNumber; |
| | | |
| | | @NotBlank(message = "The password cannot be empty") |
| | | @ApiModelProperty(value = "Password", example = "123456") |
| New file |
| | |
| | | package cc.mrbird.febs.mall.dto; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import javax.validation.Valid; |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | @Data |
| | | @ApiModel(value = "XtPayCreateOrderDto", description = "支付下单参数") |
| | | public class XtPayCreateOrderDto { |
| | | |
| | | @Valid |
| | | @NotNull(message = "订单信息不能为空") |
| | | @ApiModelProperty(value = "订单信息", required = true) |
| | | private AddOrderDto order; |
| | | } |
| | |
| | | FebsResponse deliverPdfGoods(Long id); |
| | | |
| | | FebsResponse cancelDeliver(Long id); |
| | | |
| | | FebsResponse insurePay(Long id); |
| | | } |
| | |
| | | FebsResponse createOrderVerify(ApiCreateOrderVerifyDto apiCreateOrderVerifyDto); |
| | | |
| | | FebsResponse chooseCoupon(ApiChooseCouponDto chooseCouponDto); |
| | | |
| | | FebsResponse createOrderByXtPay(); |
| | | } |
| | |
| | | import cc.mrbird.febs.common.enumerates.*; |
| | | import cc.mrbird.febs.common.exception.FebsException; |
| | | import cc.mrbird.febs.common.utils.ValidateEntityUtils; |
| | | import cc.mrbird.febs.mall.controller.dependentStation.constant.OrderConstants; |
| | | import cc.mrbird.febs.mall.dto.*; |
| | | import cc.mrbird.febs.mall.entity.*; |
| | | import cc.mrbird.febs.mall.mapper.*; |
| | |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import cn.hutool.core.util.StrUtil; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.core.toolkit.Wrappers; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import com.best.javaSdk.ClientParamEnum; |
| | |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.ArrayList; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | |
| | | @Slf4j |
| | |
| | | } |
| | | |
| | | @Override |
| | | public FebsResponse insurePay(Long id) { |
| | | // 1. 查询订单 |
| | | MallOrderInfo order = mallOrderInfoMapper.selectById(id); |
| | | if (order == null) { |
| | | return new FebsResponse().fail().message("订单不存在,刷新后重试"); |
| | | } |
| | | |
| | | // 2. 幂等检查(避免重复回调) |
| | | if (OrderStatusEnum.WAIT_PAY.getValue() != order.getStatus()) { |
| | | return new FebsResponse().fail().message("订单不是代付款状态"); |
| | | } |
| | | |
| | | // 3. 更新订单状态为待发货 |
| | | mallOrderInfoMapper.update( |
| | | null, |
| | | Wrappers.lambdaUpdate(MallOrderInfo.class) |
| | | .set(MallOrderInfo::getStatus, OrderStatusEnum.WAIT_SHIPPING.getValue()) |
| | | .set(MallOrderInfo::getPayTime, new Date()) |
| | | .set(MallOrderInfo::getPayMethod, "XT支付") |
| | | .set(MallOrderInfo::getPayResult, "1") |
| | | .eq(MallOrderInfo::getId, order.getId()) |
| | | ); |
| | | |
| | | return new FebsResponse().success(); |
| | | } |
| | | |
| | | @Override |
| | | public void deliverGoodsByOrderNo(DeliverGoodsDto deliverGoodsDto) { |
| | | MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectByOrderNo(deliverGoodsDto.getOrderNo()); |
| | | if (mallOrderInfo == null) { |
| | |
| | | throw new FebsException("The two passwords are inconsistent"); |
| | | } |
| | | mallMember = new MallMember(); |
| | | mallMember.setName(registerDto.getLastName() + registerDto.getFirstName()); |
| | | mallMember.setPhone(registerDto.getPhoneNumber()); |
| | | mallMember.setName(UUID.randomUUID().toString()); |
| | | mallMember.setEmail(registerDto.getAccount()); |
| | | mallMember.setPassword(SecureUtil.md5(password)); |
| | | mallMember.setAccountStatus(MallMember.ACCOUNT_STATUS_ENABLE); |
| | |
| | | |
| | | MallAddressInfo mallAddressInfo = new MallAddressInfo(); |
| | | mallAddressInfo.setMemberId(mallMember.getId()); |
| | | mallAddressInfo.setName(registerDto.getLastName()); |
| | | mallAddressInfo.setFristName(registerDto.getFirstName()); |
| | | mallAddressInfo.setPhone(registerDto.getPhoneNumber()); |
| | | mallAddressInfoMapper.insert(mallAddressInfo); |
| | | |
| | | |
| | |
| | | return new FebsResponse().success().data(objects); |
| | | } |
| | | |
| | | @Override |
| | | public FebsResponse createOrderByXtPay() { |
| | | |
| | | DataDictionaryCustom dataDictionaryCustom = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( |
| | | "PAY_LINK", "XT_LINK" |
| | | ); |
| | | |
| | | DataDictionaryCustom dataDictionaryCustomImg = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( |
| | | "PAY_LINK", "XT_LINK_IMG" |
| | | ); |
| | | if (ObjectUtil.isEmpty(dataDictionaryCustom)){ |
| | | return new FebsResponse().fail().message("Payment channel exception"); |
| | | } |
| | | if (ObjectUtil.isEmpty(dataDictionaryCustomImg)){ |
| | | return new FebsResponse().fail().message("Payment channel exception"); |
| | | } |
| | | if (StrUtil.isEmpty(dataDictionaryCustom.getValue())){ |
| | | return new FebsResponse().fail().message("Payment channel exception"); |
| | | } |
| | | if (StrUtil.isEmpty(dataDictionaryCustomImg.getValue())){ |
| | | return new FebsResponse().fail().message("Payment channel exception"); |
| | | } |
| | | |
| | | Map<String, Object> result = new HashMap<>(); |
| | | result.put("link", dataDictionaryCustom.getValue()); |
| | | result.put("linkImg", dataDictionaryCustomImg.getValue()); |
| | | return new FebsResponse().success().data(result); |
| | | } |
| | | |
| | | } |
| | |
| | | cancelOrder(data.id); |
| | | }); |
| | | } |
| | | if (layEvent === 'insurePay') { |
| | | febs.modal.confirm('收款', '确认收款?', function () { |
| | | insurePay(data.id); |
| | | }); |
| | | } |
| | | if (layEvent === 'deliverPdfGoods') { |
| | | febs.modal.confirm('一键发货', '确认一键发货?', function (index) { |
| | | layer.close(index); |
| | |
| | | |
| | | function cancelOrder(id) { |
| | | febs.get(ctx + 'admin/order/cancelOrder/' + id, null, function () { |
| | | febs.alert.success('操作成功'); |
| | | $query.click(); |
| | | }); |
| | | } |
| | | |
| | | function insurePay(id) { |
| | | febs.get(ctx + 'admin/order/insurePay/' + id, null, function () { |
| | | febs.alert.success('操作成功'); |
| | | $query.click(); |
| | | }); |
| | |
| | | // {field: 'wxOrderNo', title: '支付订单号', minWidth: 120,align:'left'}, |
| | | {title: '操作', |
| | | templet: function (d) { |
| | | if(d.status === 2){ |
| | | if(d.status === 1){ |
| | | return '<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="insurePay" shiro:hasPermission="user:update">确认收款</button>' |
| | | }else if(d.status === 2){ |
| | | return '<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="deliverGoods" shiro:hasPermission="user:update">发货</button>' |
| | | +'<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="seeOrder" shiro:hasPermission="user:update">详情</button>' |
| | | // +'' |
| New file |
| | |
| | | <div class="layui-fluid layui-anim febs-anim" id="pay-link" lay-title="付款链接设置"> |
| | | <div class="layui-row layui-col-space8 febs-container"> |
| | | <form class="layui-form" action="" lay-filter="pay-link-form"> |
| | | <div class="layui-card"> |
| | | <div class="layui-card-header">付款链接配置</div> |
| | | <div class="layui-card-body"> |
| | | <div class="layui-form-item"> |
| | | <label class="layui-form-label required">付款链接:</label> |
| | | <div class="layui-input-block"> |
| | | <input type="text" name="xtLink" data-th-id="${payLink.xtLink}" |
| | | lay-verify="required" autocomplete="off" class="layui-input" placeholder="请输入付款链接地址"> |
| | | </div> |
| | | <div class="layui-word-aux" style="margin-left: 150px;">用户点击付款时跳转的链接地址,必须以 http(s):// 开头</div> |
| | | </div> |
| | | <div class="layui-form-item"> |
| | | <label class="layui-form-label required">链接图片:</label> |
| | | <div class="layui-upload"> |
| | | <button type="button" class="layui-btn layui-btn-normal" id="pay-link-img-upload">上传图片</button> |
| | | <div class="layui-input-block"> |
| | | <div class="layui-upload-list"> |
| | | <img class="layui-upload-img" id="xtLinkImgUrls" style="width: 200px;"> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="layui-form-item"> |
| | | <label class="layui-form-label required">图片链接:</label> |
| | | <div class="layui-input-block"> |
| | | <input type="text" id="xtLinkImg" name="xtLinkImg" |
| | | autocomplete="off" class="layui-input" readonly> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="layui-card-footer"> |
| | | <button class="layui-btn layui-btn-normal" lay-submit="" lay-filter="pay-link-form-submit" id="submit">保存</button> |
| | | </div> |
| | | </div> |
| | | </form> |
| | | </div> |
| | | </div> |
| | | <style> |
| | | .layui-form-label { |
| | | width: 120px; |
| | | } |
| | | |
| | | .layui-form-item .layui-input-block { |
| | | margin-left: 150px; |
| | | } |
| | | |
| | | .layui-table-form .layui-form-item { |
| | | margin-bottom: 20px !important; |
| | | } |
| | | |
| | | .layui-upload-list { |
| | | margin: 0 !important; |
| | | } |
| | | </style> |
| | | <script data-th-inline="javascript" type="text/javascript"> |
| | | layui.use(['dropdown', 'jquery', 'validate', 'febs', 'form', 'upload'], function () { |
| | | var $ = layui.jquery, |
| | | febs = layui.febs, |
| | | form = layui.form, |
| | | upload = layui.upload, |
| | | payLink = [[${payLink}]], |
| | | validate = layui.validate, |
| | | $view = $('#pay-link'); |
| | | |
| | | form.verify(validate); |
| | | |
| | | if (payLink) { |
| | | form.val("pay-link-form", { |
| | | "xtLink": payLink.xtLink, |
| | | "xtLinkImg": payLink.xtLinkImg |
| | | }); |
| | | if (payLink.xtLinkImg) { |
| | | $('#xtLinkImgUrls').attr('src', payLink.xtLinkImg); |
| | | } |
| | | } |
| | | |
| | | form.render(); |
| | | |
| | | // 图片上传 |
| | | upload.render({ |
| | | elem: '#pay-link-img-upload' |
| | | ,url: ctx + 'admin/goods/uploadFileBase64' |
| | | ,before: function(obj){ |
| | | obj.preview(function(index, file, result){ |
| | | $('#xtLinkImgUrls').attr('src', result); |
| | | }); |
| | | } |
| | | ,done: function(res){ |
| | | febs.alert.success(res.data.src); |
| | | $("#xtLinkImg").val(res.data.src); |
| | | } |
| | | }); |
| | | |
| | | form.on('submit(pay-link-form-submit)', function (data) { |
| | | febs.post(ctx + 'admin/system/payLink', data.field, function (res) { |
| | | febs.alert.success('保存成功'); |
| | | }); |
| | | return false; |
| | | }); |
| | | }); |
| | | </script> |