mirror of
				https://gitee.com/binary/weixin-java-tools.git
				synced 2025-11-01 03:25:35 +08:00 
			
		
		
		
	This commit is contained in:
		| @ -23,9 +23,13 @@ public class JedisWxRedisOps implements WxRedisOps { | |||||||
|   @Override |   @Override | ||||||
|   public void setValue(String key, String value, int expire, TimeUnit timeUnit) { |   public void setValue(String key, String value, int expire, TimeUnit timeUnit) { | ||||||
|     try (Jedis jedis = this.jedisPool.getResource()) { |     try (Jedis jedis = this.jedisPool.getResource()) { | ||||||
|  |       if (expire <= 0) { | ||||||
|  |         jedis.set(key, value); | ||||||
|  |       } else { | ||||||
|         jedis.psetex(key, timeUnit.toMillis(expire), value); |         jedis.psetex(key, timeUnit.toMillis(expire), value); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|   public Long getExpire(String key) { |   public Long getExpire(String key) { | ||||||
|  | |||||||
| @ -19,8 +19,12 @@ public class RedisTemplateWxRedisOps implements WxRedisOps { | |||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|   public void setValue(String key, String value, int expire, TimeUnit timeUnit) { |   public void setValue(String key, String value, int expire, TimeUnit timeUnit) { | ||||||
|  |     if (expire <= 0) { | ||||||
|  |       redisTemplate.opsForValue().set(key, value); | ||||||
|  |     } else { | ||||||
|       redisTemplate.opsForValue().set(key, value, expire, timeUnit); |       redisTemplate.opsForValue().set(key, value, expire, timeUnit); | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|   public Long getExpire(String key) { |   public Long getExpire(String key) { | ||||||
|  | |||||||
| @ -19,12 +19,20 @@ public class RedissonWxRedisOps implements WxRedisOps { | |||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|   public void setValue(String key, String value, int expire, TimeUnit timeUnit) { |   public void setValue(String key, String value, int expire, TimeUnit timeUnit) { | ||||||
|  |     if (expire <= 0) { | ||||||
|  |       redissonClient.getBucket(key).set(value); | ||||||
|  |     } else { | ||||||
|       redissonClient.getBucket(key).set(value, expire, timeUnit); |       redissonClient.getBucket(key).set(value, expire, timeUnit); | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|   public Long getExpire(String key) { |   public Long getExpire(String key) { | ||||||
|     return redissonClient.getBucket(key).remainTimeToLive(); |     long expire = redissonClient.getBucket(key).remainTimeToLive(); | ||||||
|  |     if (expire > 0) { | ||||||
|  |       expire = expire / 1000; | ||||||
|  |     } | ||||||
|  |     return expire; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|  | |||||||
| @ -0,0 +1,51 @@ | |||||||
|  | package me.chanjar.weixin.common.redis; | ||||||
|  |  | ||||||
|  | import org.testng.Assert; | ||||||
|  | import org.testng.annotations.Test; | ||||||
|  |  | ||||||
|  | import java.util.concurrent.TimeUnit; | ||||||
|  |  | ||||||
|  | public class CommonWxRedisOpsTest { | ||||||
|  |  | ||||||
|  |   protected WxRedisOps wxRedisOps; | ||||||
|  |   private String key = "access_token"; | ||||||
|  |   private String value = String.valueOf(System.currentTimeMillis()); | ||||||
|  |  | ||||||
|  |   @Test | ||||||
|  |   public void testGetValue() { | ||||||
|  |     wxRedisOps.setValue(key, value, 3, TimeUnit.SECONDS); | ||||||
|  |     Assert.assertEquals(wxRedisOps.getValue(key), value); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Test | ||||||
|  |   public void testSetValue() { | ||||||
|  |     String key = "access_token", value = String.valueOf(System.currentTimeMillis()); | ||||||
|  |     wxRedisOps.setValue(key, value, -1, TimeUnit.SECONDS); | ||||||
|  |     wxRedisOps.setValue(key, value, 0, TimeUnit.SECONDS); | ||||||
|  |     wxRedisOps.setValue(key, value, 1, TimeUnit.SECONDS); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Test | ||||||
|  |   public void testGetExpire() { | ||||||
|  |     String key = "access_token", value = String.valueOf(System.currentTimeMillis()); | ||||||
|  |     wxRedisOps.setValue(key, value, -1, TimeUnit.SECONDS); | ||||||
|  |     Assert.assertTrue(wxRedisOps.getExpire(key) < 0); | ||||||
|  |     wxRedisOps.setValue(key, value, 4, TimeUnit.SECONDS); | ||||||
|  |     Long expireSeconds = wxRedisOps.getExpire(key); | ||||||
|  |     Assert.assertTrue(expireSeconds <= 4 && expireSeconds >= 0); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Test | ||||||
|  |   public void testExpire() { | ||||||
|  |     String key = "access_token", value = String.valueOf(System.currentTimeMillis()); | ||||||
|  |     wxRedisOps.setValue(key, value, -1, TimeUnit.SECONDS); | ||||||
|  |     wxRedisOps.expire(key, 4, TimeUnit.SECONDS); | ||||||
|  |     Long expireSeconds = wxRedisOps.getExpire(key); | ||||||
|  |     Assert.assertTrue(expireSeconds <= 4 && expireSeconds >= 0); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Test | ||||||
|  |   public void testGetLock() { | ||||||
|  |     Assert.assertNotNull(wxRedisOps.getLock("access_token_lock")); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | package me.chanjar.weixin.common.redis; | ||||||
|  |  | ||||||
|  | import org.testng.annotations.AfterTest; | ||||||
|  | import org.testng.annotations.BeforeTest; | ||||||
|  | import redis.clients.jedis.JedisPool; | ||||||
|  |  | ||||||
|  | public class JedisWxRedisOpsTest extends CommonWxRedisOpsTest { | ||||||
|  |  | ||||||
|  |   JedisPool jedisPool; | ||||||
|  |  | ||||||
|  |   @BeforeTest | ||||||
|  |   public void init() { | ||||||
|  |     this.jedisPool = new JedisPool("127.0.0.1", 6379); | ||||||
|  |     this.wxRedisOps = new JedisWxRedisOps(jedisPool); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @AfterTest | ||||||
|  |   public void destroy() { | ||||||
|  |     this.jedisPool.close(); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,26 @@ | |||||||
|  | package me.chanjar.weixin.common.redis; | ||||||
|  |  | ||||||
|  | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; | ||||||
|  | import org.springframework.data.redis.core.StringRedisTemplate; | ||||||
|  | import org.testng.annotations.AfterTest; | ||||||
|  | import org.testng.annotations.BeforeTest; | ||||||
|  |  | ||||||
|  | public class RedisTemplateWxRedisOpsTest extends CommonWxRedisOpsTest { | ||||||
|  |  | ||||||
|  |   StringRedisTemplate redisTemplate; | ||||||
|  |  | ||||||
|  |   @BeforeTest | ||||||
|  |   public void init() { | ||||||
|  |     JedisConnectionFactory connectionFactory = new JedisConnectionFactory(); | ||||||
|  |     connectionFactory.setHostName("127.0.0.1"); | ||||||
|  |     connectionFactory.setPort(6379); | ||||||
|  |     connectionFactory.afterPropertiesSet(); | ||||||
|  |     StringRedisTemplate redisTemplate = new StringRedisTemplate(connectionFactory); | ||||||
|  |     this.redisTemplate = redisTemplate; | ||||||
|  |     this.wxRedisOps = new RedisTemplateWxRedisOps(this.redisTemplate); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @AfterTest | ||||||
|  |   public void destroy() { | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,27 @@ | |||||||
|  | package me.chanjar.weixin.common.redis; | ||||||
|  |  | ||||||
|  | import org.redisson.Redisson; | ||||||
|  | import org.redisson.api.RedissonClient; | ||||||
|  | import org.redisson.config.Config; | ||||||
|  | import org.redisson.config.TransportMode; | ||||||
|  | import org.testng.annotations.AfterTest; | ||||||
|  | import org.testng.annotations.BeforeTest; | ||||||
|  |  | ||||||
|  | public class RedissonWxRedisOpsTest extends CommonWxRedisOpsTest { | ||||||
|  |  | ||||||
|  |   RedissonClient redissonClient; | ||||||
|  |  | ||||||
|  |   @BeforeTest | ||||||
|  |   public void init() { | ||||||
|  |     Config config = new Config(); | ||||||
|  |     config.useSingleServer().setAddress("redis://127.0.0.1:6379"); | ||||||
|  |     config.setTransportMode(TransportMode.NIO); | ||||||
|  |     this.redissonClient = Redisson.create(config); | ||||||
|  |     this.wxRedisOps = new RedissonWxRedisOps(this.redissonClient); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @AfterTest | ||||||
|  |   public void destroy() { | ||||||
|  |     this.redissonClient.shutdown(); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,85 @@ | |||||||
|  | package me.chanjar.weixin.mp.api; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | import me.chanjar.weixin.common.error.WxErrorException; | ||||||
|  | import me.chanjar.weixin.mp.bean.invoice.merchant.*; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 商户电子发票相关的接口 | ||||||
|  |  * <p> | ||||||
|  |  * 重要!!!, 根据不同开票平台, 以下错误码可能开票成功(开票,冲红), 内部暂时未处理: | ||||||
|  |  * 73105: 开票平台开票中,请使用相同的发票请求流水号重试开票 | ||||||
|  |  * 73107: 发票请求流水正在被处理,请通过查询接口获取结果 | ||||||
|  |  * 73100: 开票平台错误 | ||||||
|  |  * <p> | ||||||
|  |  * 流程文档: https://developers.weixin.qq.com/doc/offiaccount/WeChat_Invoice/E_Invoice/Vendor_and_Invoicing_Platform_Mode_Instruction.html | ||||||
|  |  * 接口文档: https://developers.weixin.qq.com/doc/offiaccount/WeChat_Invoice/E_Invoice/Vendor_API_List.html | ||||||
|  |  */ | ||||||
|  | public interface WxMpMerchantInvoiceService { | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 获取开票授权页链接 | ||||||
|  |    */ | ||||||
|  |   InvoiceAuthPageResult getAuthPageUrl(InvoiceAuthPageRequest params) throws WxErrorException; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 获得用户授权数据 | ||||||
|  |    */ | ||||||
|  |   InvoiceAuthDataResult getAuthData(InvoiceAuthDataRequest params) throws WxErrorException; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 拒绝开票 | ||||||
|  |    * <p> | ||||||
|  |    * 场景: 用户授权填写数据无效 | ||||||
|  |    * 结果: 用户会收到一条开票失败提示 | ||||||
|  |    */ | ||||||
|  |   void rejectInvoice(InvoiceRejectRequest params) throws WxErrorException; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 开具电子发票 | ||||||
|  |    */ | ||||||
|  |   void makeOutInvoice(MakeOutInvoiceRequest params) throws WxErrorException; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 发票冲红 | ||||||
|  |    */ | ||||||
|  |   void clearOutInvoice(ClearOutInvoiceRequest params) throws WxErrorException; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 查询发票信息 | ||||||
|  |    * | ||||||
|  |    * @param fpqqlsh 发票请求流水号 | ||||||
|  |    * @param nsrsbh  纳税人识别号 | ||||||
|  |    */ | ||||||
|  |   InvoiceResult queryInvoiceInfo(String fpqqlsh, String nsrsbh) throws WxErrorException; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 设置商户联系方式, 获取授权链接前需要设置商户联系信息 | ||||||
|  |    */ | ||||||
|  |   void setMerchantContactInfo(MerchantContactInfo contact) throws WxErrorException; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 获取商户联系方式 | ||||||
|  |    */ | ||||||
|  |   MerchantContactInfo getMerchantContactInfo() throws WxErrorException; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 配置授权页面字段 | ||||||
|  |    */ | ||||||
|  |   void setAuthPageSetting(InvoiceAuthPageSetting authPageSetting) throws WxErrorException; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 获取授权页面配置 | ||||||
|  |    */ | ||||||
|  |   InvoiceAuthPageSetting getAuthPageSetting() throws WxErrorException; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 设置商户开票平台信息 | ||||||
|  |    */ | ||||||
|  |   void setMerchantInvoicePlatform(MerchantInvoicePlatformInfo merchantInvoicePlatformInfo) throws WxErrorException; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 获取商户开票平台信息 | ||||||
|  |    */ | ||||||
|  |   MerchantInvoicePlatformInfo getMerchantInvoicePlatform(MerchantInvoicePlatformInfo merchantInvoicePlatformInfo) throws WxErrorException; | ||||||
|  | } | ||||||
| @ -6,10 +6,13 @@ import com.google.gson.JsonArray; | |||||||
| import com.google.gson.JsonElement; | import com.google.gson.JsonElement; | ||||||
| import com.google.gson.JsonObject; | import com.google.gson.JsonObject; | ||||||
| import com.google.gson.JsonParser; | import com.google.gson.JsonParser; | ||||||
|  | import lombok.Getter; | ||||||
|  | import lombok.Setter; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import me.chanjar.weixin.common.WxType; | import me.chanjar.weixin.common.WxType; | ||||||
| import me.chanjar.weixin.common.bean.WxJsapiSignature; | import me.chanjar.weixin.common.bean.WxJsapiSignature; | ||||||
| import me.chanjar.weixin.common.bean.WxNetCheckResult; | import me.chanjar.weixin.common.bean.WxNetCheckResult; | ||||||
|  | import me.chanjar.weixin.common.enums.TicketType; | ||||||
| import me.chanjar.weixin.common.error.WxError; | import me.chanjar.weixin.common.error.WxError; | ||||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||||
| import me.chanjar.weixin.common.session.StandardSessionManager; | import me.chanjar.weixin.common.session.StandardSessionManager; | ||||||
| @ -26,7 +29,6 @@ import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; | |||||||
| import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult; | import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult; | ||||||
| import me.chanjar.weixin.mp.bean.result.WxMpUser; | import me.chanjar.weixin.mp.bean.result.WxMpUser; | ||||||
| import me.chanjar.weixin.mp.config.WxMpConfigStorage; | import me.chanjar.weixin.mp.config.WxMpConfigStorage; | ||||||
| import me.chanjar.weixin.common.enums.TicketType; |  | ||||||
| import me.chanjar.weixin.mp.enums.WxMpApiUrl; | import me.chanjar.weixin.mp.enums.WxMpApiUrl; | ||||||
| import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder; | import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder; | ||||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||||
| @ -70,6 +72,10 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH | |||||||
|   private WxMpOcrService ocrService = new WxMpOcrServiceImpl(this); |   private WxMpOcrService ocrService = new WxMpOcrServiceImpl(this); | ||||||
|   private WxMpImgProcService imgProcService = new WxMpImgProcServiceImpl(this); |   private WxMpImgProcService imgProcService = new WxMpImgProcServiceImpl(this); | ||||||
|  |  | ||||||
|  |   @Getter | ||||||
|  |   @Setter | ||||||
|  |   private WxMpMerchantInvoiceService merchantInvoiceService = new WxMpMerchantInvoiceServiceImpl(this, this.cardService); | ||||||
|  |  | ||||||
|   private Map<String, WxMpConfigStorage> configStorageMap; |   private Map<String, WxMpConfigStorage> configStorageMap; | ||||||
|  |  | ||||||
|   private int retrySleepMillis = 1000; |   private int retrySleepMillis = 1000; | ||||||
| @ -359,11 +365,11 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH | |||||||
|         // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token |         // 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token | ||||||
|         Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); |         Lock lock = this.getWxMpConfigStorage().getAccessTokenLock(); | ||||||
|         lock.lock(); |         lock.lock(); | ||||||
|         try{ |         try { | ||||||
|           if(StringUtils.equals(this.getWxMpConfigStorage().getAccessToken(), accessToken)){ |           if (StringUtils.equals(this.getWxMpConfigStorage().getAccessToken(), accessToken)) { | ||||||
|             this.getWxMpConfigStorage().expireAccessToken(); |             this.getWxMpConfigStorage().expireAccessToken(); | ||||||
|           } |           } | ||||||
|         } catch (Exception ex){ |         } catch (Exception ex) { | ||||||
|           this.getWxMpConfigStorage().expireAccessToken(); |           this.getWxMpConfigStorage().expireAccessToken(); | ||||||
|         } finally { |         } finally { | ||||||
|           lock.unlock(); |           lock.unlock(); | ||||||
|  | |||||||
| @ -0,0 +1,119 @@ | |||||||
|  | package me.chanjar.weixin.mp.api.impl; | ||||||
|  |  | ||||||
|  | import com.google.gson.FieldNamingPolicy; | ||||||
|  | import com.google.gson.Gson; | ||||||
|  | import com.google.gson.GsonBuilder; | ||||||
|  | import com.google.gson.JsonObject; | ||||||
|  | import lombok.AllArgsConstructor; | ||||||
|  | import me.chanjar.weixin.common.error.WxErrorException; | ||||||
|  | import me.chanjar.weixin.mp.api.WxMpCardService; | ||||||
|  | import me.chanjar.weixin.mp.api.WxMpMerchantInvoiceService; | ||||||
|  | import me.chanjar.weixin.mp.api.WxMpService; | ||||||
|  | import me.chanjar.weixin.mp.bean.invoice.merchant.*; | ||||||
|  | import me.chanjar.weixin.mp.enums.WxMpApiUrl; | ||||||
|  |  | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Map; | ||||||
|  |  | ||||||
|  | import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Invoice.*; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @AllArgsConstructor | ||||||
|  | public class WxMpMerchantInvoiceServiceImpl implements WxMpMerchantInvoiceService { | ||||||
|  |  | ||||||
|  |   private WxMpService wxMpService; | ||||||
|  |   private WxMpCardService wxMpCardService; | ||||||
|  |  | ||||||
|  |   private final static Gson gson; | ||||||
|  |  | ||||||
|  |   static { | ||||||
|  |     gson = new GsonBuilder() | ||||||
|  |       .disableHtmlEscaping() | ||||||
|  |       .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) | ||||||
|  |       .create(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public InvoiceAuthPageResult getAuthPageUrl(InvoiceAuthPageRequest params) throws WxErrorException { | ||||||
|  |     String ticket = wxMpCardService.getCardApiTicket(); | ||||||
|  |     params.setTicket(ticket); | ||||||
|  |     return doCommonInvoiceHttpPost(GET_AUTH_URL, params, InvoiceAuthPageResult.class); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public InvoiceAuthDataResult getAuthData(InvoiceAuthDataRequest params) throws WxErrorException { | ||||||
|  |     return doCommonInvoiceHttpPost(GET_AUTH_DATA, params, InvoiceAuthDataResult.class); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void rejectInvoice(InvoiceRejectRequest params) throws WxErrorException { | ||||||
|  |     doCommonInvoiceHttpPost(REJECT_INSERT, params, null); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void makeOutInvoice(MakeOutInvoiceRequest params) throws WxErrorException { | ||||||
|  |     doCommonInvoiceHttpPost(MAKE_OUT_INVOICE, params, null); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void clearOutInvoice(ClearOutInvoiceRequest params) throws WxErrorException { | ||||||
|  |     doCommonInvoiceHttpPost(CLEAR_OUT_INVOICE, params, null); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public InvoiceResult queryInvoiceInfo(String fpqqlsh, String nsrsbh) throws WxErrorException { | ||||||
|  |     Map data = new HashMap(); | ||||||
|  |     data.put("fpqqlsh", fpqqlsh); | ||||||
|  |     data.put("nsrsbh", nsrsbh); | ||||||
|  |     return doCommonInvoiceHttpPost(QUERY_INVOICE_INFO, data, InvoiceResult.class); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void setMerchantContactInfo(MerchantContactInfo contact) throws WxErrorException { | ||||||
|  |     MerchantContactInfoWrapper data = new MerchantContactInfoWrapper(); | ||||||
|  |     data.setContact(contact); | ||||||
|  |     doCommonInvoiceHttpPost(SET_CONTACT_SET_BIZ_ATTR, data, null); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public MerchantContactInfo getMerchantContactInfo() throws WxErrorException { | ||||||
|  |     MerchantContactInfoWrapper merchantContactInfoWrapper = doCommonInvoiceHttpPost(GET_CONTACT_SET_BIZ_ATTR, null, MerchantContactInfoWrapper.class); | ||||||
|  |     return merchantContactInfoWrapper == null ? null : merchantContactInfoWrapper.getContact(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void setAuthPageSetting(InvoiceAuthPageSetting authPageSetting) throws WxErrorException { | ||||||
|  |     doCommonInvoiceHttpPost(SET_AUTH_FIELD_SET_BIZ_ATTR, authPageSetting, null); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public InvoiceAuthPageSetting getAuthPageSetting() throws WxErrorException { | ||||||
|  |     return doCommonInvoiceHttpPost(GET_AUTH_FIELD_SET_BIZ_ATTR, new JsonObject(), InvoiceAuthPageSetting.class); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public void setMerchantInvoicePlatform(MerchantInvoicePlatformInfo paymchInfo) throws WxErrorException { | ||||||
|  |     MerchantInvoicePlatformInfoWrapper data = new MerchantInvoicePlatformInfoWrapper(); | ||||||
|  |     data.setPaymchInfo(paymchInfo); | ||||||
|  |     doCommonInvoiceHttpPost(SET_PAY_MCH_SET_BIZ_ATTR, data, null); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public MerchantInvoicePlatformInfo getMerchantInvoicePlatform(MerchantInvoicePlatformInfo merchantInvoicePlatformInfo) throws WxErrorException { | ||||||
|  |     MerchantInvoicePlatformInfoWrapper result = doCommonInvoiceHttpPost(GET_PAY_MCH_SET_BIZ_ATTR, new JsonObject(), MerchantInvoicePlatformInfoWrapper.class); | ||||||
|  |     return result == null ? null : result.getPaymchInfo(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 电子发票公用post请求方法 | ||||||
|  |    */ | ||||||
|  |   private <T> T doCommonInvoiceHttpPost(WxMpApiUrl url, Object data, Class<T> resultClass) throws WxErrorException { | ||||||
|  |     String json = ""; | ||||||
|  |     if (data != null) { | ||||||
|  |       json = gson.toJson(data); | ||||||
|  |     } | ||||||
|  |     String responseText = wxMpService.post(url, json); | ||||||
|  |     if (resultClass == null) return null; | ||||||
|  |     return gson.fromJson(responseText, resultClass); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,50 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.invoice.merchant; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 发票充红请求参数 | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | public class ClearOutInvoiceRequest implements Serializable { | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   private ClearOutInvoiceInfo invoiceinfo; | ||||||
|  |  | ||||||
|  |   @Data | ||||||
|  |   public static class ClearOutInvoiceInfo implements Serializable { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 用户的openid 用户知道是谁在开票 | ||||||
|  |      */ | ||||||
|  |     private String wxopenid; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 发票请求流水号,唯一查询发票的流水号 | ||||||
|  |      */ | ||||||
|  |     private String fpqqlsh; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 纳税人识别码 | ||||||
|  |      */ | ||||||
|  |     private String nsrsbh; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 纳税人名称 | ||||||
|  |      */ | ||||||
|  |     private String nsrmc; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 原发票代码,即要冲红的蓝票的发票代码 | ||||||
|  |      */ | ||||||
|  |     private String yfpdm; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 原发票号码,即要冲红的蓝票的发票号码 | ||||||
|  |      */ | ||||||
|  |     private String yfphm; | ||||||
|  |  | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.invoice.merchant; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 获取电子开票用户授权数据 | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | public class InvoiceAuthDataRequest implements Serializable { | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 开票平台在微信的标识号,商户需要找开票平台提供 | ||||||
|  |    */ | ||||||
|  |   private String sPappid; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 订单id,在商户内单笔开票请求的唯一识别号 | ||||||
|  |    */ | ||||||
|  |   private String orderId; | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,66 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.invoice.merchant; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 用户开票认证信息返回结果DTO | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | public class InvoiceAuthDataResult implements Serializable { | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 订单授权状态,当errcode为0时会出现 | ||||||
|  |    */ | ||||||
|  |   private String invoiceStatus; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 授权时间,为十位时间戳(utc+8),当errcode为0时会出现 | ||||||
|  |    */ | ||||||
|  |   private Long authTime; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 用户授权信息 | ||||||
|  |    */ | ||||||
|  |   private UserAuthInfo userAuthInfo; | ||||||
|  |  | ||||||
|  |   @Data | ||||||
|  |   public static class UserAuthInfo implements Serializable { | ||||||
|  |     /** | ||||||
|  |      * 个人抬头 | ||||||
|  |      */ | ||||||
|  |     private UserField userField; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 单位抬头 | ||||||
|  |      */ | ||||||
|  |     private BizField bizField; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Data | ||||||
|  |   public static class UserField implements Serializable { | ||||||
|  |     private String title; | ||||||
|  |     private String phone; | ||||||
|  |     private String email; | ||||||
|  |     private List<KeyValuePair> customField; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Data | ||||||
|  |   public static class BizField implements Serializable { | ||||||
|  |     private String title; | ||||||
|  |     private String taxNo; | ||||||
|  |     private String addr; | ||||||
|  |     private String phone; | ||||||
|  |     private String bankType; | ||||||
|  |     private String bankNo; | ||||||
|  |     private List<KeyValuePair> customField; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Data | ||||||
|  |   public static class KeyValuePair implements Serializable { | ||||||
|  |     private String key; | ||||||
|  |     private String value; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,52 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.invoice.merchant; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 获取授权地址的输入参数 | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | public class InvoiceAuthPageRequest implements Serializable { | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 开票平台在微信的标识号,商户需要找开票平台提供 | ||||||
|  |    */ | ||||||
|  |   private String sPappid; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 订单id,在商户内单笔开票请求的唯一识别号 | ||||||
|  |    */ | ||||||
|  |   private String orderId; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 订单金额,以分为单位 | ||||||
|  |    */ | ||||||
|  |   private Long money; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 开票来源 | ||||||
|  |    */ | ||||||
|  |   private String source; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 授权成功后跳转页面。本字段只有在source为H5的时候需要填写,引导用户在微信中进行下一步流程。app开票因为从外部app拉起微信授权页,授权完成后自动回到原来的app,故无需填写。 | ||||||
|  |    */ | ||||||
|  |   private String redirectUrl; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 授权类型,0:开票授权,1:填写字段开票授权,2:领票授权 | ||||||
|  |    */ | ||||||
|  |   private Integer type; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 时间戳单位s | ||||||
|  |    */ | ||||||
|  |   private Long timestamp; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 内部填充(请务设置) | ||||||
|  |    */ | ||||||
|  |   private String ticket; | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.invoice.merchant; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 获取授权链接返回结果DTO | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | public class InvoiceAuthPageResult implements Serializable { | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 授权页地址 | ||||||
|  |    */ | ||||||
|  |   private String authUrl; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 当发起端为小程序时, 返回 | ||||||
|  |    */ | ||||||
|  |   private String appid; | ||||||
|  | } | ||||||
| @ -0,0 +1,61 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.invoice.merchant; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | @Data | ||||||
|  | public class InvoiceAuthPageSetting implements Serializable { | ||||||
|  |  | ||||||
|  |   private AuthField authField; | ||||||
|  |  | ||||||
|  |   @Data | ||||||
|  |   public static class AuthField implements Serializable { | ||||||
|  |     private UserField userField; | ||||||
|  |     private BizField bizField; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Data | ||||||
|  |   public static class UserField implements Serializable { | ||||||
|  |     private Integer showTitle; | ||||||
|  |     private Integer showPhone; | ||||||
|  |     private Integer showEmail; | ||||||
|  |     private Integer requirePhone; | ||||||
|  |     private Integer requireEmail; | ||||||
|  |     private List<InvoiceAuthDataResult.KeyValuePair> customField; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Data | ||||||
|  |   public static class BizField implements Serializable { | ||||||
|  |     private Integer showTitle; | ||||||
|  |     private Integer showTaxNo; | ||||||
|  |     private Integer showAddr; | ||||||
|  |     private Integer showPhone; | ||||||
|  |     private Integer showBankType; | ||||||
|  |     private Integer showBankNo; | ||||||
|  |  | ||||||
|  |     private Integer requireTaxNo; | ||||||
|  |     private Integer requireAddr; | ||||||
|  |     private Integer requirePhone; | ||||||
|  |     private Integer requireBankType; | ||||||
|  |     private Integer requireBankNo; | ||||||
|  |     private List<InvoiceAuthDataResult.KeyValuePair> customField; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Data | ||||||
|  |   public static class CustomField implements Serializable { | ||||||
|  |     /** | ||||||
|  |      * 字段名 | ||||||
|  |      */ | ||||||
|  |     private String key; | ||||||
|  |     /** | ||||||
|  |      * 0:否,1:是, 默认为0 | ||||||
|  |      */ | ||||||
|  |     private Integer isRequire; | ||||||
|  |     /** | ||||||
|  |      * 提示文案 | ||||||
|  |      */ | ||||||
|  |     private String notice; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,30 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.invoice.merchant; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 拒绝开票请求参数 | ||||||
|  |  */ | ||||||
|  | public class InvoiceRejectRequest implements Serializable { | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 开票平台标示 | ||||||
|  |    */ | ||||||
|  |   private String sPappid; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 订单id | ||||||
|  |    */ | ||||||
|  |   private String orderId; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 拒绝原因 | ||||||
|  |    */ | ||||||
|  |   private String reason; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 引导用户跳转url | ||||||
|  |    */ | ||||||
|  |   private String url; | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,52 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.invoice.merchant; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 电子发票信息查询结果 | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | public class InvoiceResult implements Serializable { | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 发票相关信息 | ||||||
|  |    */ | ||||||
|  |   private InvoiceDetail invoicedetail; | ||||||
|  |  | ||||||
|  |   @Data | ||||||
|  |   public static class InvoiceDetail implements Serializable { | ||||||
|  |     /** | ||||||
|  |      * 发票流水号 | ||||||
|  |      */ | ||||||
|  |     private String fpqqlsh; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 检验码 | ||||||
|  |      */ | ||||||
|  |     private String jym; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 校验码 | ||||||
|  |      */ | ||||||
|  |     private String kprq; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 发票代码 | ||||||
|  |      */ | ||||||
|  |     private String fpdm; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 发票号码 | ||||||
|  |      */ | ||||||
|  |     private String fphm; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 发票url | ||||||
|  |      */ | ||||||
|  |     private String pdfurl; | ||||||
|  |  | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,200 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.invoice.merchant; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 开票信息请求参数 | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | public class MakeOutInvoiceRequest implements Serializable { | ||||||
|  |  | ||||||
|  |   private InvoiceInfo invoiceinfo; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 发票信息 | ||||||
|  |    */ | ||||||
|  |   @Data | ||||||
|  |   public static class InvoiceInfo implements Serializable { | ||||||
|  |     /** | ||||||
|  |      * 维修openid | ||||||
|  |      */ | ||||||
|  |     private String wxopenid; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 订单号 | ||||||
|  |      */ | ||||||
|  |     private String ddh; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 发票请求流水号,唯一识别开票请求的流水号 | ||||||
|  |      */ | ||||||
|  |     private String fpqqlsh; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 纳税人识别码 | ||||||
|  |      */ | ||||||
|  |     private String nsrsbh; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 纳税人名称 | ||||||
|  |      */ | ||||||
|  |     private String nsrmc; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 纳税人地址 | ||||||
|  |      */ | ||||||
|  |     private String nsrdz; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 纳税人电话 | ||||||
|  |      */ | ||||||
|  |     private String nsrdh; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 纳税人开户行 | ||||||
|  |      */ | ||||||
|  |     private String nsrbank; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 纳税人银行账号 | ||||||
|  |      */ | ||||||
|  |     private String nsrbankid; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 购货方名称 | ||||||
|  |      */ | ||||||
|  |     private String ghfnsrsbh; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 购货方识别号 | ||||||
|  |      */ | ||||||
|  |     private String ghfmc; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 购货方地址 | ||||||
|  |      */ | ||||||
|  |     private String ghfdz; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 购货方电话 | ||||||
|  |      */ | ||||||
|  |     private String ghfdh; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 购货方开户行 | ||||||
|  |      */ | ||||||
|  |     private String ghfbank; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 购货方银行帐号 | ||||||
|  |      */ | ||||||
|  |     private String ghfbankid; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 开票人 | ||||||
|  |      */ | ||||||
|  |     private String kpr; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 收款人 | ||||||
|  |      */ | ||||||
|  |     private String skr; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 复核人 | ||||||
|  |      */ | ||||||
|  |     private String fhr; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 价税合计 | ||||||
|  |      */ | ||||||
|  |     private String jshj; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 合计金额 | ||||||
|  |      */ | ||||||
|  |     private String hjje; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 合计税额 | ||||||
|  |      */ | ||||||
|  |     private String hjse; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 备注 | ||||||
|  |      */ | ||||||
|  |     private String bz; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 行业类型 0 商业 1其它 | ||||||
|  |      */ | ||||||
|  |     private String hylx; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 发票商品条目 | ||||||
|  |      */ | ||||||
|  |     private List<InvoiceDetailItem> invoicedetailList; | ||||||
|  |  | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 发票条目 | ||||||
|  |    */ | ||||||
|  |   @Data | ||||||
|  |   public static class InvoiceDetailItem implements Serializable { | ||||||
|  |     /** | ||||||
|  |      * 发票性质 | ||||||
|  |      */ | ||||||
|  |     private String fphxz; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 19位税收分类编码 | ||||||
|  |      */ | ||||||
|  |     private String spbm; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 项目名称 | ||||||
|  |      */ | ||||||
|  |     private String xmmc; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 计量单位 | ||||||
|  |      */ | ||||||
|  |     private String dw; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 规格型号 | ||||||
|  |      */ | ||||||
|  |     private String ggxh; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 项目数量 | ||||||
|  |      */ | ||||||
|  |     private String xmsl; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 项目单价 | ||||||
|  |      */ | ||||||
|  |     private String xmdj; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 项目金额 不含税,单位元 两位小数 | ||||||
|  |      */ | ||||||
|  |     private String xmje; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 税率 精确到两位小数 如0.01 | ||||||
|  |      */ | ||||||
|  |     private String sl; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 税额 单位元 两位小数 | ||||||
|  |      */ | ||||||
|  |     private String se; | ||||||
|  |  | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.invoice.merchant; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 商户联系信息 | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | public class MerchantContactInfo implements Serializable { | ||||||
|  |   /** | ||||||
|  |    * 联系电话 | ||||||
|  |    */ | ||||||
|  |   private String phone; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 开票超时时间 | ||||||
|  |    */ | ||||||
|  |   private Integer timeout; | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,16 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.invoice.merchant; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 设置商户联系信息和发票过时时间参数 | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | public class MerchantContactInfoWrapper implements Serializable { | ||||||
|  |  | ||||||
|  |   private MerchantContactInfo contact; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,19 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.invoice.merchant; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 商户的开票平台信息 | ||||||
|  |  */ | ||||||
|  | public class MerchantInvoicePlatformInfo implements Serializable { | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 微信支付商户号 | ||||||
|  |    */ | ||||||
|  |   private String mchid; | ||||||
|  |  | ||||||
|  |   /** | ||||||
|  |    * 为该商户提供开票服务的开票平台 id ,由开票平台提供给商户 | ||||||
|  |    */ | ||||||
|  |   private String sPappid; | ||||||
|  | } | ||||||
| @ -0,0 +1,15 @@ | |||||||
|  | package me.chanjar.weixin.mp.bean.invoice.merchant; | ||||||
|  |  | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.io.Serializable; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 设置商户联系信息和发票过时时间参数 | ||||||
|  |  */ | ||||||
|  | @Data | ||||||
|  | public class MerchantInvoicePlatformInfoWrapper implements Serializable { | ||||||
|  |  | ||||||
|  |   private MerchantInvoicePlatformInfo paymchInfo; | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -1082,4 +1082,78 @@ public interface WxMpApiUrl { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   @AllArgsConstructor | ||||||
|  |   enum Invoice implements WxMpApiUrl { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取用户开票授权地址 | ||||||
|  |      */ | ||||||
|  |     GET_AUTH_URL(API_DEFAULT_HOST_URL, "/card/invoice/getauthurl"), | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取用户开票授权信息 | ||||||
|  |      */ | ||||||
|  |     GET_AUTH_DATA(API_DEFAULT_HOST_URL, "/card/invoice/getauthdata"), | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 拒绝为用户开票 | ||||||
|  |      */ | ||||||
|  |     REJECT_INSERT(API_DEFAULT_HOST_URL, "/card/invoice/rejectinsert"), | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 开票 | ||||||
|  |      */ | ||||||
|  |     MAKE_OUT_INVOICE(API_DEFAULT_HOST_URL, "/card/invoice/makeoutinvoice"), | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 发票冲红 | ||||||
|  |      */ | ||||||
|  |     CLEAR_OUT_INVOICE(API_DEFAULT_HOST_URL, "/card/invoice/clearoutinvoice"), | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 查询发票信息 | ||||||
|  |      */ | ||||||
|  |     QUERY_INVOICE_INFO(API_DEFAULT_HOST_URL, "/card/invoice/queryinvoceinfo"), | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 设置商户信息联系 | ||||||
|  |      */ | ||||||
|  |     SET_CONTACT_SET_BIZ_ATTR(API_DEFAULT_HOST_URL, "/card/invoice/setbizattr?action=set_contact"), | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取商户联系信息 | ||||||
|  |      */ | ||||||
|  |     GET_CONTACT_SET_BIZ_ATTR(API_DEFAULT_HOST_URL, "/card/invoice/setbizattr?action=get_contact"), | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 设置授权页面字段 | ||||||
|  |      */ | ||||||
|  |     SET_AUTH_FIELD_SET_BIZ_ATTR(API_DEFAULT_HOST_URL, "/card/invoice/setbizattr?action=set_auth_field"), | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取授权页面字段 | ||||||
|  |      */ | ||||||
|  |     GET_AUTH_FIELD_SET_BIZ_ATTR(API_DEFAULT_HOST_URL, "/card/invoice/setbizattr?action=get_auth_field"), | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 设置关联商户 | ||||||
|  |      */ | ||||||
|  |     SET_PAY_MCH_SET_BIZ_ATTR(API_DEFAULT_HOST_URL, "/card/invoice/setbizattr?action=set_pay_mch"), | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取关联商户 | ||||||
|  |      */ | ||||||
|  |     GET_PAY_MCH_SET_BIZ_ATTR(API_DEFAULT_HOST_URL, "/card/invoice/setbizattr?action=get_pay_mch"), | ||||||
|  |     ; | ||||||
|  |     private String prefix; | ||||||
|  |     private String path; | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public String getUrl(WxMpConfigStorage config) { | ||||||
|  |       if (null == config) { | ||||||
|  |         return buildUrl(null, prefix, path); | ||||||
|  |       } | ||||||
|  |       return buildUrl(config.getHostConfig(), prefix, path); | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,10 +4,10 @@ package me.chanjar.weixin.open.api.impl; | |||||||
| import cn.binarywang.wx.miniapp.config.WxMaConfig; | import cn.binarywang.wx.miniapp.config.WxMaConfig; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
| import me.chanjar.weixin.common.bean.WxAccessToken; | import me.chanjar.weixin.common.bean.WxAccessToken; | ||||||
|  | import me.chanjar.weixin.common.enums.TicketType; | ||||||
| import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; | import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder; | ||||||
| import me.chanjar.weixin.mp.bean.WxMpHostConfig; | import me.chanjar.weixin.mp.bean.WxMpHostConfig; | ||||||
| import me.chanjar.weixin.mp.config.WxMpConfigStorage; | import me.chanjar.weixin.mp.config.WxMpConfigStorage; | ||||||
| import me.chanjar.weixin.common.enums.TicketType; |  | ||||||
| import me.chanjar.weixin.open.api.WxOpenConfigStorage; | import me.chanjar.weixin.open.api.WxOpenConfigStorage; | ||||||
| import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; | import me.chanjar.weixin.open.bean.WxOpenAuthorizerAccessToken; | ||||||
| import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; | import me.chanjar.weixin.open.bean.WxOpenComponentAccessToken; | ||||||
| @ -46,9 +46,6 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { | |||||||
|   private Map<String, Token> cardApiTickets = new ConcurrentHashMap<>(); |   private Map<String, Token> cardApiTickets = new ConcurrentHashMap<>(); | ||||||
|   private Map<String, Lock> locks = new ConcurrentHashMap<>(); |   private Map<String, Lock> locks = new ConcurrentHashMap<>(); | ||||||
|  |  | ||||||
|   private Lock componentAccessTokenLock = getLockByKey("componentAccessTokenLock"); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|   public boolean isComponentAccessTokenExpired() { |   public boolean isComponentAccessTokenExpired() { | ||||||
|     return System.currentTimeMillis() > componentExpiresTime; |     return System.currentTimeMillis() > componentExpiresTime; | ||||||
| @ -64,11 +61,25 @@ public class WxOpenInMemoryConfigStorage implements WxOpenConfigStorage { | |||||||
|     updateComponentAccessToken(componentAccessToken.getComponentAccessToken(), componentAccessToken.getExpiresIn()); |     updateComponentAccessToken(componentAccessToken.getComponentAccessToken(), componentAccessToken.getExpiresIn()); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   private Lock accessTokenLockInstance; | ||||||
|  |  | ||||||
|   @Override |   @Override | ||||||
|   public Lock getLockByKey(String key){ |   public Lock getComponentAccessTokenLock() { | ||||||
|  |     if (this.accessTokenLockInstance == null) { | ||||||
|  |       synchronized (this) { | ||||||
|  |         if (this.accessTokenLockInstance == null) { | ||||||
|  |           this.accessTokenLockInstance = getLockByKey("componentAccessTokenLock"); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return this.accessTokenLockInstance; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public Lock getLockByKey(String key) { | ||||||
|     Lock lock = locks.get(key); |     Lock lock = locks.get(key); | ||||||
|     if (lock == null) { |     if (lock == null) { | ||||||
|       synchronized (WxOpenInMemoryConfigStorage.class){ |       synchronized (this) { | ||||||
|         lock = locks.get(key); |         lock = locks.get(key); | ||||||
|         if (lock == null) { |         if (lock == null) { | ||||||
|           lock = new ReentrantLock(); |           lock = new ReentrantLock(); | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Mario Luo
					Mario Luo