Skip to content

Commit

Permalink
feat: add support for php and java server sdk (#158)
Browse files Browse the repository at this point in the history
  • Loading branch information
amsourav authored Oct 10, 2024
1 parent bb12328 commit 4f9852f
Show file tree
Hide file tree
Showing 49 changed files with 1,034 additions and 9,330 deletions.
4 changes: 2 additions & 2 deletions advanced-integration/v2/client/html/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ npm install
3. Starting the development server
- **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run dev or a similar command in the server directory.
- **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run start or a similar command in the server directory.

- **Start the client**:

```bash
npm run dev
npm run start
```

This will start the development server, and you should be able to access the Advanced Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output).
Expand Down
2 changes: 1 addition & 1 deletion advanced-integration/v2/client/html/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default defineConfig({
plugins: [],
envDir: "../",
envPrefix: "PAYPAL",
root: "client",
root: "src",
server: {
port: 3000,
proxy: {
Expand Down
3 changes: 3 additions & 0 deletions advanced-integration/v2/client/react/.env.example
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
# Create an application to obtain credentials at
# https://developer.paypal.com/dashboard/applications/sandbox

PAYPAL_CLIENT_ID=PAYPAL_CLIENT_ID
4 changes: 2 additions & 2 deletions advanced-integration/v2/client/react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ npm install
3. Starting the development server
- **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run dev or a similar command in the server directory.
- **Start the server**: Follow the instructions in the server's README to start it. Typically, this involves running npm run start or a similar command in the server directory.

- **Start the client**:

```bash
npm run dev
npm run start
```

This will start the development server, and you should be able to access the Advanced Checkout Page in your browser at `http://localhost:3000` (or the port specfied in the terminal output).
Expand Down
2 changes: 1 addition & 1 deletion advanced-integration/v2/client/react/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
root: "client",
root: "src",
envDir: "../",
envPrefix: "PAYPAL",
server: {
Expand Down
6 changes: 3 additions & 3 deletions advanced-integration/v2/server/dotnet/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# Advanced Integartion .NET Sample
# Advanced Integration .NET Sample

PayPal Advanced Integration sample in .NET

## Running the sample

1. **Add your API credentials to the environment:**

- **Windows**
- **Windows (powershell)**

```powershell
$env:PAYPAL_CLIENT_ID = "<PAYPAL_CLIENT_ID>"
$env:PAYPAL_CLIENT_SECRET = "<PAYPAL_CLIENT_SECRET>"
```

- **Unix**
- **Linux / MacOS**

```bash
export PAYPAL_CLIENT_ID="<PAYPAL_CLIENT_ID>"
Expand Down
1 change: 1 addition & 0 deletions advanced-integration/v2/server/java/.tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
java zulu-21.36.19
6 changes: 3 additions & 3 deletions advanced-integration/v2/server/java/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# Advanced Integartion Java Sample
# Advanced Integration Java Sample

PayPal Advanced Integration sample in Java

## Running the sample

1. Add your API credentials to the environment:

- **Windows**
- **Windows (powershell)**

```powershell
$env:PAYPAL_CLIENT_ID = "<PAYPAL_CLIENT_ID>"
$env:PAYPAL_CLIENT_SECRET = "<PAYPAL_CLIENT_SECRET>"
```

- **Unix**
- **Linux / MacOS**

```bash
export PAYPAL_CLIENT_ID="<PAYPAL_CLIENT_ID>"
Expand Down
16 changes: 15 additions & 1 deletion advanced-integration/v2/server/java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.2</version>
<version>3.3.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.paypal.sample</groupId>
Expand Down Expand Up @@ -33,10 +33,23 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>3.3.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.3.3</version>
</dependency>
<dependency>
<groupId>
com.paypal.sdk
</groupId>
<artifactId>
paypal-server-sdk
</artifactId>
<version>
0.5.1
</version>
</dependency>
</dependencies>

Expand All @@ -45,6 +58,7 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.3.3</version>
</plugin>
</plugins>
</build>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,37 @@
package com.paypal.sample;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;

import com.paypal.sdk.Environment;
import com.paypal.sdk.PaypalServerSDKClient;
import com.paypal.sdk.authentication.ClientCredentialsAuthModel;
import com.paypal.sdk.controllers.OrdersController;
import com.paypal.sdk.exceptions.ApiException;
import com.paypal.sdk.http.response.ApiResponse;
import com.paypal.sdk.models.AmountWithBreakdown;
import com.paypal.sdk.models.CheckoutPaymentIntent;
import com.paypal.sdk.models.Order;
import com.paypal.sdk.models.OrderRequest;
import com.paypal.sdk.models.OrdersCaptureInput;
import com.paypal.sdk.models.OrdersCreateInput;
import com.paypal.sdk.models.PurchaseUnitRequest;
import java.util.Arrays;
import org.slf4j.event.Level;

import java.io.IOException;
import java.util.Base64;
import java.util.Map;

@SpringBootApplication
Expand All @@ -36,8 +43,6 @@ public class SampleAppApplication {
@Value("${PAYPAL_CLIENT_SECRET}")
private String PAYPAL_CLIENT_SECRET;

private final String BASE_URL = "https://api-m.sandbox.paypal.com";

public static void main(String[] args) {
SpringApplication.run(SampleAppApplication.class, args);
}
Expand All @@ -47,23 +52,41 @@ public RestTemplate restTemplate() {
return new RestTemplate();
}

@Bean
public PaypalServerSDKClient paypalClient() {
return new PaypalServerSDKClient.Builder()
.loggingConfig(builder -> builder
.level(Level.DEBUG)
.requestConfig(logConfigBuilder -> logConfigBuilder.body(true))
.responseConfig(logConfigBuilder -> logConfigBuilder.headers(true)))
.httpClientConfig(configBuilder -> configBuilder
.timeout(0))
.environment(Environment.SANDBOX)
.clientCredentialsAuth(new ClientCredentialsAuthModel.Builder(
PAYPAL_CLIENT_ID,
PAYPAL_CLIENT_SECRET)
.build())
.build();
}


@Controller
@RequestMapping("/")
public class CheckoutController {

private final RestTemplate restTemplate;
private final ObjectMapper objectMapper;
private final PaypalServerSDKClient client;

public CheckoutController(RestTemplate restTemplate, ObjectMapper objectMapper) {
this.restTemplate = restTemplate;
public CheckoutController(ObjectMapper objectMapper, PaypalServerSDKClient client) {
this.objectMapper = objectMapper;
this.client = client;
}

@PostMapping("/api/orders")
public ResponseEntity<JsonNode> createOrder(@RequestBody Map<String, Object> request) {
public ResponseEntity<Order> createOrder(@RequestBody Map<String, Object> request) {
try {
String cart = objectMapper.writeValueAsString(request.get("cart"));
JsonNode response = createOrder(cart);
Order response = createOrder(cart);
return new ResponseEntity<>(response, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
Expand All @@ -72,69 +95,47 @@ public ResponseEntity<JsonNode> createOrder(@RequestBody Map<String, Object> req
}

@PostMapping("/api/orders/{orderID}/capture")
public ResponseEntity<JsonNode> captureOrder(@PathVariable String orderID) {
public ResponseEntity<Order> captureOrder(@PathVariable String orderID) {
try {
JsonNode response = captureOrders(orderID);
return new ResponseEntity<>(response, HttpStatus.OK);
Order response = captureOrders(orderID);
return new ResponseEntity<Order>(response, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}

private String generateAccessToken() throws IOException {
if (PAYPAL_CLIENT_ID == null || PAYPAL_CLIENT_SECRET == null) {
throw new IllegalArgumentException("MISSING_API_CREDENTIALS");
}
String auth = Base64.getEncoder().encodeToString((PAYPAL_CLIENT_ID + ":" + PAYPAL_CLIENT_SECRET).getBytes());
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(auth);
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("grant_type", "client_credentials");

ResponseEntity<JsonNode> response = restTemplate.postForEntity(BASE_URL + "/v1/oauth2/token", new HttpEntity<>(body, headers), JsonNode.class);
return response.getBody().get("access_token").asText();
}

private JsonNode createOrder(String cart) throws IOException {
String accessToken = generateAccessToken();
String url = BASE_URL + "/v2/checkout/orders";
private Order createOrder(String cart) throws IOException, ApiException {

ObjectNode payload = objectMapper.createObjectNode();
payload.put("intent", "CAPTURE");
ObjectNode purchaseUnit = payload.putArray("purchase_units").addObject();
ObjectNode amount = purchaseUnit.putObject("amount");
amount.put("currency_code", "USD");
amount.put("value", "100.00");
OrdersCreateInput ordersCreateInput = new OrdersCreateInput.Builder(
null,
new OrderRequest.Builder(
CheckoutPaymentIntent.CAPTURE,
Arrays.asList(
new PurchaseUnitRequest.Builder(
new AmountWithBreakdown.Builder(
"USD",
"100.00")
.build())
.build()))
.build())
.build();

HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken);
headers.setContentType(MediaType.APPLICATION_JSON);
OrdersController ordersController = client.getOrdersController();

ResponseEntity<JsonNode> response = restTemplate.postForEntity(url, new HttpEntity<>(payload, headers), JsonNode.class);
return handleResponse(response);
}

private JsonNode captureOrders(String orderID) throws IOException {
String accessToken = generateAccessToken();
String url = BASE_URL + "/v2/checkout/orders/" + orderID + "/capture";
ApiResponse<Order> apiResponse = ordersController.ordersCreate(ordersCreateInput);

HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken);
headers.setContentType(MediaType.APPLICATION_JSON);

ResponseEntity<JsonNode> response = restTemplate.postForEntity(url, new HttpEntity<>(headers), JsonNode.class);
return handleResponse(response);
return apiResponse.getResult();
}

private JsonNode handleResponse(ResponseEntity<JsonNode> response) throws IOException {
if (response.getStatusCode().is2xxSuccessful()) {
return response.getBody();
} else {
throw new IOException(response.getBody().toString());
}
private Order captureOrders(String orderID) throws IOException, ApiException {
OrdersCaptureInput ordersCaptureInput = new OrdersCaptureInput.Builder(
orderID,
null)
.build();
OrdersController ordersController = client.getOrdersController();
ApiResponse<Order> apiResponse = ordersController.ordersCapture(ordersCaptureInput);
return apiResponse.getResult();
}
}
}
6 changes: 3 additions & 3 deletions advanced-integration/v2/server/node/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# Advanced Integartion Node.js Sample
# Advanced Integration Node.js Sample

PayPal Advanced Integration sample in Node.js

## Running the sample

1. Add your API credentials to the environment:

- **Windows**
- **Windows (powershell)**

```powershell
$env:PAYPAL_CLIENT_ID = "<PAYPAL_CLIENT_ID>"
$env:PAYPAL_CLIENT_SECRET = "<PAYPAL_CLIENT_SECRET>"
```

- **Unix**
- **Linux / MacOS**

```bash
export PAYPAL_CLIENT_ID="<PAYPAL_CLIENT_ID>"
Expand Down
9 changes: 5 additions & 4 deletions advanced-integration/v2/server/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
"private": true,
"type": "module",
"dependencies": {
"@paypal/paypal-server-sdk": "^0.5.1",
"body-parser": "^1.20.3",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"node-fetch": "^3.3.2"
"express": "^4.18.2"
},
"scripts": {
"server-dev": "nodemon server/server.js",
"server-dev": "nodemon server.js",
"start": "npm run server-dev",
"prod": "node server/server.js",
"prod": "node server.js",
"format": "npx prettier --write **/*.{js,jsx,md}",
"format:check": "npx prettier --check **/*.{js,jsx,md}"
},
Expand Down
Loading

0 comments on commit 4f9852f

Please sign in to comment.