Skip to content
This repository was archived by the owner on Mar 5, 2020. It is now read-only.

Commit 7879901

Browse files
committed
PayPal integration added
1 parent ea5df71 commit 7879901

File tree

7 files changed

+293
-2
lines changed

7 files changed

+293
-2
lines changed

pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</parent>
1111
<groupId>pl.simplemethod</groupId>
1212
<artifactId>codebin</artifactId>
13-
<version>0.0.1-SNAPSHOT</version>
13+
<version>1.0-SNAPSHOT</version>
1414
<name>codebin</name>
1515
<description>Demo project for Spring Boot</description>
1616

@@ -100,6 +100,11 @@
100100
<artifactId>commons-dbcp2</artifactId>
101101
<version>2.0</version>
102102
</dependency>
103+
<dependency>
104+
<groupId>com.paypal.sdk</groupId>
105+
<artifactId>rest-api-sdk</artifactId>
106+
<version>LATEST</version>
107+
</dependency>
103108
</dependencies>
104109

105110
<build>
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package pl.simplemethod.codebin.paypal;
2+
3+
import com.paypal.api.payments.Agreement;
4+
import com.paypal.api.payments.Links;
5+
import com.paypal.api.payments.Payer;
6+
import com.paypal.api.payments.Plan;
7+
import com.paypal.base.rest.APIContext;
8+
import com.paypal.base.rest.PayPalRESTException;
9+
import org.springframework.beans.factory.annotation.Autowired;
10+
import org.springframework.lang.NonNull;
11+
import org.springframework.stereotype.Component;
12+
13+
import java.io.UnsupportedEncodingException;
14+
import java.net.MalformedURLException;
15+
import java.text.DateFormat;
16+
import java.text.SimpleDateFormat;
17+
import java.util.Calendar;
18+
import java.util.Date;
19+
import java.util.Locale;
20+
import java.util.TimeZone;
21+
22+
@Component
23+
public class PayPalBillingAgreement {
24+
25+
private APIContext apiContext;
26+
27+
@Autowired
28+
public PayPalBillingAgreement(APIContext apiContext) {
29+
this.apiContext = apiContext;
30+
}
31+
32+
/**
33+
* Returns date in ISO 8601 format
34+
* @param date Date java object
35+
* @return Date in ISO 8601 format
36+
*/
37+
private static String getDate(Date date) {
38+
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
39+
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
40+
return dateFormat.format(date);
41+
}
42+
43+
/**
44+
* Define an agreement for paypal subscription
45+
* @param id Created plan id
46+
* @return Agreement object that can be used to create an agreement
47+
*/
48+
public Agreement define(@NonNull String id) {
49+
Date date = new Date();
50+
Calendar c = Calendar.getInstance();
51+
c.setTime(date);
52+
c.add(Calendar.DATE, 1);
53+
date = c.getTime();
54+
55+
Agreement agreement = new Agreement();
56+
agreement.setName("Codebin agreement");
57+
agreement.setDescription("Codebin subscription agreement");
58+
agreement.setStartDate(getDate(date));
59+
60+
Plan plan = new Plan();
61+
plan.setId(id);
62+
agreement.setPlan(plan);
63+
64+
Payer payer = new Payer();
65+
payer.setPaymentMethod("paypal");
66+
agreement.setPayer(payer);
67+
68+
return agreement;
69+
}
70+
71+
/**
72+
* Creates defined agreement which is passed in param
73+
* @param agreement Defined agreement
74+
* @return URL to be redirected
75+
* @throws PayPalRESTException When approval_url cannot be find
76+
* @throws MalformedURLException When URL to be redirected is malformed
77+
* @throws UnsupportedEncodingException When there is a unsupported encoding used
78+
*/
79+
public String create(@NonNull Agreement agreement)
80+
throws PayPalRESTException, MalformedURLException, UnsupportedEncodingException {
81+
agreement = agreement.create(apiContext);
82+
83+
for (Links link : agreement.getLinks()) {
84+
if (link.getRel().equalsIgnoreCase("approval_url")) {
85+
return link.getHref();
86+
}
87+
}
88+
89+
throw new PayPalRESTException("approval_url not found");
90+
}
91+
92+
/**
93+
* Executes created agreement
94+
* @param token Token which is passed in request parameter after successfull redirection
95+
* @throws PayPalRESTException When agreement cannot be exeucted
96+
*/
97+
public void execute(@NonNull String token) throws PayPalRESTException {
98+
Agreement agreement = new Agreement();
99+
agreement.setToken(token);
100+
101+
Agreement.execute(apiContext, agreement.getToken());
102+
}
103+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package pl.simplemethod.codebin.paypal;
2+
3+
import com.paypal.api.payments.*;
4+
import com.paypal.base.rest.APIContext;
5+
import com.paypal.base.rest.PayPalRESTException;
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.stereotype.Component;
8+
9+
import java.util.ArrayList;
10+
import java.util.HashMap;
11+
import java.util.List;
12+
import java.util.Map;
13+
14+
@Component
15+
public class PayPalBillingPlan {
16+
17+
private APIContext apiContext;
18+
19+
@Autowired
20+
public PayPalBillingPlan(APIContext apiContext) {
21+
this.apiContext = apiContext;
22+
}
23+
24+
private static final String CANCEL_URL = "http://localhost/subscribe-failure";
25+
private static final String PROCESS_URL = "http://localhost/subscribe-success";
26+
27+
/**
28+
* Creates a plan to billing plan
29+
* @return Created billing plan
30+
* @throws PayPalRESTException When some parameters are wrong
31+
*/
32+
public Plan create() throws PayPalRESTException {
33+
Plan plan = new Plan();
34+
plan.setName("Codebin Premium");
35+
plan.setDescription("Codebin premium plan");
36+
plan.setType("fixed");
37+
38+
PaymentDefinition paymentDefinition = new PaymentDefinition();
39+
paymentDefinition.setName("Codebin Subscription");
40+
paymentDefinition.setType("REGULAR");
41+
paymentDefinition.setFrequency("MONTH");
42+
paymentDefinition.setFrequencyInterval("1");
43+
paymentDefinition.setCycles("12");
44+
45+
Currency currency = new Currency();
46+
currency.setCurrency("USD");
47+
currency.setValue("9.95");
48+
paymentDefinition.setAmount(currency);
49+
50+
ChargeModels chargeModels = new ChargeModels();
51+
chargeModels.setType("TAX");
52+
chargeModels.setAmount(currency);
53+
List<ChargeModels> chargeModelsList = new ArrayList<>();
54+
chargeModelsList.add(chargeModels);
55+
paymentDefinition.setChargeModels(chargeModelsList);
56+
57+
List<PaymentDefinition> paymentDefinitions = new ArrayList<>();
58+
paymentDefinitions.add(paymentDefinition);
59+
plan.setPaymentDefinitions(paymentDefinitions);
60+
61+
MerchantPreferences merchantPreferences = new MerchantPreferences();
62+
merchantPreferences.setSetupFee(currency);
63+
merchantPreferences.setCancelUrl(CANCEL_URL);
64+
merchantPreferences.setReturnUrl(PROCESS_URL);
65+
merchantPreferences.setMaxFailAttempts("0");
66+
merchantPreferences.setAutoBillAmount("YES");
67+
merchantPreferences.setInitialFailAmountAction("CONTINUE");
68+
plan.setMerchantPreferences(merchantPreferences);
69+
70+
Plan createdPlan = plan.create(apiContext);
71+
72+
List<Patch> patchRequests = new ArrayList<>();
73+
Map<String, String> values = new HashMap<>();
74+
values.put("state", "ACTIVE");
75+
76+
Patch patch = new Patch();
77+
patch.setPath("/");
78+
patch.setValue(values);
79+
patch.setOp("replace");
80+
patchRequests.add(patch);
81+
82+
createdPlan.update(apiContext, patchRequests);
83+
84+
return createdPlan;
85+
}
86+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package pl.simplemethod.codebin.paypal;
2+
3+
import com.paypal.base.rest.APIContext;
4+
import org.springframework.beans.factory.annotation.Value;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.context.annotation.Configuration;
7+
8+
@Configuration
9+
public class PayPalConfig {
10+
11+
@Value("${paypal.client.app}")
12+
private String clientId;
13+
14+
@Value("${paypal.client.secret}")
15+
private String clientSecret;
16+
17+
@Value("${paypal.mode}")
18+
private String mode;
19+
20+
/**
21+
* Creating API context
22+
* @return Created API context from provided client id and client secret
23+
*/
24+
@Bean
25+
public APIContext getContext() {
26+
return new APIContext(clientId, clientSecret, mode);
27+
}
28+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package pl.simplemethod.codebin.paypal;
2+
3+
import com.paypal.api.payments.Agreement;
4+
import com.paypal.api.payments.Plan;
5+
import com.paypal.base.rest.PayPalRESTException;
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.web.bind.annotation.GetMapping;
8+
import org.springframework.web.bind.annotation.RequestParam;
9+
import org.springframework.web.bind.annotation.RestController;
10+
11+
import java.io.UnsupportedEncodingException;
12+
import java.net.MalformedURLException;
13+
14+
@RestController
15+
public class PayPalController {
16+
17+
private PayPalBillingPlan payPalBillingPlan;
18+
private PayPalBillingAgreement payPalBillingAgreement;
19+
20+
@Autowired
21+
public PayPalController(PayPalBillingPlan payPalBillingPlan, PayPalBillingAgreement payPalBillingAgreement) {
22+
this.payPalBillingPlan = payPalBillingPlan;
23+
this.payPalBillingAgreement = payPalBillingAgreement;
24+
}
25+
26+
/**
27+
* Define and create billing plan and billing agreement.
28+
* Redirects response to successful or unsuccessful URL
29+
*/
30+
@GetMapping("/subscribe")
31+
public void subscribe() {
32+
try {
33+
Plan plan = payPalBillingPlan.create();
34+
Agreement agreement = payPalBillingAgreement.define(plan.getId());
35+
String redirect = payPalBillingAgreement.create(agreement);
36+
// TODO: 02/06/2019 REDIRECT to redirect url
37+
} catch (PayPalRESTException e) {
38+
System.err.println(e.getDetails());
39+
} catch (MalformedURLException | UnsupportedEncodingException e) {
40+
e.printStackTrace();
41+
}
42+
}
43+
44+
/**
45+
* Executes successfully created billing agreement
46+
* @param token Token which is automatically assigned to billing agreement
47+
*/
48+
@GetMapping("/subscribe-success")
49+
public void success(@RequestParam String token) {
50+
try {
51+
payPalBillingAgreement.execute(token);
52+
} catch (PayPalRESTException e) {
53+
System.err.println(e.getDetails());
54+
}
55+
}
56+
}

src/main/resources/application.properties

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,11 @@ spring.datasource.username=work
3232
spring.datasource.password=Szk0lna17
3333
spring.jpa.generate-ddl=true
3434
spring.jpa.hibernate.ddl-auto=none
35-
spring.jpa.show-sql=true
35+
spring.jpa.show-sql=true
36+
37+
#---------------------------------------------------
38+
# PAYPAL PROPERTIES
39+
#---------------------------------------------------
40+
paypal.client.app=Aa8pCy_73bPjrlYGnFvAoxcqrL-7CGkiLKvQyXa3YsfWz1FlamqVXr5Uwynf-fnor10r5qquqbTgOjOi
41+
paypal.client.secret=EJ4V-JLYv_g26ppiFraOCq2s88ytpJgk2bVhTAMHIax6f0E1zodxY4LyC1bAPG6cXalJTF2gIPlS0XfE
42+
paypal.mode=sandbox

src/main/resources/banner.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
____ _ _ _ _ ___
2+
/ ___|___ __| | ___| |__ (_)_ __ __ _/ | / _ \
3+
| | / _ \ / _` |/ _ \ '_ \| | '_ \ \ \ / / || | | |
4+
| |__| (_) | (_| | __/ |_) | | | | | \ V /| || |_| |
5+
\____\___/ \__,_|\___|_.__/|_|_| |_| \_/ |_(_)___/
6+

0 commit comments

Comments
 (0)