[fix]修改商户账单和订单核销

This commit is contained in:
wangqx 2025-09-10 19:53:21 +08:00
parent 91655571fe
commit 65f99d7a44
46 changed files with 694 additions and 374 deletions

View File

@ -15,7 +15,7 @@ import com.wzj.soopin.member.domain.vo.AccountBillVO;
import com.wzj.soopin.member.domain.vo.MemberAccountVO;
import com.wzj.soopin.member.domain.vo.MemberBankVO;
import com.wzj.soopin.member.domain.vo.MemberVO;
import com.wzj.soopin.member.service.IAccountBillService;
import com.wzj.soopin.transaction.service.IAccountBillService;
import com.wzj.soopin.member.service.IMemberAccountService;
import com.wzj.soopin.member.service.IMemberBankService;
import com.wzj.soopin.member.service.IMemberService;
@ -36,7 +36,6 @@ import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.domain.model.SocialLoginBody;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.satoken.utils.LoginHelper;

View File

@ -1,49 +1,27 @@
package org.dromara.app;
package org.dromara.app.customer;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wzj.soopin.content.domain.bo.IndexListBO;
import com.wzj.soopin.content.domain.bo.MyListBO;
import com.wzj.soopin.content.domain.bo.SimpleListBO;
import com.wzj.soopin.content.domain.bo.VlogBO;
import com.wzj.soopin.content.service.VlogService;
import com.wzj.soopin.content.service.VlogUploadService;
import com.wzj.soopin.content.utils.PagedGridResult;
import com.wzj.soopin.content.utils.QcCloud;
import com.wzj.soopin.content.utils.RedisOperator;
import com.wzj.soopin.order.domain.bo.OrderBo;
import com.wzj.soopin.order.domain.bo.SaveOrderBO;
import com.wzj.soopin.order.domain.entity.Order;
import com.wzj.soopin.order.domain.vo.ManagerOrderDetailVO;
import com.wzj.soopin.order.domain.vo.OrderVO;
import com.wzj.soopin.order.service.OrderItemService;
import com.wzj.soopin.order.service.OrderService;
import com.wzj.soopin.order.service.impl.OrderServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static com.wzj.soopin.content.domain.base.BaseInfoProperties.*;
@Slf4j
@Api(tags = "订单相关接口")
@RequestMapping("/app/order")
@RequestMapping("/app/customer/order")
@RestController
@RequiredArgsConstructor
public class AppOrderController {

View File

@ -0,0 +1,82 @@
package org.dromara.app.shop;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wzj.soopin.member.convert.AccountBillConvert;
import com.wzj.soopin.member.domain.bo.AccountBillBO;
import com.wzj.soopin.member.domain.po.AccountBill;
import com.wzj.soopin.member.domain.vo.AccountBillVO;
import com.wzj.soopin.member.domain.vo.AccountStatisticVO;
import com.wzj.soopin.member.enums.AccountTypeEnum;
import com.wzj.soopin.transaction.service.IAccountBillService;
import io.swagger.annotations.Api;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysTenantAccount;
import org.dromara.system.service.ISysTenantAccountService;
import org.dromara.system.service.ISysTenantService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 商户端,账单接口
*
* @author Chopper
* @since 2020-12-18 16:59
*/
@Slf4j
@Api(tags = "商户端,账单接口")
@RequestMapping("/app/merchant/account/")
@RestController
@RequiredArgsConstructor
public class AppMerchantBillController {
private final IAccountBillService service;
private final AccountBillConvert convert;
private final ISysTenantAccountService sysTenantAccountService;
private final ISysTenantService sysTenantService;
private final IAccountBillService accountBillService;
@Tag(name = "分页列表")
@PostMapping("/bill/page")
public R<IPage<AccountBillVO>> page(@RequestBody AccountBillBO bo) {
LoginUser loginUser = LoginHelper.getLoginUser();
if (loginUser == null) {
return R.fail("用户未登录");
}
if(loginUser.getTenantId() == null){
return R.fail("用户不是商户");
}
//取member对应的商户
SysTenantAccount sysTenantAccount = sysTenantAccountService.getByTenantId(loginUser.getTenantId());
bo.setSource(AccountTypeEnum.MERCHANT.getCode());
bo.setAccountId(sysTenantAccount.getId());
Page<AccountBill> articleList = service.page(bo.getPage(), bo.toWrapper());
return R.ok(convert.toVO(articleList));
}
@Tag(name = "账户统计")
@PostMapping("/statistic")
public R<AccountStatisticVO> statistic() {
LoginUser loginUser = LoginHelper.getLoginUser();
if (loginUser == null) {
return R.fail("用户未登录");
}
if(loginUser.getTenantId() == null){
return R.fail("用户不是商户");
}
//根据当前登录的member获取用户信息
return R.ok(accountBillService.getStatistic(loginUser.getTenantId()));
}
}

View File

@ -0,0 +1,67 @@
package org.dromara.app.shop;
import com.wzj.soopin.order.domain.dto.CodeVerificationDto;
import com.wzj.soopin.order.service.VerificationCodeService;
import io.swagger.annotations.Api;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.web.bind.annotation.*;
/**
* 商户端,订单接口
*
* @author Chopper
* @since 2020-12-18 16:59
*/
@Slf4j
@Api(tags = "商户端,订单接口")
@RequestMapping("/app/merchant/order")
@RestController
@RequiredArgsConstructor
public class AppShopOrderController {
private final VerificationCodeService verificationCodeService;
/**
* 扫码核销接口
* @return 核销结果
*/
@GetMapping("/verify")
@Tag(name = "核销接口")
public R verifyCode(@RequestParam("code") String code) {
LoginUser loginUser = LoginHelper.getLoginUser();
if (loginUser == null) {
return R.fail("用户未登录");
}
if(loginUser.getTenantId() == null){
return R.fail("用户不是商户");
}
verificationCodeService.verifyCode(code, loginUser.getTenantId());
return R.ok("核销成功");
}
/**
* 扫码核销接口
* @return 核销结果
*/
@GetMapping("/scan")
@Tag(name = "扫码接口")
public R scan(@RequestParam("code") String code) {
LoginUser loginUser = LoginHelper.getLoginUser();
if (loginUser == null) {
return R.fail("用户未登录");
}
if(loginUser.getTenantId() == null){
return R.fail("用户不是商户");
}
return R.ok(verificationCodeService.scan(code));
}
}

View File

@ -34,6 +34,7 @@ import org.dromara.system.mapper.SysUserMapper;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
/**
@ -58,36 +59,7 @@ public class SmsAuthStrategy implements IAuthStrategy {
String tenantId = loginBody.getTenantId();
String phonenumber = loginBody.getPhonenumber();
String smsCode = loginBody.getSmsCode();
LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
if("app".equals(client.getClientKey())){
//会员登录
Member member = loadMemberByPhonenumber(phonenumber);
//手机号登录如果没有则创建一个
if (member == null) {
RegisterBody registerBody = new RegisterBody();
registerBody.setPhoneNumber(phonenumber);
registerBody.setCode(smsCode);
registerBody.setUserType(UserType.APP_USER.getUserType());
registerBody.setClientId(client.getClientId());
registerBody.setUuid(phonenumber);
member = memberRegisterService.register(registerBody);
return loginService.buildLoginUser(member);
} else {
loginService.checkLogin(LoginType.SMS, tenantId, member.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode));
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
return loginService.buildLoginUser(member);
}
}else{
//管理员登录
SysUserVo user = loadUserByPhonenumber(phonenumber);
loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode));
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
return loginService.buildLoginUser(user);
}
});
LoginUser loginUser = checkUser(client, phonenumber, smsCode);
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
SaLoginModel model = new SaLoginModel();
@ -110,6 +82,45 @@ public class SmsAuthStrategy implements IAuthStrategy {
}
private LoginUser checkUser(SysClientVo client, String phonenumber, String smsCode) {
if("app".equals(client.getClientKey())){
//会员登录
Member member = loadMemberByPhonenumber(phonenumber);
//手机号登录如果没有则创建一个
if (member == null) {
RegisterBody registerBody = new RegisterBody();
registerBody.setPhoneNumber(phonenumber);
registerBody.setCode(smsCode);
registerBody.setUserType(UserType.APP_USER.getUserType());
registerBody.setClientId(client.getClientId());
registerBody.setUuid(phonenumber);
member = memberRegisterService.register(registerBody);
return loginService.buildLoginUser(member);
} else {
loginService.checkLogin(LoginType.SMS, "tenantId", member.getUserName(), () -> !validateSmsCode("tenantId", phonenumber, smsCode));
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
LoginUser user=loginService.buildLoginUser(member);
//检查member是否绑定了用户如果有则获取用户信息
if(ObjectUtil.isNotEmpty(member.getUserId())){
SysUserVo sysUser = userMapper.selectVoById(member.getUserId());
if(ObjectUtil.isNotEmpty(sysUser)){
user.setTenantId(sysUser.getTenantId());
}
}
return user;
}
}else{
//管理员登录
SysUserVo user = loadUserByPhonenumber(phonenumber);
loginService.checkLogin(LoginType.SMS, user.getTenantId(), user.getUserName(), () -> !validateSmsCode("tenantId", phonenumber, smsCode));
// 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
return loginService.buildLoginUser(user);
}
}
private void checkMemberLogin(){

View File

@ -174,6 +174,7 @@ tenant:
- oms_verification_codes
- oms_verification_logs
- ums_feedback
- trans_account_bill
- trans_charge
- trans_withdraw
- trans_divide
@ -193,6 +194,7 @@ tenant:
- sys_commission_rate_range
- cont_article
- cont_article_category
-

View File

@ -3,6 +3,7 @@ package org.dromara.common.core.domain;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;
import org.dromara.common.core.domain.model.BaseAudit;
@ -14,7 +15,9 @@ import java.util.Map;
@Data
public class BaseBO <T> {
private Integer pageNo=1;
private Integer pageSize=10;
protected LocalDateTime beginTime;
@ -28,4 +31,8 @@ public class BaseBO <T> {
public LambdaQueryWrapper<T> toWrapper() {
return new LambdaQueryWrapper<T>();
}
public Page<T> getPage() {
return new Page<>(pageNo, pageSize);
}
}

View File

@ -2,23 +2,24 @@ package org.dromara.common.mq.enums;
public enum MessageActionEnum {
NEW_FOUCS(1,"newFocus"), //新的关注
SYSTEM_NOTIFY(2, "system"), // 系统->通知
SYSTEM_REPORT(3, "system"), // 系统->举报下架视频视频评论 视频评论
SYSTEM_CHECK(4, "system"), // 系统->审核结果复审驳回 通过
SYSTEM_PUSH(5, "system"), //系统->推广类的
INTERACTION_COMMENT(6, "interaction"), //互动->评论
INTERACTION_AT(7, "interaction"), //互动->视频评论中的@
INTERACTION_LIKE(8, "interaction"), //互动->点赞
INTERACTION_REPLY(9, "interaction"), //互动->评论回复
ORDER_RECHARGE(10, "order"), //订单->充值 online
ORDER_PAY(11, "order"), //订单->订单交易成功通知 online
ORDER_REFUND(12, "order"), //订单->退款结果通知
GROUP_NOTIFY_CHECK(13, "groupNotify"), //群通知->进群申请 online
GROUP_NOTIFY_ACCEPT(14, "groupNotify"), // 群通知->进群审核审核通过 online
GROUP_NOTIFY_FAIL(15, "groupNotify"), // 群通知->进群审核审核拒绝 online
GROUP_NOTIFY_LEAVE_UP(16, "groupNotify"), // 群通知->群升级为达人群通知
GROUP_NOTIFY_LEAVE_DOWN(17, "groupNotify"); // 群通知->群降级为普通群通知
SYSTEM_NOTIFY(10, "system"), // 系统->通知
SYSTEM_REPORT(13, "system"), // 系统->举报下架视频视频评论 视频评论
SYSTEM_CHECK(14, "system"), // 系统->审核结果复审驳回 通过
SYSTEM_PUSH(15, "system"), //系统->推广类的
INTERACTION_COMMENT(21, "interaction"), //互动->评论
INTERACTION_AT(27, "interaction"), //互动->视频评论中的@
INTERACTION_LIKE(28, "interaction"), //互动->点赞
NEW_FOUCS(21,"newFocus"), //新的关注
INTERACTION_REPLY(29, "interaction"), //互动->评论回复
ORDER_RECHARGE(30, "order"), //订单->充值 online
ORDER_PAY(31, "order"), //订单->订单交易成功通知 online
ORDER_REFUND(32, "order"), //订单->退款结果通知
GROUP_NOTIFY_CHECK(43, "groupNotify"), //群通知->进群申请 online
GROUP_NOTIFY_ACCEPT(44, "groupNotify"), // 群通知->进群审核审核通过 online
GROUP_NOTIFY_FAIL(45, "groupNotify"), // 群通知->进群审核审核拒绝 online
GROUP_NOTIFY_LEAVE_UP(46, "groupNotify"), // 群通知->群升级为达人群通知
GROUP_NOTIFY_LEAVE_DOWN(47, "groupNotify"); // 群通知->群降级为普通群通知
private int code;
private String account;

View File

@ -218,4 +218,5 @@ public class LoginHelper {
}
}
}

View File

@ -16,11 +16,4 @@ public class MyListBO extends BaseBO<Vlog> {
@Schema(description = "是否公开1公开0私密")
private Integer privateFlag;
@Schema(description = "页码", defaultValue = "1")
private Long pageNum = 1L;
@Schema(description = "每页大小", defaultValue = "10")
private Long pageSize = 10L;
}

View File

@ -71,6 +71,10 @@
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-security</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-system</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>

View File

@ -51,4 +51,5 @@ public class AccountBillBO extends BaseBO<AccountBill> {
.eq(getAccountId() != null, AccountBill::getAccountId,accountId)
.eq(getSource() != null, AccountBill::getSource,source);
}
}

View File

@ -17,7 +17,7 @@ import java.math.BigDecimal;
*/
@Schema(description="账单")
@Data
@TableName("ums_account_bill")
@TableName("trans_account_bill")
@Builder
public class AccountBill extends BaseAudit {
@ -54,4 +54,8 @@ public class AccountBill extends BaseAudit {
private Integer source;
@Schema(description ="状态 0正常 1停用")
private Integer status;
}

View File

@ -0,0 +1,46 @@
package com.wzj.soopin.member.domain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.dromara.common.core.domain.model.BaseAudit;
import org.dromara.common.excel.annotation.Excel;
import java.math.BigDecimal;
/**
*
*
* @author zcc
*/
@Schema(description="账户")
@Data
public class AccountStatisticVO extends BaseAudit {
private Long id;
private Long accountId;
@Schema(description ="余额")
@Excel(name = "余额")
private BigDecimal moneyBalance;
/**
* 入账金额
*/
private BigDecimal moneyIn;
/**
* 出账金额
*/
private BigDecimal moneyOut;
/**
* 已入账
*/
private BigDecimal credited;
/**
* 未入账
*/
private BigDecimal pending;
}

View File

@ -1,8 +0,0 @@
package com.wzj.soopin.member.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.wzj.soopin.member.domain.po.AccountBill;
public interface IAccountBillService extends IService<AccountBill> {
}

View File

@ -19,7 +19,4 @@ public interface IMemberAccountService extends IService<MemberAccount> {
Object getCount();
boolean addMoney(BigDecimal money, Long memberId, AccountBillSourceEnum type, String remark);
boolean reduceMoney(BigDecimal money, Long memberId, AccountBillSourceEnum type, String remark);
}

View File

@ -1,23 +0,0 @@
package com.wzj.soopin.member.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzj.soopin.member.domain.po.AccountBill;
import com.wzj.soopin.member.mapper.AccountBillMapper;
import com.wzj.soopin.member.service.IAccountBillService;
import org.springframework.stereotype.Service;
/**
* 会员账户表Service业务层处理
*
*
* @author zcc
*/
@Service
public class AccountBillServiceImpl extends
ServiceImpl<AccountBillMapper, AccountBill> implements IAccountBillService {
}

View File

@ -10,7 +10,6 @@ import com.wzj.soopin.member.domain.bo.MemberAccountBO;
import com.wzj.soopin.member.domain.vo.MemberAccountVO;
import com.wzj.soopin.member.enums.AccountBillChangeTypeEnum;
import com.wzj.soopin.member.enums.AccountBillSourceEnum;
import com.wzj.soopin.member.mapper.AccountBillMapper;
import com.wzj.soopin.member.mapper.MemberAccountMapper;
import com.wzj.soopin.member.service.IMemberAccountService;
import lombok.RequiredArgsConstructor;
@ -28,7 +27,6 @@ import java.math.BigDecimal;
@RequiredArgsConstructor
public class MemberAccountServiceImpl extends ServiceImpl<MemberAccountMapper,MemberAccount> implements IMemberAccountService {
private final AccountBillMapper accountBillMapper;
@Override
public MemberAccount getMemberAccount(Long memberId) {
@ -57,64 +55,4 @@ public class MemberAccountServiceImpl extends ServiceImpl<MemberAccountMapper,Me
}
@Override
public boolean addMoney(BigDecimal money, Long memberId, AccountBillSourceEnum source, String remark) {
MemberAccount memberAccount = this.getMemberAccount(memberId);
if (memberAccount == null) {
throw new RuntimeException("用户不存在");
}
//检查当前用于的账户余额是否充足
BigDecimal balance = memberAccount.getWallet();
BigDecimal newBalance = balance.add(money);
//锁定用户余额
this.updateById(memberAccount.toBuilder().wallet(newBalance).build());
//生成账单
AccountBill memberAccountChangeRecord = AccountBill.builder()
.accountId(memberAccount.getId())
.changeAmount(money)
.moneyBalance(newBalance)
.beforeBalance(balance)
.afterBalance(newBalance)
.changeType(AccountBillChangeTypeEnum.IN.getCode())
.changeDesc(remark)
.source(source.getCode())
.build();
accountBillMapper.insert(memberAccountChangeRecord);
return false;
}
@Override
public boolean reduceMoney(BigDecimal money, Long memberId, AccountBillSourceEnum source, String remark) {
MemberAccount memberAccount = this.getMemberAccount(memberId);
if (memberAccount == null) {
throw new RuntimeException("用户不存在");
}
//检查当前用于的账户余额是否充足
BigDecimal balance = memberAccount.getWallet();
if (balance.compareTo(money) < 0) {
throw new RuntimeException("用户余额不足");
}
BigDecimal newBalance = balance.subtract(money);
//锁定用户余额
this.updateById(memberAccount.toBuilder().wallet(newBalance).build());
//生成账单
AccountBill memberAccountChangeRecord = AccountBill.builder()
.accountId(memberAccount.getId())
.changeAmount(money)
.moneyBalance(newBalance)
.beforeBalance(balance)
.afterBalance(newBalance)
.changeType(AccountBillChangeTypeEnum.OUT.getCode())
.changeDesc(remark)
.source(source.getCode())
.build();
accountBillMapper.insert(memberAccountChangeRecord);
return true;
}
}

View File

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wzj.soopin.member.mapper.AccountBillMapper">
<mapper namespace="com.wzj.soopin.transaction.mapper.AccountBillMapper">
<select id="getAccountBillSum" resultType="java.math.BigDecimal">
select sum(change_amount) from trans_account_bill where account_id = #{accountId} and change_type = #{changeType}
</select>
</mapper>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.wzj.soopin.member.mapper.AccountBillMapper" >
<mapper namespace="com.wzj.soopin.transaction.mapper.AccountBillMapper" >
</mapper>

View File

@ -32,21 +32,6 @@ public class VerificationCodeController {
return verificationCodeService.generateVerificationCode(orderId);
}
/**
* 扫码核销接口
* @return 核销结果
*/
@PostMapping("/verify")
@Tag(name = "扫码核销接口")
public R verifyCode(@RequestBody CodeVerificationDto codeVerificationDto) {
R result = verificationCodeService.verifyCode(codeVerificationDto);
if (R.isSuccess(result)){
verificationCodeService.sendMessage(codeVerificationDto);
}
else{
verificationCodeService.sendMessageNo(codeVerificationDto);
}
return result;
}
}

View File

@ -10,7 +10,5 @@ public class CodeVerificationDto {
@Schema(description = "核销码")
private String codeValue;
@Schema(description = "商家id")
private Long usedMerchantId;
}

View File

@ -37,8 +37,17 @@ public class VerificationCodes extends BaseAudit {
private LocalDateTime usedTime;
@Schema(description = "使用商家id")
private Long usedMerchantId;
private String usedMerchantId;
@Schema(description = "过期时间")
private LocalDateTime expireTime;
@Schema(description = "核销时间")
private LocalDateTime verificationTime;
@Schema(description = "核销结果")
private Integer result;
@Schema(description = "失败原因")
private String reason;
}

View File

@ -3,6 +3,8 @@ package com.wzj.soopin.order.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.wzj.soopin.order.domain.dto.CodeVerificationDto;
import com.wzj.soopin.order.domain.entity.VerificationCodes;
import com.wzj.soopin.order.domain.vo.ManagerOrderDetailVO;
import com.wzj.soopin.order.domain.vo.OrderVO;
import org.dromara.common.core.domain.R;
public interface VerificationCodeService extends IService<VerificationCodes> {
@ -10,9 +12,7 @@ public interface VerificationCodeService extends IService<VerificationCodes> {
R generateVerificationCode(Long orderId);
R verifyCode(CodeVerificationDto codeVerificationDto);
void verifyCode(String code,String tenantId);
void sendMessage(CodeVerificationDto codeVerificationDto);
void sendMessageNo(CodeVerificationDto codeVerificationDto);
ManagerOrderDetailVO scan(String code);
}

View File

@ -71,11 +71,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
private final OrderOperateHistoryMapper orderOperateHistoryMapper;
private final MemberMapper memberMapper;
private final OrderDeliveryHistoryMapper orderDeliveryHistoryMapper;
private final VerificationCodeService verificationCodeService;
private final SysTenantMapper sysTenantMapper;
private final MemberWechatMapper memberWechatMapper;
private final WechatPaymentHistoryMapper wechatPaymentHistoryMapper;
private final RedisService redisService;
private final AftersaleMapper aftersaleMapper;
/**

View File

@ -5,7 +5,6 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzj.soopin.member.domain.po.AccountBill;
import com.wzj.soopin.member.enums.AccountBillChangeTypeEnum;
import com.wzj.soopin.member.enums.AccountBillSourceEnum;
import com.wzj.soopin.member.mapper.AccountBillMapper;
import com.wzj.soopin.member.mapper.MemberAccountMapper;
import com.wzj.soopin.order.domain.entity.RedPacket;
import com.wzj.soopin.order.domain.entity.RedPacketReceive;
@ -34,7 +33,6 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
private final RedPacketMapper redPacketMapper;
private final RedPacketReceiveMapper redPacketReceiveMapper;
private final MemberAccountMapper umsAccountMapper;
private final AccountBillMapper accountChangeRecordMapper;
private final RedisTemplate<String, Object> redisTemplate;
// Redis锁前缀
@ -204,18 +202,18 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
umsAccountMapper.updateMoneyBalance(senderId, afterBalance);
// 记录金额变动
AccountBill record = AccountBill.builder()
.moneyBalance(beforeBalance)
.accountId(senderId)
.beforeBalance(beforeBalance)
.afterBalance(afterBalance)
.changeAmount(redPacket.getTotalAmount())
.changeType(AccountBillChangeTypeEnum.OUT.getCode())
.source(AccountBillSourceEnum.RED_PACKAGE_SEND.getCode())
.changeDesc("发送红包扣减红包ID" + redPacket.getId())
.build();
accountChangeRecordMapper.insert(record);
// AccountBill record = AccountBill.builder()
// .moneyBalance(beforeBalance)
// .accountId(senderId)
// .beforeBalance(beforeBalance)
// .afterBalance(afterBalance)
// .changeAmount(redPacket.getTotalAmount())
// .changeType(AccountBillChangeTypeEnum.OUT.getCode())
// .source(AccountBillSourceEnum.RED_PACKAGE_SEND.getCode())
// .changeDesc("发送红包扣减红包ID" + redPacket.getId())
// .build();
//
// accountChangeRecordMapper.insert(record);
}
/**
@ -267,18 +265,18 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
BigDecimal afterBalance = beforeBalance.add(remainingAmount);
umsAccountMapper.updateMoneyBalance(senderId, afterBalance);
// 记录金额变动
AccountBill record = AccountBill.builder()
.accountId(senderId)
.beforeBalance(beforeBalance)
.afterBalance(afterBalance)
.changeAmount(remainingAmount)
.changeType(AccountBillChangeTypeEnum.IN.getCode())
.source(AccountBillSourceEnum.RED_PACKAGE_REFUND.getCode())
.changeDesc("红包退款红包ID" + redPacket.getId())
.build();
accountChangeRecordMapper.insert(record);
// // 记录金额变动
// AccountBill record = AccountBill.builder()
// .accountId(senderId)
// .beforeBalance(beforeBalance)
// .afterBalance(afterBalance)
// .changeAmount(remainingAmount)
// .changeType(AccountBillChangeTypeEnum.IN.getCode())
// .source(AccountBillSourceEnum.RED_PACKAGE_REFUND.getCode())
// .changeDesc("红包退款红包ID" + redPacket.getId())
// .build();
//
// accountChangeRecordMapper.insert(record);
// 更新红包状态为已退款
redPacket.setStatus(STATUS_REFUNDED);
@ -339,18 +337,18 @@ public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket
BigDecimal afterBalance = beforeBalance.add(amount);
umsAccountMapper.updateMoneyBalance(memberId, afterBalance);
// 记录金额变动
AccountBill record = AccountBill.builder()
.accountId(memberId)
.beforeBalance(beforeBalance)
.afterBalance(afterBalance)
.changeAmount(amount)
.changeType(AccountBillChangeTypeEnum.IN.getCode())
.source(AccountBillSourceEnum.RED_PACKAGE_RECEIVE.getCode())
.changeDesc("红包领取红包ID" + packetId)
.build();
accountChangeRecordMapper.insert(record);
// // 记录金额变动
// AccountBill record = AccountBill.builder()
// .accountId(memberId)
// .beforeBalance(beforeBalance)
// .afterBalance(afterBalance)
// .changeAmount(amount)
// .changeType(AccountBillChangeTypeEnum.IN.getCode())
// .source(AccountBillSourceEnum.RED_PACKAGE_RECEIVE.getCode())
// .changeDesc("红包领取红包ID" + packetId)
// .build();
//
// accountChangeRecordMapper.insert(record);
}
/**

View File

@ -2,19 +2,29 @@ package com.wzj.soopin.order.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzj.soopin.content.domain.po.Vlog;
import com.wzj.soopin.order.domain.dto.CodeVerificationDto;
import com.wzj.soopin.order.domain.entity.Order;
import com.wzj.soopin.order.domain.entity.VerificationCodes;
import com.wzj.soopin.order.domain.entity.VerificationLogs;
import com.wzj.soopin.order.domain.vo.ManagerOrderDetailVO;
import com.wzj.soopin.order.domain.vo.OrderVO;
import com.wzj.soopin.order.mapper.OrderMapper;
import com.wzj.soopin.order.mapper.VerificationCodesMapper;
import com.wzj.soopin.order.mapper.VerificationLogsMapper;
import com.wzj.soopin.order.service.OrderService;
import com.wzj.soopin.order.service.VerificationCodeService;
import com.wzj.soopin.order.utils.QrCodeGenerator;
import com.wzj.soopin.order.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.mq.config.RocketMQConfig;
import org.dromara.common.mq.domain.MQMessage;
import org.dromara.common.mq.enums.MessageActionEnum;
import org.dromara.common.mq.utils.MqUtil;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
@ -37,6 +47,8 @@ public class VerificationCodeServiceImpl extends ServiceImpl<VerificationCodesM
private final QrCodeGenerator qrCodeGenerator;
private final VerificationLogsMapper logMapper;
private final OrderService orderService;
/**
* 生成核销码并关联订单
*
@ -94,75 +106,108 @@ public class VerificationCodeServiceImpl extends ServiceImpl<VerificationCodesM
return R.ok("核销码生成成功", code);
}
/**
* 核销订单
* @param code
*/
@Override
public R verifyCode(CodeVerificationDto codeVerificationDto) {
String codeValue = codeVerificationDto.getCodeValue();
Long usedMerchantId = codeVerificationDto.getUsedMerchantId();
public ManagerOrderDetailVO scan(String code) {
// 查询核销码
// 参数校验
if (StringUtils.isBlank(codeValue) || usedMerchantId == null) {
recordVerificationLog(null, null, usedMerchantId, 0, "参数不能为空");
return R.fail("参数不能为空");
if (StringUtils.isBlank(code) ) {
throw new IllegalArgumentException("参数不能为空");
}
// 查询核销码
VerificationCodes code = codeMapper.selectOne(
new LambdaQueryWrapper<VerificationCodes>().eq(VerificationCodes::getCode, codeValue)
VerificationCodes verificationCodes = codeMapper.selectOne(
new LambdaQueryWrapper<VerificationCodes>().eq(VerificationCodes::getCode, code)
);
if (code == null) {
recordVerificationLog(null, null, usedMerchantId, 0, "核销码不存在");
return R.fail("核销码不存在");
if (verificationCodes == null) {
throw new IllegalArgumentException("核销码不存在");
}
// 检查核销码状态
if (code.getStatus() == 1) {
recordVerificationLog(code.getId(), code.getOrderId(), usedMerchantId, 0, "核销码已使用");
return R.fail("核销码已使用");
if (verificationCodes.getStatus() == 1) {
throw new IllegalArgumentException("核销码已使用");
}
if (code.getStatus() == 2) {
recordVerificationLog(code.getId(), code.getOrderId(), usedMerchantId, 0, "核销码已过期");
return R.fail("核销码已过期");
if (verificationCodes.getStatus() == 2) {
throw new IllegalArgumentException("核销码已过期");
}
// 检查核销码是否过期
if (LocalDateTime.now().isAfter(verificationCodes.getExpireTime())) {
// 更新状态为已过期
verificationCodes.setStatus(3);
codeMapper.updateById(verificationCodes);
throw new IllegalArgumentException("核销码已过期");
}
// 检查订单状态
Order order = orderMapper.selectById(verificationCodes.getOrderId());
if (order == null || order.getStatus() != 6) {
throw new IllegalArgumentException("订单状态异常,无法核销");
}
if (verificationCodes.getStatus() == 1 || verificationCodes.getVerificationTime() != null) {
throw new IllegalArgumentException("该订单已被核销,核销时间:" + verificationCodes.getVerificationTime());
}
return orderService.selectById(verificationCodes.getOrderId());
}
@Override
public void verifyCode(String code,String tenantId) {
// 参数校验
if (StringUtils.isBlank(code) || tenantId == null) {
throw new IllegalArgumentException("参数不能为空");
}
// 查询核销码
VerificationCodes verificationCodes = codeMapper.selectOne(
new LambdaQueryWrapper<VerificationCodes>().eq(VerificationCodes::getCode, code)
);
if (verificationCodes == null) {
throw new IllegalArgumentException("核销码不存在");
}
// 检查核销码状态
if (verificationCodes.getStatus() == 1) {
throw new IllegalArgumentException("核销码已使用");
}
if (verificationCodes.getStatus() == 2) {
throw new IllegalArgumentException("核销码已过期");
}
// 检查订单状态
Order order = orderMapper.selectById(code.getOrderId());
Order order = orderMapper.selectById(verificationCodes.getOrderId());
if (order == null || order.getStatus() != 6) {
recordVerificationLog(code.getId(), code.getOrderId(), usedMerchantId, 0, "订单状态异常,无法核销");
return R.fail("订单状态异常,无法核销");
throw new IllegalArgumentException("订单状态异常,无法核销");
}
// 检查核销码是否过期
if (LocalDateTime.now().isAfter(code.getExpireTime())) {
if (LocalDateTime.now().isAfter(verificationCodes.getExpireTime())) {
// 更新状态为已过期
code.setStatus(3);
codeMapper.updateById(code);
recordVerificationLog(code.getId(), code.getOrderId(), usedMerchantId, 0, "核销码已过期");
return R.fail("核销码已过期");
verificationCodes.setStatus(3);
codeMapper.updateById(verificationCodes);
throw new IllegalArgumentException("核销码已过期");
}
// 检查该订单是否已经核销过
VerificationLogs existingLog = logMapper.selectOne(
new LambdaQueryWrapper<VerificationLogs>()
.eq(VerificationLogs::getOrderId, code.getOrderId())
.eq(VerificationLogs::getResult, 1)
);
if (existingLog != null) {
recordVerificationLog(code.getId(), code.getOrderId(), usedMerchantId, 0,
"该订单已被核销,核销时间:" + existingLog.getVerificationTime());
return R.fail("该订单已被核销,核销时间:" + existingLog.getVerificationTime());
if (verificationCodes.getStatus() == 1 || verificationCodes.getVerificationTime() != null) {
throw new IllegalArgumentException("该订单已被核销,核销时间:" + verificationCodes.getVerificationTime());
}
// 执行核销
code.setStatus(1);
code.setUsedTime(LocalDateTime.now());
code.setUsedMerchantId(usedMerchantId);
int result = codeMapper.updateById(code);
verificationCodes.setStatus(1);
verificationCodes.setUsedTime(LocalDateTime.now());
verificationCodes.setUsedMerchantId(tenantId);
verificationCodes.setVerificationTime(LocalDateTime.now());
verificationCodes.setResult(1);
int result = codeMapper.updateById(verificationCodes);
if (result != 1) {
recordVerificationLog(code.getId(), code.getOrderId(), usedMerchantId, 0, "核销失败,请重试");
return R.fail("核销失败,请重试");
throw new IllegalArgumentException("核销失败,请重试");
}
// 更新订单状态
@ -170,39 +215,9 @@ public class VerificationCodeServiceImpl extends ServiceImpl<VerificationCodesM
order.setUsedTime(LocalDateTime.now());
orderMapper.updateById(order);
// 记录核销日志成功
recordVerificationLog(code.getId(), code.getOrderId(), usedMerchantId, 1, null);
// 返回核销成功信息
Map<String, Object> resultData = new HashMap<>();
resultData.put("orderId", order.getId());
resultData.put("orderSn", order.getOrderSn());
resultData.put("used_time", order.getUsedTime());
resultData.put("code_url", order.getCodeUrl());
return R.ok("核销成功", resultData);
}
/**
* 记录核销日志
* @param codeId 核销码ID
* @param orderId 订单ID
* @param merchantId 商户ID
* @param result 结果1成功0失败
* @param reason 失败原因
*/
private void recordVerificationLog(Long codeId, Long orderId, Long merchantId, Integer result, String reason) {
VerificationLogs log = new VerificationLogs();
log.setCodeId(codeId);
log.setOrderId(orderId);
log.setMerchantId(merchantId);
log.setVerificationTime(LocalDateTime.now());
log.setResult(result);
log.setReason(reason);
logMapper.insert(log);
}
/**
* 生成唯一核销码
*/
@ -212,48 +227,4 @@ public class VerificationCodeServiceImpl extends ServiceImpl<VerificationCodesM
}
@Override
public void sendMessage(CodeVerificationDto codeVerificationDto) {
String code = codeVerificationDto.getCodeValue();
Map<String, Object> resultMap = codeMapper.getProduvtNameAndMemberId(code);
// String productName = (String) resultMap.get("productName");
Long memberId = (Long) resultMap.get("memberId");
LocalDateTime verificationTime = codeMapper.verificationTime(code);
String formattedTime = verificationTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
// 核销成功模板ID
// 改为新版模板类型调用
Map<String, Object> params = new HashMap<>();
// params.put("productName", productName);
params.put("verificationTime", formattedTime);
// SysMessageBo messageBo = new SysMessageBo();
// // 核销成功类型编号
// messageBo.setTemplateType(org.dromara.system.domain.MessageTemplateType.VERIFY_SUCCESS);
// messageBo.setTemplateParams(params);
// messageBo.setSenderId(memberId);
// // 补充设置消息标题
// messageBo.setTitle("核销成功通知");
// sysMessageService.sendMessageToUser(messageBo, memberId);
}
@Override
public void sendMessageNo(CodeVerificationDto codeVerificationDto) {
String code = codeVerificationDto.getCodeValue();
Map<String, Object> resultMap = codeMapper.getProduvtNameAndMemberId(code);
// String productName = (String) resultMap.get("productName");
Long memberId = (Long) resultMap.get("memberId");
String reason = codeMapper.getReason(code);
// 核销失败模板ID
// 改为新版模板类型调用
Map<String, Object> params = new HashMap<>();
// params.put("productName", productName);
params.put("reason", reason);
// SysMessageBo messageBo = new SysMessageBo();
// // 核销失败类型编号
// messageBo.setTemplateType(org.dromara.system.domain.MessageTemplateType.VERIFY_FAIL);
// messageBo.setTemplateParams(params);
// messageBo.setSenderId(memberId);
// // 补充设置消息标题
// messageBo.setTitle("核销失败通知");
// sysMessageService.sendMessageToUser(messageBo, memberId);
}
}

View File

@ -14,7 +14,7 @@ public class SysTenantAccount extends BaseAudit {
@Schema(description = "主键ID")
private Long id;
@Schema(description = "租户ID")
private Long tenantId;
private String tenantId;
@Schema(description = "现金余额")
private BigDecimal moneyBalance;
@Schema(description = "钱包余额")

View File

@ -0,0 +1,46 @@
package org.dromara.system.domain.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.dromara.common.core.domain.model.BaseAudit;
import org.dromara.common.excel.annotation.Excel;
import java.math.BigDecimal;
/**
*
*
* @author zcc
*/
@Schema(description="账户")
@Data
public class SysTenantAccountStatisticVO extends BaseAudit {
private Long id;
private Long accountId;
@Schema(description ="余额")
@Excel(name = "余额")
private BigDecimal moneyBalance;
/**
* 入账金额
*/
private BigDecimal moneyIn;
/**
* 出账金额
*/
private BigDecimal moneyOut;
/**
* 已入账
*/
private BigDecimal credited;
/**
* 未入账
*/
private BigDecimal pending;
}

View File

@ -14,9 +14,11 @@ import org.dromara.system.domain.vo.SysTenantAccountVo;
@Mapper
public interface SysTenantAccountMapper extends BaseMapperPlus<SysTenantAccount, SysTenantAccountVo> {
/**
* 分页查询租户账户列表关联租户表获取店铺名称
*/
IPage<SysTenantAccountVo> selectTenantAccountPage(Page<SysTenantAccount> page, @Param("bo") SysTenantAccountBo bo);
}

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.system.domain.CommissionSection;
import org.dromara.system.domain.SysTenantAccount;
import org.dromara.system.domain.bo.SysTenantAccountBo;
import org.dromara.system.domain.vo.SysTenantAccountStatisticVO;
import org.dromara.system.domain.vo.SysTenantAccountVo;
import java.util.List;
@ -19,5 +20,6 @@ public interface ISysTenantAccountService extends IService<SysTenantAccount> {
boolean updateById(SysTenantAccount po);
boolean removeById(Long id);
SysTenantAccount getByTenantId(Long tenantId);
SysTenantAccount getByTenantId(String tenantId);
}

View File

@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.dromara.system.domain.SysTenantAccount;
import org.dromara.system.domain.bo.SysTenantAccountBo;
import org.dromara.system.domain.vo.SysTenantAccountStatisticVO;
import org.dromara.system.domain.vo.SysTenantAccountVo;
import org.dromara.system.mapper.SysTenantAccountMapper;
import org.dromara.system.service.ISysTenantAccountService;
@ -66,7 +67,10 @@ public class SysTenantAccountServiceImpl extends ServiceImpl<SysTenantAccountMa
}
@Override
public SysTenantAccount getByTenantId(Long tenantId) {
public SysTenantAccount getByTenantId(String tenantId) {
return mapper.selectOne(new LambdaQueryWrapper<SysTenantAccount>().eq(SysTenantAccount::getTenantId, tenantId));
}
}

View File

@ -249,7 +249,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
// 创建店铺账号
SysTenantAccount tenantAccount = new SysTenantAccount();
tenantAccount.setTenantId(Long.valueOf(tenantId));
tenantAccount.setTenantId(tenantId);
tenantAccount.setType(bo.getType());
tenantAccount.setMoneyBalance(BigDecimal.ZERO);
tenantAccount.setWallet(BigDecimal.ZERO);

View File

@ -1,4 +1,4 @@
package com.wzj.soopin.member.controller;
package com.wzj.soopin.transaction.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
@ -7,7 +7,7 @@ import com.wzj.soopin.member.convert.AccountBillConvert;
import com.wzj.soopin.member.domain.bo.AccountBillBO;
import com.wzj.soopin.member.domain.po.AccountBill;
import com.wzj.soopin.member.domain.vo.AccountBillVO;
import com.wzj.soopin.member.service.IAccountBillService;
import com.wzj.soopin.transaction.service.IAccountBillService;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R;

View File

@ -124,4 +124,9 @@ public class DivideDetail extends BaseAudit {
@TableField(value = "del_flag", fill = FieldFill.INSERT, jdbcType = JdbcType.CHAR)
private String delFlag;
/**
* 账户id
* */
private Long accountId;
}

View File

@ -13,6 +13,7 @@ import com.wzj.soopin.transaction.kit.Payment;
import com.wzj.soopin.transaction.kit.dto.PayParam;
import com.wzj.soopin.transaction.kit.dto.PaymentSuccessParams;
import com.wzj.soopin.transaction.kit.params.dto.CashierParam;
import com.wzj.soopin.transaction.service.IAccountBillService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
@ -51,7 +52,7 @@ public class WalletPlugin implements Payment {
/**
* 会员余额
*/
private final IMemberAccountService memberAccountService;
private final IAccountBillService accountBillService;
/**
* 收银台
*/
@ -161,7 +162,7 @@ public class WalletPlugin implements Payment {
throw new ServiceException(ResultCode.USER_NOT_LOGIN);
}
//个人账户扣减
boolean result = memberAccountService.reduceMoney(
boolean result = accountBillService.reduceMoney(
cashierParam.getPrice(),
loginUser.getUserId(),

View File

@ -1,4 +1,4 @@
package com.wzj.soopin.member.mapper;
package com.wzj.soopin.transaction.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -7,6 +7,8 @@ import com.wzj.soopin.member.domain.vo.AccountDetailVO;
import org.apache.ibatis.annotations.Param;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.math.BigDecimal;
/**
* 会员账户变动记录Mapper接口
*/
@ -19,4 +21,11 @@ public interface AccountBillMapper extends BaseMapperPlus<AccountBill, AccountDe
@Param("accountId") Long accountId, @Param("changeType") Integer changeType,
@Param("source") Integer source, @Param("startTime") String startTime,
@Param("endTime") String endTime);
BigDecimal getAccountBillSum( @Param("accountId") Long accountId, @Param("changeType") Integer changeType);
}

View File

@ -7,6 +7,7 @@ import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.math.BigDecimal;
import java.util.List;
/**
@ -19,4 +20,6 @@ public interface DivideDetailMapper extends BaseMapperPlus<DivideDetail, DivideD
@Select("select * from trans_divide_detail where divide_id = #{divideId} and del_flag = '0' ")
List<DivideDetail> selectByDivideId(@Param("divideId") Long divideId);
BigDecimal getMoney(@Param("accountId") Long accountId, @Param("status") Integer status);
}

View File

@ -0,0 +1,24 @@
package com.wzj.soopin.transaction.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.wzj.soopin.member.domain.bo.AccountBillBO;
import com.wzj.soopin.member.domain.po.AccountBill;
import com.wzj.soopin.member.domain.vo.AccountBillVO;
import com.wzj.soopin.member.domain.vo.AccountStatisticVO;
import com.wzj.soopin.member.enums.AccountBillSourceEnum;
import java.math.BigDecimal;
public interface IAccountBillService extends IService<AccountBill> {
AccountStatisticVO getStatistic(String tenantId);
IPage<AccountBillVO> selectVoPage(AccountBillBO bo);
boolean addMoney(BigDecimal money, Long memberId, AccountBillSourceEnum type, String remark);
boolean reduceMoney(BigDecimal money, Long memberId, AccountBillSourceEnum type, String remark);
}

View File

@ -3,6 +3,8 @@ package com.wzj.soopin.transaction.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.wzj.soopin.transaction.domain.po.DivideDetail;
public interface IDivideDetailService extends IService<DivideDetail> {
import java.math.BigDecimal;
public interface IDivideDetailService extends IService<DivideDetail> {
BigDecimal selectPendingMoney(Long accountId);
}

View File

@ -0,0 +1,133 @@
package com.wzj.soopin.transaction.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzj.soopin.member.convert.AccountBillConvert;
import com.wzj.soopin.member.domain.bo.AccountBillBO;
import com.wzj.soopin.member.domain.po.AccountBill;
import com.wzj.soopin.member.domain.po.MemberAccount;
import com.wzj.soopin.member.domain.vo.AccountBillVO;
import com.wzj.soopin.member.domain.vo.AccountStatisticVO;
import com.wzj.soopin.member.enums.AccountBillChangeTypeEnum;
import com.wzj.soopin.member.enums.AccountBillSourceEnum;
import com.wzj.soopin.member.service.IMemberAccountService;
import com.wzj.soopin.transaction.mapper.AccountBillMapper;
import com.wzj.soopin.transaction.mapper.DivideDetailMapper;
import com.wzj.soopin.transaction.service.IAccountBillService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.system.domain.SysTenantAccount;
import org.dromara.system.service.ISysTenantAccountService;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
/**
* 会员账户表Service业务层处理
*
*
* @author zcc
*/
@Service
@AllArgsConstructor
@Slf4j
public class AccountBillServiceImpl extends
ServiceImpl<AccountBillMapper, AccountBill> implements IAccountBillService {
private final ISysTenantAccountService tenantAccountService;
private final DivideDetailMapper divideDetailMapper;
private final AccountBillConvert convert;
private final IMemberAccountService memberAccountService;
@Override
public AccountStatisticVO getStatistic(String tenantId) {
//先获取账户信息
SysTenantAccount account =tenantAccountService.getByTenantId(tenantId);
AccountStatisticVO vo = new AccountStatisticVO();
vo.setAccountId(account.getId());
vo.setMoneyBalance(account.getMoneyBalance());
vo.setMoneyIn(baseMapper.getAccountBillSum(account.getId(), 1));
vo.setMoneyOut(baseMapper.getAccountBillSum(account.getId(), 2));
//然后统计账户的所有入的总和
//统计已入账金额
vo.setPending(divideDetailMapper.getMoney(account.getId(),1));
//统计未入账金额
vo.setPending(divideDetailMapper.getMoney(account.getId(),2));
return vo;
}
@Override
public IPage<AccountBillVO> selectVoPage( AccountBillBO bo) {
Page<AccountBill> pageResult= baseMapper.selectPage(bo.getPage(), bo.toWrapper());
return convert.toVO(pageResult);
}
@Override
public boolean addMoney(BigDecimal money, Long memberId, AccountBillSourceEnum source, String remark) {
MemberAccount memberAccount = memberAccountService.getMemberAccount(memberId);
if (memberAccount == null) {
throw new RuntimeException("用户不存在");
}
//检查当前用于的账户余额是否充足
BigDecimal balance = memberAccount.getWallet();
BigDecimal newBalance = balance.add(money);
//锁定用户余额
memberAccountService.updateById(memberAccount.toBuilder().wallet(newBalance).build());
//生成账单
AccountBill memberAccountChangeRecord = AccountBill.builder()
.accountId(memberAccount.getId())
.changeAmount(money)
.moneyBalance(newBalance)
.beforeBalance(balance)
.afterBalance(newBalance)
.changeType(AccountBillChangeTypeEnum.IN.getCode())
.changeDesc(remark)
.source(source.getCode())
.build();
baseMapper.insert(memberAccountChangeRecord);
return false;
}
@Override
public boolean reduceMoney(BigDecimal money, Long memberId, AccountBillSourceEnum source, String remark) {
MemberAccount memberAccount = memberAccountService.getMemberAccount(memberId);
if (memberAccount == null) {
throw new RuntimeException("用户不存在");
}
//检查当前用于的账户余额是否充足
BigDecimal balance = memberAccount.getWallet();
if (balance.compareTo(money) < 0) {
throw new RuntimeException("用户余额不足");
}
BigDecimal newBalance = balance.subtract(money);
//锁定用户余额
memberAccountService.updateById(memberAccount.toBuilder().wallet(newBalance).build());
//生成账单
AccountBill memberAccountChangeRecord = AccountBill.builder()
.accountId(memberAccount.getId())
.changeAmount(money)
.moneyBalance(newBalance)
.beforeBalance(balance)
.afterBalance(newBalance)
.changeType(AccountBillChangeTypeEnum.OUT.getCode())
.changeDesc(remark)
.source(source.getCode())
.build();
baseMapper.insert(memberAccountChangeRecord);
return true;
}
}

View File

@ -5,7 +5,7 @@ import com.wzj.soopin.member.domain.po.AccountBill;
import com.wzj.soopin.member.domain.po.MemberAccount;
import com.wzj.soopin.member.enums.AccountBillChangeTypeEnum;
import com.wzj.soopin.member.enums.AccountBillSourceEnum;
import com.wzj.soopin.member.service.IAccountBillService;
import com.wzj.soopin.transaction.service.IAccountBillService;
import com.wzj.soopin.member.service.IMemberAccountService;
import com.wzj.soopin.transaction.domain.po.Charge;
import com.wzj.soopin.transaction.enums.ChargeStatus;

View File

@ -8,6 +8,8 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
/**
* 分账服务实现类
*
@ -18,4 +20,9 @@ import org.springframework.stereotype.Service;
@Slf4j
public class DivideDetailServiceImpl extends ServiceImpl<DivideDetailMapper, DivideDetail> implements IDivideDetailService {
@Override
public BigDecimal selectPendingMoney(Long accountId) {
return baseMapper.getMoney(accountId,1);
}
}

View File

@ -12,6 +12,7 @@ import com.wzj.soopin.transaction.enums.WithdrawStatus;
import com.wzj.soopin.transaction.mapper.WithdrawMapper;
import com.wzj.soopin.member.service.*;
import com.wzj.soopin.transaction.domain.vo.EasypayAccountVO;
import com.wzj.soopin.transaction.service.IAccountBillService;
import com.wzj.soopin.transaction.service.IWithdrawService;
import com.wzj.soopin.transaction.service.IEasypayService;
import lombok.RequiredArgsConstructor;
@ -104,7 +105,8 @@ public class WithdrawServiceImpl extends ServiceImpl<WithdrawMapper, Withdraw> i
public boolean withdrawRevenue(Withdraw withdraw) {
//调用三方支付平台获取用户余额
SysTenantAccount tenantAccount = sysTenantAccountService.getByTenantId(withdraw.getMemberId());
// TODO: 2025/9/10 这个地方不能用null 但是现在商户提现的业务不对暂时没有提现业务
SysTenantAccount tenantAccount = sysTenantAccountService.getByTenantId(null);
if (tenantAccount == null) {
throw new RuntimeException("用户不存在");
}

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wzj.soopin.transaction.mapper.DivideDetailMapper">
<select id="getMoney" resultType="java.math.BigDecimal">
SELECT
sum( dd.money ) AS pending_money
FROM
trans_divide_detail dd
LEFT JOIN trans_divide d ON d.id = dd.divide_id
WHERE
dd.account_id = #{accountId}
AND d.STATUS =#{status}
and d.del_flag = '0' and dd.del_flag = '0'
</select>
</mapper>