From c7a7e9a24e84133fd07a2ecb2d0098a536316326 Mon Sep 17 00:00:00 2001 From: Stormeye Wu Date: Thu, 8 Aug 2019 07:16:11 +0800 Subject: [PATCH] =?UTF-8?q?[POS][=E6=96=B0=E5=A2=9E]:pos=20api=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mallinkPosApi/pom.xml | 154 ++++ .../java/com/iformall/PosApplication.java | 49 ++ .../java/com/iformall/config/AwsProperty.java | 52 ++ .../java/com/iformall/config/RedisConfig.java | 125 +++ .../com/iformall/config/Swagger2Config.java | 49 ++ .../com/iformall/config/WebMvcConfig.java | 80 ++ .../iformall/controller/BaseController.java | 83 ++ .../iformall/controller/HomeController.java | 26 + .../iformall/controller/PosController.java | 437 ++++++++++ .../java/com/iformall/service/PosService.java | 28 + .../iformall/service/impl/PosServiceImpl.java | 753 ++++++++++++++++++ .../src/main/resources/application-dev.yml | 116 +++ .../src/main/resources/application-prod.yml | 100 +++ .../src/main/resources/application-test.yml | 100 +++ .../src/main/resources/application.yml | 52 ++ .../src/main/resources/logback-spring.xml | 100 +++ .../com/iformall/pos/test/PosAppTest.java | 176 ++++ .../java/com/iformall/common/ErrorCode.java | 15 + .../domain/po/PosCouponOrderVerify.java | 37 + .../com/iformall/domain/po/ThDevInfo.java | 36 + .../com/iformall/domain/po/WxCouponOrder.java | 2 +- .../domain/vo/WxLevelMerchantCVo.java | 2 +- .../iformall/enums/EnumCouponOrderStatus.java | 4 +- .../iformall/enums/EnumVerifyActionType.java | 42 + .../com/iformall/enums/EnumVerifyType.java | 36 + .../mapper/PosCouponOrderVerifyMapper.java | 17 + .../com/iformall/mapper/ThDevInfoMapper.java | 17 + .../iformall/mapper/WxCouponOrderMapper.java | 4 + .../java/com/iformall/pay/WxPayConstant.java | 28 + .../main/java/com/iformall/pay/WxPayment.java | 15 + .../service/PosCouponOrderVerifyService.java | 57 ++ .../iformall/service/ThDevInfoService.java | 55 ++ .../service/WxCouponOrderService.java | 7 + .../service/WxCreditHistoryService.java | 7 + .../iformall/service/WxScoreRulesService.java | 8 + .../impl/PosCouponOrderVerifyServiceImpl.java | 60 ++ .../service/impl/ThDevInfoServiceImpl.java | 69 ++ .../impl/WxCouponOrderServiceImpl.java | 9 + .../impl/WxCreditHistoryServiceImpl.java | 42 + .../service/impl/WxScoreRulesServiceImpl.java | 38 + .../mapper/PosCouponOrderVerifyMapper.xml | 54 ++ .../main/resources/mapper/ThDevInfoMapper.xml | 68 ++ .../resources/mapper/WxCouponOrderMapper.xml | 24 + pom.xml | 3 +- 44 files changed, 3232 insertions(+), 4 deletions(-) create mode 100644 mallinkPosApi/pom.xml create mode 100644 mallinkPosApi/src/main/java/com/iformall/PosApplication.java create mode 100644 mallinkPosApi/src/main/java/com/iformall/config/AwsProperty.java create mode 100644 mallinkPosApi/src/main/java/com/iformall/config/RedisConfig.java create mode 100644 mallinkPosApi/src/main/java/com/iformall/config/Swagger2Config.java create mode 100644 mallinkPosApi/src/main/java/com/iformall/config/WebMvcConfig.java create mode 100644 mallinkPosApi/src/main/java/com/iformall/controller/BaseController.java create mode 100644 mallinkPosApi/src/main/java/com/iformall/controller/HomeController.java create mode 100644 mallinkPosApi/src/main/java/com/iformall/controller/PosController.java create mode 100644 mallinkPosApi/src/main/java/com/iformall/service/PosService.java create mode 100644 mallinkPosApi/src/main/java/com/iformall/service/impl/PosServiceImpl.java create mode 100644 mallinkPosApi/src/main/resources/application-dev.yml create mode 100644 mallinkPosApi/src/main/resources/application-prod.yml create mode 100644 mallinkPosApi/src/main/resources/application-test.yml create mode 100644 mallinkPosApi/src/main/resources/application.yml create mode 100644 mallinkPosApi/src/main/resources/logback-spring.xml create mode 100644 mallinkPosApi/src/test/java/com/iformall/pos/test/PosAppTest.java create mode 100644 mallinkService/src/main/java/com/iformall/domain/po/PosCouponOrderVerify.java create mode 100644 mallinkService/src/main/java/com/iformall/domain/po/ThDevInfo.java create mode 100644 mallinkService/src/main/java/com/iformall/enums/EnumVerifyActionType.java create mode 100644 mallinkService/src/main/java/com/iformall/enums/EnumVerifyType.java create mode 100644 mallinkService/src/main/java/com/iformall/mapper/PosCouponOrderVerifyMapper.java create mode 100644 mallinkService/src/main/java/com/iformall/mapper/ThDevInfoMapper.java create mode 100644 mallinkService/src/main/java/com/iformall/pay/WxPayConstant.java create mode 100644 mallinkService/src/main/java/com/iformall/service/PosCouponOrderVerifyService.java create mode 100644 mallinkService/src/main/java/com/iformall/service/ThDevInfoService.java create mode 100644 mallinkService/src/main/java/com/iformall/service/impl/PosCouponOrderVerifyServiceImpl.java create mode 100644 mallinkService/src/main/java/com/iformall/service/impl/ThDevInfoServiceImpl.java create mode 100644 mallinkService/src/main/resources/mapper/PosCouponOrderVerifyMapper.xml create mode 100644 mallinkService/src/main/resources/mapper/ThDevInfoMapper.xml diff --git a/mallinkPosApi/pom.xml b/mallinkPosApi/pom.xml new file mode 100644 index 000000000..79eda0078 --- /dev/null +++ b/mallinkPosApi/pom.xml @@ -0,0 +1,154 @@ + + + 4.0.0 + + mallink + com.iformall + 1.0 + + + mallinkPosApi + + + + com.iformall + mallinkService + 1.0 + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + ZIP + + 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 + + + + + + diff --git a/mallinkPosApi/src/main/java/com/iformall/PosApplication.java b/mallinkPosApi/src/main/java/com/iformall/PosApplication.java new file mode 100644 index 000000000..e97ef4230 --- /dev/null +++ b/mallinkPosApi/src/main/java/com/iformall/PosApplication.java @@ -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); + } +} diff --git a/mallinkPosApi/src/main/java/com/iformall/config/AwsProperty.java b/mallinkPosApi/src/main/java/com/iformall/config/AwsProperty.java new file mode 100644 index 000000000..0329f1d6d --- /dev/null +++ b/mallinkPosApi/src/main/java/com/iformall/config/AwsProperty.java @@ -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; + } +} diff --git a/mallinkPosApi/src/main/java/com/iformall/config/RedisConfig.java b/mallinkPosApi/src/main/java/com/iformall/config/RedisConfig.java new file mode 100644 index 000000000..7e167a93e --- /dev/null +++ b/mallinkPosApi/src/main/java/com/iformall/config/RedisConfig.java @@ -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 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 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 getPushLimitRedisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate template = new RedisTemplate(); + + Jackson2JsonRedisSerializer j = new Jackson2JsonRedisSerializer(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 getScoreRuleRedisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate template = new RedisTemplate(); + + Jackson2JsonRedisSerializer j = new Jackson2JsonRedisSerializer(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 getCUserTokenRedisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate template = new RedisTemplate(); + + Jackson2JsonRedisSerializer j = new Jackson2JsonRedisSerializer(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 getMallRedisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate template = new RedisTemplate(); + + Jackson2JsonRedisSerializer j = new Jackson2JsonRedisSerializer(WxMall.class); + // value值的序列化 + template.setValueSerializer(j); + template.setHashKeySerializer(j); + + // key的序列化 + template.setKeySerializer(new StringRedisSerializer()); + template.setHashKeySerializer(new StringRedisSerializer()); + + template.setConnectionFactory(connectionFactory); + return template; + } + +} diff --git a/mallinkPosApi/src/main/java/com/iformall/config/Swagger2Config.java b/mallinkPosApi/src/main/java/com/iformall/config/Swagger2Config.java new file mode 100644 index 000000000..884ba6c19 --- /dev/null +++ b/mallinkPosApi/src/main/java/com/iformall/config/Swagger2Config.java @@ -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 pars = new ArrayList(); + //增加一个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(); + } + +} \ No newline at end of file diff --git a/mallinkPosApi/src/main/java/com/iformall/config/WebMvcConfig.java b/mallinkPosApi/src/main/java/com/iformall/config/WebMvcConfig.java new file mode 100644 index 000000000..d7ea2644e --- /dev/null +++ b/mallinkPosApi/src/main/java/com/iformall/config/WebMvcConfig.java @@ -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> 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); + } +} \ No newline at end of file diff --git a/mallinkPosApi/src/main/java/com/iformall/controller/BaseController.java b/mallinkPosApi/src/main/java/com/iformall/controller/BaseController.java new file mode 100644 index 000000000..b6a067993 --- /dev/null +++ b/mallinkPosApi/src/main/java/com/iformall/controller/BaseController.java @@ -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; + } +} diff --git a/mallinkPosApi/src/main/java/com/iformall/controller/HomeController.java b/mallinkPosApi/src/main/java/com/iformall/controller/HomeController.java new file mode 100644 index 000000000..ab029d09c --- /dev/null +++ b/mallinkPosApi/src/main/java/com/iformall/controller/HomeController.java @@ -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); + } +} \ No newline at end of file diff --git a/mallinkPosApi/src/main/java/com/iformall/controller/PosController.java b/mallinkPosApi/src/main/java/com/iformall/controller/PosController.java new file mode 100644 index 000000000..c7d893de6 --- /dev/null +++ b/mallinkPosApi/src/main/java/com/iformall/controller/PosController.java @@ -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 getQrCode(@RequestBody Map params) { + JSONObject payContent = new JSONObject(); + + // 1. check sign + Map 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 checkMem(@RequestBody Map params) { + JSONObject payContent = new JSONObject(); + + // 1. check sign + Map 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 checkCouponOrderVerify(@RequestBody Map params) { + JSONObject payContent = new JSONObject(); + + // 1. check sign + Map 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 couponOrderPreVerify(@RequestBody Map params) { + JSONObject payContent = new JSONObject(); + + // 1. check sign + Map 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 couponOrderPreVerifyCancel(@RequestBody Map params) { + JSONObject payContent = new JSONObject(); + + // 1. check sign + Map 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 couponOrderIndependentVerify(@RequestBody Map params) { + JSONObject payContent = new JSONObject(); + + // 1. check sign + Map 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 couponOrderPayVerify(@RequestBody Map params) { + JSONObject payContent = new JSONObject(); + + // 1. check sign + Map 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 couponOrderIndependentVerifyCancel(@RequestBody Map params) { + JSONObject payContent = new JSONObject(); + + // 1. check sign + Map 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 buildReturnMap(String retCode, String retMsg, String resCode, Integer errCode, String errMsg) { + Map 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 buildReturnMap(Map 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 buildReturnMap(Map 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 checkSign(Map 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; + } + + + +} diff --git a/mallinkPosApi/src/main/java/com/iformall/service/PosService.java b/mallinkPosApi/src/main/java/com/iformall/service/PosService.java new file mode 100644 index 000000000..0697b2fa2 --- /dev/null +++ b/mallinkPosApi/src/main/java/com/iformall/service/PosService.java @@ -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 doGetQrCode(Map params) throws MallinkException; + + /** + * 识别会员 + * @param params + * @return + */ + Map checkMember(Map params) throws MallinkException; + + Map couponOrderVerifyDoSomething(@RequestBody Map params, EnumVerifyActionType actionType) throws MallinkException; + + Map couponOrderVerifyCancel(Map params, EnumVerifyActionType actionType) throws MallinkException; +} diff --git a/mallinkPosApi/src/main/java/com/iformall/service/impl/PosServiceImpl.java b/mallinkPosApi/src/main/java/com/iformall/service/impl/PosServiceImpl.java new file mode 100644 index 000000000..c9823c4d2 --- /dev/null +++ b/mallinkPosApi/src/main/java/com/iformall/service/impl/PosServiceImpl.java @@ -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 doGetQrCode(Map params) throws MallinkException { + Map 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 checkMember(Map params) throws MallinkException { + Map 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 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 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 coQ = new HashMap<>(); + coQ.put("tenantId", tenantId); + coQ.put("cUserId", user.getId()); + coQ.put("merchantId", merchantId); + coQ.put("posOrderId", posOrderId); + List couponOrderList = couponOrderService.findAvailCouponOrder(coQ); + retMap.put("coupon_order_list", couponOrderList.toString()); + return retMap; + } + + @Override + public Map couponOrderVerifyDoSomething(@RequestBody Map params, EnumVerifyActionType actionType) throws MallinkException { + Map 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 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 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 couponOrderVerifyCancel(Map params, EnumVerifyActionType actionType) { + Map 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 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 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 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 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 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); + } + } +} diff --git a/mallinkPosApi/src/main/resources/application-dev.yml b/mallinkPosApi/src/main/resources/application-dev.yml new file mode 100644 index 000000000..3cdaeace4 --- /dev/null +++ b/mallinkPosApi/src/main/resources/application-dev.yml @@ -0,0 +1,116 @@ +spring: + profiles: + include: rabbitMQ + # JDBC + datasource: + url: jdbc:mysql://202.165.179.86:3306/mallinkDevW?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useUnicode=true&useSSL=false&useAffectedRows=true + username: ENC(dZ8fmrtuBMQYaRytKQgTqg==) + password: ENC(IKH7HxMZwIqMttMc9+QsqWa1KMsJvTs4) + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + filters: stat + maxActive: 20 + initialSize: 1 + maxWait: 60000 + minIdle: 1 + timeBetweenEvictionRunsMillis: 28000 + minEvictableIdleTimeMillis: 28000 + validationQuery: select 'x' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + poolPreparedStatements: true + maxOpenPreparedStatements: 20 + #jackson: + #date-format: yyyy-MM-dd HH:mm:ss + # REDIS + redis: + host: 202.165.179.86 + port: 6379 + password: ENC(xPFDlgd6v8zUhJMbcKc0KmmQiqs9qHtk) + timeout: 3600 + expire: 1800 #30分钟 + database: 1 + defaultExpiration: 2592000 # 默认生命周期30天 + jedis: + pool: + max-active: 50 + max-idle: 30 + max-wait: -1 + min-idle: 0 + # EMAIL + mail: + host: smtp.exmail.qq.com + username: ENC(lknBjZsA24AaQEXuy0fFw3acd4v4Xsf3CsgDcRZgjlYnNAL9R07d/w==) + password: ENC(gIkVPuYMmJ/EDxry8QIfGumIAk4plAwolGrfg1fiM3U=) # 授权密码 + properties: + mail: + smtp: + auth: true + starttls: + enable: true + socketFactory: + port: 465 + class: javax.net.ssl.SSLSocketFactory + # ROCKETMQ + rocketmq: + nameServer: 127.0.0.1:9876 + producer: + retry-times-when-send-async-failed: 0 + send-msg-timeout: 300000 + compress-msg-body-over-howmuch: 4096 + max-message-size: 4194304 + retry-another-broker-when-not-store-ok: false + retry-times-when-send-failed: 2 + # RABBITMQ + rabbitmq: + host: 202.165.179.86 + port: 5672 + username: ENC(2f9Nqt3c4cbVGYnhpjp9Mg==) + password: ENC(2av0JfMfz141IHkG6ibI8aKzmD33bc64wcN/O43ucbo=) + publisher-confirms: true + virtual-host: / + +aws: + clientRegion: cn-northwest-1 + bucketName: iformall-net + access: ENC(3gx5ghDFBqGrEhO3Wf8aYmXsnwHO7Cj3HNKJGOeUj0o=) + secret: ENC(HVKIJwCJKVXLlUpGlQPwNqJOlnpxn4xYuy91SH0seTSm2uAttIQHvA49fXWWax90v5wloIk0QuU=) + +jasypt: + encryptor: + password: oRqdnDbK5pj3eMmB + +wechat: + open: + componentAppId: "wx897e4673286c915d" + componentSecret: "cdfdfda65c45689beb6766c4c427eed2" + componentToken: "formall2018" + componentAesKey: "htKq8EjBMPNndfZQK9JiFojFaqFwFpw42VfeWFtx7HN" + redis: + host: 202.165.179.86 + port: 6379 + password: ENC(xPFDlgd6v8zUhJMbcKc0KmmQiqs9qHtk) + timeout: 3600 + expire: 1800 #30分钟 + database: 2 + defaultExpiration: 2592000 # 默认生命周期30天 + jedis: + pool: + max-active: 100 + max-idle: 500 + max-wait: -1 + min-idle: 10 + +fm: + exception: false + exception_emails: hupeng@iformall.com,wuguoqiang@iformall.com,gongbiao@iformall.com,luozukai@iformall.com + deploy: 1 + open: true + upload_dir: /home/test/server/uploads + +logging: + level: + tk.mybatis: debug + com.iformall.mapper: debug + path: ./logs/b \ No newline at end of file diff --git a/mallinkPosApi/src/main/resources/application-prod.yml b/mallinkPosApi/src/main/resources/application-prod.yml new file mode 100644 index 000000000..23b4ab7f2 --- /dev/null +++ b/mallinkPosApi/src/main/resources/application-prod.yml @@ -0,0 +1,100 @@ +spring: + profiles: + include: rabbitMQ + # JDBC + datasource: + url: jdbc:mysql://formalldb.cfqyqflkdlit.rds.cn-northwest-1.amazonaws.com.cn:3306/mallink?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&useSSL=false&useAffectedRows=true + username: ENC(NUzgQOdJnCbVLKT6BaX0aw==) + password: ENC(mvuoDRiu0jqYaKNRwwTuXZ6U7aoIaqsjdiPqTLgi/nY=) + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + filters: stat + maxActive: 20 + initialSize: 1 + maxWait: 60000 + minIdle: 1 + timeBetweenEvictionRunsMillis: 28000 + minEvictableIdleTimeMillis: 28000 + validationQuery: select 'x' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + poolPreparedStatements: true + maxOpenPreparedStatements: 20 + # REDIS + redis: + host: 127.0.0.1 + port: 6379 + password: ENC(8gYU47Fu93NUJPhwPCiPbAT+6VFA1YDx1egK4Z0Nl6w=) + timeout: 3600 + expire: 1800 #30分钟 + database: 1 + defaultExpiration: 2592000 # 默认生命周期30天 + jedis: + pool: + max-active: 100 + max-idle: 20 + max-wait: -1 + min-idle: 0 + # EMAIL + mail: + host: smtp.exmail.qq.com + username: ENC(IiL/PHP9wCkpibWHRH/Mts8K9fh4izYqaiaF66bDrqtEHP+KUcJRRg==) + password: ENC(m7L57m8mk6tApVoa4XIDQnXF0VxnYjKe4LVdzcgb+xY=) # 授权密码 + properties: + mail: + smtp: + auth: true + starttls: + enable: true + socketFactory: + port: 465 + class: javax.net.ssl.SSLSocketFactory + # RABBITMQ + rabbitmq: + host: localhost + port: 5672 + username: ENC(lRmLd6EzgeY1RT5ktcHv9g==) + password: ENC(gBI8mCjr3OC0v57jcnSb660Ux7mW03K2oePgvohhg7w=) + publisher-confirms: true + virtual-host: / + +aws: + clientRegion: cn-northwest-1 + bucketName: iformall-net + access: ENC(a6SN1sZ1enNL49ypiOXkg/pPPAnZD8H4buQFTTKN08s=) + secret: ENC(5P5ff4bTMJUbXVR4ZsM03UHzOKZ4+Zg5Iutcdkyp/Quny/oXg+A4KpfwEyGarlLu3vQMJahGP5M=) + +wechat: + open: + componentAppId: ENC(b3JG0MUZgQfz5Zj+DC2ZM1zDeLOiGTmmeokfe2O8kaM=) + componentSecret: ENC(QVyc4BPGdnSjXGs2ivgpDBE1v8wPWHLLRMYI7Vv8uYwC0SiZHQz0QpyyQV/b48Pb) + componentToken: ENC(rkxj0733WxFFDLgA9x01m2s5Fi2L+0PC) + componentAesKey: ENC(EIbJUBpbYOrLb4YQ/HXLQmxlxgAqIp2ZmpnGICC8pu5xiTz3Cqfkbwd2S8raCcK/IvYcX2GmedI=) + redis: + host: 127.0.0.1 + port: 6379 + password: ENC(8gYU47Fu93NUJPhwPCiPbAT+6VFA1YDx1egK4Z0Nl6w=) + timeout: 3600 + expire: 1800 #30分钟 + database: 2 + defaultExpiration: 2592000 # 默认生命周期30天 + jedis: + pool: + max-active: 100 + max-idle: 100 + max-wait: -1 + min-idle: 10 + +fm: + exception: true + exception_emails: hupeng@iformall.com,wuguoqiang@iformall.com,gongbiao@iformall.com,luozukai@iformall.com + deploy: 3 + open: true + upload_dir: /home/ec2-user/server/uploads/ + +logging: + level: + tk.mybatis: debug + com.iformall.mapper: debug + path: ./logs/b \ No newline at end of file diff --git a/mallinkPosApi/src/main/resources/application-test.yml b/mallinkPosApi/src/main/resources/application-test.yml new file mode 100644 index 000000000..e0f7072ba --- /dev/null +++ b/mallinkPosApi/src/main/resources/application-test.yml @@ -0,0 +1,100 @@ +spring: + profiles: + include: rabbitMQ + # JDBC + datasource: + url: jdbc:mysql://formalldb.cfqyqflkdlit.rds.cn-northwest-1.amazonaws.com.cn:3306/mallinkTest?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&useSSL=false&useAffectedRows=true + username: ENC(Uc0AjgkytxHHCwZrmDASWg==) + password: ENC(nV4Mi3bEbBx0Fj7uUyYH55eTaqsFMjKvmNzagicH4pc=) + type: com.alibaba.druid.pool.DruidDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + filters: stat + maxActive: 20 + initialSize: 1 + maxWait: 60000 + minIdle: 1 + timeBetweenEvictionRunsMillis: 28000 + minEvictableIdleTimeMillis: 28000 + validationQuery: select 'x' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + poolPreparedStatements: true + maxOpenPreparedStatements: 20 + # REDIS + redis: + host: 127.0.0.1 + port: 6379 + password: ENC(QFwqv3NshvvGhFPiP8rwhvbnxk+rFSqhJi8Pw6TogSg=) + timeout: 3600 + expire: 1800 #30分钟 + database: 1 + defaultExpiration: 2592000 # 默认生命周期30天 + jedis: + pool: + max-active: 50 + max-idle: 30 + max-wait: -1 + min-idle: 0 + # EMAIL + mail: + host: smtp.exmail.qq.com + username: ENC(TtJQE2C4cWo8CpVGMMl5hiy5eykepd96J5XjsW3Kj5fgP+6+5ctDNQ==) + password: ENC(Zh6A6kRtA2ABtH6nzdvsqQSO1/8p3mparJr8neI2BLU=) # 授权密码 + properties: + mail: + smtp: + auth: true + starttls: + enable: true + socketFactory: + port: 465 + class: javax.net.ssl.SSLSocketFactory + # RABBITMQ + rabbitmq: + host: 127.0.0.1 + port: 5672 + username: ENC(aSRr6mnSryEqzHHz1hJf1g==) + password: ENC(GnjF/mdqKdvmDYC0tIIso7+20/jBALPw39tiWCYJ4iw=) + publisher-confirms: true + virtual-host: / + +aws: + clientRegion: cn-northwest-1 + bucketName: iformall-net + access: ENC(NCLcmjwKpAWdn/abD17OKIY7yKepVLWzEpqRYUlURCw=) + secret: ENC(TRcZqql0Rq5PExlMeH/4WiZ/i02b8FXKmLTBChJmbluTa1uoLS9LrHyNEMrqe1DK+QgOAdvqGBo=) + +wechat: + open: + componentAppId: ENC(hnH31XdNzArfMfikKgBFpqQuJUl6rVOPFFcAVyb595o=) + componentSecret: ENC(t/GUVX5L+U7LCwSvZ5WmxAnmTMrc/Uy1nljsrokuzzsBL2j6BEVnrS/n7DCdGc/G) + componentToken: ENC(gUF1m0YgCCI2IY54fX6sGLZVlCswA8tG) + componentAesKey: ENC(TYHcrIkICtfrCfGq4HW6s1b/pHf7OD2uyPN11SzJNB0acqJ/4JVX1nuljo/cAtgMG4O05TImLQc=) + redis: + host: 127.0.0.1 + port: 6379 + password: ENC(QFwqv3NshvvGhFPiP8rwhvbnxk+rFSqhJi8Pw6TogSg=) + timeout: 3600 + expire: 1800 #30分钟 + database: 2 + defaultExpiration: 2592000 # 默认生命周期30天 + jedis: + pool: + max-active: 100 + max-idle: 100 + max-wait: -1 + min-idle: 10 + +fm: + exception: true + exception_emails: hupeng@iformall.com,wuguoqiang@iformall.com,gongbiao@iformall.com,luozukai@iformall.com + deploy: 2 + open: true + upload_dir: /home/ec2-user/server/uploads/ + +logging: + level: + tk.mybatis: debug + com.iformall: debug + path: ./logs/b \ No newline at end of file diff --git a/mallinkPosApi/src/main/resources/application.yml b/mallinkPosApi/src/main/resources/application.yml new file mode 100644 index 000000000..2fd5dd18b --- /dev/null +++ b/mallinkPosApi/src/main/resources/application.yml @@ -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@ \ No newline at end of file diff --git a/mallinkPosApi/src/main/resources/logback-spring.xml b/mallinkPosApi/src/main/resources/logback-spring.xml new file mode 100644 index 000000000..2525413f1 --- /dev/null +++ b/mallinkPosApi/src/main/resources/logback-spring.xml @@ -0,0 +1,100 @@ + + + + + + + + [%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] --%mdc{client}%msg%n + + + + + ${logPath}/trace.log + + ${logPath}/daily/trace.%d{yyyy-MM-dd}.log + 180 + + + [%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n + + + + + ${logPath}/info.log + + ${logPath}/daily/info.%d{yyyy-MM-dd}.log + 180 + + + [%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n + + + INFO + ACCEPT + DENY + + + + + ${logPath}/debug.log + + ${logPath}/daily/debug.%d{yyyy-MM-dd}.log + 180 + + + [%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n + + + DEBUG + ACCEPT + DENY + + + + + + ${logPath}/warn.log + + ${logPath}/daily/warn.%d{yyyy-MM-dd}.log + 180 + + + [%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n + + + WARN + ACCEPT + DENY + + + + + + + ${logPath}/error.log + + ${logPath}/daily/error.%d{yyyy-MM-dd}.log + 180 + + + [%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mallinkPosApi/src/test/java/com/iformall/pos/test/PosAppTest.java b/mallinkPosApi/src/test/java/com/iformall/pos/test/PosAppTest.java new file mode 100644 index 000000000..647ec61b4 --- /dev/null +++ b/mallinkPosApi/src/test/java/com/iformall/pos/test/PosAppTest.java @@ -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 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 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 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 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 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 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 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 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 respMap = mapper.readValue(responseStr, Map.class); + boolean resSigned = WxPayment.verifyNotifyHMAC(respMap, devResKey); + System.out.println("response sign: " + resSigned); + Assert.assertEquals(resSigned, true); + } +} diff --git a/mallinkService/src/main/java/com/iformall/common/ErrorCode.java b/mallinkService/src/main/java/com/iformall/common/ErrorCode.java index bc029f63e..b1d877c5d 100644 --- a/mallinkService/src/main/java/com/iformall/common/ErrorCode.java +++ b/mallinkService/src/main/java/com/iformall/common/ErrorCode.java @@ -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, "卡券核销失败,请查看适用门店"), + /** * 解单 */ diff --git a/mallinkService/src/main/java/com/iformall/domain/po/PosCouponOrderVerify.java b/mallinkService/src/main/java/com/iformall/domain/po/PosCouponOrderVerify.java new file mode 100644 index 000000000..22221eef1 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/domain/po/PosCouponOrderVerify.java @@ -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 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; + + +} diff --git a/mallinkService/src/main/java/com/iformall/domain/po/ThDevInfo.java b/mallinkService/src/main/java/com/iformall/domain/po/ThDevInfo.java new file mode 100644 index 000000000..1b02cecb2 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/domain/po/ThDevInfo.java @@ -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 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; +} diff --git a/mallinkService/src/main/java/com/iformall/domain/po/WxCouponOrder.java b/mallinkService/src/main/java/com/iformall/domain/po/WxCouponOrder.java index 75807c1c2..1eb5985f5 100644 --- a/mallinkService/src/main/java/com/iformall/domain/po/WxCouponOrder.java +++ b/mallinkService/src/main/java/com/iformall/domain/po/WxCouponOrder.java @@ -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; diff --git a/mallinkService/src/main/java/com/iformall/domain/vo/WxLevelMerchantCVo.java b/mallinkService/src/main/java/com/iformall/domain/vo/WxLevelMerchantCVo.java index cb3b9bdf4..951f765ba 100644 --- a/mallinkService/src/main/java/com/iformall/domain/vo/WxLevelMerchantCVo.java +++ b/mallinkService/src/main/java/com/iformall/domain/vo/WxLevelMerchantCVo.java @@ -32,7 +32,7 @@ public class WxLevelMerchantCVo implements Serializable { @io.swagger.annotations.ApiModelProperty(value = "店铺列表", name = "shopVoList") private List shopVoList; - @io.swagger.annotations.ApiModelProperty(value="折扣",name="discount") + @io.swagger.annotations.ApiModelProperty(value="折扣(0-100折扣)",name="discount") private Integer discount; @Transient diff --git a/mallinkService/src/main/java/com/iformall/enums/EnumCouponOrderStatus.java b/mallinkService/src/main/java/com/iformall/enums/EnumCouponOrderStatus.java index c54dd044a..9d66e0d54 100644 --- a/mallinkService/src/main/java/com/iformall/enums/EnumCouponOrderStatus.java +++ b/mallinkService/src/main/java/com/iformall/enums/EnumCouponOrderStatus.java @@ -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) { diff --git a/mallinkService/src/main/java/com/iformall/enums/EnumVerifyActionType.java b/mallinkService/src/main/java/com/iformall/enums/EnumVerifyActionType.java new file mode 100644 index 000000000..715ca2824 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/enums/EnumVerifyActionType.java @@ -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; + } +} diff --git a/mallinkService/src/main/java/com/iformall/enums/EnumVerifyType.java b/mallinkService/src/main/java/com/iformall/enums/EnumVerifyType.java new file mode 100644 index 000000000..e2ce306a5 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/enums/EnumVerifyType.java @@ -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; + } +} diff --git a/mallinkService/src/main/java/com/iformall/mapper/PosCouponOrderVerifyMapper.java b/mallinkService/src/main/java/com/iformall/mapper/PosCouponOrderVerifyMapper.java new file mode 100644 index 000000000..fd6555c4c --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/mapper/PosCouponOrderVerifyMapper.java @@ -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 { + + List findList(PosCouponOrderVerify posCouponOrderVerify); + + + + + + +} diff --git a/mallinkService/src/main/java/com/iformall/mapper/ThDevInfoMapper.java b/mallinkService/src/main/java/com/iformall/mapper/ThDevInfoMapper.java new file mode 100644 index 000000000..4ae2d26ce --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/mapper/ThDevInfoMapper.java @@ -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 { + + List findList(ThDevInfo thDevInfo); + + + + + + +} diff --git a/mallinkService/src/main/java/com/iformall/mapper/WxCouponOrderMapper.java b/mallinkService/src/main/java/com/iformall/mapper/WxCouponOrderMapper.java index 7c74034ec..318b5178e 100644 --- a/mallinkService/src/main/java/com/iformall/mapper/WxCouponOrderMapper.java +++ b/mallinkService/src/main/java/com/iformall/mapper/WxCouponOrderMapper.java @@ -69,4 +69,8 @@ public interface WxCouponOrderMapper extends CommonMapper { //// 卡相关接口 List findCardListOfCUser(WxCardCVo wxCardCVo); WxCardCVo findCardDetailOfCUser(@Param("id")Long id); + + + /// POS接口 + List findAvailCouponOrder(Map params); } diff --git a/mallinkService/src/main/java/com/iformall/pay/WxPayConstant.java b/mallinkService/src/main/java/com/iformall/pay/WxPayConstant.java new file mode 100644 index 000000000..b0eecf929 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/pay/WxPayConstant.java @@ -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"; + +} diff --git a/mallinkService/src/main/java/com/iformall/pay/WxPayment.java b/mallinkService/src/main/java/com/iformall/pay/WxPayment.java index f5da84065..f8931e90b 100644 --- a/mallinkService/src/main/java/com/iformall/pay/WxPayment.java +++ b/mallinkService/src/main/java/com/iformall/pay/WxPayment.java @@ -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 buildSignAfterParasMapForHMAC(Map params, String paternerKey) { + params.put("nonce_str", Utility.generateUUID().replace("-", "")); + String sign = WxPayment.createSignHMAC(params, paternerKey); + params.put("sign", sign); + return params; + } + /** * 生成签名 * diff --git a/mallinkService/src/main/java/com/iformall/service/PosCouponOrderVerifyService.java b/mallinkService/src/main/java/com/iformall/service/PosCouponOrderVerifyService.java new file mode 100644 index 000000000..076262ce1 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/PosCouponOrderVerifyService.java @@ -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 listAsPage(PosCouponOrderVerify record, Integer pageIndex, Integer pageSize); + + /** + * 根据实体查询列表 + * + * @param record + * @return + */ + List getList(PosCouponOrderVerify record); + + /** + * 根据Id获得实体 + * + * @param id + * @return + */ + PosCouponOrderVerify getById(Long id); + + /** + * 保存或更新实体 + * + * @param record + */ + void saveOrUpdate(PosCouponOrderVerify record); + + /** + * 根据Id删除实体 + * + * @param id + */ + void deleteById(Long id); + + + + + + + + +} diff --git a/mallinkService/src/main/java/com/iformall/service/ThDevInfoService.java b/mallinkService/src/main/java/com/iformall/service/ThDevInfoService.java new file mode 100644 index 000000000..50133a7ff --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/ThDevInfoService.java @@ -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 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); + + + + + + + + +} diff --git a/mallinkService/src/main/java/com/iformall/service/WxCouponOrderService.java b/mallinkService/src/main/java/com/iformall/service/WxCouponOrderService.java index 339507e93..42e63f8dd 100644 --- a/mallinkService/src/main/java/com/iformall/service/WxCouponOrderService.java +++ b/mallinkService/src/main/java/com/iformall/service/WxCouponOrderService.java @@ -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 findAvailCouponOrder(Map params); + } diff --git a/mallinkService/src/main/java/com/iformall/service/WxCreditHistoryService.java b/mallinkService/src/main/java/com/iformall/service/WxCreditHistoryService.java index 95195bb91..9daa17641 100644 --- a/mallinkService/src/main/java/com/iformall/service/WxCreditHistoryService.java +++ b/mallinkService/src/main/java/com/iformall/service/WxCreditHistoryService.java @@ -45,6 +45,13 @@ public interface WxCreditHistoryService { */ WxCreditHistory saveOrUpdate(WxCreditHistory record); + /** + * 积分历史回退 + * + * @param record + */ + int cancelCredit(WxCreditHistory record); + /** * 根据Id删除实体 * diff --git a/mallinkService/src/main/java/com/iformall/service/WxScoreRulesService.java b/mallinkService/src/main/java/com/iformall/service/WxScoreRulesService.java index fd9ffa57e..398192a24 100644 --- a/mallinkService/src/main/java/com/iformall/service/WxScoreRulesService.java +++ b/mallinkService/src/main/java/com/iformall/service/WxScoreRulesService.java @@ -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); + /** * 增加成长值 */ diff --git a/mallinkService/src/main/java/com/iformall/service/impl/PosCouponOrderVerifyServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/PosCouponOrderVerifyServiceImpl.java new file mode 100644 index 000000000..3fc87acf8 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/impl/PosCouponOrderVerifyServiceImpl.java @@ -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 listAsPage(PosCouponOrderVerify record, Integer pageIndex, Integer pageSize) { + return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> posCouponOrderVerifyMapper.findList(record)); + } + + @Override + public List 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); + } + + + + + + + + +} diff --git a/mallinkService/src/main/java/com/iformall/service/impl/ThDevInfoServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/ThDevInfoServiceImpl.java new file mode 100644 index 000000000..9e2f2ed61 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/impl/ThDevInfoServiceImpl.java @@ -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 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); + } + + + + + + + + +} diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxCouponOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxCouponOrderServiceImpl.java index 14416d3af..3570c364a 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxCouponOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxCouponOrderServiceImpl.java @@ -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 findAvailCouponOrder(Map params) { + return wxCouponOrderMapper.findAvailCouponOrder(params); + } + } diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxCreditHistoryServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxCreditHistoryServiceImpl.java index e81e7d23b..11edc21b8 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxCreditHistoryServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxCreditHistoryServiceImpl.java @@ -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 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); diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxScoreRulesServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxScoreRulesServiceImpl.java index e44559cc1..b869fb09f 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxScoreRulesServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxScoreRulesServiceImpl.java @@ -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 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); diff --git a/mallinkService/src/main/resources/mapper/PosCouponOrderVerifyMapper.xml b/mallinkService/src/main/resources/mapper/PosCouponOrderVerifyMapper.xml new file mode 100644 index 000000000..7de6dec42 --- /dev/null +++ b/mallinkService/src/main/resources/mapper/PosCouponOrderVerifyMapper.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + `id`,`tenant_id`,`coupon_order_id`,`pos_order_id`,`state` + + + + where 1 = 1 + + and `id` = #{id} + + + and `tenant_id` like concat('%', #{tenantId},'%') + + + and `coupon_order_id` = #{couponOrderId} + + + and `pos_order_id` = #{posOrderId} + + + and `state` = #{state} + + + and id in + + #{idItem} + + + order by ${sortColumns} + + + + + + + + + + diff --git a/mallinkService/src/main/resources/mapper/ThDevInfoMapper.xml b/mallinkService/src/main/resources/mapper/ThDevInfoMapper.xml new file mode 100644 index 000000000..1962ae687 --- /dev/null +++ b/mallinkService/src/main/resources/mapper/ThDevInfoMapper.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + `id`,`dev_id`,`name`,`type`,`req_key`,`res_key`,`state`,`create_date`,`update_date` + + + + where 1 = 1 + + and `id` = #{id} + + + and `dev_id` like concat('%', #{devId},'%') + + + and `name` like concat('%', #{name},'%') + + + and `type` = #{type} + + + and `req_key` like concat('%', #{reqKey},'%') + + + and `res_key` like concat('%', #{resKey},'%') + + + and `state` = #{state} + + + and `create_date` = #{createDate} + + + and `update_date` = #{updateDate} + + + and id in + + #{idItem} + + + order by ${sortColumns} + + + + + + + + + + diff --git a/mallinkService/src/main/resources/mapper/WxCouponOrderMapper.xml b/mallinkService/src/main/resources/mapper/WxCouponOrderMapper.xml index fc7d92ff1..c18eca8b2 100644 --- a/mallinkService/src/main/resources/mapper/WxCouponOrderMapper.xml +++ b/mallinkService/src/main/resources/mapper/WxCouponOrderMapper.xml @@ -1018,4 +1018,28 @@ and co.id = #{id} + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index d18d6fd50..2e36ba0a1 100644 --- a/pom.xml +++ b/pom.xml @@ -18,6 +18,7 @@ mallinkSysAdmin mallinkCApi mallinkBApi + mallinkPosApi mallinkSchedule mallinkMQConsumer mallinkWebSocketServer @@ -375,4 +376,4 @@ --> - \ No newline at end of file +