Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for php and java server sdk #158

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
098addc
add client & server implementation in codespace
Sep 18, 2024
1429c63
add steps to run codespace in README.md
Sep 18, 2024
b1aa4c8
change name of devcontainers
Sep 18, 2024
62a9fbe
feat: fetch paypal_client_id and paypal_client_secret from env
Sep 19, 2024
2759a07
Merge branch 'codespace' into feature/dotenv-for-php-and-dotnet
amsourav Sep 19, 2024
e501d89
feat: fetch paypal_client_id and paypal_client_secret from env
louislowjk Sep 20, 2024
3a2bf40
feat: add support for php and java server sdk
Sep 10, 2024
5e13a25
remove logic to create new .env in codespace
Sep 20, 2024
0926c01
feat: update standard integration to use server sdks
Sep 25, 2024
9260f0c
Feature/node updates (#3)
amsourav Sep 25, 2024
b94c66b
Feature/node updates (#4)
amsourav Sep 25, 2024
c5d72dd
feat: add nodejs to standard-integration
Sep 25, 2024
2c91bf2
change devcontainer names
rbaidipati Sep 26, 2024
6f2157a
feat: add component show to show transaction message
Sep 27, 2024
0b28182
Merge pull request #1 from amsourav/feature/add-html-message-for-card…
rekhaabaidipati Sep 27, 2024
7c41f9a
Merge remote-tracking branch 'rekhaabaidipati/louis_branch' into feat…
Oct 1, 2024
c316cc1
chore: rename client/server folders and update README
Oct 1, 2024
25efdb3
docs: update steps for setting env variable
Oct 1, 2024
2037731
Merge branch 'main' into feature/update-using-server-sdk
amsourav Oct 2, 2024
a1d5484
chore: remove authorize intent
amsourav Oct 2, 2024
07c6974
chore: remove node-fetch dependency
Oct 7, 2024
02622b7
chore: remove unsed php packages
Oct 8, 2024
c964b70
20241008_rename_sample_standard_xo_dotnet_file (#6)
devapplepaypal Oct 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading