Commit b9093bb4 authored by jiaorz's avatar jiaorz

Merge remote-tracking branch 'origin/dev' into dev

parents 8a1c7486 5d8b60fd
......@@ -15,9 +15,9 @@ import java.util.stream.Collectors;
* @data 2019/11/13 17:23
*/
public enum LevelEnum {
DIAMOND(3, "钻石"),
GOLD(2, "黄金"),
GENERAL(1, "普通");
DIAMOND(3, "钻石会员"),
GOLD(2, "黄金会员"),
GENERAL(1, "普通会员");
LevelEnum(Integer level, String desc) {
this.level = level;
......
......@@ -2,6 +2,7 @@ package com.github.wxiaoqi.security.admin.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.util.StringUtils;
/**
* @author libin
......@@ -43,4 +44,8 @@ public class UserMemberSaveDTO {
*/
@ApiModelProperty(value = "剩余天数")
private Integer source;
public String getPhone() {
return StringUtils.hasText(phone)?phone.trim():"";
}
}
......@@ -26,4 +26,8 @@ public class WalletCathFindDTO extends PageParam {
private Long startTime;
private Long endTime;
/**
* 提现方式 1:线下自动 2:线下手动 3:线上自动
*/
private Integer withdrawWay;
}
......@@ -56,6 +56,6 @@ public class WalletCathListDTO {
private String accountName;
@ApiModelProperty(value = "线下提现方式 1:自动 2:手动")
private Integer offlineWay;
@ApiModelProperty(value = "提现方式 1:线下自动 2:线下手动 3:线上自动")
private Integer withdrawWay;
}
......@@ -48,6 +48,11 @@ public class BaseUserMemberExport implements Serializable {
private Integer beforeDiscount;
@Column(name = "source")
private Integer source;
/**
* 核销时间
*/
@Column(name = "verification_time")
private Long verificationTime;
}
......
......@@ -134,9 +134,9 @@ public class MyWalletCath implements Serializable {
@Column(name = "account_name")
private String accountName;
@Column(name = "offline_way")
@ApiModelProperty(value = "线下提现方式 1:自动 2:手动")
private Integer offlineWay;
@Column(name = "withdraw_way")
@ApiModelProperty(value = "提现方式 1:线下自动 2:线下手动 3:线上自动")
private Integer withdrawWay;
@Column(name = "real_reason")
private String realReason;
......
......@@ -164,11 +164,6 @@ public interface UserFeign {
@RequestParam(value = "isSuccess") Boolean isSuccess,
@RequestParam(value = "realReason",required = false) String realReason);
@GetMapping("/app/user/collect/exist")
boolean isCollectionByTypeAndTypeId(@RequestParam("userId") Integer userId,
@RequestParam(value = "type") int type,
@RequestParam("id") Integer typId);
/**
* 通过公司id,获取员工的下级用户id
* @param parentCompanyId
......@@ -193,4 +188,11 @@ public interface UserFeign {
@GetMapping("/public/getUsersByUserIdList")
ObjectRestResponse<List<AppUserVo>> getByUserIdList(@RequestParam("userIds") List<Integer> userIds);
@GetMapping("/app/user/collect/exist")
boolean isCollectionByTypeAndTypeId(@RequestParam("userId") Integer userId,
@RequestParam(value = "type") int type,
@RequestParam("id") Integer typId);
@GetMapping("/app/user/list_user_info")
List<UserBo> findUserDetailUserIds(@RequestParam(value = "userIds",required = false) List<Integer> userIds);
}
......@@ -52,6 +52,6 @@ public class WalletCathAdminVo {
private String accountName;
@ApiModelProperty(value = "线下提现方式 1:自动 2:手动")
private Integer offlineWay;
@ApiModelProperty(value = "提现方式 1:线下自动 2:线下手动 3:线上自动")
private Integer withdrawWay;
}
......@@ -192,6 +192,7 @@ public class AppShareholderDetailBiz extends BaseBiz<AppShareholderDetailMapper,
//更新股东表 持股状态改为已退股
mapper.updShareHolderIsQuit(appShareholderDetailDTO.getPhone(), companyId, 1);
AppShareholderDetail updAppShareholderDetail = selectById(appShareholderDetailDTO);
updAppShareholderDetail.setRelTime(appShareholderDetailDTO.getRelTime());
//查询股东表,是否为总部股东
Integer oldPositionId = null;
oldPositionId = mapper.selectShareHolderByUserIdOrPhone(updAppShareholderDetail.getUserId(), updAppShareholderDetail.getPhone());
......@@ -256,6 +257,7 @@ public class AppShareholderDetailBiz extends BaseBiz<AppShareholderDetailMapper,
//修改
mapper.updShareHolderIsQuit(appShareholderDetailDTO.getPhone(), companyId, 0);
//updateSelectiveById(appShareholderDetail);
updAppShareholderDetail.setRelTime(appShareholderDetailDTO.getRelTime());
appShareholderDetailChangeRecordBiz.addAppShareholderDetailChangeRecord(updAppShareholderDetail, updUserId, SHAREHOLDERDE_IS_TRUE);
}
}
......
......@@ -23,8 +23,8 @@ import java.util.List;
* @author Administrator
*/
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
@Slf4j
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class AppStaffUserBiz extends BaseBiz<AppStaffUserMapper, AppStaffUser> {
private final AppUserDetailBiz appUserDetailBiz;
private final Integer POSITION_ID=4;
......
......@@ -241,4 +241,9 @@ public class AppUserDetailBiz extends BaseBiz<AppUserDetailMapper, AppUserDetail
List<AppUserDetail> appUserDetails = mapper.selectAllWithNoProviinceCode();
return CollectionUtils.isEmpty(appUserDetails)?Collections.EMPTY_LIST:appUserDetails;
}
public List<UserBo> findUserDetailByUserIds(List<Integer> userIds) {
List<UserBo> userBoList = mapper.selectUserByUserIds(userIds);
return CollectionUtils.isEmpty(userBoList)?Collections.EMPTY_LIST:userBoList;
}
}
......@@ -19,6 +19,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;
import java.time.Instant;
......@@ -88,9 +89,11 @@ public class BaseUserMemberExportBiz extends BaseBiz<BaseUserMemberExportMapper,
.discount(level == null ? 0 : level.getDiscount() == null ? 0 : level.getDiscount())
.status(hasUsed?1:0)
.userId(hasUsed?phoneAndUserIdMap.get(userMemberSaveDTO.getPhone()):null)
.source(0)
.crtId(userId)
.crtName(name)
.crtTime(Instant.now().toEpochMilli())
.verificationTime(hasUsed?Instant.now().toEpochMilli():0)
.isDel(0)
.build();
if (log.isDebugEnabled()) {
......@@ -152,6 +155,7 @@ public class BaseUserMemberExportBiz extends BaseBiz<BaseUserMemberExportMapper,
Integer memberLevel, Integer discount, AtomicInteger counter,Map<Integer,UserMemberDTO> numAndUserMemberMap) {
for (String[] data : userMemberData) {
String phone = data[0];
phone = StringUtils.hasText(phone)?phone.trim():"";
String memberLevelName = data[1];
String memberName = data[2];
String totalNumber = data[3];
......@@ -196,8 +200,10 @@ public class BaseUserMemberExportBiz extends BaseBiz<BaseUserMemberExportMapper,
.userId(hasUsed?phoneAndUserIdMap.get(phone):null)
.crtId(userId)
.memberName(memberName)
.source(0)
.crtName(userName)
.crtTime(Instant.now().toEpochMilli())
.verificationTime(hasUsed?Instant.now().toEpochMilli():null)
.isDel(0)
.build();
if (log.isDebugEnabled()) {
......@@ -209,7 +215,9 @@ public class BaseUserMemberExportBiz extends BaseBiz<BaseUserMemberExportMapper,
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void InsertBatch(List<BaseUserMemberExport> baseUserMemberExports) {
mapper.insertList(baseUserMemberExports);
for (BaseUserMemberExport userMemberExport : baseUserMemberExports) {
mapper.insertSelective(userMemberExport);
}
}
public List<BaseUserMemberExportDTO> findUserMemberExportDataByPhoneAndHashEffective(String phone) {
......@@ -235,7 +243,7 @@ public class BaseUserMemberExportBiz extends BaseBiz<BaseUserMemberExportMapper,
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void updateUserMemberExportDataToLoseEfficacyByPhone(String phone,Integer userId) {
mapper.updateUserMemberExportDataToLoseEfficacyByPhone(phone,userId);
mapper.updateUserMemberExportDataToLoseEfficacyByPhone(phone,userId,Instant.now().toEpochMilli());
}
public PageDataVO<BaseUserMemberExportVo> findUserMemberExportDataPage(BaseUserMemberExportDataFindDTO exportDataFindDTO) {
......
......@@ -21,6 +21,7 @@ import com.github.wxiaoqi.security.common.util.OrderUtil;
import com.github.wxiaoqi.security.common.util.process.ResultCode;
import com.github.wxiaoqi.security.common.vo.PageDataVO;
import com.xxfc.platform.app.entity.vo.WithDrawRuleVo;
import com.xxfc.platform.app.enumconstant.WithDrawWayEnum;
import com.xxfc.platform.app.feign.ConfigFeign;
import com.xxfc.platform.universal.feign.ThirdFeign;
import com.xxfc.platform.universal.vo.FundPayVo;
......@@ -100,9 +101,6 @@ public class MyWalletBiz extends BaseBiz<MyWalletMapper, MyWallet> implements In
private DateTimeFormatter dateTimeFormatter;
private static final Integer WITHDRAW_ONLINE_WAY = 1;
private static final Integer WITHDRAW_OFFLINE_WAY = 2;
private BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);
......@@ -347,8 +345,10 @@ public class MyWalletBiz extends BaseBiz<MyWalletMapper, MyWallet> implements In
walletCath.setAccountName(applyCathVo.getAccountName());
walletCath.setAccountNumber(accountNumber);
walletCath.setAmount(amount);
//手续费
walletCath.setCommission(commission);
walletCath.setRealAmount(realAmount);
walletCath.setWithdrawWay(withdrawWay);
myWalletCathBiz.insertSelective(walletCath);
//提现金额
BigDecimal withdrawals = realAmount.add(commission);
......@@ -362,7 +362,7 @@ public class MyWalletBiz extends BaseBiz<MyWalletMapper, MyWallet> implements In
myWallet.setVersion(sumDto.getVersion());
mapper.updMyWater(myWallet);
//线上自动提现
if (WITHDRAW_ONLINE_WAY.equals(withdrawWay)) {
if (WithDrawWayEnum.WITHDRAW_ONLINE_WAY.getCode() == withdrawWay) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String host = StringUtils.defaultIfBlank(request.getHeader("userHost"), ClientUtil.getClientIp(request));
FundPayVo fundPayVo = FundPayVo.builder()
......
......@@ -101,12 +101,7 @@ public class MyWalletCathBiz extends BaseBiz<MyWalletCathMapper, MyWalletCath> {
PageDataVO<WalletCathListDTO> walletCathListDTOPage = PageDataVO.pageInfo(walletCathFindDTO.getPage(),
walletCathFindDTO.getLimit(),
() -> mapper.selectByUserNameOrPhoneOrWithDrawSate(walletCathFindDTO.getUsername(),
walletCathFindDTO.getPhone(),
walletCathFindDTO.getState(),
walletCathFindDTO.getOrderNo(),
walletCathFindDTO.getStartTime(),
walletCathFindDTO.getEndTime()));
() -> mapper.selectWalletCatchAll(walletCathFindDTO));
List<WalletCathListDTO> walletCathListDTOList = walletCathListDTOPage.getData();
if (CollectionUtils.isEmpty(walletCathListDTOList)) {
......
......@@ -41,4 +41,5 @@ public interface AppUserDetailMapper extends Mapper<AppUserDetail> {
List<AppUserDetail> selectAllWithNoProviinceCode();
List<UserBo> selectUserByUserIds(@Param("userIds") List<Integer> userIds);
}
\ No newline at end of file
......@@ -18,7 +18,7 @@ import java.util.List;
public interface BaseUserMemberExportMapper extends Mapper<BaseUserMemberExport>, InsertListMapper<BaseUserMemberExport> {
void updateUserMemberExportDataToLoseEfficacyByPhone(@Param("phone") String phone,@Param("userId") Integer userId);
void updateUserMemberExportDataToLoseEfficacyByPhone(@Param("phone") String phone,@Param("userId") Integer userId,@Param("time") Long time);
List<BaseUserMemberExportDTO> findExportDataPage(BaseUserMemberExportDataFindDTO exportDataFindDTO);
......
package com.github.wxiaoqi.security.admin.mapper;
import com.github.wxiaoqi.security.admin.dto.PersonalConsumptionDTO;
import com.github.wxiaoqi.security.admin.dto.WalletCathFindDTO;
import com.github.wxiaoqi.security.admin.dto.WalletCathListDTO;
import com.github.wxiaoqi.security.admin.dto.WalletCathSumDto;
import com.github.wxiaoqi.security.admin.entity.MyWalletCath;
......@@ -17,12 +18,7 @@ import java.util.List;
*/
public interface MyWalletCathMapper extends Mapper<MyWalletCath> {
List<WalletCathListDTO> selectByUserNameOrPhoneOrWithDrawSate(@Param("userName") String userName,
@Param("phone") String phone,
@Param("state") Integer state,
@Param("orderNo") String orderNo,
@Param("startTime") Long startTime,
@Param("endTime") Long endTime);
List<WalletCathListDTO> selectWalletCatchAll(WalletCathFindDTO walletCathFindDTO);
List<PersonalConsumptionDTO> findUserWithDrawingByUserIds(@Param("userIds") List<Integer> userIds);
......
......@@ -25,7 +25,6 @@ import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
......@@ -378,4 +377,9 @@ public class AppUserController extends CommonBaseController{
AppUserVo appUserVo = userDetailBiz.findByCode(code);
return ObjectRestResponse.succ(appUserVo);
}
@GetMapping("/list_user_info")
public List<UserBo> findUserDetailByUserIds(@RequestParam(value = "userIds",required = false) List<Integer> userIds){
return userDetailBiz.findUserDetailByUserIds(userIds);
}
}
......@@ -343,4 +343,16 @@ from `app_user_detail` as `aud` left join `app_user_login` as `aul` on aul.id=
resultType="com.github.wxiaoqi.security.admin.entity.AppUserDetail">
select `id`,`crt_host` from `app_user_detail` where crt_host is not null and ( province_code = 0 or province_code is null)
</select>
<select id="selectUserByUserIds" resultType="com.github.wxiaoqi.security.admin.bo.UserBo">
select aud.userid as `userId`,case when length(aud.realname)>0 then aud.realname else aud.nickname end as `name`,aul.username as `phone` from `app_user_detail` as aud left join `app_user_login` as aul on aul.id=aud.userid
<where>
<if test="userIds != null and userIds.size() != 0">
userid in
<foreach collection="userIds" item="userId" open="(" close=")" separator=",">
#{userId}
</foreach>
</if>
</where>
</select>
</mapper>
\ No newline at end of file
......@@ -14,10 +14,11 @@
<result property="crtName" column="crt_name"/>
<result property="crtTime" column="crt_time"/>
<result property="userId" column="user_id"/>
<result property="verificationTime" column="verification_time"/>
</resultMap>
<update id="updateUserMemberExportDataToLoseEfficacyByPhone">
update `base_user_member_export` set `status`=1,`user_id`=#{userId} where `username`=#{phone}
update `base_user_member_export` set `status`=1,`user_id`=#{userId},`verification_time`=#{time} where `username`=#{phone}
</update>
<select id="findExportDataPage" resultType="com.github.wxiaoqi.security.admin.dto.BaseUserMemberExportDTO">
......
......@@ -3,7 +3,7 @@
<mapper namespace="com.github.wxiaoqi.security.admin.mapper.MyWalletCathMapper">
<select id="selectByUserNameOrPhoneOrWithDrawSate"
<select id="selectWalletCatchAll"
resultType="com.github.wxiaoqi.security.admin.dto.WalletCathListDTO">
SELECT
wc.id,
......@@ -19,12 +19,16 @@
wc.order_no AS `orderNo`,
wc.account_number AS `accountNumber`,
wc.account_name AS `accountName`,
wc.offline_way AS `offlineWay`
wc.withdraw_way AS `withdrawWay`
FROM
(SELECT * FROM `my_wallet_cath` WHERE 1 = 1
(SELECT * FROM `my_wallet_cath`
<where>
<if test="state != null">
AND `stauts`=#{state}
</if>
<if test="withdrawWay != null">
AND `withdraw_way`=#{withdrawWay}
</if>
<if test="orderNo !=null and orderNo !=''">
AND `order_no` = #{orderNo}
</if>
......@@ -41,13 +45,14 @@
`crt_time` <= #{endTime}
]]>
</if>
</where>
) AS `wc`
INNER JOIN ( SELECT `id`, `username` FROM `app_user_login` <if test="phone != null and phone != ''">
WHERE `username`=#{phone}
</if> ) AS `aul` ON aul.id = wc.user_id
INNER JOIN ( SELECT `userid`, `nickname`, `realname` FROM `app_user_detail` <if
test="userName != null and userName != ''">
WHERE nickname =#{userName} OR realname =#{userName}
test="username != null and username != ''">
WHERE nickname =#{username} OR realname =#{username}
</if> ) AS `aud` ON aud.userid = aul.id order by wc.crt_time DESC
</select>
......
......@@ -44,7 +44,7 @@ public class WithDrawRuleVo {
private Integer maxNumberOfDay;
/**
* 1. 线上 2.线下
* 1.线下:自动 2.线下:手动 3. 线上
*/
private Integer withdrawWay;
......
package com.xxfc.platform.app.enumconstant;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author libin
* @version 1.0
* @description 提现方式
* @data 2020/1/7 8:44
*/
@AllArgsConstructor
@Getter
public enum WithDrawWayEnum {
WITHDRAW_ONLINE_WAY(3, "线上"),
WITHDRAW_OFFLINE_AUTO_WAY(2, "线下手动"),
WITHDRAW_OFFLINE_WAY(1, "线下自动");
private int code;
private String desc;
}
......@@ -15,7 +15,6 @@
<modules>
<module>xx-common-platform</module>
<module>xx-common-platform-web</module>
<module>xx-common-platform-component</module>
</modules>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>xx-common</artifactId>
<groupId>com.xxfc</groupId>
<version>2.0-SNAPSHOT</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.xxfc.platform</groupId>
<artifactId>li</artifactId>
<properties>
<swagger.version>2.9.2</swagger.version>
</properties>
<dependencies>
<dependency>
<groupId>com.github.wxiaoqi</groupId>
<artifactId>ace-admin-api</artifactId>
<version>2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-configuration-processor -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>com.github.wxiaoqi</groupId>
<artifactId>ace-common</artifactId>
<version>2.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
<scope>provided</scope>
</dependency>
<!-- cache -->
<dependency>
<groupId>com.github.wxiaoqi</groupId>
<artifactId>ace-cache</artifactId>
<version>0.0.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.ace.cache.parser.impl;
import com.ace.cache.parser.ICacheResultParser;
import com.alibaba.fastjson.JSON;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
/**
* 转map 有问题
*/
public class DefaultResultParser implements ICacheResultParser {
public DefaultResultParser() {
}
public Object parse(String value, Type type, Class<?>... origins) {
Object result = null;
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType)type;
Type rawType = parameterizedType.getRawType();
if (((Class)rawType).isAssignableFrom(List.class)) {
result = JSON.parseArray(value, (Class)parameterizedType.getActualTypeArguments()[0]);
}else if(((Class)rawType).isAssignableFrom(Map.class)) {
Map transition = JSON.parseObject(value, Map.class);
transition.forEach((k, v) -> {
transition.put(k, JSON.parseObject(value, (Class)parameterizedType.getActualTypeArguments()[1]));
});
result = transition;
}
} else if (origins == null) {
result = JSON.parseObject(value, (Class)type);
} else {
result = JSON.parseObject(value, origins[0]);
}
return result;
}
}
\ No newline at end of file
package com.xxfc.platform.common.annotaion;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author libin
* @version 1.0
* @description 复杂类型校验
* @data 2019/6/13 13:42
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface BeanValid {
Class<?>[] value() default {};
}
package com.xxfc.platform.common.annotaion;
import java.lang.annotation.*;
/**
* @author libin
* @version 1.0
* @description
* @data 2019/7/8 15:26
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface LoginUser {
}
package com.xxfc.platform.common.annotaion;
import com.xxfc.platform.common.util.RedisLock;
import java.lang.annotation.*;
/**
* @author libin
* @version 1.0
* @description
* @data 2019/7/8 15:26
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface NoRepeatSubmit {
long timeout() default 10;
String pre() default "";
RedisLock.ExpireTimeUnitEnum exptunit() default RedisLock.ExpireTimeUnitEnum.EXPIRETIME;
}
package com.xxfc.platform.common.annotaion;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface RateLimit {
}
package com.xxfc.platform.common.annotaion;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author libin
* @version 1.0
* @description 简单参数类型校验
* @data 2019/6/13 13:42
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface SimpleValid {
}
package com.xxfc.platform.common.aop;
import com.xxfc.platform.common.annotaion.NoRepeatSubmit;
import com.xxfc.platform.common.msg.ApiResult;
import com.xxfc.platform.common.msg.PageApiResult;
import com.xxfc.platform.common.util.RedisLock;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* @author libin
* @version 1.0
* @description
* @data 2019/7/8 21:04
*/
@Aspect
@Component
@Slf4j
public class NoRepeatSubmitAop {
@Value("${auth.user.token-header:Authorization}")
private String tokenHeader;
private static final String NO_REPEAT_SUBMIT_PREKEY = "no:submit";
@Autowired
private RedisLock redisLock;
@Pointcut("@annotation(noRepeatSubmit)")
public void noRepeateSubmitExpress(NoRepeatSubmit noRepeatSubmit) {}
@Around("noRepeateSubmitExpress(noRepeatSubmit)")
public Object noRepeateSubmitAround(ProceedingJoinPoint proceedingJoinPoint, NoRepeatSubmit noRepeatSubmit) {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
String uri = request.getRequestURI();
String token = request.getHeader(tokenHeader);
String lockKey = String.format("%s%s:%s:%s", StringUtils.isEmpty(noRepeatSubmit.pre()) ? "" : noRepeatSubmit.pre() + ":", NO_REPEAT_SUBMIT_PREKEY, token, uri);
boolean tryLock = redisLock.tryLock(lockKey, uri, noRepeatSubmit.exptunit(), noRepeatSubmit.timeout());
Object result = null;
if (tryLock) {
log.info("tryLock success, key=【{}】,接口地址:uri=【{}】", lockKey, uri);
try {
result = proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
log.error(throwable.getMessage(), throwable);
} finally {
redisLock.releaseLock(lockKey, uri);
log.info("releassLock success,key=【{}】,接口地址:uri=【{}】", lockKey, uri);
}
return result;
} else {
log.info("tryLock fail key=【{}】", lockKey);
return ApiResult.fail(100001, "获取锁失败");
}
}
}
package com.xxfc.platform.common.aop;
import cn.hutool.core.util.ArrayUtil;
import com.github.wxiaoqi.security.common.annotation.BeanValid;
import com.github.wxiaoqi.security.common.annotation.SimpleValid;
import com.xxfc.platform.common.msg.ApiResult;
import lombok.Data;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.executable.ExecutableValidator;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Objects;
import java.util.Set;
/**
* @author libin
* @version 1.0
* @description 切面验证
* @data 2019/6/13 13:46
*/
@Aspect
@Data
public class ValidParamAop {
/**
* 复合类型验证器
*/
private Validator validator;
/**
* 简单类型验证器
*/
private ExecutableValidator executableValidator;
@Pointcut("execution(* com.xxfc.platform..rest..*(..))")
public void validatorExpress(){}
@Around("validatorExpress()")
public Object validatorAround(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
//获取方法的所有参数
Object[] args = proceedingJoinPoint.getArgs();
if (ArrayUtil.isEmpty(args)){
//没有参数,不用验证
return proceedingJoinPoint.proceed();
}
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
Method currentMethod = methodSignature.getMethod();
Parameter[] parameters = currentMethod.getParameters();
boolean hashSimpleValid = false;
int argLength = args.length;
for (int i =0;i<argLength;i++){
BeanValid beanValidAnnotation = parameters[i].getDeclaredAnnotation(BeanValid.class);
if (Objects.nonNull(beanValidAnnotation)){
if (args[i].getClass().isArray()){
Object[] arrayArg =(Object[])args[i];
for (Object item:arrayArg){
Set<ConstraintViolation<Object>> validateResult = this.validator.validate(item, beanValidAnnotation.value());
if (!validateResult.isEmpty()){
String message = validateResult.iterator().next().getMessage();
return ApiResult.fail(400,message);
}
}
}else {
Set<ConstraintViolation<Object>> validateResult = this.validator.validate(args[i], beanValidAnnotation.value());
if (!validateResult.isEmpty()){
String message = validateResult.iterator().next().getMessage();
return ApiResult.fail(400,message);
}
}
continue;
}
if (!hashSimpleValid){
SimpleValid simpleValidAnnotation = parameters[i].getDeclaredAnnotation(SimpleValid.class);
if (Objects.nonNull(simpleValidAnnotation)){
hashSimpleValid = true;
}
}
}
if (hashSimpleValid){
Object target = proceedingJoinPoint.getTarget();
Set<ConstraintViolation<Object>> validResult = this.executableValidator.validateParameters(target, currentMethod, args);
if(!validResult.isEmpty()){
String message = validResult.iterator().next().getMessage();
return ApiResult.fail(400,message);
}
}
return proceedingJoinPoint.proceed();
}
}
package com.xxfc.platform.common.config;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
/**
* @author libin
* @version 1.0
* @description 设置请求头部信息,防止微服务之间调用请求头部信息丢失
* @data 2019/6/25 16:22
*/
public class HeaderConfig implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes){
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = servletRequestAttributes.getRequest();
//请求头设置
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames!=null){
while (headerNames.hasMoreElements()){
String headerName = headerNames.nextElement();
String headerValue = request.getHeader(headerName);
template.header(headerName,headerValue);
}
}
}
}
}
package com.xxfc.platform.common.config;
import io.swagger.annotations.Api;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
/**
* @author libin
* @version 1.0
* @description 通用swagger设置
* @data 2019/6/26 10:28
*/
@Profile(value = {"dev","test"})
@ConditionalOnClass(value = EnableSwagger2.class)
@ConditionalOnProperty(prefix = "xxfc",name = "swagger",havingValue = "true")
@EnableSwagger2
@Setter
public class SwaggerConfig {
@Value("${xxfc.swagger.title:xxfc api swagger document}")
private String title;
@Value("${xxfc.swagger.description:前后端联调xxfc api 文档}")
private String description;
@Value("${xxfc.swagger.version:1.0.0}")
private String version;
@Value("${jwt.tokenHeader:Authorization}")
private String header;
@Bean
public Docket docket(){
ParameterBuilder ticketPar = new ParameterBuilder();
List<Parameter> parameters = new ArrayList<Parameter>();
ticketPar.name(header).description("user Authorization")
.modelRef(new ModelRef("string")).parameterType("header")
//header中的ticket参数非必填,传空也可以
.required(false).build();
//根据每个方法名也知道当前方法在设置什么参数
parameters.add(ticketPar.build());
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
.paths(PathSelectors.any())
.build()
.globalOperationParameters(parameters);
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title(title)
.description(description)
.version(version)
.build();
}
}
package com.xxfc.platform.common.config;
import com.github.wxiaoqi.security.common.support.aop.ValidParamAop;
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.executable.ExecutableValidator;
/**
* @author libin
* @version 1.0
* @description 验证器validator
* @data 2019/6/13 13:48
*/
@Configuration
public class ValidatorConfig {
/**
* 复合类型所用的验证器
* @return Validator
*/
@Bean
public Validator validator(){
// .failFast( true ) 为设置快速错误模式,默认为false
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
.failFast( true )
.buildValidatorFactory();
return validatorFactory.getValidator();
}
/**
* 简单类型所用的验证器
* @return ExecutableValidator
*/
@Bean
public ExecutableValidator executableValidator() {
return validator().forExecutables();
}
/**
* 装配验证器切面
* @param validator Bean验证器
* @param executableValidator 简单类型验证器
* @return ValidParamAop
*/
@Bean
public ValidParamAop validAop(Validator validator, ExecutableValidator executableValidator) {
ValidParamAop validParamAop = new ValidParamAop();
validParamAop.setValidator(validator);
validParamAop.setExecutableValidator(executableValidator);
return validParamAop;
}
}
package com.xxfc.platform.common.config;
import com.xxfc.platform.common.resover.LoginUserParamResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* @author libin
* @version 1.0
* @description
* @data 2019/7/9 17:29
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private LoginUserParamResolver loginUserParamResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(loginUserParamResolver);
}
}
package com.xxfc.platform.common.msg;
import lombok.Data;
/**
* @author libin
* @version 1.0
* @description
* @data 2019/7/9 16:55
*/
@Data
public class ApiResult<T> extends BaseApiResult<T> {
private ApiResult(long code, String msg, T data, boolean successResponse, String requestId) {
super(code,msg,data,successResponse,requestId);
}
public static <T> ApiResult<T> ok() {
return new ApiResult(200, "ok", "ok", true, "0");
}
public static <T> ApiResult<T> ok(T data) {
return new ApiResult(200, "ok", data, true, "0");
}
public static <T> ApiResult<T> ok(T data, String requestId) {
return new ApiResult(200, "ok", data, true, requestId);
}
}
package com.xxfc.platform.common.msg;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author libin
* @version 1.0
* @description
* @data 2019/7/9 17:55
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseApiResult<T> implements Serializable {
private static final long serialVersionUID = 1L;
protected long code;
protected String msg;
protected T data;
protected boolean successResponse;
protected String requestId;
public static <T> BaseApiResult<T> fail() {
return new BaseApiResult(400, "fail", "fail", false, "0");
}
public static <T> BaseApiResult<T> fail(String msg) {
return new BaseApiResult(400, msg, "fail", false, "0");
}
public static <T> BaseApiResult<T> fail(long code, String msg) {
return new BaseApiResult(code, msg, "fail", false, "0");
}
}
package com.xxfc.platform.common.msg;
import lombok.Data;
/**
* @author libin
* @version 1.0
* @description
* @data 2019/7/9 17:45
*/
@Data
public class PageApiResult<T> extends BaseApiResult<T> {
private PageInfo pageInfo;
private PageApiResult(long code, String msg, T data, boolean successResponse, String requestId, PageInfo pageInfo) {
super(code, msg, data, successResponse, requestId);
this.pageInfo = pageInfo;
}
public static <T> PageApiResult<T> ok() {
return new PageApiResult(200, "ok", "ok", true, "0", PageInfo.createEmptyPageInfo());
}
public static <T> PageApiResult<T> ok(T data, PageInfo pageInfo) {
return new PageApiResult(200, "ok", data, true, "0", pageInfo);
}
public static <T> PageApiResult<T> ok(T data, PageInfo pageInfo, String requestId) {
return new PageApiResult(200, "ok", data, true, requestId, pageInfo);
}
@Data
static class PageInfo {
private Integer page;
private Integer pageSize;
private Integer total;
private PageInfo(){}
private PageInfo(Integer page, Integer pageSize, Integer total) {
this.page = page;
this.pageSize = pageSize;
this.total = total;
}
public static PageInfo createEmptyPageInfo() {
return new PageInfo();
}
public static PageInfo createPageInfo(Integer page, Integer pageSize, Integer total) {
return new PageInfo(page,pageSize,total);
}
}
}
package com.xxfc.platform.common.resover;
import com.github.wxiaoqi.security.admin.feign.UserFeign;
import com.github.wxiaoqi.security.admin.feign.dto.AppUserDTO;
import com.github.wxiaoqi.security.admin.feign.dto.UserDTO;
import com.xxfc.platform.common.annotaion.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpServletRequest;
/**
* @author libin
* @version 1.0
* @description
* @data 2019/7/8 20:17
*/
@ConditionalOnBean(value = UserFeign.class)
@Component
public class LoginUserParamResolver implements HandlerMethodArgumentResolver {
@Value("${auth.user.token-header:Authorization}")
private String tokenHeader;
@Autowired
private UserFeign userFeign;
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(LoginUser.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
String token = request.getHeader(tokenHeader);
Class<?> parameterType = parameter.getParameterType();
if (AppUserDTO.class.equals(parameterType)){
return userFeign.userDetailByToken(token).getData();
}
if (UserDTO.class.equals(parameterType)){
return userFeign.userinfoByToken(token).getData();
}
return null;
}
}
package com.xxfc.platform.common.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import java.util.Collections;
/**
* @author libin
* @version 1.0
* @description
* @data 2019/7/8 21:02
*/
@Component
public class RedisLock {
private static final Long RELEASE_SUCCESS = 1L;
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
/**
* if get(key) == value return del(key)
*/
private static final String RELEASE_LOCK_SCRIPT = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
@Autowired
private StringRedisTemplate redisTemplate;
/**
* 该加锁方法仅针对单实例 Redis 可实现分布式加锁
* 对于 Redis 集群则无法使用
* <p>
* 支持重复,线程安全
*
* @param lockKey 加锁键
* @param clientId 加锁客户端唯一标识(采用UUID)
* @param seconds 锁过期时间
* @return
*/
public boolean tryLock(String lockKey, String clientId, ExpireTimeUnitEnum expireTimeEnum,long seconds) {
return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> {
Jedis jedis = (Jedis) redisConnection.getNativeConnection();
String result = jedis.set(lockKey, clientId, SET_IF_NOT_EXIST, expireTimeEnum.getUnit(), seconds);
if (LOCK_SUCCESS.equals(result)) {
return true;
}
return false;
});
}
/**
* 与 tryLock 相对应,用作释放锁
*
* @param lockKey
* @param clientId
* @return
*/
public boolean releaseLock(String lockKey, String clientId) {
return redisTemplate.execute((RedisCallback<Boolean>) redisConnection -> {
Jedis jedis = (Jedis) redisConnection.getNativeConnection();
Object result = jedis.eval(RELEASE_LOCK_SCRIPT, Collections.singletonList(lockKey),
Collections.singletonList(clientId));
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
return false;
});
}
public enum ExpireTimeUnitEnum {
/**
* 当前设置 过期时间单位, EX = seconds; PX = milliseconds
*/
EXPIRETIME("EX"),
PXPIRETIME("PX");
ExpireTimeUnitEnum(String unit) {
this.unit = unit;
}
String unit;
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
}
}
package com.xxfc.platform.order.contant.enumerate;
/**
* @author libin
* @version 1.0
* @description
* @data 2020/1/6 12:48
*/
public enum MemberStatisticsBehaviorTypeEnum {
FIRST_TIME_BUY(0, "首次购买"),
RENEW(1, "续费"),
ACTIVATE(2, "激活"),
PAY(3, "付费(首次购买+续费)");
private int code;
private String desc;
MemberStatisticsBehaviorTypeEnum(int code, String desc) {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
package com.xxfc.platform.order.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.math.BigDecimal;
/**
* @author libin
* @version 1.0
* @description
* @data 2020/1/6 12:38
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "order_member_view")
@Entity
public class MemberStatistics {
@Id
@GeneratedValue(generator = "JDBC")
private Long id;
@Column(name = "user_id")
private Integer userId;
@Column(name = "real_amount")
private BigDecimal realAmount;
@Column(name = "pay_time")
private Long payTime;
@Column(name = "order_no")
private String orderNo;
/**
* 0:首次购买 1:续费 2:激活
*/
@Column(name = "behavior_type")
private Integer behaviorType;
@Column(name = "member_level")
private Integer memberLevel;
@Column(name = "parent_id")
private Integer parentId;
/**
* 是否是第一时时间成为会员
*/
@Column(name = "is_first_time_member")
private Integer isFirstTimeMember;
}
......@@ -3,13 +3,11 @@ package com.xxfc.platform.order.feign;
import com.github.wxiaoqi.security.auth.client.annotation.IgnoreClientToken;
import com.github.wxiaoqi.security.auth.client.annotation.IgnoreUserToken;
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import com.xxfc.platform.order.entity.OrderInvoice;
import com.xxfc.platform.order.pojo.dto.OrderDTO;
import com.xxfc.platform.order.pojo.order.OrderPageVO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.*;
import java.util.List;
......@@ -27,4 +25,8 @@ public interface OrderFeign {
@GetMapping(value = "/count/basebase/findByOrderIds")
public ObjectRestResponse<List<OrderDTO>> findOrdersByorderId(@RequestParam(value = "orderIds") List<Integer> orderIds);
@PostMapping(value = "/order/invoice/updateByOrderId")
ObjectRestResponse updateByOrderId(@RequestBody OrderInvoice orderInvoice);
}
package com.xxfc.platform.order.pojo.bo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author libin
* @version 1.0
* @description
* @data 2020/1/6 11:04
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MemberStatisticsBo implements Serializable {
private static final long serialVersionUID = 1L;
@JsonIgnore
private Integer userId;
private String name;
private String phone;
private BigDecimal realAmount;
private Long payTime;
private String orderNo;
/**
* 0:首次购买 1:续费 2:激活
*/
private Integer behaviorType;
@JsonIgnore
private Integer memberLevel;
private String memberName;
@JsonIgnore
private Integer parentId;
private String parentName;
private String parentPhone;
}
package com.xxfc.platform.order.pojo.bo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
/**
* @author libin
* @version 1.0
* @description
* @data 2020/1/6 11:21
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MemberStatisticsPageBo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 会员订单数
*/
private long memberOrdersNum;
/**
* 新增会员人数
*/
private long newMembersNum;
/**
* 激活人数
*/
private long activateMembersNum;
/**
* 会员费
*/
private BigDecimal memberAmount = BigDecimal.ZERO;
/**
* 普通会员订单数
*/
private long commonMemberOrdersNum;
/**
* 普通会员订单金额
*/
private BigDecimal commonMemberOrderAmount = BigDecimal.ZERO;
/**
* 黄金会员订单数
*/
private long goldMemberOrdersNum;
/**
* 黄金会员订单金额
*/
private BigDecimal goldMemberOrderAmount = BigDecimal.ZERO;
/**
* 钻石会员订单数
*/
private long diamondMemberOrdersNum;
/**
* 钻石会员订单金额
*/
private BigDecimal diamondMemberOrderAmount = BigDecimal.ZERO;
/**
* 会员统计
*/
private List<MemberStatisticsBo> memberStatistics;
private Long totalCount;
private Integer totalPage;
private Integer pageNum;
private Integer pageSize;
public List<MemberStatisticsBo> getMemberStatistics() {
return CollectionUtils.isEmpty(memberStatistics)? Collections.EMPTY_LIST:memberStatistics;
}
}
package com.xxfc.platform.order.pojo.dto;
import com.github.wxiaoqi.security.common.vo.PageParam;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author libin
* @version 1.0
* @description
* @data 2020/1/6 12:31
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MemberStatisticsFindDTO extends PageParam {
private Long startTime;
private Long endTime;
private Integer behaviorType;
private Boolean isExport;
}
......@@ -19,6 +19,8 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import tk.mybatis.mapper.entity.Example;
import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
......@@ -164,4 +166,17 @@ public class OrderInvoiceBiz extends BaseBiz<OrderInvoiceMapper, OrderInvoice> {
}
@Transactional(rollbackFor = Exception.class)
public boolean updateByOrderId(OrderInvoice orderInvoice) {
try {
Example example = new Example(OrderInvoice.class);
example.createCriteria().andEqualTo("orderIds",orderInvoice.getOrderIds());
mapper.updateByExample(orderInvoice,example);
return true;
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
log.error("修改状态异常={}",e);
return false;
}
}
}
package com.xxfc.platform.order.mapper;
import com.xxfc.platform.order.entity.MemberStatistics;
import tk.mybatis.mapper.common.Mapper;
/**
* @author libin
* @version 1.0
* @description
* @data 2020/1/6 12:36
*/
public interface MemberStatisticsMapper extends Mapper<MemberStatistics> {
}
......@@ -47,4 +47,9 @@ public class OrderInvoiceController extends BaseController<OrderInvoiceBiz, Orde
return baseBiz.update(orderInvoice);
}
@PostMapping(value = "/updateByOrderId")
public ObjectRestResponse updateByOrderId(@RequestBody OrderInvoice orderInvoice) {
boolean flag = baseBiz.updateByOrderId(orderInvoice);
return ObjectRestResponse.succ();
}
}
package com.xxfc.platform.order.rest.background;
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import com.xxfc.platform.order.biz.MemberStatisticsBiz;
import com.xxfc.platform.order.pojo.bo.MemberStatisticsPageBo;
import com.xxfc.platform.order.pojo.dto.MemberStatisticsFindDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
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.ResponseBody;
/**
* @author libin
* @version 1.0
* @description
* @data 2020/1/6 12:34
*/
@Controller
@RequestMapping("/admin/member/statistics")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MemberStatisticsAdminController {
private final MemberStatisticsBiz memberStatisticsBiz;
@PostMapping("/page")
@ResponseBody
public ObjectRestResponse<MemberStatisticsPageBo> findMemberStatisticsWithPage(@RequestBody MemberStatisticsFindDTO memberStatisticsFindDTO){
MemberStatisticsPageBo memberStatisticsPageBo = memberStatisticsBiz.findMemberStatisticsWithPage(memberStatisticsFindDTO);
return ObjectRestResponse.succ(memberStatisticsPageBo);
}
}
package com.xxfc.platform.universal.constant;
import lombok.Data;
/**
* @Auther: Administrator
* @Date: 2020/1/6 18:04
* @Description:
*/
public enum InvoiceStatusEum {
UNBILLED(0,"未开票"),ONGOING(1,"开票中"),SUCCESS(2,"开票成功"),
FAILURE(3,"开票失败");
private Integer code;
private String msg;
InvoiceStatusEum(int code, String msg) {
this.code=code;
this.msg=msg;
}
public Integer getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
package com.xxfc.platform.universal.entity;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;
@Data
@Table(name = "invoice")
@ApiModel
public class Invoice {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
/**
* 用户id
*/
private Integer userId;
/**
* 订单id :多个以逗号隔开
*/
private String orderId;
/**
* 公司代码
*/
private String companyCode;
/**
* 发票订单号
*/
private String orderNo;
/**
* 机构代码
*/
private String orgCode;
/**
* 发票代码
*/
private String invoiceCode;
/**
* 发票号码
*/
private String invoiceNo;
/**
* 开票日期
*/
private Date invoiceDate;
/**
* 发票分类:01 专票,02 货物运输业增值税专用发票,03 机动车销售统一发票,
* 04 增值税普通发票,10 增值税普通发票(电子),11 增值税普通发票(卷票),14 增值税普通发票(卷票)
*/
private Integer invoiceCategory;
/**
* 合计金额
*/
private BigDecimal invoiceAmount;
/**
* 合计税额
*/
private BigDecimal taxAmount;
/**
* 价税合计总额
*/
private BigDecimal invoiceSummaryAmount;
/**
* 价税合计总额大写
*/
private String invoiceSummaryAmountText;
/**
* 备注
*/
private String remark;
/**
* 验证码
*/
private String verifyCode;
/**
* 机器编号
*/
private String machineNo;
/**
* 密码区
*/
private String invoicePassword;
/**
* 地区
*/
private String areaCode;
/**
* 地区名称
*/
private String areaName;
/**
* 销售方名称
*/
private String salerName;
/**
* 销售方纳税人识别号
*/
private String salerTaxCode;
/**
* 销售方地址
*/
private String salerAddress;
/**
* 销售方电话
*/
private String salerPhone;
/**
* 销售方银行及账户
*/
private String salerAccountBank;
/**
* 购买方名称
*/
private String purchaserName;
/**
* 购买方纳税人识别号
*/
private String purchaserTaxCode;
/**
* 购方手机
*/
private String purchaserPhone;
/**
* 购方邮箱
*/
private String purchaserEmail;
/**
* 购买方地址电话
*/
private String purchaserAddressPhone;
/**
* 购买方银行账号
*/
private String purchaserAccountBank;
/**
* 收款人
*/
private String payee;
/**
* 复核人
*/
private String reviewer;
/**
* 开票人
*/
private String issuer;
// /**
// * 发票状态
// */
// private Integer invoiceStatus;
/**
* 附件
*/
private String attachment;
/**
* 原票代码
*/
private String originalCode;
/**
* 原票号
*/
private String originalNo;
/**
* 查验状态
*/
private Integer recognizeFlag;
/**
* 查验
*/
private Integer validState;
/**
* 开票状态 0:未开票;1:开票中;2:为开票成功;3:开票失败;
*/
private Integer status;
/**
* 发票图片链接
*/
private String pictureUrl;
/**
* 开票类型:1-正票;2-红票
*/
private Integer invoiceType=1;
/**
* 开票内容
*/
private String content;
/**
* 推送方式:-1,不推送;0,邮箱;1,手机(默认);2,邮箱、手机
*/
private Integer pushMode=2;
/**
* 开票代码
*/
private String invoiceSerialNum;
private String createBy;
private String updateBy;
private Date createTime;
private Date updateTime;
}
package com.xxfc.platform.universal.entity;
import lombok.Data;
import javax.persistence.Table;
import java.util.Date;
/**
* 发票最终查询结果,错误记录表
* @author Administrator
*/
@Data
@Table(name = "invoice_query_error")
public class InvoiceQueryError {
private Integer id;
private Integer invoiceId;
private String invoiceSerialNum;
private Integer status;
private Date creTime;
}
package com.xxfc.platform.universal.entity;
import lombok.Data;
import java.math.BigDecimal;
/**
* @Auther: Administrator
* @Date: 2020/1/3 11:20
* @Description:
*/
@Data
public class OrderData {
/**
* 产品名称
*/
private String orderName;
/**
* 产品数量
*/
private Integer num;
/**
* 是否含税价格 0:不含税,1:含税
*/
private Integer withTaxFlag=1;
/**
* 产品单价
*/
private BigDecimal price;
/**
* 税率
*/
private BigDecimal taxRate=new BigDecimal(0.03);
/**
* 单位
*/
private String unit="次";
}
package com.xxfc.platform.universal.entity.vo;
import com.xxfc.platform.universal.entity.OrderData;
import lombok.Data;
import java.util.List;
/**
* @Auther: Administrator
* @Date: 2020/1/3 14:43
* @Description:
*/
@Data
public class InvoiceVo {
/**
* 发票分类:01 专票,02 货物运输业增值税专用发票,03 机动车销售统一发票,
* 04 增值税普通发票,10 增值税普通发票(电子),11 增值税普通发票(卷票),14 增值税普通发票(卷票)
*/
private Integer invoiceCategory=10;
/**
* 订单id :多个以逗号隔开
*/
private String orderId;
/**
* 备注
*/
private String remark;
/**
* 购买方名称
*/
private String purchaserName;
/**
* 购买方纳税人识别号
*/
private String purchaserTaxCode;
/**
* 购方邮箱
*/
private String purchaserEmail;
/**
* 购买方地址电话
*/
private String purchaserAddressPhone;
/**
* 购买方银行账号
*/
private String purchaserAccountBank;
/**
* 开票内容
*/
private String content;
/**
* 购方手机
*/
private String purchaserPhone;
private List<OrderData> orders;
}
package com.xxfc.platform.universal.utils;
import java.math.BigDecimal;
/**
*
*
* 数字转换为汉语中人民币的大写<br>
*
*/
public class NumberToCN {
/**
* 汉语中数字大写
*/
private static final String[] CN_UPPER_NUMBER = { "零", "壹", "贰", "叁", "肆",
"伍", "陆", "柒", "捌", "玖" };
/**
* 汉语中货币单位大写,这样的设计类似于占位符
*/
private static final String[] CN_UPPER_MONETRAY_UNIT = { "分", "角", "元",
"拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "兆", "拾",
"佰", "仟" };
/**
* 特殊字符:整
*/
private static final String CN_FULL = "整";
/**
* 特殊字符:负
*/
private static final String CN_NEGATIVE = "负";
/**
* 金额的精度,默认值为2
*/
private static final int MONEY_PRECISION = 2;
/**
* 特殊字符:零元整
*/
private static final String CN_ZEOR_FULL = "零元" + CN_FULL;
/**
* 把输入的金额转换为汉语中人民币的大写
*
* @param numberOfMoney
* 输入的金额
* @return 对应的汉语大写
*/
public static String number2CNMontrayUnit(BigDecimal numberOfMoney) {
StringBuffer sb = new StringBuffer();
// -1, 0, or 1 as the value of this BigDecimal is negative, zero, or
// positive.
int signum = numberOfMoney.signum();
// 零元整的情况
if (signum == 0) {
return CN_ZEOR_FULL;
}
// 这里会进行金额的四舍五入
long number = numberOfMoney.movePointRight(MONEY_PRECISION)
.setScale(0, 4).abs().longValue();
// 得到小数点后两位值
long scale = number % 100;
int numUnit = 0;
int numIndex = 0;
boolean getZero = false;
// 判断最后两位数,一共有四中情况:00 = 0, 01 = 1, 10, 11
if (!(scale > 0)) {
numIndex = 2;
number = number / 100;
getZero = true;
}
if ((scale > 0) && (!(scale % 10 > 0))) {
numIndex = 1;
number = number / 10;
getZero = true;
}
int zeroSize = 0;
while (true) {
if (number <= 0) {
break;
}
// 每次获取到最后一个数
numUnit = (int) (number % 10);
if (numUnit > 0) {
if ((numIndex == 9) && (zeroSize >= 3)) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[6]);
}
if ((numIndex == 13) && (zeroSize >= 3)) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[10]);
}
sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
sb.insert(0, CN_UPPER_NUMBER[numUnit]);
getZero = false;
zeroSize = 0;
} else {
++zeroSize;
if (!(getZero)) {
sb.insert(0, CN_UPPER_NUMBER[numUnit]);
}
if (numIndex == 2) {
if (number > 0) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
}
} else if (((numIndex - 2) % 4 == 0) && (number % 1000 > 0)) {
sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
}
getZero = true;
}
// 让number每次都去掉最后一个数
number = number / 10;
++numIndex;
}
// 如果signum == -1,则说明输入的数字为负数,就在最前面追加特殊字符:负
if (signum == -1) {
sb.insert(0, CN_NEGATIVE);
}
// 输入的数字小数点后两位为"00"的情况,则要在最后追加特殊字符:整
if (!(scale > 0)) {
sb.append(CN_FULL);
}
return sb.toString();
}
public static void main(String[] args) {
double money = 2500.32;
BigDecimal numberOfMoney = new BigDecimal(money);
String s = NumberToCN.number2CNMontrayUnit(numberOfMoney);
System.out.println("你输入的金额为:【" + money + "】 #--# [" + s.toString()
+ "]");
}
}
\ No newline at end of file
package com.xxfc.platform.universal.utils;
public class SnowflakeIdWorker {
// ==============================Fields==================
/** 开始时间截 (2019-01-07) */
private final long twepoch = 1578326400000L;
/** 机器id所占的位数 */
private final long workerIdBits = 5L;
/** 数据标识id所占的位数 */
private final long datacenterIdBits = 5L;
/** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
/** 支持的最大数据标识id,结果是31 */
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
/** 序列在id中占的位数 */
private final long sequenceBits = 12L;
/** 机器ID向左移12位 */
private final long workerIdShift = sequenceBits;
/** 数据标识id向左移17位(12+5) */
private final long datacenterIdShift = sequenceBits + workerIdBits;
/** 时间截向左移22位(5+5+12) */
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
/** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
/** 工作机器ID(0~31) */
private long workerId;
/** 数据中心ID(0~31) */
private long datacenterId;
/** 毫秒内序列(0~4095) */
private long sequence = 0L;
/** 上次生成ID的时间截 */
private long lastTimestamp = -1L;
//==============================Constructors====================
/**
* 构造函数
* @param workerId 工作ID (0~31)
* @param datacenterId 数据中心ID (0~31)
*/
public SnowflakeIdWorker(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
// ==============================Methods=================================
/**
* 获得下一个ID (该方法是线程安全的)
* @return SnowflakeId
*/
public synchronized long nextId() {
long timestamp = timeGen();
//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
if (timestamp < lastTimestamp) {
throw new RuntimeException(
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
//如果是同一时间生成的,则进行毫秒内序列
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
//毫秒内序列溢出
if (sequence == 0) {
//阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
}
}
//时间戳改变,毫秒内序列重置
else {
sequence = 0L;
}
//上次生成ID的时间截
lastTimestamp = timestamp;
//移位并通过或运算拼到一起组成64位的ID
return ((timestamp - twepoch) << timestampLeftShift) //
| (datacenterId << datacenterIdShift) //
| (workerId << workerIdShift) //
| sequence;
}
/**
* 阻塞到下一个毫秒,直到获得新的时间戳
* @param lastTimestamp 上次生成ID的时间截
* @return 当前时间戳
*/
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
/**
* 返回以毫秒为单位的当前时间
* @return 当前时间(毫秒)
*/
protected long timeGen() {
return System.currentTimeMillis();
}
//==============================Test=============================================
/** 测试 */
public static void main(String[] args) {
SnowflakeIdWorker idWorker = new SnowflakeIdWorker(0, 0);
for (int i = 0; i < 1000; i++) {
long id = idWorker.nextId();
System.out.println(Long.toBinaryString(id));
System.out.println(id);
}
}
}
\ No newline at end of file
......@@ -105,6 +105,18 @@
<version>2.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<!-- 诺诺发票sdk-->
<dependency>
<groupId>com.nuonuo</groupId>
<artifactId>open-sdk</artifactId>
<version>1.0.3</version>
</dependency>
<dependency>
<groupId>com.xxfc.platform</groupId>
<artifactId>xx-order-api</artifactId>
<version>2.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
......
package com.xxfc.platform.universal.biz;
import com.github.wxiaoqi.security.common.biz.BaseBiz;
import com.xxfc.platform.universal.entity.InvoiceQueryError;
import com.xxfc.platform.universal.mapper.InvoiceQueryErrorMapper;
import org.springframework.stereotype.Service;
/**
* @Auther: Administrator
* @Date: 2020/1/8 10:48
* @Description:
*/
@Service
public class InvoiceQueryErrorBiz extends BaseBiz<InvoiceQueryErrorMapper, InvoiceQueryError> {
}
package com.xxfc.platform.universal.controller;
import com.github.wxiaoqi.security.common.msg.ObjectRestResponse;
import com.github.wxiaoqi.security.common.rest.BaseController;
import com.xxfc.platform.universal.entity.Invoice;
import com.xxfc.platform.universal.entity.vo.InvoiceVo;
import com.xxfc.platform.universal.service.InvoiceBiz;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 发票接口
* @Auther: Administrator
* @Date: 2019/12/31 09:57
* @Description:
*/
@RestController
@RequestMapping("/invoice")
public class InvoiceController extends BaseController<InvoiceBiz, Invoice> {
/**
* 根据开票代码获取税号
* @param code
* @return
*/
@GetMapping("/dutyParagraph")
public ObjectRestResponse getDutyParagraphByCode(@RequestParam("code")String code){
String dutyParagraph = baseBiz.getDutyParagraphByCode(code);
return ObjectRestResponse.succ(dutyParagraph);
}
/**
* 模糊查询获取公司全名和开票代码
* @param name
* @return
*/
@GetMapping("/corporateName")
public ObjectRestResponse corporateName(@RequestParam("name")String name){
List<Map<String, String>> mapList = baseBiz.corporateName(name);
return ObjectRestResponse.succ(mapList);
}
/**
* 开票接口
* @param invoiceVo
* @return
* @throws Exception
*/
@PostMapping("/invoicing")
public ObjectRestResponse invoicing(@RequestBody InvoiceVo invoiceVo) throws Exception {
String invoicing = baseBiz.Invoicing(invoiceVo);
return ObjectRestResponse.succ(invoicing);
}
/**
* 查询开票结果
* @param invoiceSerialNum
* @return
*/
@GetMapping("/result")
public ObjectRestResponse invoiceResult(@RequestParam("invoiceSerialNum")String invoiceSerialNum){
List<Map<String,Object>> result= baseBiz.invoiceResult(invoiceSerialNum);
return ObjectRestResponse.succ(result);
}
}
package com.xxfc.platform.universal.mapper;
import com.xxfc.platform.universal.entity.Invoice;
import tk.mybatis.mapper.common.Mapper;
/**
* @author Administrator
* @Auther: Administrator
* @Date: 2020/1/6 16:38
* @Description:
*/
public interface InvoiceMapper extends Mapper<Invoice> {
}
package com.xxfc.platform.universal.mapper;
import com.xxfc.platform.universal.entity.InvoiceQueryError;
import tk.mybatis.mapper.common.Mapper;
/**
* @author Administrator
* @Date: 2020/1/8 10:49
* @Description:
*/
public interface InvoiceQueryErrorMapper extends Mapper<InvoiceQueryError> {
}
package com.xxfc.platform.universal.service.invoice;
import com.xxfc.platform.universal.entity.Invoice;
import com.xxfc.platform.universal.entity.OrderData;
import java.util.List;
import java.util.Map;
/**
* @Auther: Administrator
* @Date: 2019/12/31 10:23
* @Description:
*/
public interface InvoiceDao {
List<Map<String, String>> corporateName(String name);
String getDutyParagraphByCode(String code);
String Invoicing(Invoice invoice, List<OrderData> orders);
List<Map<String,Object>> invoiceResult(String invoiceSerialNum);
}
package com.xxfc.platform.universal.service.invoice.impl;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.wxiaoqi.security.common.exception.BaseException;
import com.google.common.collect.Lists;
import com.xxfc.platform.universal.entity.Invoice;
import com.xxfc.platform.universal.entity.OrderData;
import com.xxfc.platform.universal.service.invoice.InvoiceDao;
import lombok.extern.slf4j.Slf4j;
import nuonuo.open.sdk.NNOpenSDK;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @Auther: Administrator
* @Date: 2019/12/31 10:26
* @Description:
*/
@Service
@Primary
@Slf4j
public class InvoiceDaoImpl implements InvoiceDao {
@Autowired
private RedisTemplate redisTemplate;
/**
* 诺诺-极速开票
*/
@Value("${invoice.nuonuo.js.taxnum}")
private String taxnum;
@Value("${invoice.nuonuo.js.appKey}")
private String appKey;
@Value("${invoice.nuonuo.js.appSecret}")
private String appSecret;
/**
* 诺诺-诺诺发票
*/
@Value("${invoice.nuonuo.nn.taxnum}")
private String taxnum2;
@Value("${invoice.nuonuo.nn.appKey}")
private String appKey2;
@Value("${invoice.nuonuo.nn.appSecret}")
private String appSecret2;
@Value("${invoice.nuonuo.queryUrl}")
private String queryUrl ;
@Value("${invoice.nuonuo.invoiceUrl}")
private String invoiceUrl ;
/**
* 给定的部分名,获取税号
*
* @param name
* @return
*/
@Override
public List<Map<String, String>> corporateName(String name) {
NNOpenSDK sdk = NNOpenSDK.getIntance();
HashMap<String, String> map = new HashMap();
map.put("q", name);
String content = JSON.toJSONString(map);
//方法名
String method = "nuonuo.speedBilling.prefixQuery";
// SDK请求地址
String url = "https://sdk.nuonuo.com/open/v1/services";
// 唯一标识,由企业自己生成32位随机码
String senid = UUID.randomUUID().toString().replace("-", "");
String result = sdk.sendPostSyncRequest(url, senid, appKey, appSecret, getTokenJS(), taxnum, method, content);
JSONObject jsonObject = JSON.parseObject(result);
List<Map<String, String>> mapList = (List<Map<String, String>>) jsonObject.get("result");
if (CollectionUtil.isNotEmpty(mapList)) {
return mapList;
}
return new ArrayList<>();
}
/**
* 根据开票代码,调用第三方接口获取税号
*
* @param code
* @return
*/
@Override
public String getDutyParagraphByCode(String code) {
NNOpenSDK sdk = NNOpenSDK.getIntance();
// API方法名
String method = "nuonuo.speedBilling.queryNameAndTaxByCode";
// SDK请求地址
String url = "https://sdk.jss.com.cn/open/v1/services";
HashMap<String, String> map = new HashMap();
map.put("code", code);
String content = JSON.toJSONString(map);
// 唯一标识,由企业自己生成32位随机码
String senid = UUID.randomUUID().toString().replace("-", "");
String result = sdk.sendPostSyncRequest(url, senid, appKey, appSecret, getTokenJS(), taxnum, method, content);
JSONObject jsonObject = JSON.parseObject(result);
Map<String, String> resultMap = (Map<String, String>) jsonObject.get("result");
return resultMap.get("kpCode");
}
/**
* 调用第三方开票接口进行开票
* @param invoice
* @param orders
* @return
*/
@Override
public String Invoicing(Invoice invoice, List<OrderData> orders) {
NNOpenSDK sdk = NNOpenSDK.getIntance();
// API方法名
String method = "nuonuo.electronInvoice.requestBilling";
String senid = UUID.randomUUID().toString().replace("-", "");
HashMap<String, Object> map = new HashMap<>();
HashMap<String, Map<String, Object>> orderMap = new HashMap<>();
orderMap.put("order", map);
//购方信息
map.put("buyerName", invoice.getPurchaserName());
map.put("buyerTaxNum", invoice.getPurchaserTaxCode());
// map.put("buyerTel", invoice.getPurchaserPhone());
map.put("buyerAddress", invoice.getPurchaserAddressPhone());
map.put("buyerAccount", invoice.getPurchaserAccountBank());
map.put("buyerPhone", invoice.getPurchaserPhone());
map.put("email", invoice.getPurchaserEmail());
map.put("remark", invoice.getRemark());
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//销方信息
map.put("orderNo", invoice.getOrderNo());
map.put("invoiceDate", dateFormat.format(invoice.getInvoiceDate()));
map.put("salerName", invoice.getSalerName());
map.put("salerTaxNum", invoice.getSalerTaxCode());
map.put("salerTel", invoice.getSalerPhone());
map.put("salerAddress", invoice.getSalerAddress());
map.put("salerAccount", invoice.getSalerAccountBank());
map.put("clerk", invoice.getIssuer());
map.put("payee", invoice.getPayee());
map.put("checker", invoice.getReviewer());
//其他设置
map.put("pushMode", String.valueOf(invoice.getPushMode()));
map.put("invoiceType", String.valueOf(invoice.getInvoiceType()));
//订单信息
ArrayList<Map<String, String>> arrayList = Lists.newArrayList();
map.put("invoiceDetail", arrayList);
for (OrderData order : orders) {
HashMap<String, String> mx = new HashMap<>();
mx.put("goodsName", invoice.getContent());
mx.put("num", String.valueOf(order.getNum()));
//单价含税标志,0:不含税,1:含税
mx.put("withTaxFlag", String.valueOf(order.getWithTaxFlag()));
mx.put("price", String.valueOf(order.getPrice()));
mx.put("taxRate", String.valueOf(order.getTaxRate()));
mx.put("unit", order.getUnit());
mx.put("specType", order.getOrderName());
arrayList.add(mx);
}
String token = getTokenFP();
String jsonString = JSON.toJSONString(orderMap);
//调用第三方接口
String result = sdk.sendPostSyncRequest(invoiceUrl, senid, appKey2, appSecret2, token, taxnum2, method, jsonString);
log.info("result={}", result);
//把字符串json数据转换为map
JSONObject jsonObject = JSON.parseObject(result);
Map<String, String> data = (Map<String, String>) jsonObject.get("result");
String invoiceSerialNum = data.get("invoiceSerialNum");
if (StringUtils.isBlank(invoiceSerialNum)) {
log.error("失败原因={}", result);
throw new BaseException("开票失败");
}
return invoiceSerialNum;
}
@Override
public List<Map<String, Object>> invoiceResult(String invoiceSerialNum) {
NNOpenSDK sdk = NNOpenSDK.getIntance();
// API方法名
String method = "nuonuo.electronInvoice.CheckEInvoice";
HashMap<String, List<String>> map = new HashMap<>();
ArrayList<String> arrayList = Lists.newArrayList();
arrayList.add(invoiceSerialNum);
map.put("invoiceSerialNum", arrayList);
String content = JSON.toJSONString(map);
// 唯一标识,由企业自己生成32位随机码
String senid = UUID.randomUUID().toString().replace("-", "");
String data = null;
try {
data = sdk.sendPostSyncRequest(queryUrl, senid, appKey2, appSecret2, getTokenFP(), taxnum2, method, content);
} catch (Exception e) {
e.printStackTrace();
}
if (data!=null){
try {
JSONObject jsonObject = JSON.parseObject(data);
List<Map<String, Object>> mapList = (List<Map<String, Object>>) jsonObject.get("result");
return mapList;
} catch (Exception e) {
throw new BaseException("发票请求流水号错误");
}
}
return null;
}
/**
* 获取极速开票token
*/
private String getTokenJS() {
return getToken(appKey, appSecret);
}
/**
* 获取诺诺发票token
*/
public String getTokenFP() {
return getToken(appKey2, appSecret2);
}
private String getToken(String appKey, String appSecret) {
String token = (String) redisTemplate.opsForValue().get(appKey);
if (StringUtils.isBlank(token)) {
String json = NNOpenSDK.getIntance().getMerchantToken(appKey, appSecret);
log.info("token={}", json);
JSONObject jsonObject = JSONObject.parseObject(json);
token = (String) jsonObject.get("access_token");
if (StringUtils.isBlank(token)) {
throw new BaseException("获取极速开票token失败");
}
redisTemplate.opsForValue().set(appKey, token, 23, TimeUnit.HOURS);
}
return token;
}
}
......@@ -103,6 +103,9 @@ public class VehicleWarningMsgBiz extends BaseBiz<VehicleWarningMsgMapper, Vehic
*/
public RestResponse<PageDataVO<VehicleWarningMsg>> getByPage(String queryVehicleWarningMsgVoJson){
try {
if (StringUtils.isBlank(queryVehicleWarningMsgVoJson)) {
return RestResponse.codeAndMessage(ResCode.INVALID_REST_REQ_PARAM.getCode(), ResCode.INVALID_REST_REQ_PARAM.getDesc());
}
QueryVehicleWarningMsgVo queryVehicleWarningMsgVo = JSON.parseObject(queryVehicleWarningMsgVoJson, QueryVehicleWarningMsgVo.class);
PageHelper.startPage(queryVehicleWarningMsgVo.getPage(),queryVehicleWarningMsgVo.getLimit());
UserDTO userDTO = getAdminUserInfo();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment