| @@ -3,7 +3,7 @@ ADD COLUMN `cash_out_support` INT(1) COMMENT '是否支持商户提现(不开启 | |||||
| UPDATE wx_mall SET cash_out_support = 0 ; | UPDATE wx_mall SET cash_out_support = 0 ; | ||||
| ALTER TABLE wx_merchant ADD COLUMN `cash_out_number` INT(11) COMMENT '商户待提现金额(分)' ; | |||||
| ALTER TABLE wx_merchant ADD COLUMN `cash_out_number` INT(11) DEFAULT 0 COMMENT '商户待提现金额(分)' ; | |||||
| ###页面添加工作流,提现审批,22, 初始化里面也加上 | ###页面添加工作流,提现审批,22, 初始化里面也加上 | ||||
| @@ -29,6 +29,12 @@ CREATE TABLE `wx_cash_out` ( | |||||
| PRIMARY KEY (`id`) | PRIMARY KEY (`id`) | ||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; | ||||
| ALTER TABLE `wx_mall` | |||||
| ADD COLUMN `cash_out_limit` INT(3) COMMENT '商户提现每日次数限制' AFTER `cash_out_support`; | |||||
| UPDATE wx_mall SET cash_out_limit = 10 ; | |||||
| ALTER TABLE wx_merchant ADD COLUMN `cash_out_count` INT(3) DEFAULT 0 COMMENT '当日提现次数' ; | |||||
| @@ -63,21 +63,6 @@ public class WxCashOutController extends BaseController { | |||||
| @PostMapping("recashout") | @PostMapping("recashout") | ||||
| public ResultData recashout(@RequestBody WxCashOut wxCashOut) { | public ResultData recashout(@RequestBody WxCashOut wxCashOut) { | ||||
| WxMerchantBUser buser = getLoginBUser(); | WxMerchantBUser buser = getLoginBUser(); | ||||
| //当前管理员的账户必须在c端授权了 | |||||
| WxCUser cuUser = new WxCUser(); | |||||
| cuUser.updateTenantInfo(buser); | |||||
| cuUser.setPhone(buser.getPhone()); | |||||
| try { | |||||
| WxCUser mUser = wxCUserService.getByObject(cuUser); | |||||
| if (mUser == null) { | |||||
| return new ResultData(Result.ERROR,"请用绑定["+buser.getPhone()+"]的微信在C端完成授权手机号操作。"); | |||||
| } | |||||
| wxCashOut.setReciveOpenId(mUser.getOpenId()); | |||||
| wxCashOut.setReciveNickName(mUser.getNickName()); | |||||
| }catch(Exception e) { | |||||
| return new ResultData(Result.ERROR,buser.getPhone()+"匹配C端用户失败,该情况可能是存在多个微信对应统一手机号,请联系管理员处理, 。"); | |||||
| } | |||||
| return wxCashOutService.reCashout(buser, wxCashOut,EnumPayWay.PAY_WAY_WECHAT); | return wxCashOutService.reCashout(buser, wxCashOut,EnumPayWay.PAY_WAY_WECHAT); | ||||
| } | } | ||||
| @@ -88,7 +88,8 @@ public class WxMall extends TenantEntity { | |||||
| private Integer liveSupport; | private Integer liveSupport; | ||||
| @io.swagger.annotations.ApiModelProperty(value="是否支持商户提现(不开启分账才有效) 0-不支持 1-支持",name="cashOutSupport") | @io.swagger.annotations.ApiModelProperty(value="是否支持商户提现(不开启分账才有效) 0-不支持 1-支持",name="cashOutSupport") | ||||
| private Integer cashOutSupport; | private Integer cashOutSupport; | ||||
| @io.swagger.annotations.ApiModelProperty(value="商户提现每日次数限制",name="cashOutLimit") | |||||
| private Integer cashOutLimit; | |||||
| @TableField(exist = false) | @TableField(exist = false) | ||||
| protected List<WxMallBuilding> buildings; | protected List<WxMallBuilding> buildings; | ||||
| @@ -265,6 +265,9 @@ public class WxMerchant extends TenantEntity { | |||||
| @io.swagger.annotations.ApiModelProperty(value = "商户待提现金额(分)", name = "cashOutNumber") | @io.swagger.annotations.ApiModelProperty(value = "商户待提现金额(分)", name = "cashOutNumber") | ||||
| private Integer cashOutNumber; | private Integer cashOutNumber; | ||||
| @io.swagger.annotations.ApiModelProperty(value = "当日提现次数", name = "cashOutCount") | |||||
| private Integer cashOutCount; | |||||
| @TableField(exist = false) | @TableField(exist = false) | ||||
| @SortColumn(column = "couponSale") | @SortColumn(column = "couponSale") | ||||
| @@ -45,4 +45,6 @@ public interface WxMerchantMapper extends CommonMapper<WxMerchant, Long> { | |||||
| void increaseCash(WxMerchant record); | void increaseCash(WxMerchant record); | ||||
| void reduceCash(WxMerchant record); | void reduceCash(WxMerchant record); | ||||
| void increaseCashCount(WxMerchant record); | |||||
| } | } | ||||
| @@ -84,6 +84,13 @@ public class WxCashOutServiceImpl implements WxCashOutService { | |||||
| wxCashOutMapper.insert(record); | wxCashOutMapper.insert(record); | ||||
| } | } | ||||
| private boolean hasCashCount(WxMall mall,WxMerchant merchant) { | |||||
| if (mall.getCashOutLimit().intValue()<=merchant.getCashOutCount().intValue()) { | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| @Override | @Override | ||||
| @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) | @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) | ||||
| public ResultData applyCashout(WxMerchantBUser buser, WxCashOut record,EnumPayWay payWay) { | public ResultData applyCashout(WxMerchantBUser buser, WxCashOut record,EnumPayWay payWay) { | ||||
| @@ -96,6 +103,11 @@ public class WxCashOutServiceImpl implements WxCashOutService { | |||||
| if (!(buser.getPhone().equals(merchant.getLinkPhone()))) { | if (!(buser.getPhone().equals(merchant.getLinkPhone()))) { | ||||
| return new ResultData(Result.ERROR,"当前账号非商户管理员,不能进行此操作。"); | return new ResultData(Result.ERROR,"当前账号非商户管理员,不能进行此操作。"); | ||||
| } | } | ||||
| if(!hasCashCount(mall,merchant)) { | |||||
| return new ResultData(Result.ERROR,"当日提现次数已达限额。"); | |||||
| } | |||||
| if (record.getTotalFee().intValue()<=0) { | if (record.getTotalFee().intValue()<=0) { | ||||
| return new ResultData(Result.ERROR,"提现金额非法。"); | return new ResultData(Result.ERROR,"提现金额非法。"); | ||||
| } | } | ||||
| @@ -114,6 +126,7 @@ public class WxCashOutServiceImpl implements WxCashOutService { | |||||
| if (cashsetlock) { | if (cashsetlock) { | ||||
| try { | try { | ||||
| merchant.setCashOutNumber(record.getTotalFee()); | merchant.setCashOutNumber(record.getTotalFee()); | ||||
| //更新金额,并减小次数 | |||||
| wxMerchantMapper.reduceCash(merchant); | wxMerchantMapper.reduceCash(merchant); | ||||
| redisLock.unlock("merchantLockReduceCashSet_"+merchant.getId(), timeStr); | redisLock.unlock("merchantLockReduceCashSet_"+merchant.getId(), timeStr); | ||||
| }catch(Exception e) { | }catch(Exception e) { | ||||
| @@ -166,7 +179,6 @@ public class WxCashOutServiceImpl implements WxCashOutService { | |||||
| sendCashOutMsg(merchant, cashout.getId(),payWay); | sendCashOutMsg(merchant, cashout.getId(),payWay); | ||||
| } | } | ||||
| return new ResultData("提现提交成功。"); | return new ResultData("提现提交成功。"); | ||||
| } | } | ||||
| @@ -199,7 +211,7 @@ public class WxCashOutServiceImpl implements WxCashOutService { | |||||
| WxMerchant merchant = wxMerchantMapper.selectById(record.getMerchantId()); | WxMerchant merchant = wxMerchantMapper.selectById(record.getMerchantId()); | ||||
| //增加账户金额 | //增加账户金额 | ||||
| //此处需要加锁,防止并发设置 | //此处需要加锁,防止并发设置 | ||||
| long time = System.currentTimeMillis() + RedisLock.TIMEOUT; | |||||
| long time = System.currentTimeMillis() + RedisLock.LONG_TIMEOUT; | |||||
| String timeStr = String.valueOf(time); | String timeStr = String.valueOf(time); | ||||
| boolean cashsetlock = redisLock.lock("merchantLockRejectCashSet_"+merchant.getId(), timeStr); | boolean cashsetlock = redisLock.lock("merchantLockRejectCashSet_"+merchant.getId(), timeStr); | ||||
| if (cashsetlock) { | if (cashsetlock) { | ||||
| @@ -243,44 +255,67 @@ public class WxCashOutServiceImpl implements WxCashOutService { | |||||
| @Override | @Override | ||||
| public ResultData reCashout(WxMerchantBUser buser, WxCashOut record, EnumPayWay payWay) { | public ResultData reCashout(WxMerchantBUser buser, WxCashOut record, EnumPayWay payWay) { | ||||
| WxCashOut cashout = this.getById(record.getId(), buser.getTenantId()); | |||||
| if (null == cashout ) { | |||||
| return new ResultData(Result.ERROR,"该提现记录不存在"); | |||||
| } | |||||
| if( EnumCashOutStatus.FAIL.getCode().intValue() != record.getStatus().intValue()) { | |||||
| return new ResultData(Result.ERROR,"提现失败状态才能重新提现。"); | |||||
| } | |||||
| //只有商户管理员才能进行此操作 | |||||
| WxMerchant merchant = wxMerchantMapper.selectById(buser.getMerchantId()); | |||||
| if (!(buser.getPhone().equals(merchant.getLinkPhone()))) { | |||||
| return new ResultData(Result.ERROR,"当前账号非商户管理员,不能进行此操作。"); | |||||
| } | |||||
| WxAppinfo appInfo = wxAppinfoService.getCAppInfo(buser, payWay); | |||||
| if (null == appInfo) { | |||||
| return new ResultData(Result.ERROR,"当前账号非商户管理员,不能进行此操作。"); | |||||
| } | |||||
| WxPayAccount payAccount = wxPayAccountService.getByTenantId(buser.getTenantId()); | |||||
| if (null == payAccount) { | |||||
| return new ResultData(Result.ERROR,"当前账号非商户管理员,不能进行此操作。"); | |||||
| } | |||||
| //查询是否已经真实的转过了 | |||||
| CashOutAdapterResult qresult = payServiceFactory.getCashOutAdapterService(payWay.getCode()).queryCashOut(appInfo, payAccount, cashout); | |||||
| if (qresult.isSuccess()) { | |||||
| cashout.setStatus(EnumCashOutStatus.SUCCESS.getCode()); | |||||
| wxCashOutMapper.updateStatus(cashout); | |||||
| }else { | |||||
| CashOutAdapterResult result = payServiceFactory.getCashOutAdapterService(payWay.getCode()).cashOut(appInfo, payAccount, cashout); | |||||
| cashout.setUpdateDate(new Date()); | |||||
| if (result.isSuccess()) { | |||||
| cashout.setStatus(EnumCashOutStatus.SUCCESS.getCode()); | |||||
| }else { | |||||
| cashout.setStatus(EnumCashOutStatus.FAIL.getCode()); | |||||
| cashout.setFailRemark(result.getMsg()); | |||||
| } | |||||
| wxCashOutMapper.updateById(cashout); | |||||
| } | |||||
| //不能重复提交操作 | |||||
| long time = System.currentTimeMillis() + RedisLock.LONG_TIMEOUT; | |||||
| String timeStr = String.valueOf(time); | |||||
| boolean cashsetlock = redisLock.lock("merchantLockReCashSet_"+record.getId(), timeStr); | |||||
| if (cashsetlock) { | |||||
| try { | |||||
| WxCashOut cashout = this.getById(record.getId(), buser.getTenantId()); | |||||
| if (null == cashout ) { | |||||
| return new ResultData(Result.ERROR,"该提现记录不存在"); | |||||
| } | |||||
| if( EnumCashOutStatus.FAIL.getCode().intValue() != record.getStatus().intValue()) { | |||||
| return new ResultData(Result.ERROR,"提现失败状态才能重新提现。"); | |||||
| } | |||||
| //只有商户管理员才能进行此操作 | |||||
| WxMerchant merchant = wxMerchantMapper.selectById(buser.getMerchantId()); | |||||
| if (!(buser.getPhone().equals(merchant.getLinkPhone()))) { | |||||
| return new ResultData(Result.ERROR,"当前账号非商户管理员,不能进行此操作。"); | |||||
| } | |||||
| WxMall mall = wxMallMapper.getByTenantId(buser.getTenantId()); | |||||
| if(!hasCashCount(mall,merchant)) { | |||||
| return new ResultData(Result.ERROR,"当日提现次数已达限额。"); | |||||
| } | |||||
| WxAppinfo appInfo = wxAppinfoService.getCAppInfo(buser, payWay); | |||||
| if (null == appInfo) { | |||||
| return new ResultData(Result.ERROR,"系统错误,appInfo未查询到。"); | |||||
| } | |||||
| WxPayAccount payAccount = wxPayAccountService.getByTenantId(buser.getTenantId()); | |||||
| if (null == payAccount) { | |||||
| return new ResultData(Result.ERROR,"系统错误,payAccount未查询到。"); | |||||
| } | |||||
| //查询是否已经真实的转过了 | |||||
| CashOutAdapterResult qresult = payServiceFactory.getCashOutAdapterService(payWay.getCode()).queryCashOut(appInfo, payAccount, cashout); | |||||
| if (qresult.isSuccess()) { | |||||
| cashout.setStatus(EnumCashOutStatus.SUCCESS.getCode()); | |||||
| wxCashOutMapper.updateStatus(cashout); | |||||
| }else { | |||||
| CashOutAdapterResult result = payServiceFactory.getCashOutAdapterService(payWay.getCode()).cashOut(appInfo, payAccount, cashout); | |||||
| cashout.setUpdateDate(new Date()); | |||||
| if (result.isSuccess()) { | |||||
| cashout.setStatus(EnumCashOutStatus.SUCCESS.getCode()); | |||||
| }else { | |||||
| cashout.setStatus(EnumCashOutStatus.FAIL.getCode()); | |||||
| cashout.setFailRemark(result.getMsg()); | |||||
| } | |||||
| wxCashOutMapper.updateById(cashout); | |||||
| } | |||||
| //更新次数 | |||||
| wxMerchantMapper.increaseCashCount(merchant); | |||||
| redisLock.unlock("merchantLockReCashSet_"+record.getId(), timeStr); | |||||
| }catch(Exception e) { | |||||
| redisLock.unlock("merchantLockReCashSet_"+record.getId(), timeStr); | |||||
| logger.error("update cashout fail.",e); | |||||
| }finally { | |||||
| redisLock.unlock("merchantLockReCashSet_"+record.getId(), timeStr); | |||||
| } | |||||
| } | |||||
| return new ResultData(); | return new ResultData(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -37,6 +37,7 @@ | |||||
| <result column="longitude" jdbcType="DECIMAL" property="longitude"/> | <result column="longitude" jdbcType="DECIMAL" property="longitude"/> | ||||
| <result column="live_support" jdbcType="INTEGER" property="liveSupport"/> | <result column="live_support" jdbcType="INTEGER" property="liveSupport"/> | ||||
| <result column="cash_out_support" jdbcType="INTEGER" property="cashOutSupport"/> | <result column="cash_out_support" jdbcType="INTEGER" property="cashOutSupport"/> | ||||
| <result column="cash_out_limit" jdbcType="INTEGER" property="cashOutLimit"/> | |||||
| </resultMap> | </resultMap> | ||||
| <sql id="allColumns"> | <sql id="allColumns"> | ||||
| @@ -45,7 +46,7 @@ | |||||
| `img_url`,`img_url_h`, `weap_note`, `img_qrcode_weapp`, `img_qrcode_wemp`, | `img_url`,`img_url_h`, `weap_note`, `img_qrcode_weapp`, `img_qrcode_wemp`, | ||||
| `weapp_share_title`,`weapp_share_cover_img`, `pos_qrcode_rule`, | `weapp_share_title`,`weapp_share_cover_img`, `pos_qrcode_rule`, | ||||
| `sale_type`, `valid_start`, `valid_end`,`business_hours`,`introduction`,`img`, | `sale_type`, `valid_start`, `valid_end`,`business_hours`,`introduction`,`img`, | ||||
| `group_support`,`latitude`,`longitude`,`live_support`,`cash_out_support` | |||||
| `group_support`,`latitude`,`longitude`,`live_support`,`cash_out_support`,`cash_out_limit` | |||||
| </sql> | </sql> | ||||
| <sql id="dynamicWhereConditions"> | <sql id="dynamicWhereConditions"> | ||||
| @@ -36,18 +36,19 @@ | |||||
| <result column="rental_end_date" property="rentalEndDate"/> | <result column="rental_end_date" property="rentalEndDate"/> | ||||
| <result column="credit_locked" property="creditLocked"/> | <result column="credit_locked" property="creditLocked"/> | ||||
| <result column="cash_out_number" jdbcType="INTEGER" property="cashOutNumber"/> | <result column="cash_out_number" jdbcType="INTEGER" property="cashOutNumber"/> | ||||
| <result column="cash_out_count" jdbcType="INTEGER" property="cashOutCount"/> | |||||
| </resultMap> | </resultMap> | ||||
| <sql id="allColumns"> | <sql id="allColumns"> | ||||
| `id`,`tenant_id`,`parent_tenant_id`,`img_url`,`name`,`link_phone`,`create_date`,`update_date`,`car_vendor_type`,`car_params`,`status`,`link_person`, | `id`,`tenant_id`,`parent_tenant_id`,`img_url`,`name`,`link_phone`,`create_date`,`update_date`,`car_vendor_type`,`car_params`,`status`,`link_person`, | ||||
| `business_id`,`sub_business_id`,`shop_type`,`brand`,`type`,`is_public`,email,`title`,`cover_picture`,`is_admin`,`bill_setting`,`qr_code`, | `business_id`,`sub_business_id`,`shop_type`,`brand`,`type`,`is_public`,email,`title`,`cover_picture`,`is_admin`,`bill_setting`,`qr_code`, | ||||
| `introduction`,`action_desc`,`is_del`,`talk_user_main`,`talk_user_aux`,link_line_phone,credit_locked,cash_out_number | |||||
| `introduction`,`action_desc`,`is_del`,`talk_user_main`,`talk_user_aux`,link_line_phone,credit_locked,cash_out_number,cash_out_count | |||||
| </sql> | </sql> | ||||
| <sql id="allColumnsVo"> | <sql id="allColumnsVo"> | ||||
| m.`id`,m.`tenant_id`,m.`parent_tenant_id`,m.`img_url`,m.`name`,m.`link_phone`,m.`create_date`,m.`update_date`,m.`car_vendor_type`,m.`car_params`,m.`status`,m.`link_person`, | m.`id`,m.`tenant_id`,m.`parent_tenant_id`,m.`img_url`,m.`name`,m.`link_phone`,m.`create_date`,m.`update_date`,m.`car_vendor_type`,m.`car_params`,m.`status`,m.`link_person`, | ||||
| m.`business_id`,m.`sub_business_id`,m.`shop_type`,m.`brand`,m.`type`,m.`is_public`,m.email,m.`title`,m.`cover_picture`,m.`is_admin`,m.`bill_setting`,m.`qr_code`, | m.`business_id`,m.`sub_business_id`,m.`shop_type`,m.`brand`,m.`type`,m.`is_public`,m.email,m.`title`,m.`cover_picture`,m.`is_admin`,m.`bill_setting`,m.`qr_code`, | ||||
| m.`introduction`,m.`action_desc`,m.`is_del`,m.`talk_user_main`,m.`talk_user_aux`,m.link_line_phone,r.rental_start_date,r.rental_end_date,cash_out_number | |||||
| m.`introduction`,m.`action_desc`,m.`is_del`,m.`talk_user_main`,m.`talk_user_aux`,m.link_line_phone,r.rental_start_date,r.rental_end_date,cash_out_number,cash_out_count | |||||
| </sql> | </sql> | ||||
| <sql id="dynamicWhereConditions"> | <sql id="dynamicWhereConditions"> | ||||
| @@ -615,7 +616,11 @@ | |||||
| </update> | </update> | ||||
| <update id="reduceCash" parameterType="com.iformall.domain.po.WxMerchant"> | <update id="reduceCash" parameterType="com.iformall.domain.po.WxMerchant"> | ||||
| update wx_merchant set cash_out_number = cash_out_number-#{cashOutNumber} where id = #{id} | |||||
| update wx_merchant set cash_out_number = cash_out_number-#{cashOutNumber}, cash_out_count = cash_out_count+1 where id = #{id} | |||||
| </update> | |||||
| <update id="increaseCashCount" parameterType="com.iformall.domain.po.WxMerchant"> | |||||
| update wx_merchant set cash_out_count = cash_out_count+1 where id = #{id} | |||||
| </update> | </update> | ||||
| </mapper> | </mapper> | ||||