Browse Source

[POS][新增]:pos api添加

release_toaliyun_real
Stormeye Wu 6 years ago
parent
commit
c7a7e9a24e
44 changed files with 3232 additions and 4 deletions
  1. +154
    -0
      mallinkPosApi/pom.xml
  2. +49
    -0
      mallinkPosApi/src/main/java/com/iformall/PosApplication.java
  3. +52
    -0
      mallinkPosApi/src/main/java/com/iformall/config/AwsProperty.java
  4. +125
    -0
      mallinkPosApi/src/main/java/com/iformall/config/RedisConfig.java
  5. +49
    -0
      mallinkPosApi/src/main/java/com/iformall/config/Swagger2Config.java
  6. +80
    -0
      mallinkPosApi/src/main/java/com/iformall/config/WebMvcConfig.java
  7. +83
    -0
      mallinkPosApi/src/main/java/com/iformall/controller/BaseController.java
  8. +26
    -0
      mallinkPosApi/src/main/java/com/iformall/controller/HomeController.java
  9. +437
    -0
      mallinkPosApi/src/main/java/com/iformall/controller/PosController.java
  10. +28
    -0
      mallinkPosApi/src/main/java/com/iformall/service/PosService.java
  11. +753
    -0
      mallinkPosApi/src/main/java/com/iformall/service/impl/PosServiceImpl.java
  12. +116
    -0
      mallinkPosApi/src/main/resources/application-dev.yml
  13. +100
    -0
      mallinkPosApi/src/main/resources/application-prod.yml
  14. +100
    -0
      mallinkPosApi/src/main/resources/application-test.yml
  15. +52
    -0
      mallinkPosApi/src/main/resources/application.yml
  16. +100
    -0
      mallinkPosApi/src/main/resources/logback-spring.xml
  17. +176
    -0
      mallinkPosApi/src/test/java/com/iformall/pos/test/PosAppTest.java
  18. +15
    -0
      mallinkService/src/main/java/com/iformall/common/ErrorCode.java
  19. +37
    -0
      mallinkService/src/main/java/com/iformall/domain/po/PosCouponOrderVerify.java
  20. +36
    -0
      mallinkService/src/main/java/com/iformall/domain/po/ThDevInfo.java
  21. +1
    -1
      mallinkService/src/main/java/com/iformall/domain/po/WxCouponOrder.java
  22. +1
    -1
      mallinkService/src/main/java/com/iformall/domain/vo/WxLevelMerchantCVo.java
  23. +3
    -1
      mallinkService/src/main/java/com/iformall/enums/EnumCouponOrderStatus.java
  24. +42
    -0
      mallinkService/src/main/java/com/iformall/enums/EnumVerifyActionType.java
  25. +36
    -0
      mallinkService/src/main/java/com/iformall/enums/EnumVerifyType.java
  26. +17
    -0
      mallinkService/src/main/java/com/iformall/mapper/PosCouponOrderVerifyMapper.java
  27. +17
    -0
      mallinkService/src/main/java/com/iformall/mapper/ThDevInfoMapper.java
  28. +4
    -0
      mallinkService/src/main/java/com/iformall/mapper/WxCouponOrderMapper.java
  29. +28
    -0
      mallinkService/src/main/java/com/iformall/pay/WxPayConstant.java
  30. +15
    -0
      mallinkService/src/main/java/com/iformall/pay/WxPayment.java
  31. +57
    -0
      mallinkService/src/main/java/com/iformall/service/PosCouponOrderVerifyService.java
  32. +55
    -0
      mallinkService/src/main/java/com/iformall/service/ThDevInfoService.java
  33. +7
    -0
      mallinkService/src/main/java/com/iformall/service/WxCouponOrderService.java
  34. +7
    -0
      mallinkService/src/main/java/com/iformall/service/WxCreditHistoryService.java
  35. +8
    -0
      mallinkService/src/main/java/com/iformall/service/WxScoreRulesService.java
  36. +60
    -0
      mallinkService/src/main/java/com/iformall/service/impl/PosCouponOrderVerifyServiceImpl.java
  37. +69
    -0
      mallinkService/src/main/java/com/iformall/service/impl/ThDevInfoServiceImpl.java
  38. +9
    -0
      mallinkService/src/main/java/com/iformall/service/impl/WxCouponOrderServiceImpl.java
  39. +42
    -0
      mallinkService/src/main/java/com/iformall/service/impl/WxCreditHistoryServiceImpl.java
  40. +38
    -0
      mallinkService/src/main/java/com/iformall/service/impl/WxScoreRulesServiceImpl.java
  41. +54
    -0
      mallinkService/src/main/resources/mapper/PosCouponOrderVerifyMapper.xml
  42. +68
    -0
      mallinkService/src/main/resources/mapper/ThDevInfoMapper.xml
  43. +24
    -0
      mallinkService/src/main/resources/mapper/WxCouponOrderMapper.xml
  44. +2
    -1
      pom.xml

+ 154
- 0
mallinkPosApi/pom.xml View File

@@ -0,0 +1,154 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>mallink</artifactId>
<groupId>com.iformall</groupId>
<version>1.0</version>
</parent>

<artifactId>mallinkPosApi</artifactId>

<dependencies>
<dependency>
<groupId>com.iformall</groupId>
<artifactId>mallinkService</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
<layout>ZIP</layout>
<excludeGroupIds>
antlr,
cn.afterturn,
ch.qos.logback,
com.alibaba,
com.amazonaws,
com.mchange,
com.fasterxml.jackson.core,
com.fasterxml.jackson.dataformat,
com.fasterxml.jackson.datatype,
com.fasterxml.jackson.module,
com.fasterxml.uuid,
com.fasterxml,
com.github.axet,
com.github.binarywang,
com.github.jsqlparser,
com.github.pagehelper,
com.github.ulisesbocchio,
com.github.virtuald,
com.google.code.findbugs,
com.google.code.gson,
com.google.errorprone,
com.google.guava,
com.google.protobuf,
com.google.zxing,
com.jayway.jsonpath,
com.jhlabs,
com.puppycrawl.tools,
com.rabbitmq,
com.squareup.okhttp3,
com.squareup.okio,
com.sun,
com.sun.mail,
com.thoughtworks.xstream,
com.zaxxer,
commons-beanutils,
commons-cli,
commons-codec,
commons-collections,
commons-fileupload,
commons-io,
commons-logging,
io.lettuce,
io.netty,
io.projectreactor,
io.springfox,
io.swagger,
io.undertow,
javax.activation,
javax.annotation,
javax.mail,
javax.persistence,
javax.servlet,
javax.validation,
javax.xml.bind,
joda-time,
junit,
mysql,
net.bytebuddy,
net.minidev,
net.sf.dozer,
net.sf.saxon,
ognl,
org.antlr,
org.apache.commons,
org.apache.httpcomponents,
org.apache.logging.log4j,
org.apache.poi,
org.apache.poi.wso2,
org.apache.rocketmq,
org.apache.shiro,
org.apache.tomcat.embed,
org.apache.xmlbeans,
org.aspectj,
org.assertj,
org.bouncycastle,
org.checkerframework,
org.codehaus.mojo,
org.crazycake,
org.dom4j,
org.flowable,
org.flywaydb,
org.glassfish,
org.hibernate.validator,
org.jasypt,
org.javassist,
org.jboss.logging,
org.jboss.spec.javax.annotation,
org.jboss.spec.javax.websocket,
org.jboss.xnio,
org.jdom,
org.jodd,
org.mapstruct,
org.mockito,
org.mybatis,
org.mybatis.generator,
org.mybatis.spring.boot,
org.ow2.asm,
org.projectlombok,
org.quartz-scheduler,
org.reflections,
org.rocketmq.spring.boot,
org.slf4j,
org.springframework,
org.springframework.amqp,
org.springframework.boot,
org.springframework.data,
org.springframework.retry,
org.springframework.ws,
org.yaml,
redis.clients,
software.amazon.ion,
tk.mybatis,
xmlpull,
xpp3
</excludeGroupIds>
</configuration>
</plugin>
</plugins>
</build>
</project>

+ 49
- 0
mallinkPosApi/src/main/java/com/iformall/PosApplication.java View File

@@ -0,0 +1,49 @@
package com.iformall;

import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties;
import org.rocketmq.starter.annotation.EnableRocketMQ;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import tk.mybatis.spring.annotation.MapperScan;

/**
* @author chenkx
* @date 2017-12-26
*/
@SpringBootApplication
@MapperScan(basePackages = {"com.iformall.mapper"})
@EnableEncryptableProperties
@EnableRocketMQ
public class PosApplication {

@Value("${fm.exception}")
private boolean fmException;

@Value("${fm.exception_emails}")
private String fmExceptionEmails;

@Value("${fm.open}")
private boolean fmOpen;

@Bean
public boolean isFmException() {
return fmException;
}

@Bean
public String fmExceptionEmails() {
return fmExceptionEmails;
}

@Bean
public boolean isFmOpen() {
return fmOpen;
}


public static void main(String[] args) {
SpringApplication.run(PosApplication.class, args);
}
}

+ 52
- 0
mallinkPosApi/src/main/java/com/iformall/config/AwsProperty.java View File

@@ -0,0 +1,52 @@
package com.iformall.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
* @author Stormeye
*/
@Component
@ConfigurationProperties(prefix = "aws")
public class AwsProperty {
// AWS ACCESS KEY
private String access;

private String secret;

private String clientRegion;

private String bucketName;

public String getAccess() {
return access;
}

public void setAccess(String access) {
this.access = access;
}

public String getSecret() {
return secret;
}

public void setSecret(String secret) {
this.secret = secret;
}

public String getClientRegion() {
return clientRegion;
}

public void setClientRegion(String clientRegion) {
this.clientRegion = clientRegion;
}

public String getBucketName() {
return bucketName;
}

public void setBucketName(String bucketName) {
this.bucketName = bucketName;
}
}

+ 125
- 0
mallinkPosApi/src/main/java/com/iformall/config/RedisConfig.java View File

@@ -0,0 +1,125 @@
package com.iformall.config;

import com.iformall.domain.po.PushLimit;
import com.iformall.domain.po.WxCUser;
import com.iformall.domain.po.WxMall;
import com.iformall.domain.po.WxScoreRules;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
* Created by Stormeye on 2018/10/1.
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

//缓存管理器
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
//user信息缓存配置
RedisCacheConfiguration userCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(10)).disableCachingNullValues().prefixKeysWith("user");
Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
redisCacheConfigurationMap.put("user", userCacheConfiguration);
//初始化一个RedisCacheWriter
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
// 设置CacheManager的值序列化方式为JdkSerializationRedisSerializer,但其实RedisCacheConfiguration默认就是使用StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value,所以以下注释代码为默认实现
// ClassLoader loader = this.getClass().getClassLoader();
// JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer(loader);
// RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(jdkSerializer);
// RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
//设置默认超过期时间是30秒
defaultCacheConfig.entryTtl(Duration.ofSeconds(30));
//初始化RedisCacheManager
RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig, redisCacheConfigurationMap);
return cacheManager;
}

@Bean("pushLimitRedisTemplate")
public RedisTemplate<String, PushLimit> getPushLimitRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, PushLimit> template = new RedisTemplate<String, PushLimit>();

Jackson2JsonRedisSerializer<PushLimit> j = new Jackson2JsonRedisSerializer<PushLimit>(PushLimit.class);
// value值的序列化
template.setValueSerializer(j);
template.setHashKeySerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());

template.setConnectionFactory(connectionFactory);
return template;
}

@Bean("scoreRuleRedisTemplate")
public RedisTemplate<String, WxScoreRules> getScoreRuleRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, WxScoreRules> template = new RedisTemplate<String, WxScoreRules>();

Jackson2JsonRedisSerializer<WxScoreRules> j = new Jackson2JsonRedisSerializer<WxScoreRules>(WxScoreRules.class);
// value值的序列化
template.setValueSerializer(j);
template.setHashKeySerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());

template.setConnectionFactory(connectionFactory);
return template;
}

@Bean("cuserTokenRedisTemplate")
public RedisTemplate<String, WxCUser> getCUserTokenRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, WxCUser> template = new RedisTemplate<String, WxCUser>();

Jackson2JsonRedisSerializer<WxCUser> j = new Jackson2JsonRedisSerializer<WxCUser>(WxCUser.class);
// value值的序列化
template.setValueSerializer(j);
template.setHashKeySerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());

template.setConnectionFactory(connectionFactory);
return template;
}

@Bean("mallRedisTemplate")
public RedisTemplate<String, WxMall> getMallRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, WxMall> template = new RedisTemplate<String, WxMall>();

Jackson2JsonRedisSerializer<WxMall> j = new Jackson2JsonRedisSerializer<WxMall>(WxMall.class);
// value值的序列化
template.setValueSerializer(j);
template.setHashKeySerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());

template.setConnectionFactory(connectionFactory);
return template;
}

}

+ 49
- 0
mallinkPosApi/src/main/java/com/iformall/config/Swagger2Config.java View File

@@ -0,0 +1,49 @@
package com.iformall.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;

//参考:http://blog.csdn.net/catoop/article/details/50668896
@Configuration
@EnableSwagger2
public class Swagger2Config {

@Bean
public Docket createRestApi() {
ParameterBuilder tokenPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<Parameter>();
//增加一个request的header参数
tokenPar.name("token").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
pars.add(tokenPar.build());
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.iformall.controller"))
.paths(PathSelectors.any())
.build()
.globalOperationParameters(pars);
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("b端 api")
.description("b端 api")
.termsOfServiceUrl("http://localhost:8000")
.version("2.0")
.build();
}

}

+ 80
- 0
mallinkPosApi/src/main/java/com/iformall/config/WebMvcConfig.java View File

@@ -0,0 +1,80 @@
package com.iformall.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.*;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.List;

/**
* MVC配置
*
* @author stormeye.wu
* @email wugq@mippoint.com
* @date 2017-04-20 22:30
*/
@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
//registry.addResourceHandler("/app/**").addResourceLocations("classpath:/app/");

}

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT")
.maxAge(3600);
}

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
//ObjectMapper 是Jackson库的主要类。它提供一些功能将转换成Java对象匹配JSON结构,反之亦然
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();

//不显示为null的字段
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

DeserializationConfig dc = objectMapper.getDeserializationConfig();
// 设置反序列化日期格式、忽略不存在get、set的属性
objectMapper.setConfig(
dc.with(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
.without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
);
//序列化将Long转String类型
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
SimpleModule bigIntegerModule = new SimpleModule();
//序列化将BigInteger转String类型
bigIntegerModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
SimpleModule bigDecimalModule = new SimpleModule();
//序列化将BigDecimal转String类型
bigDecimalModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
objectMapper.registerModule(bigDecimalModule);
objectMapper.registerModule(bigIntegerModule);
jackson2HttpMessageConverter.setObjectMapper(objectMapper);
converters.add(jackson2HttpMessageConverter);
}
}

+ 83
- 0
mallinkPosApi/src/main/java/com/iformall/controller/BaseController.java View File

@@ -0,0 +1,83 @@
package com.iformall.controller;

import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import cn.binarywang.wx.miniapp.api.WxMaService;
import com.iformall.domain.po.WxAppinfo;
import com.iformall.service.WxAppinfoService;
import com.iformall.service.wechat.FmOpenService;
import com.iformall.utils.IPUtil;
import com.iformall.utils.MaUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@RestController
public class BaseController {
@Autowired
private boolean isFmOpen;

@Autowired
private WxAppinfoService wxAppinfoService;

@Autowired
private FmOpenService openService;

@InitBinder
public void InitBinder(WebDataBinder dataBinder) {
dataBinder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
public void setAsText(String value) {
try {
setValue(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(value));
} catch (ParseException e) {
try {
setValue(new SimpleDateFormat("yyyy-MM-dd ").parse(value));
} catch (ParseException e1) {
setValue(null);
}
}
}

public String getAsText() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) getValue());
}

});
}

public WxAppinfo getAppInfo(String appId) {
return wxAppinfoService.getByAppId(appId);
}

public WxMaService getWeappService(String appId) {
if(isFmOpen) {
return openService.getWxOpenComponentService().getWxMaServiceByAppid(appId);
} else {
WxAppinfo appinfo = wxAppinfoService.getByAppId(appId);
WxMaService service = MaUtil.getWeappService(appinfo);
return service;
}
}

public WxMaService getWeappServiceByAppInfo(WxAppinfo appinfo) {
if(!isFmOpen) {
WxMaService service = MaUtil.getWeappService(appinfo);
return service;
}
return null;
}

public String getIpAddr() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String ipaddress = IPUtil.getIpAddr(request);
return ipaddress;
}
}

+ 26
- 0
mallinkPosApi/src/main/java/com/iformall/controller/HomeController.java View File

@@ -0,0 +1,26 @@
package com.iformall.controller;

import com.iformall.common.ResultData;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Api(description = "登录相关接口")
public class HomeController extends BaseController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Value("${version}")
private String version;

@GetMapping("/version")
@ApiOperation("获取后端版本号")
public ResultData version() {
logger.debug("[" + getIpAddr() + "] HomeController::version");
return new ResultData(version);
}
}

+ 437
- 0
mallinkPosApi/src/main/java/com/iformall/controller/PosController.java View File

@@ -0,0 +1,437 @@
package com.iformall.controller;

import com.alibaba.fastjson.JSONObject;
import com.iformall.common.ErrorCode;
import com.iformall.domain.po.*;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.pay.WxPayConstant;
import com.iformall.pay.WxPayment;
import com.iformall.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

@RestController
@AllArgsConstructor
//@RequestMapping(value = "/p")
@Api(description = "POS相关接口")
public class PosController extends BaseController {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

private final PosService posService;
private final ThDevInfoService thDevInfoService;

@ApiOperation(value = "获取注册二维码", notes = "{" +
"\"dev_id\":\"string(必填)\"," +
"\"tenant_id\":\"string(必填)\"," +
"\"nonce_str\":\"string(必填)\"}")
@PostMapping("/getQrCode")
public Map<String, String> getQrCode(@RequestBody Map<String, String> params) {
JSONObject payContent = new JSONObject();

// 1. check sign
Map<String, String> retMap = checkSign(params, payContent);
if (retMap != null) {
// 签名相关异常返回
return retMap;
}
String resKey = payContent.getString("resKey");
logger.info("resKey: " + resKey);

try {
retMap = posService.doGetQrCode(params);
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "", WxPayConstant.RET_SUCCESS, null);
} catch (MallinkException e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "", WxPayConstant.RET_FAIL,
e.getErrorCode(),
e.getMessage());
} catch (Exception e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "", WxPayConstant.RET_FAIL,
500,
e.getMessage());
}
}


@ApiOperation(value = "会员识别", notes = "{" +
"\"dev_id\":\"string(必填)\"," +
"\"tenant_id\":\"string(必填)\"," +
"\"merchant_id\":\"string(必填)\"," +
"\"mem_id\":\"string(选填)\"," +
"\"mem_phone\":\"string(选填)\"," +
"\"pos_order_id\":\"string(必填)\"" +
"\"nonce_str\":\"string(必填)\"}")
@PostMapping("/checkMem")
public Map<String, String> checkMem(@RequestBody Map<String, String> params) {
JSONObject payContent = new JSONObject();

// 1. check sign
Map<String, String> retMap = checkSign(params, payContent);
if (retMap != null) {
// 签名相关异常返回
return retMap;
}
String resKey = payContent.getString("resKey");
logger.info("resKey: " + resKey);

try {
retMap = posService.checkMember(params);
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_SUCCESS, null);
} catch (MallinkException e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
e.getErrorCode(), e.getMessage());
} catch (Exception e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
500, e.getMessage());
}
}

@ApiOperation(value = "券是否可以核销", notes = "{" +
"\"dev_id\":\"string(必填)\"," +
"\"tenant_id\":\"string(必填)\"," +
"\"merchant_id\":\"string(必填)\"," +
"\"bu_user_id\":\"string(必填)\"," +
"\"coupon_order_id\":\"string(必填)\" +" +
"\"nonce_str\":\"string(必填)\" +" +
"\"pos_order_id\":\"string(选填)\" }")
@PostMapping("/checkCouponOrderForVerify")
public Map<String, String> checkCouponOrderVerify(@RequestBody Map<String, String> params) {
JSONObject payContent = new JSONObject();

// 1. check sign
Map<String, String> retMap = checkSign(params, payContent);
if (retMap != null) {
// 签名相关异常返回
return retMap;
}
String resKey = payContent.getString("resKey");
logger.info("resKey: " + resKey);

try {
retMap = posService.couponOrderVerifyDoSomething(params, EnumVerifyActionType.CHECK);
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_SUCCESS, null);
} catch (MallinkException e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
e.getErrorCode(), e.getMessage());
} catch (Exception e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
500, e.getMessage());
}
}

@ApiOperation(value = "券预核销", notes = "{" +
"\"dev_id\":\"string(必填)\"," +
"\"tenant_id\":\"string(必填)\"," +
"\"merchant_id\":\"string(必填)\"," +
"\"bu_user_id\":\"string(必填)\"," +
"\"coupon_order_id\":\"string(必填)\" +" +
"\"nonce_str\":\"string(必填)\" +" +
"\"pos_order_id\":\"string(必填)\" }")
@PostMapping("/couponOrderPreVerify")
public Map<String, String> couponOrderPreVerify(@RequestBody Map<String, String> params) {
JSONObject payContent = new JSONObject();

// 1. check sign
Map<String, String> retMap = checkSign(params, payContent);
if (retMap != null) {
// 签名相关异常返回
return retMap;
}
String resKey = payContent.getString("resKey");
logger.info("resKey: " + resKey);

try {
retMap = posService.couponOrderVerifyDoSomething(params, EnumVerifyActionType.PRE_VERIFY);
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_SUCCESS, null);
} catch (MallinkException e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
e.getErrorCode(), e.getMessage());
} catch (Exception e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
500, e.getMessage());
}
}

@ApiOperation(value = "券预核销取消", notes = "{" +
"\"dev_id\":\"string(必填)\"," +
"\"tenant_id\":\"string(必填)\"," +
"\"merchant_id\":\"string(必填)\"," +
"\"bu_user_id\":\"string(必填)\"," +
"\"coupon_order_id\":\"string(必填)\" +" +
"\"nonce_str\":\"string(必填)\" +" +
"\"pos_order_id\":\"string(必填)\" }")
@PostMapping("/couponOrderPreVerifyCancel")
public Map<String, String> couponOrderPreVerifyCancel(@RequestBody Map<String, String> params) {
JSONObject payContent = new JSONObject();

// 1. check sign
Map<String, String> retMap = checkSign(params, payContent);
if (retMap != null) {
// 签名相关异常返回
return retMap;
}
String resKey = payContent.getString("resKey");
logger.info("resKey: " + resKey);

try {
retMap = posService.couponOrderVerifyCancel(params, EnumVerifyActionType.PRE_VERIFY_CANCEL);
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_SUCCESS, null);
} catch (MallinkException e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
e.getErrorCode(), e.getMessage());
} catch (Exception e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
500, e.getMessage());
}
}

@ApiOperation(value = "券独立核销", notes = "{" +
"\"dev_id\":\"string(必填)\"," +
"\"tenant_id\":\"string(必填)\"," +
"\"merchant_id\":\"string(必填)\"," +
"\"bu_user_id\":\"string(必填)\"," +
"\"coupon_order_id\":\"string(必填)\" +" +
"\"nonce_str\":\"string(必填)\" +" +
"\"pos_order_id\":\"string(必填)\" }")
@PostMapping("/couponOrderIndependentVerify")
public Map<String, String> couponOrderIndependentVerify(@RequestBody Map<String, String> params) {
JSONObject payContent = new JSONObject();

// 1. check sign
Map<String, String> retMap = checkSign(params, payContent);
if (retMap != null) {
// 签名相关异常返回
return retMap;
}
String resKey = payContent.getString("resKey");
logger.info("resKey: " + resKey);

try {
retMap = posService.couponOrderVerifyDoSomething(params, EnumVerifyActionType.VERIFY_INDEPENT);
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_SUCCESS, null);
} catch (MallinkException e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
e.getErrorCode(), e.getMessage());
} catch (Exception e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
500, e.getMessage());
}
}

@ApiOperation(value = "券交易核销", notes = "{" +
"\"dev_id\":\"string(必填)\"," +
"\"tenant_id\":\"string(必填)\"," +
"\"merchant_id\":\"string(必填)\"," +
"\"bu_user_id\":\"string(必填)\"," +
"\"coupon_order_id\":\"string(必填)\" +" +
"\"nonce_str\":\"string(必填)\" +" +
"\"pos_order_id\":\"string(必填)\" }")
@PostMapping("/couponOrderPayVerify")
public Map<String, String> couponOrderPayVerify(@RequestBody Map<String, String> params) {
JSONObject payContent = new JSONObject();

// 1. check sign
Map<String, String> retMap = checkSign(params, payContent);
if (retMap != null) {
// 签名相关异常返回
return retMap;
}
String resKey = payContent.getString("resKey");
logger.info("resKey: " + resKey);

try {
retMap = posService.couponOrderVerifyDoSomething(params, EnumVerifyActionType.VERIFY_PAY);
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_SUCCESS, null);
} catch (MallinkException e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
e.getErrorCode(), e.getMessage());
} catch (Exception e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
500, e.getMessage());
}
}

@ApiOperation(value = "券核销取消", notes = "{" +
"\"dev_id\":\"string(必填)\"," +
"\"tenant_id\":\"string(必填)\"," +
"\"merchant_id\":\"string(必填)\"," +
"\"bu_user_id\":\"string(必填)\"," +
"\"coupon_order_id\":\"string(必填)\" +" +
"\"nonce_str\":\"string(必填)\" +" +
"\"pos_order_id\":\"string(必填)\" }")
@PostMapping("/couponOrderVerifyCancel")
public Map<String, String> couponOrderIndependentVerifyCancel(@RequestBody Map<String, String> params) {
JSONObject payContent = new JSONObject();

// 1. check sign
Map<String, String> retMap = checkSign(params, payContent);
if (retMap != null) {
// 签名相关异常返回
return retMap;
}
String resKey = payContent.getString("resKey");
logger.info("resKey: " + resKey);

try {
retMap = posService.couponOrderVerifyCancel(params, EnumVerifyActionType.VERIFY_CANCEL);
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_SUCCESS, null);
} catch (MallinkException e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
e.getErrorCode(), e.getMessage());
} catch (Exception e) {
return buildReturnMap(retMap, resKey, WxPayConstant.RET_SUCCESS, "",
WxPayConstant.RET_FAIL,
500, e.getMessage());
}
}


/**
* 构造返回map,无签名, 有错误
* @param retCode
* @param retMsg
* @param resCode
* @param errCode
* @param errMsg
* @return
*/
private Map<String, String> buildReturnMap(String retCode, String retMsg, String resCode, Integer errCode, String errMsg) {
Map<String, String> retMap = new HashMap<>();
retMap.put(WxPayConstant.RETURN_CODE, retCode);
retMap.put(WxPayConstant.RETURN_MSG, retMsg);
retMap.put(WxPayConstant.RESULT_CODE, resCode);
retMap.put(WxPayConstant.ERR_CODE, "" + errCode);
retMap.put(WxPayConstant.ERR_CODE_DESC, errMsg);
return retMap;
}

/**
* 构造返回map,带签名, 有错误
* @param retMap
* @param resKey
* @param retCode
* @param retMsg
* @param resCode
* @param err
* @return
*/
private Map<String, String> buildReturnMap(Map<String, String> retMap, String resKey, String retCode, String retMsg, String resCode, ErrorCode err) {
if(retMap == null) {
retMap = new HashMap<>();
}
retMap.put(WxPayConstant.RETURN_CODE, retCode);
retMap.put(WxPayConstant.RETURN_MSG, retMsg);
retMap.put(WxPayConstant.RESULT_CODE, resCode);
if (err != null) {
retMap.put(WxPayConstant.ERR_CODE, "" + err.getCode());
retMap.put(WxPayConstant.ERR_CODE_DESC, err.getMessage());
}
return WxPayment.buildSignAfterParasMapForHMAC(retMap, resKey);
}

/**
* 构造返回map,带签名, 有错误
* @param retMap
* @param resKey
* @param retCode
* @param retMsg
* @param resCode
* @param errCode
* @param errMsg
* @return
*/
private Map<String, String> buildReturnMap(Map<String, String> retMap, String resKey, String retCode, String retMsg, String resCode, Integer errCode, String errMsg) {
if(retMap == null) {
retMap = new HashMap<>();
}
retMap.put(WxPayConstant.RETURN_CODE, retCode);
retMap.put(WxPayConstant.RETURN_MSG, retMsg);
retMap.put(WxPayConstant.RESULT_CODE, resCode);
retMap.put(WxPayConstant.ERR_CODE, "" + errCode);
retMap.put(WxPayConstant.ERR_CODE_DESC, errMsg);
return WxPayment.buildSignAfterParasMapForHMAC(retMap, resKey);
}


/**
* 验证创建订单请求参数,参数通过返回JSONObject对象,否则返回错误文本信息
* @param params
* @return
*/
private Map<String, String> checkSign(Map<String, String> params, JSONObject payContent) {
// 1. check sign
// 开发者参数
String devId = params.get(WxPayConstant.DEV_ID); // 开发者ID
String sign = params.get(WxPayConstant.SIGN); // 签名
if (StringUtils.isBlank(devId)) {
String errorMessage = "request params[dev_id] error.";
return buildReturnMap(WxPayConstant.RET_FAIL, "参数错误", WxPayConstant.RET_FAIL, ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errorMessage);
}
if (StringUtils.isBlank(sign)) {
String errorMessage = "request params[sign] error.";
return buildReturnMap(WxPayConstant.RET_FAIL, "参数错误", WxPayConstant.RET_FAIL, ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errorMessage);
}

// 查询开发者信息
ThDevInfo devInfo = thDevInfoService.getByDevId(devId);
if (devInfo == null) {
String errorMessage = "Can't found devInfo[dev_id="+devId+"] record in db.";
return buildReturnMap(WxPayConstant.RET_FAIL, "参数错误", WxPayConstant.RET_FAIL, ErrorCode.DEV_ID_NOT_FOUND.getCode(), errorMessage);
}
if (devInfo.getState().equals(EnumEnableType.Disable.getCode())) {
String errorMessage = "devInfo not available [dev_id="+devId+"] record in db.";
return buildReturnMap(WxPayConstant.RET_FAIL, "参数错误", WxPayConstant.RET_FAIL, ErrorCode.DEV_ID_IS_DISABLED.getCode(), errorMessage);
}

if (StringUtils.isBlank(devInfo.getReqKey())) {
String errorMessage = "reqKey is null[dev_id="+devId+"] record in db.";
return buildReturnMap(WxPayConstant.RET_FAIL, "参数错误", WxPayConstant.RET_FAIL, ErrorCode.DEV_ID_REQ_KEY_IS_NULL.getCode(), errorMessage);
}
if (StringUtils.isBlank(devInfo.getResKey())) {
String errorMessage = "resKey is null[dev_id="+devId+"] record in db.";
return buildReturnMap(WxPayConstant.RET_FAIL, "参数错误", WxPayConstant.RET_FAIL, ErrorCode.DEV_ID_RES_KEY_IS_NULL.getCode(), errorMessage);
}
payContent.put("resKey", devInfo.getResKey());

boolean signVerified = WxPayment.verifyNotifyHMAC(params, devInfo.getReqKey());
if (!signVerified) {
String errorMessage = "签名错误";
logger.error("checksign error, params: " + params.toString());
return buildReturnMap(WxPayConstant.RET_FAIL, errorMessage, WxPayConstant.RET_FAIL, ErrorCode.DEV_ID_RES_KEY_IS_NULL.getCode(), errorMessage);
}
return null;
}



}

+ 28
- 0
mallinkPosApi/src/main/java/com/iformall/service/PosService.java View File

@@ -0,0 +1,28 @@
package com.iformall.service;

import com.iformall.enums.EnumVerifyActionType;
import com.iformall.exception.MallinkException;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.Map;


public interface PosService {
/**
* 获取商城二维码
* @param params
* @return
*/
Map<String, String> doGetQrCode(Map<String, String> params) throws MallinkException;

/**
* 识别会员
* @param params
* @return
*/
Map<String, String> checkMember(Map<String, String> params) throws MallinkException;

Map<String, String> couponOrderVerifyDoSomething(@RequestBody Map<String, String> params, EnumVerifyActionType actionType) throws MallinkException;

Map<String, String> couponOrderVerifyCancel(Map<String, String> params, EnumVerifyActionType actionType) throws MallinkException;
}

+ 753
- 0
mallinkPosApi/src/main/java/com/iformall/service/impl/PosServiceImpl.java View File

@@ -0,0 +1,753 @@
package com.iformall.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.iformall.common.ErrorCode;
import com.iformall.domain.po.*;
import com.iformall.domain.vo.WxCouponOrderCVo;
import com.iformall.domain.vo.WxLevelMerchantCVo;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.WxCouponMapper;
import com.iformall.mapper.WxCouponMerchantMapper;
import com.iformall.mapper.WxCouponOrderMapper;
import com.iformall.mapper.WxOrderMapper;
import com.iformall.pay.WxPayConstant;
import com.iformall.service.*;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@AllArgsConstructor
public class PosServiceImpl implements PosService {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

private final WxMallService mallService;
private final WxCUserService cUserService;
private final WxLevelConfigService levelConfigService;
private final WxCouponOrderService couponOrderService;
private final WxMerchantService merchantService;
private final WxMerchantBUserService merchantBUserService;
private final PosCouponOrderVerifyService posCouponOrderVerifyService;
private final WxScoreRulesService scoreRulesService;
private final WxCreditHistoryService creditHistoryService;

private final WxOrderMapper orderMapper;
private final WxCouponOrderMapper couponOrderMapper;
private final WxCouponMerchantMapper couponMerchantMapper;
private final WxCouponMapper couponMapper;

/**
* 获取商城二维码
* @param params
* @return
*/
@Override
public Map<String, String> doGetQrCode(Map<String, String> params) throws MallinkException {
Map<String, String> retMap = new HashMap<>();

String nonceStr = params.get(WxPayConstant.NONCE_STR); // 随机数
String tenantId = params.get(WxPayConstant.TENANT_ID); // 租户ID

if (StringUtils.isBlank(tenantId)) {
String errMessage = "request params[tenant_id] error.";
logger.error(errMessage);
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
WxMall mall = mallService.getByTenantId(tenantId);
if (mall == null) {
logger.error(ErrorCode.MALL_INFO_NOT_FOUND.getMessage());
throw new MallinkException(ErrorCode.MALL_INFO_NOT_FOUND);
}
retMap.put("qrcode_url", mall.getImgQrcodeWeapp());
return retMap;
}

/**
* 识别会员
* @param params
* @return
*/
@Override
public Map<String, String> checkMember(Map<String, String> params) throws MallinkException {
Map<String, String> retMap = new HashMap<>();

String nonceStr = params.get(WxPayConstant.NONCE_STR); // 随机数
String tenantId = params.get(WxPayConstant.TENANT_ID); // 租户ID
String merchantIdStr = params.get(WxPayConstant.MERCHANT_ID); // 商户ID
String memIdStr = params.get(WxPayConstant.MEM_ID); // 会员ID
String memPhoneStr = params.get(WxPayConstant.MEM_PHONE); // 会员手机
String posOrderIdStr = params.get(WxPayConstant.POS_ORDER_ID); // POS订单ID

if (StringUtils.isBlank(tenantId)) {
String errMessage = "request params[tenant_id] error.";
logger.error(errMessage);
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
if (StringUtils.isBlank(merchantIdStr)) {
String errMessage = "request params[merchant_id] error.";
logger.error(errMessage);
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
if (StringUtils.isBlank(posOrderIdStr)) {
String errMessage = "request params[pos_order_id] error.";
logger.error(errMessage);
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}

if (StringUtils.isBlank(memIdStr) && StringUtils.isBlank(memPhoneStr)) {
String errMessage = "please give one value for mem_id or mem_phone";
logger.error(errMessage);
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
WxCUser user = null;
if (StringUtils.isNotBlank(memIdStr)) {
Long memId;
try {
memId = Long.valueOf(memIdStr);
} catch (NumberFormatException e) {
logger.error(e.getMessage());
throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), e.getMessage());
}

user = cUserService.getById(memId);
}
if (StringUtils.isNotBlank(memPhoneStr)) {
WxCUser q = new WxCUser();
q.setTenantId(tenantId);
q.setPhone(memPhoneStr);
user = cUserService.getByObject(q);
}

if (user == null) {
logger.error(ErrorCode.USER_NOT_MEMBER.getMessage());
throw new MallinkException(ErrorCode.USER_NOT_MEMBER);
}

Long merchantId, posOrderId;
try {
merchantId = Long.valueOf(merchantIdStr);
posOrderId = Long.valueOf(posOrderIdStr);
} catch (NumberFormatException e) {
logger.error(e.getMessage());
throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR);
}

// Level, 折扣
List<WxLevelConfig> levelList = levelConfigService.getByTenantId(tenantId);

String level = WxLevelConfigService.DEFAULT_LEVEL;
Long levelId = 0L;
for (WxLevelConfig levelConfig : levelList) {
if (user.getScore() >= levelConfig.getPoints()) {
if (levelConfig.getDiscountEnable().equals(EnumLevelConfigDiscountStatus.ENABLE.getCode()))
levelId = levelConfig.getId();
level = levelConfig.getLevel();
}
}
WxLevelMerchant levelMerchant = new WxLevelMerchant();
levelMerchant.setTenantId(tenantId);
levelMerchant.setLevelId(levelId);
levelMerchant.setMerchantId(merchantId);
List<WxLevelMerchantCVo> levelMerchantList = levelConfigService.findListCVo(levelMerchant);
if(levelMerchantList.size() >= 1) {
WxLevelMerchantCVo levelMerchantCVo = levelMerchantList.get(0);
if(levelMerchantCVo != null) {
retMap.put("discount", levelMerchantCVo.getDiscount().toString());
retMap.put("levelMerchant", levelMerchantCVo.toString());
}
} else {
retMap.put("discount", "100");
}

retMap.put("id", user.getId().toString());
retMap.put("phone", user.getPhone());
retMap.put("level", level);

// 优惠券列表
Map<String, Object> coQ = new HashMap<>();
coQ.put("tenantId", tenantId);
coQ.put("cUserId", user.getId());
coQ.put("merchantId", merchantId);
coQ.put("posOrderId", posOrderId);
List<Map> couponOrderList = couponOrderService.findAvailCouponOrder(coQ);
retMap.put("coupon_order_list", couponOrderList.toString());
return retMap;
}

@Override
public Map<String, String> couponOrderVerifyDoSomething(@RequestBody Map<String, String> params, EnumVerifyActionType actionType) throws MallinkException {
Map<String, String> retMap = new HashMap<>();

String nonceStr = params.get(WxPayConstant.NONCE_STR); // 随机数
String tenantId = params.get(WxPayConstant.TENANT_ID); // 租户ID
String merchantIdStr = params.get(WxPayConstant.MERCHANT_ID); // 商户ID
String buUserIdStr = params.get(WxPayConstant.BUSER_ID); // POS操作员ID
String couponOrderIdStr = params.get(WxPayConstant.COUPON_ORDER_ID); // 券ID
String posOrderIdStr = params.get(WxPayConstant.COUPON_ORDER_ID); // POS订单ID

if (StringUtils.isBlank(tenantId)) {
String errMessage = "request params[tenant_id] error.";
logger.error(errMessage);
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
if (StringUtils.isBlank(merchantIdStr)) {
String errMessage = "request params[merchant_id] error.";
logger.error(errMessage);
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
if (StringUtils.isBlank(buUserIdStr)) {
String errMessage = "request params[bu_user_id] error.";
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
if (StringUtils.isBlank(couponOrderIdStr)) {
String errMessage = "request params[coupon_order_id] error.";
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
if (actionType.equals(EnumVerifyActionType.PRE_VERIFY) || actionType.equals(EnumVerifyActionType.VERIFY_INDEPENT)) {
if (StringUtils.isBlank(posOrderIdStr)) {
String errMessage = "request params[pos_order_id] error.";
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
}

Long merchantId, buUserId, couponOrderId, posOrderId = 0L;
try {
merchantId = Long.valueOf(merchantIdStr);
buUserId = Long.valueOf(buUserIdStr);
couponOrderId = Long.valueOf(couponOrderIdStr);
if (actionType.equals(EnumVerifyActionType.PRE_VERIFY) ||
actionType.equals(EnumVerifyActionType.VERIFY_INDEPENT) ||
actionType.equals(EnumVerifyActionType.VERIFY_PAY)) {
posOrderId = Long.valueOf(posOrderIdStr);
}
} catch (NumberFormatException e) {
logger.error(e.getMessage());
throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), e.getMessage());
}
// 2. check merchant
WxMerchant merchant = merchantService.getById(merchantId);
if (merchant == null) {
logger.error(ErrorCode.MERCHANT_INFO_NOT_FOUND.getMessage() + ": " + merchantIdStr);
throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND);
}
if (merchant.getIsDel().equals(EnumDelStatus.DEL.getCode()) || merchant.getStatus().equals(EnumMerchantStatus.NOT_VALID.getCode())) {
logger.error(ErrorCode.MERCHANT_INFO_NOT_VALID.getMessage() + ": " + merchantIdStr);
throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_VALID);
}
// 3. check buUser
WxMerchantBUser buUser = merchantBUserService.getById(buUserId);
if (buUser == null) {
logger.error(ErrorCode.USER_IS_EMPTY.getMessage() + ": " + buUserIdStr);
throw new MallinkException(ErrorCode.USER_IS_EMPTY);
}
if (!buUser.getMerchantId().equals(merchantId)) {
logger.error(ErrorCode.VERIFY_BUSER_MERCHANT_NOT_BELONG.getMessage() + ": " + buUserIdStr);
throw new MallinkException(ErrorCode.VERIFY_BUSER_MERCHANT_NOT_BELONG);
}
// 4. check couponOrderId
WxCouponOrderCVo couponOrderCVo = couponOrderService.detailCUserVo(couponOrderIdStr);
if (couponOrderCVo == null) {
logger.error(ErrorCode.COUPON_ORDER_IS_NULL.getMessage() + ": " + couponOrderIdStr);
throw new MallinkException(ErrorCode.COUPON_ORDER_IS_NULL);
}

// 5. get coupon
WxCoupon wxCoupon = couponMapper.selectByPrimaryKey(couponOrderCVo.getCouponId());
if (wxCoupon == null) {
logger.error("券: coupon-" + wxCoupon.getId() + "不存在" + "couponOrder-" + couponOrderCVo.getId());
throw new MallinkException(ErrorCode.COUPON_ORDER_IS_NULL);
}

// 5. 检查有效期
if (couponOrderCVo.getValidStartDate() != null && couponOrderCVo.getValidEndDate() != null) {
Date now = new Date();
if (couponOrderCVo.getValidStartDate().getTime() > now.getTime()) {
logger.error("此券有效期未开始:" + couponOrderIdStr);
throw new MallinkException(ErrorCode.COUPON_ORDER_IS_EARLIER_THAN_VALIDDATE);
}
if (couponOrderCVo.getValidEndDate().getTime() < now.getTime()) {
logger.error("此券有效期已结束:" + couponOrderIdStr);
throw new MallinkException(ErrorCode.COUPON_ORDER_IS_EARLIER_THAN_VALIDDATE);
}
}
// 6. 检查适用门店
WxCouponMerchant wxCouponMerchant = new WxCouponMerchant();
wxCouponMerchant.setProductId(couponOrderCVo.getCouponId());
wxCouponMerchant.setStatus(EnumCouponMerchantStatus.COUPON_MERCHANT_STATUS_VALID.getCode());
List<WxCouponMerchant> couponMerchantList = couponMerchantMapper.findList(wxCouponMerchant);
if (!couponMerchantList.stream().anyMatch(cm->cm.getMerchantId().equals(merchantId))){
logger.error("券: coupon-" + couponOrderCVo.getCouponId() + "核销: couponMerchantId-" + merchantIdStr + " 门店不适用");
throw new MallinkException(ErrorCode.VERIFY_COUPON_ORDER_MERCHANT_IS_NULL);
}

// 7. 券包状态检查
if (couponOrderCVo.getCouponOrderStatus() == EnumCouponOrderStatus.COUPON_ORDER_OVER_TIME.getCode()) {
logger.error("已过期: couponOrder-" + couponOrderCVo.getId());
throw new MallinkException(ErrorCode.COUPON_ORDER_IS_OVER_TIME);
}
if (couponOrderCVo.getCouponOrderStatus() == EnumCouponOrderStatus.COUPON_ORDER_INVALID.getCode()) {
logger.error("已作废: couponOrder-" + couponOrderCVo.getId());
throw new MallinkException(ErrorCode.COUPON_ORDER_IS_INVALID);
}
if (couponOrderCVo.getCouponOrderStatus() == EnumCouponOrderStatus.COUPON_ORDER_USED.getCode()) {
logger.error("已经核销过的券: couponOrder-" + couponOrderCVo.getId());
throw new MallinkException(ErrorCode.COUPON_ORDER_IS_USED);
}
if (couponOrderCVo.getCouponOrderStatus().equals(EnumCouponOrderStatus.POS_PRE_VERIFY.getCode())) {
logger.info("券已被预核销: " + couponOrderIdStr);
if (!couponOrderCVo.getBUserId().equals(buUserId)) {
logger.error(ErrorCode.VERIFY_PRE_BUSER_NOT_EQUAL.getMessage() + ": " + buUserIdStr);
throw new MallinkException(ErrorCode.VERIFY_PRE_BUSER_NOT_EQUAL);
}
if (actionType.equals(EnumVerifyActionType.CHECK)) {
if (StringUtils.isBlank(posOrderIdStr)) {
logger.error(ErrorCode.VERIFY_PRE_POS_ORDER_IS_EMPTY.getMessage());
throw new MallinkException(ErrorCode.VERIFY_PRE_POS_ORDER_IS_EMPTY);
}
try {
posOrderId = Long.valueOf(posOrderIdStr);
} catch (NumberFormatException e) {
logger.error("pos_order_id转换异常");
throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(),
ErrorCode.SYS_PARAMETER_CAST_ERROR.getMessage() + ", pos_order_id:" + posOrderIdStr);
}
}
// check pos order是否一致
PosCouponOrderVerify posCouponOrderVerifyQ = new PosCouponOrderVerify();
posCouponOrderVerifyQ.setTenantId(tenantId);
posCouponOrderVerifyQ.setCouponOrderId(couponOrderId);
posCouponOrderVerifyQ.setPosOrderId(posOrderId);
posCouponOrderVerifyQ.setState(EnumEnableType.Enable.getCode());
List<PosCouponOrderVerify> posCouponOrderVerifyList = posCouponOrderVerifyService.getList(posCouponOrderVerifyQ);
if (posCouponOrderVerifyList.size() != 1) {
logger.error(ErrorCode.VERIFY_PRE_POS_ORDER_NOT_EQUAL.getMessage() + ": " + posOrderIdStr);
throw new MallinkException(ErrorCode.VERIFY_PRE_POS_ORDER_NOT_EQUAL);
}
logger.info("券可以核销: " + couponOrderIdStr);
if (actionType.equals(EnumVerifyActionType.CHECK)) {
return retMap;
}
if (actionType.equals(EnumVerifyActionType.VERIFY_INDEPENT) || actionType.equals(EnumVerifyActionType.VERIFY_PAY)) {
try {
doVerify(couponOrderCVo, wxCoupon, merchantId, buUserId, posOrderId, retMap);
return retMap;
} catch (MallinkException e) {
logger.error(e.getMessage());
throw new MallinkException(e.getErrorCode(), e.getMessage());
} catch (Exception e) {
logger.error(e.getMessage());
throw new MallinkException(500, e.getMessage());
}
}
}
if (couponOrderCVo.getCouponOrderStatus().equals(EnumCouponOrderStatus.COUPON_ORDER_USE_WAIT.getCode())) {
logger.info("券可以核销: " + couponOrderIdStr);
if (actionType.equals(EnumVerifyActionType.CHECK)) {
return retMap;
}
if (actionType.equals(EnumVerifyActionType.PRE_VERIFY)) {
try {
doPreVerify(couponOrderCVo, buUserId, posOrderId);
return retMap;
} catch (MallinkException e) {
logger.error(e.getMessage());
throw new MallinkException(e.getErrorCode(), e.getMessage());
} catch (Exception e) {
logger.error(e.getMessage());
throw new MallinkException(500, e.getMessage());
}
}
if (actionType.equals(EnumVerifyActionType.VERIFY_INDEPENT) || actionType.equals(EnumVerifyActionType.VERIFY_PAY)) {
try {
doVerify(couponOrderCVo, wxCoupon, merchantId, buUserId, posOrderId, retMap);
return retMap;
} catch (MallinkException e) {
logger.error(e.getMessage());
throw new MallinkException(e.getErrorCode(), e.getMessage());
} catch (Exception e) {
logger.error(e.getMessage());
throw new MallinkException(500, e.getMessage());
}
}
}
String errMessage = "核销异常:未知的核销状态" + couponOrderCVo.getCouponOrderStatus();
logger.error(errMessage);
throw new MallinkException(500, errMessage);
}

@Override
public Map<String, String> couponOrderVerifyCancel(Map<String, String> params, EnumVerifyActionType actionType) {
Map<String, String> retMap = new HashMap<>();

String nonceStr = params.get(WxPayConstant.NONCE_STR); // 随机数
String tenantId = params.get(WxPayConstant.TENANT_ID); // 租户ID
String merchantIdStr = params.get(WxPayConstant.MERCHANT_ID); // 商户ID
String buUserIdStr = params.get(WxPayConstant.BUSER_ID); // POS操作员ID
String couponOrderIdStr = params.get(WxPayConstant.COUPON_ORDER_ID); // 券ID
String posOrderIdStr = params.get(WxPayConstant.COUPON_ORDER_ID); // POS订单ID

if (StringUtils.isBlank(tenantId)) {
String errMessage = "request params[tenant_id] error.";
logger.error(errMessage);
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
if (StringUtils.isBlank(merchantIdStr)) {
String errMessage = "request params[merchant_id] error.";
logger.error(errMessage);
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
if (StringUtils.isBlank(buUserIdStr)) {
String errMessage = "request params[bu_user_id] error.";
logger.error(errMessage);
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
if (StringUtils.isBlank(couponOrderIdStr)) {
String errMessage = "request params[coupon_order_id] error.";
logger.error(errMessage);
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
if (actionType.equals(EnumVerifyActionType.PRE_VERIFY) || actionType.equals(EnumVerifyActionType.VERIFY_INDEPENT)) {
if (StringUtils.isBlank(posOrderIdStr)) {
String errMessage = "request params[pos_order_id] error.";
logger.error(errMessage);
throw new MallinkException(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), errMessage);
}
}

Long merchantId, buUserId, couponOrderId, posOrderId = 0L;
try {
merchantId = Long.valueOf(merchantIdStr);
buUserId = Long.valueOf(buUserIdStr);
couponOrderId = Long.valueOf(couponOrderIdStr);
posOrderId = Long.valueOf(posOrderIdStr);
} catch (NumberFormatException e) {
logger.error(e.getMessage());
throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR);
}
// 2. check merchant
WxMerchant merchant = merchantService.getById(merchantId);
if (merchant == null) {
logger.error(ErrorCode.MERCHANT_INFO_NOT_FOUND.getMessage() + ": " + merchantIdStr);
throw new MallinkException(ErrorCode.MERCHANT_INFO_NOT_FOUND);
}
// 3. check buUser
WxMerchantBUser buUser = merchantBUserService.getById(buUserId);
if (buUser == null) {
logger.error(ErrorCode.USER_IS_EMPTY.getMessage() + ": " + buUserIdStr);
throw new MallinkException(ErrorCode.USER_IS_EMPTY);
}
// 4. check couponOrderId
WxCouponOrderCVo couponOrderCVo = couponOrderService.detailCUserVo(couponOrderIdStr);
if (couponOrderCVo == null) {
logger.error(ErrorCode.COUPON_ORDER_IS_NULL.getMessage() + ": " + couponOrderIdStr);
throw new MallinkException(ErrorCode.COUPON_ORDER_IS_NULL);
}
// 6. 检查适用门店
WxCouponMerchant wxCouponMerchant = new WxCouponMerchant();
wxCouponMerchant.setProductId(couponOrderCVo.getCouponId());
wxCouponMerchant.setStatus(EnumCouponMerchantStatus.COUPON_MERCHANT_STATUS_VALID.getCode());
List<WxCouponMerchant> couponMerchantList = couponMerchantMapper.findList(wxCouponMerchant);
if (!couponMerchantList.stream().anyMatch(cm->cm.getMerchantId().equals(merchantId))){
logger.error("券: coupon-" + couponOrderCVo.getCouponId() + "核销: couponMerchantId-" + merchantIdStr + " 门店不适用");
throw new MallinkException(ErrorCode.VERIFY_COUPON_ORDER_MERCHANT_IS_NULL);
}

WxCouponOrder couponOrder = new WxCouponOrder();
couponOrder.setId(couponOrderCVo.getId());

// 预核销取消
if (couponOrderCVo.getCouponOrderStatus().equals(EnumCouponOrderStatus.POS_PRE_VERIFY.getCode()) &&
actionType.equals(EnumVerifyActionType.PRE_VERIFY_CANCEL)) {
logger.info("券已被预核销: " + couponOrderIdStr);
if (!couponOrderCVo.getBUserId().equals(buUserId)) {
logger.error(ErrorCode.VERIFY_PRE_BUSER_NOT_EQUAL.getMessage() + ": " + buUserIdStr);
throw new MallinkException(ErrorCode.VERIFY_PRE_BUSER_NOT_EQUAL);
}
try {
cancelPreVerify(couponOrderCVo, buUserId, posOrderId);
} catch (MallinkException e) {
logger.error(e.getMessage());
throw new MallinkException(e.getErrorCode(), e.getMessage());
}
}
// 核销取消
if (couponOrderCVo.getCouponOrderStatus().equals(EnumCouponOrderStatus.COUPON_ORDER_USED.getCode()) &&
actionType.equals(EnumVerifyActionType.VERIFY_CANCEL)) {
logger.info("券已被核销: " + couponOrderIdStr);
try {
cancelVerify(couponOrderCVo, buUserId, posOrderId);
} catch (MallinkException e) {
logger.error(e.getMessage());
throw new MallinkException(e.getErrorCode(), e.getMessage());
}
}
String errMessage = "取消异常:未知的核销状态" + couponOrderCVo.getCouponOrderStatus();
logger.error(errMessage);
throw new MallinkException(500, errMessage);
}

/**
* 预核销
* @param buUserId
* @param couponOrderCVo
* @param posOrderId
*/
@Transactional(rollbackFor = Exception.class)
public void doPreVerify(WxCouponOrderCVo couponOrderCVo, Long buUserId, Long posOrderId) {
int num = 0;
// 1. insert posOrderId
PosCouponOrderVerify posCouponOrderVerify = new PosCouponOrderVerify();
posCouponOrderVerify.setTenantId(couponOrderCVo.getTenantId());
posCouponOrderVerify.setCouponOrderId(couponOrderCVo.getId());
posCouponOrderVerify.setPosOrderId(posOrderId);
posCouponOrderVerify.setState(EnumEnableType.Enable.getCode());
posCouponOrderVerify.setCreateDate(new Date());
posCouponOrderVerify.setUpdateDate(new Date());
try {
posCouponOrderVerifyService.saveOrUpdate(posCouponOrderVerify);
} catch (Exception e) {
logger.error("db failed: couponOrder-" + couponOrderCVo.getId() + ", e:" + e.getMessage());
throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
}

// 2. update couponOrder
try {
WxCouponOrder couponOrder = new WxCouponOrder();
couponOrder.setId(couponOrderCVo.getId());
couponOrder.setCouponOrderStatus(EnumCouponOrderStatus.POS_PRE_VERIFY.getCode());
couponOrder.setBUserId(buUserId);
couponOrder.setUpdateDate(new Date());
num = couponOrderMapper.updateVerifyCouponOrder(couponOrder);
} catch (Exception e) {
logger.error("db failed: couponOrder-" + couponOrderCVo.getId() + ", e:" + e.getMessage());
throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
}
if (num != 1) {
logger.error("核销异常:updatete num " + num);
throw new MallinkException(ErrorCode.VERIFY_ERROR.getCode(), "updatete num " + num);
}
}

/**
* 预核销回退
* @param couponOrderCVo
* @param buUserId
* @param posOrderId
*/
@Transactional(rollbackFor = Exception.class)
public void cancelPreVerify(WxCouponOrderCVo couponOrderCVo, Long buUserId, Long posOrderId) {
int num = 0;
// 1. update posOrderId
PosCouponOrderVerify posCouponOrderVerify = new PosCouponOrderVerify();
posCouponOrderVerify.setTenantId(couponOrderCVo.getTenantId());
posCouponOrderVerify.setCouponOrderId(couponOrderCVo.getId());
posCouponOrderVerify.setPosOrderId(posOrderId);
posCouponOrderVerify.setState(EnumEnableType.Enable.getCode());
List<PosCouponOrderVerify> posCouponOrderVerifyList = posCouponOrderVerifyService.getList(posCouponOrderVerify);
if (posCouponOrderVerifyList.size() == 1) {
try {
PosCouponOrderVerify updateOrder = new PosCouponOrderVerify();
updateOrder.setId(posCouponOrderVerify.getId());
updateOrder.setState(EnumEnableType.Disable.getCode());
updateOrder.setUpdateDate(new Date());
posCouponOrderVerifyService.saveOrUpdate(updateOrder);
} catch (Exception e) {
logger.error("db failed: couponOrder-" + couponOrderCVo.getId() + ", e:" + e.getMessage());
throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
}
} else {
logger.error(ErrorCode.VERIFY_PRE_POS_ORDER_NOT_EQUAL.getMessage() + ": " + posOrderId);
throw new MallinkException(ErrorCode.VERIFY_PRE_POS_ORDER_NOT_EQUAL);
}

// 2. update couponOrder
try {
WxCouponOrder couponOrder = new WxCouponOrder();
couponOrder.setId(couponOrderCVo.getId());
couponOrder.setCouponOrderStatus(EnumCouponOrderStatus.COUPON_ORDER_USE_WAIT.getCode());
couponOrder.setBUserId(buUserId);
couponOrder.setUpdateDate(new Date());
num = couponOrderMapper.updateVerifyCouponOrder(couponOrder);
} catch (Exception e) {
logger.error("db failed: couponOrder-" + couponOrderCVo.getId() + ", e:" + e.getMessage());
throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
}
if (num != 1) {
logger.error("核销异常:updatete num " + num);
throw new MallinkException(ErrorCode.VERIFY_ERROR.getCode(), "updatete num " + num);
}
}

/**
* 核销
* @param couponOrderCVo
* @param merchantId
* @param buUserId
* @param posOrderId
*/
@Transactional(rollbackFor = Exception.class)
public void doVerify(WxCouponOrderCVo couponOrderCVo, WxCoupon coupon, Long merchantId, Long buUserId, Long posOrderId, Map<String, String> retMap) {
int num = 0;
// 1. insert posOrderId
PosCouponOrderVerify posCouponOrderVerify = new PosCouponOrderVerify();
posCouponOrderVerify.setTenantId(couponOrderCVo.getTenantId());
posCouponOrderVerify.setCouponOrderId(couponOrderCVo.getId());
posCouponOrderVerify.setPosOrderId(posOrderId);
posCouponOrderVerify.setState(EnumEnableType.Enable.getCode());
List<PosCouponOrderVerify> posCouponOrderVerifyList = posCouponOrderVerifyService.getList(posCouponOrderVerify);
if (posCouponOrderVerifyList.size() == 0) {
try {
posCouponOrderVerifyService.saveOrUpdate(posCouponOrderVerify);
} catch (Exception e) {
logger.error("db failed: couponOrder-" + couponOrderCVo.getId() + ", e:" + e.getMessage());
throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
}
} else if (posCouponOrderVerifyList.size() == 1){

} else if (posCouponOrderVerifyList.size() > 1){

}
// 2. update couponOrder
try {
WxCouponOrder couponOrder = new WxCouponOrder();
couponOrder.setId(couponOrderCVo.getId());
couponOrder.setTenantId(couponOrderCVo.getTenantId());
couponOrder.setCouponOrderStatus(EnumCouponOrderStatus.COUPON_ORDER_USED.getCode()); //1核销
couponOrder.setBUserId(buUserId);
couponOrder.setUpdateDate(new Date());
num = couponOrderMapper.updateVerifyCouponOrder(couponOrder);
} catch (Exception e) {
logger.error("db failed: couponOrder-" + couponOrderCVo.getId() + ", e:" + e.getMessage());
throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
}
if (num != 1) {
logger.error("核销异常:updatete num " + num);
throw new MallinkException(ErrorCode.VERIFY_ERROR.getCode(), "updatete num " + num);
}

// 3. 成长值
try {
WxOrder order = orderMapper.selectByPrimaryKey(couponOrderCVo.getOrderId());
int point = scoreRulesService.addScore2(EnumScoreType.CONSUMPTION, order, couponOrderCVo.getBusinessId());
retMap.put("point", String.valueOf(point));
} catch (Exception e) {
logger.error("核销成长值异常:" + e.getMessage());
}

// 4. 积分
try {
//-------此处为【现金支付】记录增加积分操作-------
WxCreditHistory creditHistory = new WxCreditHistory();
creditHistory.setOperatorType(EnumUserType.BUSER.getCode());
creditHistory.setOperatorId(buUserId);
creditHistory.setCUserId(couponOrderCVo.getcUserId());
creditHistory.setCreateDate(new Date());
creditHistory.setTenantId(couponOrderCVo.getTenantId());
creditHistory.setCreditType(EnumScoreType.CONSUMPTION.getCode());
creditHistory.setCouponId(couponOrderCVo.getCouponId());
creditHistory.setBusinessId(Long.valueOf(coupon.getBusiness()));
creditHistory.setSpend(couponOrderCVo.getCouponPrice());
//如果券与商户一对一 则直接将消费商户更新为此商户 若一对多 则消费商户显示多商户
creditHistory.setMerchantId(merchantId);
creditHistory = creditHistoryService.saveOrUpdate(creditHistory);
if (creditHistory.getCreditNum() != null) {
retMap.put("credit", String.valueOf(creditHistory.getCreditNum()));
}
} catch (Exception e) {
logger.error("核销积分值异常:" + e.getMessage());
}
}

/**
* 核销回退
* @param couponOrderCVo
* @param buUserId
* @param posOrderId
*/
@Transactional(rollbackFor = Exception.class)
public void cancelVerify(WxCouponOrderCVo couponOrderCVo, Long buUserId, Long posOrderId) {
// 1. 积分历史回退
try {
WxCreditHistory creditHistory = new WxCreditHistory();
creditHistory.setOperatorType(EnumUserType.BUSER.getCode());
creditHistory.setOperatorId(buUserId);
creditHistory.setCUserId(couponOrderCVo.getcUserId());
creditHistory.setTenantId(couponOrderCVo.getTenantId());
creditHistory.setCreditType(EnumScoreType.CONSUMPTION.getCode());
creditHistory.setCouponId(couponOrderCVo.getCouponId());
int num = creditHistoryService.cancelCredit(creditHistory);
if (num <= 1) {
logger.error("核销积分历史回退失败: " + creditHistory.toString());
return;
}
} catch (Exception e) {
logger.error("核销积分历史回退:" + e.getMessage());
}
// 2. 成长值历史回退
try {
WxScoreHistory scoreHistory = new WxScoreHistory();
scoreHistory.setTenantId(couponOrderCVo.getTenantId());
scoreHistory.setScoreType(EnumScoreType.CONSUMPTION.getCode());
scoreHistory.setCUserId(couponOrderCVo.getcUserId());
scoreHistory.setOrderId(couponOrderCVo.getOrderId());
int num = scoreRulesService.cancelScore(scoreHistory);
if (num <= 1) {
logger.error("核销成长值历史回退失败: " + scoreHistory.toString());
return;
}
} catch (Exception e) {
logger.error("核销成长值历史回退:" + e.getMessage());
}

// 3. update posOrderId
PosCouponOrderVerify posCouponOrderVerify = new PosCouponOrderVerify();
posCouponOrderVerify.setTenantId(couponOrderCVo.getTenantId());
posCouponOrderVerify.setCouponOrderId(couponOrderCVo.getId());
posCouponOrderVerify.setPosOrderId(posOrderId);
posCouponOrderVerify.setState(EnumEnableType.Enable.getCode());
List<PosCouponOrderVerify> posCouponOrderVerifyList = posCouponOrderVerifyService.getList(posCouponOrderVerify);
if (posCouponOrderVerifyList.size() == 1) {
try {
PosCouponOrderVerify updateOrder = new PosCouponOrderVerify();
updateOrder.setId(posCouponOrderVerify.getId());
updateOrder.setState(EnumEnableType.Disable.getCode());
updateOrder.setUpdateDate(new Date());
posCouponOrderVerifyService.saveOrUpdate(updateOrder);
} catch (Exception e) {
logger.error("db failed: couponOrder-" + couponOrderCVo.getId() + ", e:" + e.getMessage());
throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
}
} else {
logger.error(ErrorCode.VERIFY_PRE_POS_ORDER_NOT_EQUAL.getMessage() + ": " + posOrderId);
throw new MallinkException(ErrorCode.VERIFY_PRE_POS_ORDER_NOT_EQUAL);
}
// 4. update couponOrder
int num = 0;
try {
WxCouponOrder couponOrder = new WxCouponOrder();
couponOrder.setId(couponOrderCVo.getId());
couponOrder.setCouponOrderStatus(EnumCouponOrderStatus.COUPON_ORDER_USED.getCode()); //1核销
couponOrder.setBUserId(buUserId);
couponOrder.setUpdateDate(new Date());
num = couponOrderMapper.updateVerifyCouponOrder(couponOrder);
} catch (Exception e) {
logger.error("db failed: couponOrder-" + couponOrderCVo.getId() + ", e:" + e.getMessage());
throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
}
if (num != 1) {
logger.error("核销异常:updatete num " + num);
throw new MallinkException(ErrorCode.VERIFY_ERROR.getCode(), "updatete num " + num);
}
}
}

+ 116
- 0
mallinkPosApi/src/main/resources/application-dev.yml View File

@@ -0,0 +1,116 @@
spring:
profiles:
include: rabbitMQ
# JDBC
datasource:
url: jdbc:mysql://202.165.179.86:3306/mallinkDevW?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useUnicode=true&useSSL=false&useAffectedRows=true
username: ENC(dZ8fmrtuBMQYaRytKQgTqg==)
password: ENC(IKH7HxMZwIqMttMc9+QsqWa1KMsJvTs4)
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 28000
minEvictableIdleTimeMillis: 28000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
#jackson:
#date-format: yyyy-MM-dd HH:mm:ss
# REDIS
redis:
host: 202.165.179.86
port: 6379
password: ENC(xPFDlgd6v8zUhJMbcKc0KmmQiqs9qHtk)
timeout: 3600
expire: 1800 #30分钟
database: 1
defaultExpiration: 2592000 # 默认生命周期30天
jedis:
pool:
max-active: 50
max-idle: 30
max-wait: -1
min-idle: 0
# EMAIL
mail:
host: smtp.exmail.qq.com
username: ENC(lknBjZsA24AaQEXuy0fFw3acd4v4Xsf3CsgDcRZgjlYnNAL9R07d/w==)
password: ENC(gIkVPuYMmJ/EDxry8QIfGumIAk4plAwolGrfg1fiM3U=) # 授权密码
properties:
mail:
smtp:
auth: true
starttls:
enable: true
socketFactory:
port: 465
class: javax.net.ssl.SSLSocketFactory
# ROCKETMQ
rocketmq:
nameServer: 127.0.0.1:9876
producer:
retry-times-when-send-async-failed: 0
send-msg-timeout: 300000
compress-msg-body-over-howmuch: 4096
max-message-size: 4194304
retry-another-broker-when-not-store-ok: false
retry-times-when-send-failed: 2
# RABBITMQ
rabbitmq:
host: 202.165.179.86
port: 5672
username: ENC(2f9Nqt3c4cbVGYnhpjp9Mg==)
password: ENC(2av0JfMfz141IHkG6ibI8aKzmD33bc64wcN/O43ucbo=)
publisher-confirms: true
virtual-host: /

aws:
clientRegion: cn-northwest-1
bucketName: iformall-net
access: ENC(3gx5ghDFBqGrEhO3Wf8aYmXsnwHO7Cj3HNKJGOeUj0o=)
secret: ENC(HVKIJwCJKVXLlUpGlQPwNqJOlnpxn4xYuy91SH0seTSm2uAttIQHvA49fXWWax90v5wloIk0QuU=)

jasypt:
encryptor:
password: oRqdnDbK5pj3eMmB

wechat:
open:
componentAppId: "wx897e4673286c915d"
componentSecret: "cdfdfda65c45689beb6766c4c427eed2"
componentToken: "formall2018"
componentAesKey: "htKq8EjBMPNndfZQK9JiFojFaqFwFpw42VfeWFtx7HN"
redis:
host: 202.165.179.86
port: 6379
password: ENC(xPFDlgd6v8zUhJMbcKc0KmmQiqs9qHtk)
timeout: 3600
expire: 1800 #30分钟
database: 2
defaultExpiration: 2592000 # 默认生命周期30天
jedis:
pool:
max-active: 100
max-idle: 500
max-wait: -1
min-idle: 10

fm:
exception: false
exception_emails: hupeng@iformall.com,wuguoqiang@iformall.com,gongbiao@iformall.com,luozukai@iformall.com
deploy: 1
open: true
upload_dir: /home/test/server/uploads

logging:
level:
tk.mybatis: debug
com.iformall.mapper: debug
path: ./logs/b

+ 100
- 0
mallinkPosApi/src/main/resources/application-prod.yml View File

@@ -0,0 +1,100 @@
spring:
profiles:
include: rabbitMQ
# JDBC
datasource:
url: jdbc:mysql://formalldb.cfqyqflkdlit.rds.cn-northwest-1.amazonaws.com.cn:3306/mallink?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&useSSL=false&useAffectedRows=true
username: ENC(NUzgQOdJnCbVLKT6BaX0aw==)
password: ENC(mvuoDRiu0jqYaKNRwwTuXZ6U7aoIaqsjdiPqTLgi/nY=)
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 28000
minEvictableIdleTimeMillis: 28000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
# REDIS
redis:
host: 127.0.0.1
port: 6379
password: ENC(8gYU47Fu93NUJPhwPCiPbAT+6VFA1YDx1egK4Z0Nl6w=)
timeout: 3600
expire: 1800 #30分钟
database: 1
defaultExpiration: 2592000 # 默认生命周期30天
jedis:
pool:
max-active: 100
max-idle: 20
max-wait: -1
min-idle: 0
# EMAIL
mail:
host: smtp.exmail.qq.com
username: ENC(IiL/PHP9wCkpibWHRH/Mts8K9fh4izYqaiaF66bDrqtEHP+KUcJRRg==)
password: ENC(m7L57m8mk6tApVoa4XIDQnXF0VxnYjKe4LVdzcgb+xY=) # 授权密码
properties:
mail:
smtp:
auth: true
starttls:
enable: true
socketFactory:
port: 465
class: javax.net.ssl.SSLSocketFactory
# RABBITMQ
rabbitmq:
host: localhost
port: 5672
username: ENC(lRmLd6EzgeY1RT5ktcHv9g==)
password: ENC(gBI8mCjr3OC0v57jcnSb660Ux7mW03K2oePgvohhg7w=)
publisher-confirms: true
virtual-host: /

aws:
clientRegion: cn-northwest-1
bucketName: iformall-net
access: ENC(a6SN1sZ1enNL49ypiOXkg/pPPAnZD8H4buQFTTKN08s=)
secret: ENC(5P5ff4bTMJUbXVR4ZsM03UHzOKZ4+Zg5Iutcdkyp/Quny/oXg+A4KpfwEyGarlLu3vQMJahGP5M=)

wechat:
open:
componentAppId: ENC(b3JG0MUZgQfz5Zj+DC2ZM1zDeLOiGTmmeokfe2O8kaM=)
componentSecret: ENC(QVyc4BPGdnSjXGs2ivgpDBE1v8wPWHLLRMYI7Vv8uYwC0SiZHQz0QpyyQV/b48Pb)
componentToken: ENC(rkxj0733WxFFDLgA9x01m2s5Fi2L+0PC)
componentAesKey: ENC(EIbJUBpbYOrLb4YQ/HXLQmxlxgAqIp2ZmpnGICC8pu5xiTz3Cqfkbwd2S8raCcK/IvYcX2GmedI=)
redis:
host: 127.0.0.1
port: 6379
password: ENC(8gYU47Fu93NUJPhwPCiPbAT+6VFA1YDx1egK4Z0Nl6w=)
timeout: 3600
expire: 1800 #30分钟
database: 2
defaultExpiration: 2592000 # 默认生命周期30天
jedis:
pool:
max-active: 100
max-idle: 100
max-wait: -1
min-idle: 10

fm:
exception: true
exception_emails: hupeng@iformall.com,wuguoqiang@iformall.com,gongbiao@iformall.com,luozukai@iformall.com
deploy: 3
open: true
upload_dir: /home/ec2-user/server/uploads/

logging:
level:
tk.mybatis: debug
com.iformall.mapper: debug
path: ./logs/b

+ 100
- 0
mallinkPosApi/src/main/resources/application-test.yml View File

@@ -0,0 +1,100 @@
spring:
profiles:
include: rabbitMQ
# JDBC
datasource:
url: jdbc:mysql://formalldb.cfqyqflkdlit.rds.cn-northwest-1.amazonaws.com.cn:3306/mallinkTest?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&useSSL=false&useAffectedRows=true
username: ENC(Uc0AjgkytxHHCwZrmDASWg==)
password: ENC(nV4Mi3bEbBx0Fj7uUyYH55eTaqsFMjKvmNzagicH4pc=)
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 28000
minEvictableIdleTimeMillis: 28000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
# REDIS
redis:
host: 127.0.0.1
port: 6379
password: ENC(QFwqv3NshvvGhFPiP8rwhvbnxk+rFSqhJi8Pw6TogSg=)
timeout: 3600
expire: 1800 #30分钟
database: 1
defaultExpiration: 2592000 # 默认生命周期30天
jedis:
pool:
max-active: 50
max-idle: 30
max-wait: -1
min-idle: 0
# EMAIL
mail:
host: smtp.exmail.qq.com
username: ENC(TtJQE2C4cWo8CpVGMMl5hiy5eykepd96J5XjsW3Kj5fgP+6+5ctDNQ==)
password: ENC(Zh6A6kRtA2ABtH6nzdvsqQSO1/8p3mparJr8neI2BLU=) # 授权密码
properties:
mail:
smtp:
auth: true
starttls:
enable: true
socketFactory:
port: 465
class: javax.net.ssl.SSLSocketFactory
# RABBITMQ
rabbitmq:
host: 127.0.0.1
port: 5672
username: ENC(aSRr6mnSryEqzHHz1hJf1g==)
password: ENC(GnjF/mdqKdvmDYC0tIIso7+20/jBALPw39tiWCYJ4iw=)
publisher-confirms: true
virtual-host: /

aws:
clientRegion: cn-northwest-1
bucketName: iformall-net
access: ENC(NCLcmjwKpAWdn/abD17OKIY7yKepVLWzEpqRYUlURCw=)
secret: ENC(TRcZqql0Rq5PExlMeH/4WiZ/i02b8FXKmLTBChJmbluTa1uoLS9LrHyNEMrqe1DK+QgOAdvqGBo=)

wechat:
open:
componentAppId: ENC(hnH31XdNzArfMfikKgBFpqQuJUl6rVOPFFcAVyb595o=)
componentSecret: ENC(t/GUVX5L+U7LCwSvZ5WmxAnmTMrc/Uy1nljsrokuzzsBL2j6BEVnrS/n7DCdGc/G)
componentToken: ENC(gUF1m0YgCCI2IY54fX6sGLZVlCswA8tG)
componentAesKey: ENC(TYHcrIkICtfrCfGq4HW6s1b/pHf7OD2uyPN11SzJNB0acqJ/4JVX1nuljo/cAtgMG4O05TImLQc=)
redis:
host: 127.0.0.1
port: 6379
password: ENC(QFwqv3NshvvGhFPiP8rwhvbnxk+rFSqhJi8Pw6TogSg=)
timeout: 3600
expire: 1800 #30分钟
database: 2
defaultExpiration: 2592000 # 默认生命周期30天
jedis:
pool:
max-active: 100
max-idle: 100
max-wait: -1
min-idle: 10

fm:
exception: true
exception_emails: hupeng@iformall.com,wuguoqiang@iformall.com,gongbiao@iformall.com,luozukai@iformall.com
deploy: 2
open: true
upload_dir: /home/ec2-user/server/uploads/

logging:
level:
tk.mybatis: debug
com.iformall: debug
path: ./logs/b

+ 52
- 0
mallinkPosApi/src/main/resources/application.yml View File

@@ -0,0 +1,52 @@
server:
port: 4000
servlet:
context-path: /POS

spring:
application:
name: mallink
profiles:
active: dev
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
default-property-inclusion: non_null
rocketmq:
nameServer: 127.0.0.1:9876
producer:
retry-times-when-send-async-failed: 0
send-msg-timeout: 300000
compress-msg-body-over-howmuch: 4096
max-message-size: 4194304
retry-another-broker-when-not-store-ok: false
retry-times-when-send-failed: 2

# @{link} https://github.com/abel533
#Mybatis
mybatis:
type-aliases-package: com.iformall.domain.po
mapper-locations: classpath:mapper/*Mapper.xml
configuration:
map-underscore-to-camel-case: true
cache-enabled: true
lazy-loading-enabled: true
use-generated-keys: true
default-fetch-size: 100
default-statement-timeout: 10

#PageHelper
pagehelper:
helperDialect: mysql
reasonable: false
supportMethodsArguments: true
params: count=countSql
offset-as-page-num: true
page-size-zero: true
row-bounds-with-count: true

mapper:
mappers:
- com.iformall.common.CommonMapper

version: @project.version@

+ 100
- 0
mallinkPosApi/src/main/resources/logback-spring.xml View File

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<!-- 外部指定路径 -->
<springProperty scop="context" name="logPath" source="logging.path" />

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] --%mdc{client}%msg%n</Pattern>
</encoder>
</appender>

<appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/trace.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${logPath}/daily/trace.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>180</maxHistory> <!-- 保留180天 -->
</rollingPolicy>
<layout>
<pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n</pattern>
</layout>
</appender>

<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${logPath}/daily/info.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>180</maxHistory> <!-- 保留180天 -->
</rollingPolicy>
<layout>
<pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n</pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${logPath}/daily/debug.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>180</maxHistory> <!-- 保留180天 -->
</rollingPolicy>
<layout>
<pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n</pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>


<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${logPath}/daily/warn.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>180</maxHistory> <!-- 保留180天 -->
</rollingPolicy>
<layout>
<pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n</pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>



<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${logPath}/daily/error.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>180</maxHistory> <!-- 保留180天 -->
</rollingPolicy>
<layout>
<pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n</pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<root level="TRACE">
<appender-ref ref="TRACE_FILE" />
<appender-ref ref="INFO_FILE" />
<!-- <appender-ref ref="DEBUG_FILE" /> -->
<!-- <appender-ref ref="WARN_FILE" /> -->
<appender-ref ref="ERROR_FILE" />
</root>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

+ 176
- 0
mallinkPosApi/src/test/java/com/iformall/pos/test/PosAppTest.java View File

@@ -0,0 +1,176 @@
package com.iformall.pos.test;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iformall.PosApplication;
import com.iformall.pay.WxPayConstant;
import com.iformall.pay.WxPayment;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;

import java.util.HashMap;
import java.util.Map;

/**
*
* @author Stormeye
*
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = { PosApplication.class})
@ActiveProfiles("dev")
@AutoConfigureMockMvc
public class PosAppTest {

@Autowired
private MockMvc mockMvc;

private static final String devId = "fmpos";
private static final String devReqKey = "ZiGFLC4@3c5sTLZT";
private static final String devResKey = "ugPAM7wd&%p6I0W8";

private static final String tenantId = "456";

@Test
public void versionTest() throws Exception {
// 1. version test
this.mockMvc
.perform(MockMvcRequestBuilders.get("/version"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string("{\"code\":200,\"message\":\"success\",\"data\":\"1.0\"}"))
.andDo(MockMvcResultHandlers.print());
}

@Test
public void signErrorTest() throws Exception {
Map<String, String> reqObj = new HashMap<>();
reqObj.put(WxPayConstant.DEV_ID, "");
reqObj.put(WxPayConstant.TENANT_ID, "456");
reqObj.put(WxPayConstant.MERCHANT_ID, "456");
reqObj.put(WxPayConstant.BUSER_ID, "");
reqObj.put(WxPayConstant.COUPON_ORDER_ID, "");
reqObj.put(WxPayConstant.NONCE_STR, "");
reqObj.put(WxPayConstant.POS_ORDER_ID, "");
reqObj.put(WxPayConstant.SIGN, WxPayment.createSignHMAC(reqObj, devReqKey));
String reqJsonStr = JSONObject.toJSONString(reqObj);
this.mockMvc.perform(MockMvcRequestBuilders.post("/checkCouponOrderForVerify")
.contentType(MediaType.APPLICATION_JSON)
.content(reqJsonStr)
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(MockMvcResultMatchers.jsonPath("$.return_code").value("FAIL"))
.andDo(MockMvcResultHandlers.print());
}

@Test
public void getQrCodeTest() throws Exception {
Map<String, String> reqObj = new HashMap<>();
reqObj.put(WxPayConstant.DEV_ID, devId);
reqObj.put(WxPayConstant.TENANT_ID, tenantId);
reqObj.put(WxPayConstant.SIGN, WxPayment.createSignHMAC(reqObj, devReqKey));
String reqJsonStr = JSONObject.toJSONString(reqObj);
RequestBuilder request = MockMvcRequestBuilders.post("/getQrCode")
.contentType(MediaType.APPLICATION_JSON)
.content(reqJsonStr);
MvcResult result = mockMvc.perform(request).andReturn();
String responseStr = result.getResponse().getContentAsString();
System.out.println(responseStr);

ObjectMapper mapper = new ObjectMapper();
Map<String,String> respMap = mapper.readValue(responseStr, Map.class);
boolean resSigned = WxPayment.verifyNotifyHMAC(respMap, devResKey);
System.out.println("response sign: " + resSigned);
Assert.assertEquals(resSigned, true);
}

@Test
public void getMemTest() throws Exception {
Map<String, String> reqObj = new HashMap<>();
reqObj.put(WxPayConstant.DEV_ID, devId);
reqObj.put(WxPayConstant.TENANT_ID, tenantId);
reqObj.put(WxPayConstant.MERCHANT_ID, "317109453987631104");
// reqObj.put(WxPayConstant.MEM_ID, "318314000718200832");
reqObj.put(WxPayConstant.MEM_PHONE, "13910154397");
reqObj.put(WxPayConstant.POS_ORDER_ID, "1");
reqObj.put(WxPayConstant.SIGN, WxPayment.createSignHMAC(reqObj, devReqKey));
String reqJsonStr = JSONObject.toJSONString(reqObj);
RequestBuilder request = MockMvcRequestBuilders.post("/checkMem")
.contentType(MediaType.APPLICATION_JSON)
.content(reqJsonStr);
MvcResult result = mockMvc.perform(request).andReturn();
String responseStr = result.getResponse().getContentAsString();
System.out.println(responseStr);

ObjectMapper mapper = new ObjectMapper();
Map<String,String> respMap = mapper.readValue(responseStr, Map.class);
boolean resSigned = WxPayment.verifyNotifyHMAC(respMap, devResKey);
System.out.println("response sign: " + resSigned);
Assert.assertEquals(resSigned, true);
}

@Test
public void checkCouponOrderForVerifyTest() throws Exception {
Map<String, String> reqObj = new HashMap<>();
reqObj.put(WxPayConstant.DEV_ID, devId);
reqObj.put(WxPayConstant.TENANT_ID, "456");
reqObj.put(WxPayConstant.MERCHANT_ID, "317109453987631104");
reqObj.put(WxPayConstant.BUSER_ID, "317111133332426752");
reqObj.put(WxPayConstant.COUPON_ORDER_ID, "318978990426783744");
reqObj.put(WxPayConstant.NONCE_STR, "1");
reqObj.put(WxPayConstant.POS_ORDER_ID, "1");
reqObj.put(WxPayConstant.SIGN, WxPayment.createSignHMAC(reqObj, devReqKey));
String reqJsonStr = JSONObject.toJSONString(reqObj);
RequestBuilder request = MockMvcRequestBuilders.post("/checkCouponOrderForVerify")
.contentType(MediaType.APPLICATION_JSON)
.content(reqJsonStr);
MvcResult result = mockMvc.perform(request).andReturn();
String responseStr = result.getResponse().getContentAsString();
System.out.println(responseStr);

ObjectMapper mapper = new ObjectMapper();
Map<String,String> respMap = mapper.readValue(responseStr, Map.class);
boolean resSigned = WxPayment.verifyNotifyHMAC(respMap, devResKey);
System.out.println("response sign: " + resSigned);
Assert.assertEquals(resSigned, true);
}

@Test
public void couponOrderIndependForVerifyTest() throws Exception {
Map<String, String> reqObj = new HashMap<>();
reqObj.put(WxPayConstant.DEV_ID, devId);
reqObj.put(WxPayConstant.TENANT_ID, "456");
reqObj.put(WxPayConstant.MERCHANT_ID, "317109453987631104");
reqObj.put(WxPayConstant.BUSER_ID, "317111133332426752");
reqObj.put(WxPayConstant.COUPON_ORDER_ID, "318978990426783744");
reqObj.put(WxPayConstant.NONCE_STR, "1");
reqObj.put(WxPayConstant.POS_ORDER_ID, "1");
reqObj.put(WxPayConstant.SIGN, WxPayment.createSignHMAC(reqObj, devReqKey));
String reqJsonStr = JSONObject.toJSONString(reqObj);
RequestBuilder request = MockMvcRequestBuilders.post("/couponOrderIndependentVerify")
.contentType(MediaType.APPLICATION_JSON)
.content(reqJsonStr);
MvcResult result = mockMvc.perform(request).andReturn();
String responseStr = result.getResponse().getContentAsString();
System.out.println(responseStr);

ObjectMapper mapper = new ObjectMapper();
Map<String,String> respMap = mapper.readValue(responseStr, Map.class);
boolean resSigned = WxPayment.verifyNotifyHMAC(respMap, devResKey);
System.out.println("response sign: " + resSigned);
Assert.assertEquals(resSigned, true);
}
}

+ 15
- 0
mallinkService/src/main/java/com/iformall/common/ErrorCode.java View File

@@ -52,6 +52,15 @@ public enum ErrorCode{
NET_TOKEN_INVALID(1052, "TOKEN无效"),
NET_TOKEN_EMPTY(1053, "TOKEN不能为空"),

/**
* 第三方开发者
*/
DEV_ID_NOT_FOUND(1200, "未知的第三方开发者"),
DEV_ID_IS_DISABLED(1201, "第三方开发者已被禁用"),
DEV_ID_REQ_KEY_IS_NULL(1202, "开发者request key未设置"),
DEV_ID_RES_KEY_IS_NULL(1203, "开发者response Key未设置"),
DEV_ID_SIGN_ERR(1204, "开发者签名错误"),


/**
* 业务级别
@@ -179,6 +188,7 @@ public enum ErrorCode{
COUPON_ORDER_MERANT_IS_NULL(4005, "卡券商户不存在"),
COUPON_ORDER_IS_EARLIER_THAN_VALIDDATE(4006, "卡券使用期还未开始"),
COUPON_ORDER_IS_LATER_THAN_VALIDDATE(4007, "卡券使用期已结束"),
COUPON_ORDER_IS_PRE_VERIFY(4008, "卡券已被预核销"),

/**
* 卡
@@ -267,9 +277,14 @@ public enum ErrorCode{
* 核销
*/
VERIFY_ERROR(12050, "核销异常"),
VERIFY_PRE_BUSER_NOT_EQUAL(12051, "预核销操作员不一致,请先取消上次预核销"),
VERIFY_PRE_POS_ORDER_IS_EMPTY(12052, "预核销POS订单ID为空"),
VERIFY_PRE_POS_ORDER_NOT_EQUAL(12053, "预核销POS订单不一致,请先取消上次预核销"),
VERIFY_BUSER_MERCHANT_NOT_BELONG(12054, "核销员不属于此商户"),
MSG_REPEAT_SEND(12061, "短信重复发送"),
VERIFY_COUPON_ORDER_MERCHANT_IS_NULL(12062, "卡券核销失败,请查看适用门店"),


/**
* 解单
*/


+ 37
- 0
mallinkService/src/main/java/com/iformall/domain/po/PosCouponOrderVerify.java View File

@@ -0,0 +1,37 @@
package com.iformall.domain.po;

import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.*;
import javax.persistence.Transient;
import java.util.Date;
import java.util.List;
import javax.persistence.Id;

@Table(name = "pos_coupon_order_verify")
@Data
@EqualsAndHashCode(callSuper = true)
public class PosCouponOrderVerify extends BaseEntity {

@Id
protected Long id;
@Transient
protected List<Long> ids;
@io.swagger.annotations.ApiModelProperty(value="租户ID",name="tenantId")
private String tenantId;
@io.swagger.annotations.ApiModelProperty(value="券包ID",name="couponOrderId")
private Long couponOrderId;
@io.swagger.annotations.ApiModelProperty(value="POS订单ID",name="posOrderId")
private Long posOrderId;
@io.swagger.annotations.ApiModelProperty(value="状态,0-使用中,1-禁用",name="state")
private Integer state;
@io.swagger.annotations.ApiModelProperty(value="创建时间",name="createDate")
private Date createDate;
@io.swagger.annotations.ApiModelProperty(value="更新时间",name="updateDate")
private Date updateDate;


}

+ 36
- 0
mallinkService/src/main/java/com/iformall/domain/po/ThDevInfo.java View File

@@ -0,0 +1,36 @@
package com.iformall.domain.po;

import lombok.Data;
import javax.persistence.*;
import java.util.*;
import javax.persistence.Transient;
import java.util.List;
import javax.persistence.Id;

@Table(name = "th_dev_info")
@Data
public class ThDevInfo extends BaseEntity {
@Id
protected Long id;
@Transient
protected List<Long> ids;
@io.swagger.annotations.ApiModelProperty(value="开发者ID",name="devId")
private String devId;
@io.swagger.annotations.ApiModelProperty(value="名称",name="name")
private String name;
@io.swagger.annotations.ApiModelProperty(value="类型(0:自用, 1:东软POS)",name="type")
private Integer type;
@io.swagger.annotations.ApiModelProperty(value="请求私钥",name="reqKey")
private String reqKey;
@io.swagger.annotations.ApiModelProperty(value="响应私钥",name="resKey")
private String resKey;
@io.swagger.annotations.ApiModelProperty(value="商户状态,0-使用中,1-禁用",name="state")
private Integer state;
@io.swagger.annotations.ApiModelProperty(value="创建时间",name="createDate")
private Date createDate;
@io.swagger.annotations.ApiModelProperty(value="更新时间",name="updateDate")
private Date updateDate;
}

+ 1
- 1
mallinkService/src/main/java/com/iformall/domain/po/WxCouponOrder.java View File

@@ -39,7 +39,7 @@ public class WxCouponOrder extends BaseEntity{
private Long orderId;
@io.swagger.annotations.ApiModelProperty(value = "该订单对应券的实际过期时间 ", name = "expiredTime")
private Date expiredTime;
@io.swagger.annotations.ApiModelProperty(value = "状态:0-待使用 1-已核销 2-已过期 3-已作废 4-卡使用中 5-卡已过期 6-卡已用完 7-卡已线下退款", name = "couponOrderStatus")
@io.swagger.annotations.ApiModelProperty(value = "状态:0-待使用 1-已核销 2-已过期 3-已作废 4-卡使用中 5-卡已过期 6-卡已用完 7-卡已线下退款 100-预核销", name = "couponOrderStatus")
private Integer couponOrderStatus;
@io.swagger.annotations.ApiModelProperty(value = "创建时间", name = "createDate")
private Date createDate;


+ 1
- 1
mallinkService/src/main/java/com/iformall/domain/vo/WxLevelMerchantCVo.java View File

@@ -32,7 +32,7 @@ public class WxLevelMerchantCVo implements Serializable {
@io.swagger.annotations.ApiModelProperty(value = "店铺列表", name = "shopVoList")
private List<WxShopVo> shopVoList;

@io.swagger.annotations.ApiModelProperty(value="折扣",name="discount")
@io.swagger.annotations.ApiModelProperty(value="折扣(0-100折扣)",name="discount")
private Integer discount;

@Transient


+ 3
- 1
mallinkService/src/main/java/com/iformall/enums/EnumCouponOrderStatus.java View File

@@ -16,7 +16,9 @@ public enum EnumCouponOrderStatus {
CARD_OVER_TIME(5, "已过期"),
CARD_COMPLETE(6, "已用完"),
CARD_RETURNED(7, "已线下退款"),
CARD_TRANSFER(8, "已转赠") /// 此状态不在wx_coupon_order中使用,已移到transfer表
CARD_TRANSFER(8, "已转赠"), /// 此状态不在wx_coupon_order中使用,已移到transfer表

POS_PRE_VERIFY(100, "POS预核销"), // POS设置状态
;

public static EnumCouponOrderStatus getEnum(Integer code) {


+ 42
- 0
mallinkService/src/main/java/com/iformall/enums/EnumVerifyActionType.java View File

@@ -0,0 +1,42 @@
package com.iformall.enums;

/**
* Created by Stormeye on 2018/08/09.
*/
public enum EnumVerifyActionType {

// 0: 检查, 1: 预核销 2: 预核销撤销 3:独立核销 4: 交易核销 5:核销撤销

CHECK(0, "检查"),
PRE_VERIFY(1, "预核销"),
PRE_VERIFY_CANCEL(2, "预核销撤销"),
VERIFY_INDEPENT(3,"独立核销"),
VERIFY_PAY(4,"交易核销"),
VERIFY_CANCEL(5,"核销撤销")
;

public static EnumVerifyActionType getEnum(Integer code) {
for (EnumVerifyActionType value : values()) {
if (value.getCode().equals(code)) {
return value;
}
}
return null;
}

private Integer code;
private String message;

EnumVerifyActionType(Integer code, String message) {
this.code = code;
this.message = message;
}

public Integer getCode() {
return code;
}

public String getMessage() {
return message;
}
}

+ 36
- 0
mallinkService/src/main/java/com/iformall/enums/EnumVerifyType.java View File

@@ -0,0 +1,36 @@
package com.iformall.enums;

/**
* Created by Stormeye on 2018/08/09.
*/
public enum EnumVerifyType {

YES(1, "是"),
NO(0, "否")
;

public static EnumVerifyType getEnum(Integer code) {
for (EnumVerifyType value : values()) {
if (value.getCode().equals(code)) {
return value;
}
}
return null;
}

private Integer code;
private String message;

EnumVerifyType(Integer code, String message) {
this.code = code;
this.message = message;
}

public Integer getCode() {
return code;
}

public String getMessage() {
return message;
}
}

+ 17
- 0
mallinkService/src/main/java/com/iformall/mapper/PosCouponOrderVerifyMapper.java View File

@@ -0,0 +1,17 @@
package com.iformall.mapper;

import java.util.*;
import com.iformall.common.CommonMapper;
import org.apache.ibatis.annotations.Param;
import com.iformall.domain.po.PosCouponOrderVerify;

public interface PosCouponOrderVerifyMapper extends CommonMapper<PosCouponOrderVerify, Long> {

List<PosCouponOrderVerify> findList(PosCouponOrderVerify posCouponOrderVerify);

}

+ 17
- 0
mallinkService/src/main/java/com/iformall/mapper/ThDevInfoMapper.java View File

@@ -0,0 +1,17 @@
package com.iformall.mapper;

import java.util.*;
import com.iformall.common.CommonMapper;
import org.apache.ibatis.annotations.Param;
import com.iformall.domain.po.ThDevInfo;

public interface ThDevInfoMapper extends CommonMapper<ThDevInfo, Long> {

List<ThDevInfo> findList(ThDevInfo thDevInfo);

}

+ 4
- 0
mallinkService/src/main/java/com/iformall/mapper/WxCouponOrderMapper.java View File

@@ -69,4 +69,8 @@ public interface WxCouponOrderMapper extends CommonMapper<WxCouponOrder, Long> {
//// 卡相关接口
List<WxCardCVo> findCardListOfCUser(WxCardCVo wxCardCVo);
WxCardCVo findCardDetailOfCUser(@Param("id")Long id);


/// POS接口
List<Map> findAvailCouponOrder(Map<String,Object> params);
}

+ 28
- 0
mallinkService/src/main/java/com/iformall/pay/WxPayConstant.java View File

@@ -0,0 +1,28 @@
package com.iformall.pay;

public class WxPayConstant {
public final static String REQ_KEY = "reqKey";
public final static String RES_KEY = "resKey";

public final static String RET_SUCCESS = "SUCCESS";
public final static String RET_FAIL = "FAIL";

public final static String RETURN_CODE = "return_code";
public final static String RETURN_MSG = "return_msg";
public final static String RESULT_CODE = "result_code";
public final static String ERR_CODE = "err_code";
public final static String ERR_CODE_DESC = "err_code_des";
public final static String NONCE_STR = "nonce_str";
public final static String DEV_ID = "dev_id";
public final static String SIGN = "sign";


public final static String TENANT_ID = "tenant_id";
public final static String MERCHANT_ID = "merchant_id";
public final static String BUSER_ID = "bu_user_id";
public final static String COUPON_ORDER_ID = "coupon_order_id";
public final static String POS_ORDER_ID = "pos_order_id";
public final static String MEM_ID = "mem_id";
public final static String MEM_PHONE = "mem_phone";

}

+ 15
- 0
mallinkService/src/main/java/com/iformall/pay/WxPayment.java View File

@@ -14,6 +14,7 @@ import java.util.Map.Entry;
import java.util.TreeMap;

public class WxPayment {

/**
* 构建参数
*
@@ -386,6 +387,20 @@ public class WxPayment {
return params;
}

/**
* 构建签名之后的参数
*
* @param params
* @param paternerKey
* @return Map
*/
public static Map<String, String> buildSignAfterParasMapForHMAC(Map<String, String> params, String paternerKey) {
params.put("nonce_str", Utility.generateUUID().replace("-", ""));
String sign = WxPayment.createSignHMAC(params, paternerKey);
params.put("sign", sign);
return params;
}

/**
* 生成签名
*


+ 57
- 0
mallinkService/src/main/java/com/iformall/service/PosCouponOrderVerifyService.java View File

@@ -0,0 +1,57 @@
package com.iformall.service;

import com.github.pagehelper.PageInfo;
import com.iformall.domain.po.PosCouponOrderVerify;

import java.util.List;

public interface PosCouponOrderVerifyService {

/**
* 根据实体查询分页列表
*
* @param record
* @param pageIndex
* @param pageSize
* @return
*/
PageInfo<PosCouponOrderVerify> listAsPage(PosCouponOrderVerify record, Integer pageIndex, Integer pageSize);

/**
* 根据实体查询列表
*
* @param record
* @return
*/
List<PosCouponOrderVerify> getList(PosCouponOrderVerify record);
/**
* 根据Id获得实体
*
* @param id
* @return
*/
PosCouponOrderVerify getById(Long id);
/**
* 保存或更新实体
*
* @param record
*/
void saveOrUpdate(PosCouponOrderVerify record);

/**
* 根据Id删除实体
*
* @param id
*/
void deleteById(Long id);

}

+ 55
- 0
mallinkService/src/main/java/com/iformall/service/ThDevInfoService.java View File

@@ -0,0 +1,55 @@
package com.iformall.service;

import com.github.pagehelper.PageInfo;
import com.iformall.domain.po.ThDevInfo;

public interface ThDevInfoService {

/**
* 根据实体查询分页列表
*
* @param record
* @param pageIndex
* @param pageSize
* @return
*/
PageInfo<ThDevInfo> listAsPage(ThDevInfo record, Integer pageIndex, Integer pageSize);
/**
* 根据Id获得实体
*
* @param id
* @return
*/
ThDevInfo getById(Long id);

/**
* 根据devId获得实体
*
* @param devId
* @return
*/
ThDevInfo getByDevId(String devId);
/**
* 保存或更新实体
*
* @param record
*/
void saveOrUpdate(ThDevInfo record);

/**
* 根据Id删除实体
*
* @param id
*/
void deleteById(Long id);

}

+ 7
- 0
mallinkService/src/main/java/com/iformall/service/WxCouponOrderService.java View File

@@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.Map;

public interface WxCouponOrderService {

@@ -189,4 +190,10 @@ public interface WxCouponOrderService {

void exportData(WxCouponOrderBVo wxCouponOrder, HttpServletRequest request, HttpServletResponse response);


/**
* POS相关接口
*/
List<Map> findAvailCouponOrder(Map<String, Object> params);

}

+ 7
- 0
mallinkService/src/main/java/com/iformall/service/WxCreditHistoryService.java View File

@@ -45,6 +45,13 @@ public interface WxCreditHistoryService {
*/
WxCreditHistory saveOrUpdate(WxCreditHistory record);

/**
* 积分历史回退
*
* @param record
*/
int cancelCredit(WxCreditHistory record);

/**
* 根据Id删除实体
*


+ 8
- 0
mallinkService/src/main/java/com/iformall/service/WxScoreRulesService.java View File

@@ -1,5 +1,6 @@
package com.iformall.service;

import com.iformall.domain.po.WxScoreHistory;
import com.iformall.domain.po.WxScoreRules;
import com.iformall.enums.EnumScoreType;

@@ -27,6 +28,13 @@ public interface WxScoreRulesService {
*/
void saveOrUpdate(WxScoreRules record);

/**
* 成长值回退
*
* @param record
*/
int cancelScore(WxScoreHistory record);

/**
* 增加成长值
*/


+ 60
- 0
mallinkService/src/main/java/com/iformall/service/impl/PosCouponOrderVerifyServiceImpl.java View File

@@ -0,0 +1,60 @@
package com.iformall.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.domain.po.PosCouponOrderVerify;
import com.iformall.mapper.PosCouponOrderVerifyMapper;
import com.iformall.service.PosCouponOrderVerifyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.iformall.common.IdWorker;

import java.util.List;

@Service
public class PosCouponOrderVerifyServiceImpl implements PosCouponOrderVerifyService {
@Autowired
PosCouponOrderVerifyMapper posCouponOrderVerifyMapper;


@Override
public PageInfo<PosCouponOrderVerify> listAsPage(PosCouponOrderVerify record, Integer pageIndex, Integer pageSize) {
return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> posCouponOrderVerifyMapper.findList(record));
}

@Override
public List<PosCouponOrderVerify> getList(PosCouponOrderVerify record) {
return posCouponOrderVerifyMapper.findList(record);
}

@Override
public PosCouponOrderVerify getById(Long id) {
return posCouponOrderVerifyMapper.selectByPrimaryKey(id);
}

@Override
public void saveOrUpdate(PosCouponOrderVerify record) {
if (record.getId() == null) {
//record.setId(UUID.randomUUID().toString().replaceAll("-", ""));
final IdWorker idWorker = IdWorker.get();
record.setId(idWorker.nextId());
posCouponOrderVerifyMapper.insertSelective(record);
} else {
posCouponOrderVerifyMapper.updateByPrimaryKeySelective(record);
}
}

@Override
public void deleteById(Long id) {
posCouponOrderVerifyMapper.deleteByPrimaryKey(id);
}
}

+ 69
- 0
mallinkService/src/main/java/com/iformall/service/impl/ThDevInfoServiceImpl.java View File

@@ -0,0 +1,69 @@
package com.iformall.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.domain.po.ThDevInfo;
import com.iformall.mapper.ThDevInfoMapper;
import com.iformall.service.ThDevInfoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.iformall.common.IdWorker;

@Service
public class ThDevInfoServiceImpl implements ThDevInfoService {

private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
ThDevInfoMapper thDevInfoMapper;


@Override
public PageInfo<ThDevInfo> listAsPage(ThDevInfo record, Integer pageIndex, Integer pageSize) {
return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> thDevInfoMapper.findList(record));
}

@Override
public ThDevInfo getById(Long id) {
return thDevInfoMapper.selectByPrimaryKey(id);
}

@Override
public ThDevInfo getByDevId(String devId) {
ThDevInfo q = new ThDevInfo();
q.setDevId(devId);
try {
return thDevInfoMapper.selectOne(q);
} catch (Exception e) {
logger.error(e.getMessage());
}
return null;
}

@Override
public void saveOrUpdate(ThDevInfo record) {
if (record.getId() == null) {
//record.setId(UUID.randomUUID().toString().replaceAll("-", ""));
final IdWorker idWorker = IdWorker.get();
record.setId(idWorker.nextId());
thDevInfoMapper.insertSelective(record);
} else {
thDevInfoMapper.updateByPrimaryKeySelective(record);
}
}

@Override
public void deleteById(Long id) {
thDevInfoMapper.deleteByPrimaryKey(id);
}
}

+ 9
- 0
mallinkService/src/main/java/com/iformall/service/impl/WxCouponOrderServiceImpl.java View File

@@ -336,6 +336,10 @@ public class WxCouponOrderServiceImpl implements WxCouponOrderService {
logger.error("已经核销过的券: couponOrder-" + couponOrder.getId());
throw new MallinkException(ErrorCode.COUPON_ORDER_IS_USED);
}
if (couponOrder.getCouponOrderStatus() == EnumCouponOrderStatus.POS_PRE_VERIFY.getCode()) {
logger.error("券已被预核销: couponOrder-" + couponOrder.getId());
throw new MallinkException(ErrorCode.COUPON_ORDER_IS_PRE_VERIFY);
}
int num = 0;
try {
couponOrder.setCouponOrderStatus(EnumCouponOrderStatus.COUPON_ORDER_USED.getCode()); //1核销
@@ -975,4 +979,9 @@ public class WxCouponOrderServiceImpl implements WxCouponOrderService {
wxCardTransferInfoMapper.insertSelective(wxCardTransferInfo);
}

@Override
public List<Map> findAvailCouponOrder(Map<String, Object> params) {
return wxCouponOrderMapper.findAvailCouponOrder(params);
}

}

+ 42
- 0
mallinkService/src/main/java/com/iformall/service/impl/WxCreditHistoryServiceImpl.java View File

@@ -19,6 +19,8 @@ import com.iformall.service.WxScoreRulesService;
import com.iformall.utils.RedisLock;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
@@ -35,6 +37,7 @@ import java.util.stream.Collectors;
@Service
@Slf4j
public class WxCreditHistoryServiceImpl implements WxCreditHistoryService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Autowired
WxCreditHistoryMapper wxCreditHistoryMapper;
@@ -230,6 +233,45 @@ public class WxCreditHistoryServiceImpl implements WxCreditHistoryService {
return record;
}

@Override
@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
public int cancelCredit(WxCreditHistory record) {
int num = 0;
WxCreditHistory wxCreditHistory = null;
// 1. clear history
List<WxCreditHistory> creditHistories = wxCreditHistoryMapper.findList(record);
if (creditHistories.size() >= 1) {
wxCreditHistory = creditHistories.get(0);
}
if (wxCreditHistory != null) {
num = wxCreditHistoryMapper.deleteByPrimaryKey(wxCreditHistory.getId());
if (num != 1) {
logger.error("删除积分历史出错"+ wxCreditHistory.toString());
}
} else {
logger.error("未找到积分历史");
return 0;
}
// 2. user
WxCUser wxCUser = wxCUserMapper.selectByPrimaryKey(record.getCUserId());
WxCUserBasicInfo wxCUserBasicInfo = wxCUserBasicInfoMapper.selectByPrimaryKey(record.getCUserId());
if (wxCUser != null) {
WxCUser wxCUserNew = new WxCUser();
wxCUserNew.setId(wxCUser.getId());
wxCUserNew.setCredit(wxCUser.getCredit()-wxCreditHistory.getCreditNum());
wxCUserNew.setUpdateDate(new Date());
wxCUserMapper.updateByPrimaryKeySelective(wxCUserNew);
}
if (wxCUserBasicInfo != null) {
WxCUserBasicInfo wxCUserBasicInfoNew = new WxCUserBasicInfo();
wxCUserBasicInfoNew.setId(wxCUserBasicInfo.getId());
wxCUserBasicInfoNew.setCredit(wxCUserBasicInfo.getCredit()-wxCreditHistory.getCreditNum());
wxCUserBasicInfoNew.setUpdateDate(new Date());
wxCUserBasicInfoMapper.updateByPrimaryKeySelective(wxCUserBasicInfoNew);
}
return num;
}

@Override
public void deleteById(Long id) {
wxCreditHistoryMapper.deleteByPrimaryKey(id);


+ 38
- 0
mallinkService/src/main/java/com/iformall/service/impl/WxScoreRulesServiceImpl.java View File

@@ -185,6 +185,44 @@ public class WxScoreRulesServiceImpl implements WxScoreRulesService {
}
}

@Override
public int cancelScore(WxScoreHistory record) {
int num = 0;
WxScoreHistory history = null;
// 1. delete history
List<WxScoreHistory> histories = wxScoreHistoryMapper.findList(record);
if (histories.size() >= 1) {
history = histories.get(0);
}
if (history != null) {
num = wxScoreHistoryMapper.deleteByPrimaryKey(history.getId());
if (num != 1) {
logger.error("删除成长值历史出错"+ history.toString());
}
} else {
logger.error("未找到成长值历史");
return 0;
}
// 2. user score back
WxCUser wxCUser = wxCUserMapper.selectByPrimaryKey(record.getCUserId());
WxCUserBasicInfo wxCUserBasicInfo = wxCUserBasicInfoMapper.selectByPrimaryKey(record.getCUserId());
if (wxCUser != null) {
WxCUser wxCUserNew = new WxCUser();
wxCUserNew.setId(wxCUser.getId());
wxCUserNew.setScore(wxCUser.getScore() - history.getScoreAmount());
wxCUserNew.setUpdateDate(new Date());
wxCUserMapper.updateByPrimaryKeySelective(wxCUserNew);
}
if (wxCUserBasicInfo != null) {
WxCUserBasicInfo wxCUserBasicInfoNew = new WxCUserBasicInfo();
wxCUserBasicInfoNew.setId(wxCUserBasicInfo.getId());
wxCUserBasicInfoNew.setPoins(wxCUserBasicInfo.getPoins()-history.getScoreAmount());
wxCUserBasicInfoNew.setUpdateDate(new Date());
wxCUserBasicInfoMapper.updateByPrimaryKeySelective(wxCUserBasicInfoNew);
}
return num;
}

private void updateScore(Long userId, int addedScoreNumber) {
// 1. 获取cUser
WxCUser wxCUser = wxCUserService.getById(userId);


+ 54
- 0
mallinkService/src/main/resources/mapper/PosCouponOrderVerifyMapper.xml View File

@@ -0,0 +1,54 @@
<?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.iformall.mapper.PosCouponOrderVerifyMapper">
<resultMap id="BaseResultMap" type="com.iformall.domain.po.PosCouponOrderVerify">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="tenant_id" jdbcType="VARCHAR" property="tenantId" />
<result column="coupon_order_id" jdbcType="BIGINT" property="couponOrderId" />
<result column="pos_order_id" jdbcType="BIGINT" property="posOrderId" />
<result column="state" jdbcType="INTEGER" property="state" />
<result column="create_date" jdbcType="TIMESTAMP" property="createDate"/>
<result column="update_date" jdbcType="TIMESTAMP" property="updateDate"/>
</resultMap>
<sql id="allColumns">
`id`,`tenant_id`,`coupon_order_id`,`pos_order_id`,`state`
</sql>

<sql id="dynamicWhereConditions">
where 1 = 1
<if test=" null != id ">
and `id` = #{id}
</if>
<if test=" null != tenantId ">
and `tenant_id` like concat('%', #{tenantId},'%')
</if>
<if test=" null != couponOrderId ">
and `coupon_order_id` = #{couponOrderId}
</if>
<if test=" null != posOrderId ">
and `pos_order_id` = #{posOrderId}
</if>
<if test=" null != state ">
and `state` = #{state}
</if>
<if test=" null != ids ">
and id in
<foreach collection="ids" index="index" item="idItem" open="(" separator="," close=")">
#{idItem}
</foreach>
</if>
<if test=" null != sortColumns"> order by ${sortColumns} </if>
</sql>
<select id="findList" parameterType="com.iformall.domain.po.PosCouponOrderVerify" resultMap="BaseResultMap">
select <include refid="allColumns" /> from pos_coupon_order_verify
<include refid="dynamicWhereConditions" />
</select>
</mapper>

+ 68
- 0
mallinkService/src/main/resources/mapper/ThDevInfoMapper.xml View File

@@ -0,0 +1,68 @@
<?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.iformall.mapper.ThDevInfoMapper">
<resultMap id="BaseResultMap" type="com.iformall.domain.po.ThDevInfo">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="dev_id" jdbcType="VARCHAR" property="devId" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="type" jdbcType="INTEGER" property="type" />
<result column="req_key" jdbcType="VARCHAR" property="reqKey" />
<result column="res_key" jdbcType="VARCHAR" property="resKey" />
<result column="state" jdbcType="INTEGER" property="state" />
<result column="create_date" jdbcType="TIMESTAMP" property="createDate" />
<result column="update_date" jdbcType="TIMESTAMP" property="updateDate" />
</resultMap>
<sql id="allColumns">
`id`,`dev_id`,`name`,`type`,`req_key`,`res_key`,`state`,`create_date`,`update_date`
</sql>

<sql id="dynamicWhereConditions">
where 1 = 1
<if test=" null != id ">
and `id` = #{id}
</if>
<if test=" null != devId ">
and `dev_id` like concat('%', #{devId},'%')
</if>
<if test=" null != name ">
and `name` like concat('%', #{name},'%')
</if>
<if test=" null != type ">
and `type` = #{type}
</if>
<if test=" null != reqKey ">
and `req_key` like concat('%', #{reqKey},'%')
</if>
<if test=" null != resKey ">
and `res_key` like concat('%', #{resKey},'%')
</if>
<if test=" null != state ">
and `state` = #{state}
</if>
<if test=" null != createDate ">
and `create_date` = #{createDate}
</if>
<if test=" null != updateDate ">
and `update_date` = #{updateDate}
</if>
<if test=" null != ids ">
and id in
<foreach collection="ids" index="index" item="idItem" open="(" separator="," close=")">
#{idItem}
</foreach>
</if>
<if test=" null != sortColumns"> order by ${sortColumns} </if>
</sql>
<select id="findList" parameterType="com.iformall.domain.po.ThDevInfo" resultMap="BaseResultMap">
select <include refid="allColumns" /> from th_dev_info
<include refid="dynamicWhereConditions" />
</select>
</mapper>

+ 24
- 0
mallinkService/src/main/resources/mapper/WxCouponOrderMapper.xml View File

@@ -1018,4 +1018,28 @@
and co.id = #{id}
</select>

<select id="findAvailCouponOrder" parameterType="java.util.Map" resultType="hashmap">
select co.id,c.title, co.create_date, co.expired_time, c.price
from wx_coupon_order co
left join wx_coupon_merchant cm on cm.product_id = co.coupon_id
left join wx_coupon c on c.id = co.coupon_id
where co.tenant_id = #{tenantId} and co.c_user_id = #{cUserId}
and co.coupon_order_status = 0
and cm.merchant_id = #{merchantId}
and co.expired_time > now()
union
select co.id,c.title, co.create_date, co.expired_time, c.price
from wx_coupon_order co
left join wx_coupon_merchant cm on cm.product_id = co.coupon_id
left join wx_coupon c on c.id = co.coupon_id
left join pos_coupon_order_verify pco on pco.coupon_order_id = co.id
where co.tenant_id = #{tenantId} and co.c_user_id = #{cUserId}
and co.coupon_order_status = 100
and cm.merchant_id = #{merchantId}
and co.expired_time > now()
and pco.pos_order_id = #{posOrderId}
</select>



</mapper>

+ 2
- 1
pom.xml View File

@@ -18,6 +18,7 @@
<module>mallinkSysAdmin</module>
<module>mallinkCApi</module>
<module>mallinkBApi</module>
<module>mallinkPosApi</module>
<module>mallinkSchedule</module>
<module>mallinkMQConsumer</module>
<module>mallinkWebSocketServer</module>
@@ -375,4 +376,4 @@
</plugins>
</build>
-->
</project>
</project>

Loading…
Cancel
Save