Java paypal如何实现付费订阅(循环扣费)

2 篇文章 1 订阅

背景

业务需求要集成Paypal,实现循环扣款功能,初识PayPal开发文档,搞得人一脸懵逼,终于完整实现所有功能,这里对如何使用Paypal的支付接口做下总结。

账号申请

页面地址:https://www.paypal.com/us/webapps/mpp/account-selection
进入:
在这里插入图片描述
因为我没有商家账户,所以使用的个人账户。
注册完成后,进入开发者应用页面

页面地址:https://developer.paypal.com/developer/applications

在这里插入图片描述

api阅读

在这里插入图片描述

订阅流程

  • 创建商品
  • 创建计划
  • 创建订阅
  • 接收回调


这里着重介绍一下计划,计划里面包含了收费规则,安装费用(或者说使用费),重试机制,税率等。设置完成后,创建订阅时,传入计划ID即可

上代码

1、获取token

本文使用纯API交互,远程工具使用的是httpClient,但是PayPal与其他不同,需要登录才能使用,所以本文使用的hutool的httpclient工具类,需要设置类型为basicAuth,且输入用户密码(clientId,secret),话不多说,上代码:

/**
     * 获取token
     * @return
     * @throws IOException
     */
    public String getToken() {
        String body = HttpRequest.post(BASE_URL + "/v1/oauth2/token")
                .basicAuth(username, password)
                .form("grant_type", "client_credentials")
                .execute().body();
        JSONObject jsonObject = JSONObject.parseObject(body);
        return jsonObject.get("access_token").toString();
    }

参考文档:https://developer.paypal.com/docs/business/get-started/#exchange-your-api-credentials-for-an-access-token

2、创建商品

/**
     * 创建商品
     * @return
     * @throws JsonProcessingException
     */
public String createProduct() throws JsonProcessingException {
        Product product = new Product();
        product.setName("tc-004");
        //商品种类,枚举
        product.setCategory("BOOKS_PERIODICALS_AND_NEWSPAPERS");
        product.setDescription("test product 4");
        product.setHomeUrl("xxxx");
        product.setImageUrl("xxxx");
        //类型 枚举
        product.setType("SERVICE");
        Map<String,String> map = new HashMap<>(4);
        map.put("Content-Type","application/json");
        map.put("Authorization",getToken());
        // 请求ID,如果保持一致,可以进行多次请求,结果一致
//        map.put("PayPal-Request-Id","PLAN-18062019-001");
        String string = new ObjectMapper().writeValueAsString(product);
        String body = HttpRequest.post(BASE_URL + "/v1/catalogs/products")
                .addHeaders(map)
                .basicAuth(username,password)
                .body(string)
                .execute().body();
//        System.out.println(body);
        return body;
    }

详情参考:https://developer.paypal.com/docs/api/catalog-products/v1/#definition-product_collection_element
链接中包含枚举

3、创建计划

/**
     * 创建计划
     * @param productId
     * @return
     * @throws JsonProcessingException
     */
    public String createPlan(String productId) throws JsonProcessingException {
        String dateTime = LocalDateTime.now().toString();
        String token = getToken();
        Map<String,String> map = new HashMap<>(4);
        map.put("Content-Type","application/json");
        map.put("Authorization",token);
//        map.put("PayPal-Request-Id","PLAN-18062019-001");
        PayPalSubscriptionPlanParam planParam = new PayPalSubscriptionPlanParam();
        List<BillingCycles> list = new ArrayList<>();
        BillingCycles billingCycles = new BillingCycles();
        billingCycles.setTenureType("REGULAR");
        billingCycles.setSequence(1);
        billingCycles.setTotalCycles(12);
        //计费周期
        Frequency frequency = new Frequency();
        frequency.setIntervalUnit("DAY");
        frequency.setIntervalCount(1);
        PricingScheme pricingScheme = new PricingScheme();
        pricingScheme.setVersion(1);
        pricingScheme.setCreateTime(dateTime);
        //定价
        FixedPrice fixedPrice = new FixedPrice();
        fixedPrice.setCurrencyCode("USD");
        fixedPrice.setValue("100");
        pricingScheme.setFixedPrice(fixedPrice);
        billingCycles.setFrequency(frequency);
        billingCycles.setPricingScheme(pricingScheme);
        list.add(billingCycles);
        // 付款偏好
        PaymentPreferences paymentPreferences = new PaymentPreferences();
        paymentPreferences.setAutoBillOutstanding(true);
        paymentPreferences.setPaymentFailureThreshold(3);
        paymentPreferences.setSetupFeeFailureAction("CANCEL");
        SetupFee setupFee = new SetupFee();
        setupFee.setCurrencyCode("USD");
        setupFee.setValue("0");
        paymentPreferences.setSetupFee(setupFee);
        // 税率
        Taxes taxes = new Taxes();
        taxes.setInclusive(true);
        taxes.setPercentage("0");
        planParam.setTaxes(taxes);
        planParam.setPaymentPreferences(paymentPreferences);
        planParam.setBillingCycles(list);
        planParam.setProductId(productId);
        planParam.setName("test plan");
        planParam.setStatus("ACTIVE");
        planParam.setDescription("test");
        planParam.setCreateTime(dateTime);
        planParam.setUpdateTime(dateTime);
        String string = new ObjectMapper().writeValueAsString(planParam);
        System.out.println(string);
//        System.out.println();
        String body = HttpRequest.post(BASE_URL + "/v1/billing/plans")
                .addHeaders(map)
                .basicAuth(username,password)
                .body(string)
                .execute().body();
        return body;
    }

4、创建订阅

/**
     * 创建订阅
     * @param planId
     * @return
     */
    public String createSubscription(String planId) {
        Map<String,String> map = new HashMap<>(4);
        map.put("Content-Type","application/json");
        map.put("Authorization",getToken());
        // P-7EG815794T029494CMFR77TA
//        String planId = "P-4ND94871NA4029913MFSTSXI";
        String string = handlerSubsParam(planId);
        String body = HttpRequest.post(BASE_URL + "/v1/billing/subscriptions")
                .addHeaders(map)
                .basicAuth(username,password)
                .body(string)
                .execute().body();
        JSONObject jsonObject = JSONObject.parseObject(body);
        List<Links> links = JSONObject.parseArray(jsonObject.get("links").toString(), Links.class);
        Links links1 = links.stream().filter(o -> "approve".equals(o.getRel())).findFirst()
                .orElseThrow(() -> new RuntimeException("sadsadsada"));
        System.out.println(JSONObject.toJSONString(links));
        System.out.println(links1.getHref());
        return body;
    }

/**
     * 处理订阅参数
     * 
     * @param planId
     * @return
     */
    private String handlerSubsParam(String planId) {
        SubscriptionDTO subscriptionDTO = new SubscriptionDTO();
        subscriptionDTO.setPlanId(planId);
//        subscriptionDTO.setQuantity("10");
//        subscriptionDTO.setShippingAmount("10");
//        subscriptionDTO.setStartTime(new Date());
//        subscriptionDTO.setQuantity("10");
        Subscriber subscriber = new Subscriber();
        SubscriberName subscriberName = new SubscriberName();
        subscriberName.setGiven_name("lijing");
        subscriberName.setSurname("xiong");
        subscriber.setName(subscriberName);
        subscriber.setEmailAddress("xiong.ricoh@gmail.com");
        ShippingAddress shippingAddress = new ShippingAddress();
        //注意最后一个字段,必须严格参照枚举字典,中国是C2,不是CN
        shippingAddress.setAddress(new Address("XXXX","","","","","C2"));
        shippingAddress.setName(new Name("xiong lijing"));
        subscriber.setShippingAddress(shippingAddress);
        subscriptionDTO.setSubscriber(subscriber);
        ApplicationContext applicationContext = new ApplicationContext();
//        applicationContext.setBrandName("");
        applicationContext.setCancelUrl("http://www.baidu.com");
//        applicationContext.setShippingPreference("");
//        applicationContext.setUserAction("");
        applicationContext.setReturnUrl("http://www.sina.com");
        applicationContext.setPaymentMethod(new PaymentMethod());
        subscriptionDTO.setApplicationContext(applicationContext);
        String string = "";
        try {
            string = new ObjectMapper().writeValueAsString(subscriptionDTO);
//            System.out.println(string);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return string;
    }

PayPal订阅与PayPal单笔支付类似,最后会一个最终处理URL,点击进入即可登陆账号,付款等,所以处理结果即可。

本文需要引入依赖:

<dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.13</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.11.4</version>
        </dependency>

        <!--paypal-->
        <dependency>
            <groupId>com.braintreepayments.gateway</groupId>
            <artifactId>braintree-java</artifactId>
            <version>2.87.0</version>
        </dependency>

        <dependency>
            <groupId>com.paypal.sdk</groupId>
            <artifactId>checkout-sdk</artifactId>
            <version>1.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.paypal.sdk</groupId>
            <artifactId>rest-api-sdk</artifactId>
            <version>1.14.0</version>
        </dependency>

文章代码已上传至github,源码有需要可以自行下载,实体类太多,可以从源码直接clone下来。

gitee地址https://gitee.com/bear_crystal/paypal
github地址https://github.com/xionglijing/paypal.git

有问题可以QQ联系:1144249977

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值