RestApiPaypalService.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. package com.fdkankan.pay.util.paypal.restApi;
  2. import cn.hutool.core.date.DateTime;
  3. import cn.hutool.core.date.DateUtil;
  4. import cn.hutool.http.Header;
  5. import cn.hutool.http.HttpRequest;
  6. import cn.hutool.http.HttpResponse;
  7. import com.alibaba.fastjson.JSONObject;
  8. import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
  9. import com.fasterxml.jackson.core.JsonProcessingException;
  10. import com.fasterxml.jackson.databind.ObjectMapper;
  11. import com.fdkankan.pay.common.ResultCode;
  12. import com.fdkankan.pay.entity.AutopayOrder;
  13. import com.fdkankan.pay.entity.Order;
  14. import com.fdkankan.pay.entity.PaypalConfig;
  15. import com.fdkankan.pay.exception.BusinessException;
  16. import com.fdkankan.pay.service.IPaypalConfigService;
  17. import com.fdkankan.pay.util.CacheUtil;
  18. import com.fdkankan.pay.util.paypal.restApi.vo.EventTypeVo;
  19. import com.fdkankan.pay.util.paypal.restApi.vo.Product;
  20. import com.fdkankan.pay.util.paypal.restApi.vo.WebhookVo;
  21. import com.fdkankan.pay.util.paypal.restApi.vo.plan.*;
  22. import com.fdkankan.pay.util.paypal.restApi.vo.subscription.*;
  23. import com.paypal.api.payments.EventType;
  24. import com.paypal.api.payments.Links;
  25. import com.paypal.api.payments.Webhook;
  26. import com.paypal.api.payments.WebhookList;
  27. import com.paypal.base.rest.APIContext;
  28. import lombok.extern.slf4j.Slf4j;
  29. import org.apache.commons.lang.StringUtils;
  30. import org.springframework.beans.factory.annotation.Autowired;
  31. import org.springframework.stereotype.Service;
  32. import javax.annotation.PostConstruct;
  33. import java.io.IOException;
  34. import java.io.InputStream;
  35. import java.io.OutputStreamWriter;
  36. import java.net.HttpURLConnection;
  37. import java.net.URL;
  38. import java.time.*;
  39. import java.time.format.DateTimeFormatter;
  40. import java.util.*;
  41. @Service
  42. @Slf4j
  43. public class RestApiPaypalService {
  44. @Autowired
  45. IPaypalConfigService paypalConfigService;
  46. /**
  47. * 启动创建webhooks
  48. * https://testeur.4dkankan.com/service/pay/paypal/webhook
  49. */
  50. @PostConstruct
  51. public void createWebhooks() {
  52. log.info("--------------项目启动初始化webhook-------------");
  53. List<PaypalConfig> list = paypalConfigService.list();
  54. for (PaypalConfig paypalConfig : list) {
  55. if(StringUtils.isBlank(paypalConfig.getWebhookId())){
  56. try {
  57. Map<String,String> map = new HashMap<>(4);
  58. map.put("Content-Type","application/json");
  59. WebhookVo webhookVo = new WebhookVo();
  60. webhookVo.setUrl(paypalConfig.getWebhookHost() +"/service/pay/paypal/webhook");
  61. webhookVo.getEvent_types().add(new EventTypeVo("CATALOG.PRODUCT.CREATED"));
  62. webhookVo.getEvent_types().add(new EventTypeVo("BILLING.PLAN.CREATED"));
  63. webhookVo.getEvent_types().add(new EventTypeVo("BILLING.PLAN.ACTIVATED"));
  64. webhookVo.getEvent_types().add(new EventTypeVo("BILLING.SUBSCRIPTION.CREATED"));
  65. webhookVo.getEvent_types().add(new EventTypeVo("BILLING.SUBSCRIPTION.EXPIRED"));
  66. webhookVo.getEvent_types().add(new EventTypeVo("BILLING.SUBSCRIPTION.SUSPENDED"));
  67. webhookVo.getEvent_types().add(new EventTypeVo("PAYMENT.SALE.COMPLETED"));
  68. String string = JSONObject.toJSONString(webhookVo);
  69. String body = HttpRequest.post(paypalConfig.getBaseUrl() + "/v1/notifications/webhooks")
  70. .addHeaders(map)
  71. .basicAuth(paypalConfig.getClientId(), paypalConfig.getSecret())
  72. .body(string)
  73. .execute().body();
  74. log.info("paypal-createWebhooks:{}",body);
  75. JSONObject resp = JSONObject.parseObject(body);
  76. String webhookId = resp.getString("id");
  77. paypalConfig.setWebhookId(webhookId);
  78. LambdaUpdateWrapper<PaypalConfig> wrapper = new LambdaUpdateWrapper<>();
  79. wrapper.eq(PaypalConfig::getId,paypalConfig.getId());
  80. wrapper.set(PaypalConfig::getWebhookId,webhookId);
  81. paypalConfigService.update(wrapper);
  82. }catch (Exception e){
  83. log.info("paypal-createWebhooks:error:",e);
  84. }
  85. }
  86. }
  87. }
  88. /**
  89. * 获取token
  90. */
  91. public static String getToken(PaypalConfig paypalConfig) {
  92. String body = HttpRequest.post(paypalConfig.getBaseUrl() + "/v1/oauth2/token")
  93. .basicAuth(paypalConfig.getClientId(), paypalConfig.getSecret())
  94. .form("grant_type", "client_credentials")
  95. .execute().body();
  96. JSONObject jsonObject = JSONObject.parseObject(body);
  97. return jsonObject.get("access_token").toString();
  98. }
  99. /**
  100. * 创建商品
  101. */
  102. public String createProduct(PaypalConfig paypalConfig,Product product) {
  103. try {
  104. Map<String,String> map = new HashMap<>(4);
  105. map.put("Content-Type","application/json");
  106. map.put("Authorization",getToken(paypalConfig));
  107. // map.put("PayPal-Request-Id","PLAN-18062019-001");
  108. String string = new ObjectMapper().writeValueAsString(product);
  109. String body = HttpRequest.post(paypalConfig.getBaseUrl() + "/v1/catalogs/products")
  110. .addHeaders(map)
  111. .basicAuth(paypalConfig.getClientId(),paypalConfig.getSecret())
  112. .body(string)
  113. .execute().body();
  114. log.info("paypal-createProduct:{}",body);
  115. JSONObject jsonObject = JSONObject.parseObject(body);
  116. return jsonObject.getString("id");
  117. }catch (Exception e){
  118. log.info("paypal-createProduct:error:",e);
  119. }
  120. return null;
  121. }
  122. /**
  123. * 创建计划
  124. *
  125. */
  126. public String createPlan(PaypalConfig paypalConfig,PlanVo planVo) {
  127. try {
  128. String dateTime = LocalDateTime.now().toString();
  129. Map<String,String> map = new HashMap<>(4);
  130. map.put("Content-Type","application/json");
  131. map.put("Authorization",getToken(paypalConfig));
  132. // map.put("PayPal-Request-Id","PLAN-18062019-001");
  133. PayPalSubscriptionPlanParam planParam = new PayPalSubscriptionPlanParam();
  134. List<BillingCycles> list = new ArrayList<>();
  135. BillingCycles billingCycles = new BillingCycles();
  136. billingCycles.setTenureType("REGULAR");
  137. billingCycles.setSequence(1);
  138. billingCycles.setTotalCycles(0);
  139. //计费周期
  140. Frequency frequency = new Frequency();
  141. frequency.setIntervalUnit(planVo.getTimeUnit());
  142. frequency.setIntervalCount(1);
  143. PricingScheme pricingScheme = new PricingScheme();
  144. pricingScheme.setVersion(1);
  145. pricingScheme.setCreateTime(dateTime);
  146. //定价
  147. FixedPrice fixedPrice = new FixedPrice();
  148. fixedPrice.setCurrencyCode(planVo.getCurrencyCode());
  149. fixedPrice.setValue(planVo.getPrice());
  150. pricingScheme.setFixedPrice(fixedPrice);
  151. billingCycles.setFrequency(frequency);
  152. billingCycles.setPricingScheme(pricingScheme);
  153. list.add(billingCycles);
  154. // 付款偏好
  155. PaymentPreferences paymentPreferences = new PaymentPreferences();
  156. paymentPreferences.setAutoBillOutstanding(true);
  157. paymentPreferences.setPaymentFailureThreshold(3);
  158. paymentPreferences.setSetupFeeFailureAction("CANCEL");
  159. //设置首次扣款费用
  160. SetupFee setupFee = new SetupFee();
  161. setupFee.setCurrencyCode(planVo.getCurrencyCode());
  162. setupFee.setValue(planVo.getPrice());
  163. paymentPreferences.setSetupFee(setupFee);
  164. // 税率
  165. Taxes taxes = new Taxes();
  166. taxes.setInclusive(true);
  167. taxes.setPercentage("0");
  168. planParam.setTaxes(taxes);
  169. planParam.setPaymentPreferences(paymentPreferences);
  170. planParam.setBillingCycles(list);
  171. planParam.setProductId(planVo.getProductId());
  172. planParam.setName(planVo.getPlanName());
  173. planParam.setStatus("ACTIVE");
  174. planParam.setDescription(planVo.getPlanName());
  175. planParam.setCreateTime(dateTime);
  176. planParam.setUpdateTime(dateTime);
  177. String string = new ObjectMapper().writeValueAsString(planParam);
  178. String body = HttpRequest.post(paypalConfig.getBaseUrl() + "/v1/billing/plans")
  179. .addHeaders(map)
  180. .basicAuth(paypalConfig.getClientId(),paypalConfig.getSecret())
  181. .body(string)
  182. .execute().body();
  183. log.info("paypal-createPlan:{}",body);
  184. JSONObject planObj = JSONObject.parseObject(body);
  185. return planObj.getString("id");
  186. }catch (Exception e){
  187. log.info("paypal-createPlan:error:",e);
  188. }
  189. return null;
  190. }
  191. /**
  192. * 处理订阅参数
  193. *
  194. * @return
  195. */
  196. private String handlerSubsParam(Order order, ApplicationContext applicationContext) {
  197. CompanyVo companyVo = new CompanyVo();
  198. SubscriptionDTO subscriptionDTO = new SubscriptionDTO();
  199. subscriptionDTO.setPlanId(order.getPlanId());
  200. subscriptionDTO.setStartTime(order.getStartTime());
  201. // ShippingAmount amount = new ShippingAmount();
  202. // amount.setCurrencyCode("USD");
  203. // amount.setValue(order.getOrderMoney().toString());
  204. // subscriptionDTO.setShippingAmount(amount);
  205. // subscriptionDTO.setQuantity("1");
  206. Subscriber subscriber = new Subscriber();
  207. SubscriberName subscriberName = new SubscriberName();
  208. subscriberName.setGiven_name(companyVo.getName());
  209. subscriberName.setSurname(companyVo.getName());
  210. subscriber.setName(subscriberName);
  211. subscriber.setEmailAddress(companyVo.getEmail());
  212. ShippingAddress shippingAddress = new ShippingAddress();
  213. shippingAddress.setAddress(new Address(companyVo.getAddress(),"","","","","C2"));
  214. shippingAddress.setName(new Name(companyVo.getName()));
  215. subscriber.setShippingAddress(shippingAddress);
  216. subscriptionDTO.setSubscriber(subscriber);
  217. subscriptionDTO.setApplicationContext(applicationContext);
  218. String string = "";
  219. try {
  220. string = new ObjectMapper().writeValueAsString(subscriptionDTO);
  221. // System.out.println(string);
  222. } catch (JsonProcessingException e) {
  223. e.printStackTrace();
  224. }
  225. return string;
  226. }
  227. /**
  228. * 创建订阅
  229. */
  230. public SubscriptionVo createSubscription(PaypalConfig paypalConfig, Order order) {
  231. Map<String,String> map = new HashMap<>(4);
  232. map.put("Content-Type","application/json");
  233. map.put("Authorization",getToken(paypalConfig));
  234. // P-7EG815794T029494CMFR77TA
  235. // String planId = "P-4ND94871NA4029913MFSTSXI";
  236. ApplicationContext applicationContext = new ApplicationContext();
  237. applicationContext.setCancelUrl(paypalConfig.getCancelUrl());
  238. applicationContext.setReturnUrl(paypalConfig.getSuccessUrl());
  239. applicationContext.setPaymentMethod(new PaymentMethod());
  240. String string = handlerSubsParam(order,applicationContext);
  241. String body = HttpRequest.post(paypalConfig.getBaseUrl() + "/v1/billing/subscriptions")
  242. .addHeaders(map)
  243. .basicAuth(paypalConfig.getClientId(),paypalConfig.getSecret())
  244. .body(string)
  245. .execute().body();
  246. JSONObject jsonObject = JSONObject.parseObject(body);
  247. log.info("createSubscription-resp:{}",jsonObject);
  248. String id = jsonObject.getString("id");
  249. List<com.paypal.api.payments.Links> links = JSONObject.parseArray(jsonObject.get("links").toString(), com.paypal.api.payments.Links.class);
  250. Links links1 = links.stream().filter(o -> "approve".equals(o.getRel())).findFirst()
  251. .orElseThrow(() -> new RuntimeException("创建订阅失败"));
  252. String href = links1.getHref();
  253. SubscriptionVo vo = new SubscriptionVo(id, href);
  254. return vo;
  255. }
  256. /**
  257. * 取消订阅
  258. */
  259. public void cancelSubscriptions(PaypalConfig paypalConfig, String subscriptionsId) {
  260. Map<String,String> map = new HashMap<>(4);
  261. map.put("Content-Type","application/json");
  262. map.put("Authorization",getToken(paypalConfig));
  263. HttpResponse response = HttpRequest.post(paypalConfig.getBaseUrl() + "/v1/billing/subscriptions/"+subscriptionsId+"/cancel")
  264. .addHeaders(map)
  265. .basicAuth(paypalConfig.getClientId(),paypalConfig.getSecret())
  266. .execute();
  267. // 订阅正常创建
  268. log.info("cancelSubscriptions-resp:{}",response);
  269. if(response.getStatus() != 204 && response.getStatus() != 404){
  270. throw new BusinessException(ResultCode.CANCEL_SUBSCRIPTIONS_ERROR);
  271. }
  272. }
  273. public static void main(String[] args) throws Exception {
  274. PaypalConfig paypalConfig = new PaypalConfig();
  275. paypalConfig.setBaseUrl("https://api-m.sandbox.paypal.com");
  276. paypalConfig.setClientId("ATzzbHdy4kgJxUJegzDbBO1kRUE5kcur5VXaNtja4JDpLsfPokdlKAtunTVa_mWPcTQTMy06JAW6Ae5j");
  277. paypalConfig.setSecret("EPBsjKmNHHrmu0joNkWcrVpdqXTs3pow5jRdD1daOMyomteOxHMUDXhsM6Z-bjMi8MfSMB4iIyuhIihV");
  278. try {
  279. Map<String,String> map = new HashMap<>(4);
  280. map.put("Content-Type","application/json");
  281. WebhookVo webhookVo = new WebhookVo();
  282. webhookVo.setUrl("https://testeur.4dkankan.com/service/pay/paypal/webhook");
  283. webhookVo.getEvent_types().add(new EventTypeVo("CATALOG.PRODUCT.CREATED"));
  284. webhookVo.getEvent_types().add(new EventTypeVo("BILLING.PLAN.CREATED"));
  285. webhookVo.getEvent_types().add(new EventTypeVo("BILLING.PLAN.ACTIVATED"));
  286. webhookVo.getEvent_types().add(new EventTypeVo("BILLING.SUBSCRIPTION.CREATED"));
  287. webhookVo.getEvent_types().add(new EventTypeVo("BILLING.SUBSCRIPTION.EXPIRED"));
  288. webhookVo.getEvent_types().add(new EventTypeVo("BILLING.SUBSCRIPTION.SUSPENDED"));
  289. webhookVo.getEvent_types().add(new EventTypeVo("PAYMENT.SALE.COMPLETED"));
  290. String string = JSONObject.toJSONString(webhookVo);
  291. String body = HttpRequest.post(paypalConfig.getBaseUrl() + "/v1/notifications/webhooks")
  292. .addHeaders(map)
  293. .basicAuth(paypalConfig.getClientId(), paypalConfig.getSecret())
  294. .body(string)
  295. .execute().body();
  296. log.info("paypal-createWebhooks:{}",body);
  297. JSONObject resp = JSONObject.parseObject(body);
  298. String webhookId = resp.getString("id");
  299. paypalConfig.setWebhookId(webhookId);
  300. }catch (Exception e){
  301. log.info("paypal-createWebhooks:error:",e);
  302. }
  303. }
  304. }