v1.0:接入谷歌支付
This commit is contained in:
@@ -389,6 +389,8 @@ public class Constant {
|
||||
public static final String lucky_tarot = "lucky_tarot";
|
||||
// 新公众号:平台助手 h5支付
|
||||
public static final String wx_pub2_h5 = "wx_pub2_h5";
|
||||
// google play billing
|
||||
public static final String google_play_billing = "google_play_billing";
|
||||
}
|
||||
|
||||
public static class DepositStatus {
|
||||
@@ -1739,6 +1741,8 @@ public class Constant {
|
||||
|
||||
/** 魔法学院奖励配置 */
|
||||
public static final String ACT_MAGIC_SCHOOL_AWARD_CONFIG = "act_magic_school_award_config";
|
||||
|
||||
public static final String GOOGLE_PAY_LIMIT_CONFIG = "google_pay_limit_config";
|
||||
}
|
||||
|
||||
public static class ActiveMq {
|
||||
@@ -5574,5 +5578,23 @@ public class Constant {
|
||||
// 初次高级探险
|
||||
public static final Integer FIRST_HIGH = 2;
|
||||
}
|
||||
|
||||
public static final class GooglePurchaseState {
|
||||
/**
|
||||
* 已支付
|
||||
*/
|
||||
public static final Integer PURCHASED = 0;
|
||||
|
||||
/**
|
||||
* 取消
|
||||
*/
|
||||
public static final Integer CANCELED = 1;
|
||||
|
||||
/**
|
||||
* 支付中
|
||||
*/
|
||||
public static final Integer PENDING = 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -28,7 +28,11 @@
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>3.7.110.ALL</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.apis</groupId>
|
||||
<artifactId>google-api-services-androidpublisher</artifactId>
|
||||
<version>v3-rev24-1.24.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
@@ -0,0 +1,72 @@
|
||||
package com.accompany.payment.config;
|
||||
|
||||
import com.accompany.payment.google.AndroidPublisherHelper;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.google.api.services.androidpublisher.AndroidPublisher;
|
||||
import lombok.Data;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@Order(-1)
|
||||
@Lazy(false)
|
||||
@ConfigurationProperties(prefix = "google-play")
|
||||
@RefreshScope
|
||||
@Data
|
||||
public class GooglePlayConfig {
|
||||
|
||||
private String applicationName;
|
||||
|
||||
private String credentialJson;
|
||||
|
||||
private static final String CONFIG_NAME_APPLICATIONNAME = "google-play.applicationName";
|
||||
private static final String CONFIG_NAME_JSON = "google-play.credentialJson";
|
||||
@Autowired
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
@Bean("androidPublisher")
|
||||
public AndroidPublisher initAndroidPublisher() throws IOException, GeneralSecurityException {
|
||||
return AndroidPublisherHelper.init(applicationName, credentialJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置修改监听器,用于当配置修改后,重新生成AndroidPublisher bean
|
||||
* @param event
|
||||
*/
|
||||
@EventListener
|
||||
@Async
|
||||
public void handle(EnvironmentChangeEvent event) throws IOException, GeneralSecurityException {
|
||||
List<String> needReinitConfigFields = Arrays.asList(CONFIG_NAME_APPLICATIONNAME, CONFIG_NAME_JSON);
|
||||
boolean needReInit = false;
|
||||
for (String needReinitConfigField : needReinitConfigFields) {
|
||||
if (event.getKeys().contains(needReinitConfigField)) {
|
||||
needReInit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (needReInit) {
|
||||
String application = applicationContext.getEnvironment().getProperty(CONFIG_NAME_APPLICATIONNAME);
|
||||
String json = applicationContext.getEnvironment().getProperty(CONFIG_NAME_JSON);
|
||||
|
||||
AndroidPublisherHelper.init(application, json);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
package com.accompany.payment.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Created by 北岭山下 on 2017/7/13.
|
||||
*/
|
||||
@Data
|
||||
public class AppInnerPayRecordDTO {
|
||||
|
||||
private String recordId;
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package com.accompany.payment.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class GooglePayLimitConfigDTO {
|
||||
|
||||
/**
|
||||
* 每日总共限制总额金额
|
||||
*/
|
||||
private Long limitEveryDayAmount;
|
||||
|
||||
/**
|
||||
* 每日单人总共限制总额金额
|
||||
*/
|
||||
private Long limitEveryOneDaySumAmount;
|
||||
|
||||
/**
|
||||
* 错误提示
|
||||
*/
|
||||
private String errorTip;
|
||||
|
||||
/**
|
||||
* google内购项id
|
||||
*/
|
||||
private List<String> googleChargeProdIds;
|
||||
}
|
@@ -0,0 +1,107 @@
|
||||
package com.accompany.payment.google;
|
||||
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
||||
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.json.JsonFactory;
|
||||
import com.google.api.client.json.jackson2.JacksonFactory;
|
||||
import com.google.api.client.util.Preconditions;
|
||||
import com.google.api.client.util.Strings;
|
||||
import com.google.api.services.androidpublisher.AndroidPublisher;
|
||||
import com.google.api.services.androidpublisher.AndroidPublisherScopes;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Helper class to initialize the publisher APIs client library.
|
||||
* <p>
|
||||
* Before making any calls to the API through the client library you need to
|
||||
* call the {@link AndroidPublisherHelper#init(String, String, String, String)} method. This will run
|
||||
* all precondition checks for for client id and secret setup properly in
|
||||
* resources/client_secrets.json and authorize this client against the API.
|
||||
* </p>
|
||||
*/
|
||||
public class AndroidPublisherHelper {
|
||||
|
||||
private static final Log log = LogFactory.getLog(AndroidPublisherHelper.class);
|
||||
|
||||
/** Global instance of the JSON factory. */
|
||||
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
|
||||
|
||||
/** Global instance of the HTTP transport. */
|
||||
private static HttpTransport HTTP_TRANSPORT;
|
||||
|
||||
private static volatile AndroidPublisher androidPublisher;
|
||||
|
||||
private static volatile String oldApplicationName;
|
||||
|
||||
private static volatile String oldCredentialJson;
|
||||
|
||||
|
||||
public static AndroidPublisher init(String applicationName, String json) throws IOException, GeneralSecurityException {
|
||||
if (needInit(applicationName, json)) {
|
||||
synchronized (AndroidPublisherHelper.class) {
|
||||
if (needInit(applicationName, json) || androidPublisher == null) {
|
||||
log.info("start init AndroidPublisher");
|
||||
Preconditions.checkArgument(!Strings.isNullOrEmpty(applicationName),
|
||||
"applicationName cannot be null or empty!");
|
||||
|
||||
List<String> scopes = new ArrayList<>();
|
||||
scopes.add(AndroidPublisherScopes.ANDROIDPUBLISHER);
|
||||
ByteArrayResource resource = new ByteArrayResource(json.getBytes());
|
||||
GoogleCredential credential = GoogleCredential.fromStream(resource.getInputStream())
|
||||
.createScoped(scopes);
|
||||
|
||||
newTrustedTransport();
|
||||
|
||||
//使用谷歌凭据和收据从谷歌获取购买信息
|
||||
androidPublisher = new AndroidPublisher.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
|
||||
.setApplicationName(applicationName)
|
||||
.build();
|
||||
|
||||
oldApplicationName = applicationName;
|
||||
oldCredentialJson = json;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return androidPublisher;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否需要初始化
|
||||
* @param applicationName
|
||||
* @param credentialJsonPath
|
||||
* @return
|
||||
*/
|
||||
private static boolean needInit(String applicationName, String credentialJsonPath) {
|
||||
boolean firstInit = AndroidPublisherHelper.oldApplicationName == null || AndroidPublisherHelper.oldCredentialJson == null;
|
||||
|
||||
// json配置修改后,重新初始化
|
||||
boolean configChanged = StringUtils.isNotBlank(AndroidPublisherHelper.oldCredentialJson)
|
||||
&& !AndroidPublisherHelper.oldCredentialJson.equals(credentialJsonPath);
|
||||
|
||||
return firstInit || configChanged;
|
||||
}
|
||||
|
||||
private static void newTrustedTransport() throws GeneralSecurityException,
|
||||
IOException {
|
||||
if (null == HTTP_TRANSPORT) {
|
||||
HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
|
||||
}
|
||||
}
|
||||
|
||||
public static AndroidPublisher getPublisher() {
|
||||
Assert.notNull(androidPublisher, "should init before get bean");
|
||||
return androidPublisher;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,200 @@
|
||||
package com.accompany.payment.google;
|
||||
|
||||
import com.accompany.common.constant.Constant;
|
||||
import com.accompany.common.redis.RedisKey;
|
||||
import com.accompany.common.status.BusiStatus;
|
||||
import com.accompany.common.utils.DateTimeUtil;
|
||||
import com.accompany.common.utils.UUIDUitl;
|
||||
import com.accompany.core.exception.ServiceException;
|
||||
import com.accompany.core.model.Users;
|
||||
import com.accompany.core.service.SysConfService;
|
||||
import com.accompany.core.service.user.UsersBaseService;
|
||||
import com.accompany.payment.dto.AppInnerPayRecordDTO;
|
||||
import com.accompany.payment.dto.GooglePayLimitConfigDTO;
|
||||
import com.accompany.payment.model.ChargeProd;
|
||||
import com.accompany.payment.model.ChargeRecord;
|
||||
import com.accompany.payment.service.ChargeProdService;
|
||||
import com.accompany.payment.service.ChargeRecordService;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.api.services.androidpublisher.model.ProductPurchase;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* google 内购
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class GooglePlayBillingService {
|
||||
|
||||
@Autowired
|
||||
private RedissonClient redissonClient;
|
||||
@Autowired
|
||||
private ChargeRecordService chargeRecordService;
|
||||
@Autowired
|
||||
private ChargeProdService chargeProdService;
|
||||
@Autowired
|
||||
private SysConfService sysConfService;
|
||||
@Autowired
|
||||
private UsersBaseService usersBaseService;
|
||||
|
||||
protected String getPayChannel() {
|
||||
return Constant.ChargeChannel.google_play_billing;
|
||||
}
|
||||
|
||||
public AppInnerPayRecordDTO placeOrder(Long uid, String chargeProdId, String clientIp, String deviceId) {
|
||||
validMoneyLimit(uid, chargeProdId);
|
||||
|
||||
RLock lock = redissonClient.getLock(RedisKey.lock_apply_charge.getKey(uid.toString()));
|
||||
try {
|
||||
lock.tryLock(10, TimeUnit.SECONDS);
|
||||
|
||||
ChargeProd chargeProd = chargeProdService.getChargeProdById(chargeProdId);
|
||||
if (chargeProd == null) {
|
||||
log.error("充值产品不存在,prodId: {} ", chargeProdId);
|
||||
throw new ServiceException(BusiStatus.CHARGE_PROD_NOT_EXIST);
|
||||
}
|
||||
|
||||
String payChannel = getPayChannel();
|
||||
log.info("用户 {} 内购充值,渠道: {}", uid, payChannel);
|
||||
//保存充值记录
|
||||
//1.创建订单号
|
||||
//UUID不会重复,所以不需要判断是否生成重复的订单号
|
||||
String chargeRecordId = UUIDUitl.get();
|
||||
|
||||
Users users = usersBaseService.getUsersByUid(uid);
|
||||
//Integer region = users.getRegion() == null ? Constant.region.overseas : users.getRegion();
|
||||
|
||||
ChargeRecord chargeRecord = new ChargeRecord();
|
||||
chargeRecord.setChargeRecordId(chargeRecordId);
|
||||
chargeRecord.setChargeProdId(chargeProdId);
|
||||
chargeRecord.setUid(uid);
|
||||
//chargeRecord.setRegion(region.byteValue());
|
||||
chargeRecord.setChannel(payChannel);
|
||||
chargeRecord.setChargeStatus(Constant.ChargeRecordStatus.create);
|
||||
// product中money单位为分
|
||||
chargeRecord.setAmount(chargeProd.getMoney());
|
||||
chargeRecord.setSubject(chargeProd.getProdName());
|
||||
chargeRecord.setBody(chargeProd.getProdName());
|
||||
chargeRecord.setClientIp(clientIp);
|
||||
|
||||
//写入数据库
|
||||
chargeRecordService.insertChargeRecord(chargeRecord);
|
||||
log.info("用户 {} 内购充值,本地订单号: {}", uid, chargeRecordId);
|
||||
|
||||
//订单创建成功返回订单号
|
||||
AppInnerPayRecordDTO recordIdVo = new AppInnerPayRecordDTO();
|
||||
recordIdVo.setRecordId(chargeRecordId);
|
||||
return recordIdVo;
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
throw new ServiceException(BusiStatus.SERVERBUSY);
|
||||
} finally {
|
||||
if (lock.isLocked()){
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void validMoneyLimit(Long uid, String chargeProdId) {
|
||||
GooglePayLimitConfigDTO config = getLimitConfig();
|
||||
Date now = new Date();
|
||||
Date beginTimeOfDay = DateTimeUtil.getBeginTimeOfDay(now);
|
||||
Date endTimeOfDay = DateTimeUtil.getEndTimeOfDay(now);
|
||||
|
||||
ChargeProd chargeProd = chargeProdService.getChargeProdById(chargeProdId);
|
||||
if (chargeProd == null) {
|
||||
log.error("充值产品不存在,prodId: {} ", chargeProdId);
|
||||
throw new ServiceException(BusiStatus.CHARGE_PROD_NOT_EXIST);
|
||||
}
|
||||
|
||||
Long userChargeAmmount = chargeRecordService.getChargeUserAmountWithProdIds(Collections.singletonList(uid), config.getGoogleChargeProdIds(), beginTimeOfDay, endTimeOfDay);
|
||||
log.info("{}在{}-{}时间段内使用google内购充值了{}", uid, DateTimeUtil.convertDate(beginTimeOfDay), DateTimeUtil.convertDate(endTimeOfDay), userChargeAmmount);
|
||||
// 配置的单位是元,充值记录和产品的数据单位为分
|
||||
if (config.getLimitEveryOneDaySumAmount() * 100 < (chargeProd.getMoney() + userChargeAmmount)) {
|
||||
throw new ServiceException(config.getErrorTip());
|
||||
}
|
||||
Long allUserChargeAmount = chargeRecordService.getChargeUserAmountWithProdIds(null, config.getGoogleChargeProdIds(), beginTimeOfDay, endTimeOfDay);
|
||||
log.info("全部用户{}-{}内使用google内购充值了{}", DateTimeUtil.convertDate(beginTimeOfDay), DateTimeUtil.convertDate(endTimeOfDay), allUserChargeAmount);
|
||||
if (config.getLimitEveryDayAmount() * 100 < (chargeProd.getMoney() + allUserChargeAmount)) {
|
||||
throw new ServiceException(config.getErrorTip());
|
||||
}
|
||||
}
|
||||
|
||||
private GooglePayLimitConfigDTO getLimitConfig() {
|
||||
GooglePayLimitConfigDTO limitConfig = JSONObject.parseObject(sysConfService.getDefaultSysConfValueById(Constant.SysConfId.GOOGLE_PAY_LIMIT_CONFIG, "{}"), GooglePayLimitConfigDTO.class);
|
||||
if (limitConfig.getLimitEveryDayAmount() == null) {
|
||||
limitConfig.setLimitEveryDayAmount(9999999L);
|
||||
}
|
||||
if (limitConfig.getLimitEveryOneDaySumAmount() == null) {
|
||||
limitConfig.setLimitEveryOneDaySumAmount(9999999L);
|
||||
}
|
||||
if (limitConfig.getGoogleChargeProdIds() == null) {
|
||||
limitConfig.setGoogleChargeProdIds(Collections.emptyList());
|
||||
}
|
||||
if (StringUtils.isEmpty(limitConfig.getErrorTip())) {
|
||||
limitConfig.setErrorTip("充值失败,请联系客服处理");
|
||||
}
|
||||
return limitConfig;
|
||||
}
|
||||
|
||||
public ChargeRecord verifyOrder(String chargeRecordId, String packageName, String googlePlayProdId, String purchaseToken) {
|
||||
String lockKey = RedisKey.lock_pay_callback_notify.getKey(chargeRecordId);
|
||||
RLock lock = redissonClient.getLock(lockKey);
|
||||
try {
|
||||
lock.tryLock(5L, TimeUnit.SECONDS);
|
||||
|
||||
ChargeRecord chargeRecord = chargeRecordService.getChargeRecordById(chargeRecordId);
|
||||
if (chargeRecord == null) {
|
||||
log.error("[google play billing]充值记录不存在。chargeRecordId: {}", chargeRecordId);
|
||||
throw new ServiceException(BusiStatus.RECORD_NOT_EXIST);
|
||||
}
|
||||
if (!Constant.ChargeRecordStatus.create.equals(chargeRecord.getChargeStatus()) && !Constant.ChargeRecordStatus.error.equals(chargeRecord.getChargeStatus())) {
|
||||
log.info("[google play billing]订单状态不是创建或错误,不进行处理。chargeRecordId: {}", chargeRecordId);
|
||||
throw new ServiceException(BusiStatus.RECORD_ALREADY_EXIST);
|
||||
}
|
||||
|
||||
if (!chargeRecord.getChargeProdId().equalsIgnoreCase(googlePlayProdId)) {
|
||||
log.error("[google play billing]记录中的产品id和待查询内购产品id不一致。ChargeProdId: {}, googlePlayProdId: {}", chargeRecord.getChargeProdId(), googlePlayProdId);
|
||||
throw new ServiceException(BusiStatus.RECORD_NOT_EXIST);
|
||||
}
|
||||
|
||||
ProductPurchase purchase = AndroidPublisherHelper.getPublisher().purchases().products().get(packageName, googlePlayProdId, purchaseToken).execute();
|
||||
log.info("purchase: {}", JSONObject.toJSONString(purchase));
|
||||
if (purchase == null) {
|
||||
log.error("查询google购买记录返回为空。packageName: {}, prodId: {}, purchaseToken: {}", packageName, googlePlayProdId, purchaseToken);
|
||||
throw new ServiceException(BusiStatus.RECORD_NOT_EXIST);
|
||||
}
|
||||
|
||||
if (!Constant.GooglePurchaseState.PURCHASED.equals(purchase.getPurchaseState())) {
|
||||
log.error("[google play billing]订单未完成支付。当前状态: {}", purchase.getPurchaseState());
|
||||
throw new ServiceException(BusiStatus.RECORD_NOT_EXIST);
|
||||
}
|
||||
|
||||
chargeRecord.setPingxxChargeId(purchase.getOrderId());
|
||||
|
||||
return chargeRecord;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("[google play billing]校验google内购失败", e);
|
||||
if (e instanceof ServiceException) {
|
||||
throw (ServiceException)e;
|
||||
} else {
|
||||
throw new ServiceException(BusiStatus.BUSIERROR);
|
||||
}
|
||||
} finally {
|
||||
if (lock.isLocked()){
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -66,4 +66,8 @@ public interface ChargeRecordMapperMgr {
|
||||
|
||||
Long getHistoryRechargeAmountByChannel(@Param("userId") long userId, @Param("channel") String channel);
|
||||
|
||||
Long getChargeUserAmountWithProdIds(@Param("list") List<Long> uids, @Param("prodIds") List<String> prodIds,
|
||||
@Param("startTime") Date startTime, @Param("endTime") Date endTime);
|
||||
|
||||
|
||||
}
|
||||
|
@@ -173,4 +173,15 @@ public class ChargeRecordService extends BaseService {
|
||||
jedisLockService.unlock(RedisKey.ios__pay_user_toatl_amount_lock.getKey(userIdStr), lockVal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前时间段内用户充值金额
|
||||
**/
|
||||
public Long getChargeUserAmountWithProdIds(List<Long> uid, List<String> prods, Date startDate, Date endDate) {
|
||||
Long chargeUserAmountWithProdIds = chargeRecordMapperMgr.getChargeUserAmountWithProdIds(uid, prods, startDate, endDate);
|
||||
if (chargeUserAmountWithProdIds == null) {
|
||||
return 0L;
|
||||
}
|
||||
return chargeUserAmountWithProdIds;
|
||||
}
|
||||
}
|
||||
|
@@ -145,7 +145,8 @@
|
||||
#{wxPubOpenid,jdbcType=VARCHAR}, #{subject,jdbcType=VARCHAR}, #{body,jdbcType=VARCHAR},
|
||||
#{extra,jdbcType=VARCHAR}, #{metadata,jdbcType=VARCHAR}, #{chargeDesc,jdbcType=VARCHAR},
|
||||
#{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP})
|
||||
</insert>
|
||||
</insert>
|
||||
|
||||
<insert id="insertSelective" parameterType="com.accompany.payment.model.ChargeRecord">
|
||||
insert into charge_record
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
|
@@ -283,4 +283,19 @@
|
||||
<select id="getHistoryRechargeAmountByChannel" resultType="java.lang.Long">
|
||||
select IFNULL(sum(amount)/100,0) from charge_record WHERE buss_type in (0,4) and charge_status = 2 and uid = #{userId} and channel <> 'exchange' and channel = #{channel};
|
||||
</select>
|
||||
|
||||
<select id="getChargeUserAmountWithProdIds" resultType="java.lang.Long">
|
||||
select sum(amount) from charge_record
|
||||
where charge_status = 2
|
||||
<if test="list != null and list.size()>0">
|
||||
and uid in <foreach collection="list" item="uid" open="(" separator="," close=")">#{uid}</foreach>
|
||||
</if>
|
||||
and charge_prod_id in <foreach collection="prodIds" item="prodId" open="(" separator="," close=")">#{prodId}</foreach>
|
||||
<if test="startTime != null">
|
||||
and create_time > #{startTime}
|
||||
</if>
|
||||
<if test="endTime != null">
|
||||
and create_time < #{endTime}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
@@ -0,0 +1,56 @@
|
||||
package com.accompany.business.controller.apppay;
|
||||
|
||||
import com.accompany.business.service.ChargeService;
|
||||
import com.accompany.common.annotation.Authorization;
|
||||
import com.accompany.common.utils.IPUitls;
|
||||
import com.accompany.core.enumeration.BusinessStatusCodeEnum;
|
||||
import com.accompany.core.vo.BaseRequestVO;
|
||||
import com.accompany.core.vo.BaseResponseVO;
|
||||
import com.accompany.payment.dto.AppInnerPayRecordDTO;
|
||||
import com.accompany.payment.google.GooglePlayBillingService;
|
||||
import com.accompany.payment.model.ChargeProd;
|
||||
import com.accompany.payment.model.ChargeRecord;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@Api(tags = {"google内购"}, value = "google内购")
|
||||
@RestController
|
||||
@RequestMapping("/googlePlayBilling")
|
||||
@Slf4j
|
||||
public class GooglePlayBillingChargeController {
|
||||
|
||||
@Autowired
|
||||
private ChargeService chargeService;
|
||||
@Autowired
|
||||
private GooglePlayBillingService googlePlayBillingService;
|
||||
|
||||
@ApiOperation("google内购预下单")
|
||||
@PostMapping("/placeOrder")
|
||||
@Authorization
|
||||
public BaseResponseVO<AppInnerPayRecordDTO> placeOrder(String chargeProdId, HttpServletRequest request) {
|
||||
BaseRequestVO baseRequestVO = new BaseRequestVO();
|
||||
Long uid = baseRequestVO.getMyUserId();
|
||||
String clientIp = IPUitls.getRealIpAddress(request);
|
||||
String deviceId = baseRequestVO.getDeviceId();
|
||||
|
||||
AppInnerPayRecordDTO appInnerPayRecordDTO = googlePlayBillingService.placeOrder(uid, chargeProdId, clientIp, deviceId);
|
||||
|
||||
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS, appInnerPayRecordDTO);
|
||||
}
|
||||
|
||||
@ApiOperation("google内购订单校验")
|
||||
@PostMapping("/verifyOrder")
|
||||
@Authorization
|
||||
public BaseResponseVO<String> verifyOrder(String chargeRecordId, String packageName, String googlePlayProdId, String purchaseToken) {
|
||||
ChargeRecord chargeRecord = googlePlayBillingService.verifyOrder(chargeRecordId, packageName, googlePlayProdId, purchaseToken);
|
||||
chargeService.updateAppPayData(chargeRecord);
|
||||
return new BaseResponseVO<>(BusinessStatusCodeEnum.SUCCESS, BusinessStatusCodeEnum.SUCCESS.getReasonPhrase(), purchaseToken);
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
package servicetest;
|
||||
|
||||
import com.accompany.payment.google.AndroidPublisherHelper;
|
||||
import com.accompany.payment.google.GooglePlayBillingService;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.api.services.androidpublisher.model.ProductPurchase;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class GooglePlayBillingServiceTest extends CommonTest {
|
||||
|
||||
@Autowired
|
||||
private GooglePlayBillingService googlePlayBillingVerifyService;
|
||||
|
||||
@Test
|
||||
public void verifyOrderTest() throws Exception {
|
||||
String chargeRecordId = "d9e457c4e7bc4d918d1a869bc49003fd ";
|
||||
String packageName = "com.vele.ananplay";
|
||||
String prodId = "goods_cent_1499";
|
||||
String token ="lefpcedapihlpjcmjgnombhd.AO-J1OyZHdP6rv5D1sqFUyWsk1QbBuMS1oV4aTuet7CtgeKLZe_S6yjpOdkLpSTRT123gIQ8LSR7mWcayJtXCizwmMis7tqnTg";
|
||||
googlePlayBillingVerifyService.verifyOrder(chargeRecordId, packageName, prodId, token);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getGooglePurchaseTest() throws IOException {
|
||||
String packageName = "com.vele.ananplay";
|
||||
String prodId = "goods_cent_1499";
|
||||
String token ="lefpcedapihlpjcmjgnombhd.AO-J1OyZHdP6rv5D1sqFUyWsk1QbBuMS1oV4aTuet7CtgeKLZe_S6yjpOdkLpSTRT123gIQ8LSR7mWcayJtXCizwmMis7tqnTg";
|
||||
ProductPurchase purchase = AndroidPublisherHelper.getPublisher().purchases().products().get(packageName, prodId, token).execute();
|
||||
System.out.println(JSONObject.toJSONString(purchase));
|
||||
//System.out.println(JSONObject.parse(purchase.getObfuscatedExternalProfileId()).toString());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user