| @@ -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> | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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(); | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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; | |||
| } | |||
| @@ -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); | |||
| } | |||
| } | |||
| } | |||
| @@ -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 | |||
| 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 | |||
| @@ -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 | |||
| 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 | |||
| @@ -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 | |||
| 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 | |||
| @@ -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@ | |||
| @@ -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> | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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, "卡券核销失败,请查看适用门店"), | |||
| /** | |||
| * 解单 | |||
| */ | |||
| @@ -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; | |||
| } | |||
| @@ -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; | |||
| } | |||
| @@ -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; | |||
| @@ -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 | |||
| @@ -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) { | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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"; | |||
| } | |||
| @@ -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; | |||
| } | |||
| /** | |||
| * 生成签名 | |||
| * | |||
| @@ -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); | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -45,6 +45,13 @@ public interface WxCreditHistoryService { | |||
| */ | |||
| WxCreditHistory saveOrUpdate(WxCreditHistory record); | |||
| /** | |||
| * 积分历史回退 | |||
| * | |||
| * @param record | |||
| */ | |||
| int cancelCredit(WxCreditHistory record); | |||
| /** | |||
| * 根据Id删除实体 | |||
| * | |||
| @@ -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); | |||
| /** | |||
| * 增加成长值 | |||
| */ | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||
| } | |||
| @@ -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); | |||
| @@ -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); | |||
| @@ -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> | |||
| @@ -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> | |||
| @@ -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> | |||
| @@ -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> | |||