WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ To learn how to use an example, open its `README.md` file. You'll find the detai
| [Okta Authentication](./okta-integration/) | Integration | Allow admin users to authenticate with Okta. |
| [Add Gift Messages to Line Items](./order-gift-message/README.md) | Custom Feature | Customize the Next.js Starter Storefront and Medusa Admin to support gift options for line items. |
| [Payload Integration](./payload-integration/README.md) | Integration | Integrate Payload CMS with Medusa |
| [PayPal Integration](./paypal-integration/README.md) | Integration | Integrate PayPal with Medusa |
| [Personalized Products](./personalized-products/README.md) | Custom Feature | Allow customers to personalize products with custom values and prices. |
| [Phone Authentication + Twilio SMS Integration](./phone-auth/README.md) | Integration | Authenticate users with their phone number + send OTPs with Twilio. |
| [Pre-orders](./preorder/README.md) | Custom Feature | Allow customers to pre-order products and automatically fulfill the pre-orders. |
Expand Down
14 changes: 14 additions & 0 deletions paypal-integration/.env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
STORE_CORS=http://localhost:8000,https://docs.medusajs.com
ADMIN_CORS=http://localhost:5173,http://localhost:9000,https://docs.medusajs.com
AUTH_CORS=http://localhost:5173,http://localhost:9000,https://docs.medusajs.com
REDIS_URL=redis://localhost:6379
JWT_SECRET=supersecret
COOKIE_SECRET=supersecret
DATABASE_URL=postgres://postgres@localhost/$DB_NAME # change user and password if necessary
DB_NAME=medusa-paypal-integration
POSTGRES_URL=

PAYPAL_CLIENT_ID=
PAYPAL_CLIENT_SECRET=
PAYPAL_WEBHOOK_ID=
PAYPAL_AUTO_CAPTURE=
26 changes: 26 additions & 0 deletions paypal-integration/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/dist
.env
.DS_Store
/uploads
/node_modules
yarn-error.log

.idea

coverage

!src/**

./tsconfig.tsbuildinfo
medusa-db.sql
build
.cache

.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

.medusa
1 change: 1 addition & 0 deletions paypal-integration/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
130 changes: 130 additions & 0 deletions paypal-integration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Medusa v2 Example: PayPal Integration

This directory holds the code for the [PayPal Integration Tutorial](https://docs.medusajs.com/resources/integrations/guides/paypal).

You can either:

- [install and use it as a Medusa application](#installation);
- or [copy its source files into an existing Medusa application](#copy-into-existing-medusa-application).

## Prerequisites

- [Node.js v20+](https://nodejs.org/en/download)
- [Git CLI](https://git-scm.com/downaloads)
- [PostgreSQL](https://www.postgresql.org/download/)
- [PayPal Developer Account](https://developer.paypal.com/dashboard) account with an application.

## Installation

1. Clone the repository and change to the `paypal-integration` directory:

```bash
git clone https://github.com/medusajs/examples.git
cd examples/paypal-integration
```

2\. Rename the `.env.template` file to `.env`.

3\. If necessary, change the PostgreSQL username, password, and host in the `DATABASE_URL` environment variable.

4\. Set the PayPal environment variables:

```bash
PAYPAL_CLIENT_ID=
PAYPAL_CLIENT_SECRET=
PAYPAL_WEBHOOK_ID=
PAYPAL_AUTO_CAPTURE=
```

Where:

- `PAYPAL_CLIENT_ID` is the client ID of your PayPal application.
- `PAYPAL_CLIENT_SECRET` is the client secret of your PayPal application.
- `PAYPAL_WEBHOOK_ID` is the ID of the webhook you've set up in your PayPal application. This will only work if your application is deployed with a publically accessible URL, or you're using a service like [ngrok](https://ngrok.com/)
- `PAYPAL_AUTO_CAPTURE`: set to `true` if you want payments to be captured immediately when an order is placed. By default, payments are authorized and captured later by an admin user through the Medusa Admin dashboard.

Learn more about retrieving these variables in the [tutorial](https://docs.medusajs.com/resources/integrations/guides/paypal#f-set-options-as-environment-variables)

5\. Install dependencies:

```bash
yarn # or npm install
```

6\. Setup and seed the database:

```bash
npx medusa db:setup
yarn seed # or npm run seed
```

7\. Start the Medusa application:

```bash
yarn dev # or npm run dev
```

Then, open the Medusa Admin at `localhost:9000/app` and log in. You must enable the PayPal Payment Module Provider in at least one region to use PayPal during checkout. Learn more in the [tutorial](https://docs.medusajs.com/resources/integrations/guides/paypal#step-3-enable-paypal-module-provider).

## Copy into Existing Medusa Application

If you have an existing Medusa application, copy the `src/modules/paypal` directory to your project.

Then, add the PayPal Payment Module Provider to `medusa-config.ts`:

```ts
module.exports = defineConfig({
// ...
modules: [
{
resolve: "@medusajs/medusa/payment",
options: {
providers: [
{
resolve: "./src/modules/paypal",
id: "paypal",
options: {
client_id: process.env.PAYPAL_CLIENT_ID!,
client_secret: process.env.PAYPAL_CLIENT_SECRET!,
environment: process.env.PAYPAL_ENVIRONMENT || "sandbox",
autoCapture: process.env.PAYPAL_AUTO_CAPTURE === "true",
webhook_id: process.env.PAYPAL_WEBHOOK_ID,
},
},
],
},
},
],
})
```

Next, add the following environment variables:

```bash
PAYPAL_CLIENT_ID=
PAYPAL_CLIENT_SECRET=
PAYPAL_WEBHOOK_ID=
PAYPAL_AUTO_CAPTURE=
```

Where:

- `PAYPAL_CLIENT_ID` is the client ID of your PayPal application.
- `PAYPAL_CLIENT_SECRET` is the client secret of your PayPal application.
- `PAYPAL_WEBHOOK_ID` is the ID of the webhook you've set up in your PayPal application. This will only work if your application is deployed with a publically accessible URL, or you're using a service like [ngrok](https://ngrok.com/)
- `PAYPAL_AUTO_CAPTURE`: set to `true` if you want payments to be captured immediately when an order is placed. By default, payments are authorized and captured later by an admin user through the Medusa Admin dashboard.

Learn more about retrieving these variables in the [tutorial](https://docs.medusajs.com/resources/integrations/guides/paypal#f-set-options-as-environment-variables)

After that, install the `@paypal/paypal-server-sdk` package:

```bash
yarn add @paypal/paypal-server-sdk # or npm install @paypal/paypal-server-sdk
```

> This guide was implemented with `@paypal/paypal-server-sdk@^2.1.0`.

## More Resources

- [Medusa Documentatin](https://docs.medusajs.com)
- [PayPal Documentation](https://developer.paypal.com)
24 changes: 24 additions & 0 deletions paypal-integration/instrumentation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Uncomment this file to enable instrumentation and observability using OpenTelemetry
// Refer to the docs for installation instructions: https://docs.medusajs.com/learn/debugging-and-testing/instrumentation

// import { registerOtel } from "@medusajs/medusa"
// // If using an exporter other than Zipkin, require it here.
// import { ZipkinExporter } from "@opentelemetry/exporter-zipkin"

// // If using an exporter other than Zipkin, initialize it here.
// const exporter = new ZipkinExporter({
// serviceName: 'my-medusa-project',
// })

// export function register() {
// registerOtel({
// serviceName: 'medusajs',
// // pass exporter
// exporter,
// instrument: {
// http: true,
// workflows: true,
// query: true
// },
// })
// }
29 changes: 29 additions & 0 deletions paypal-integration/integration-tests/http/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Integration Tests

The `medusa-test-utils` package provides utility functions to create integration tests for your API routes and workflows.

For example:

```ts
import { medusaIntegrationTestRunner } from "medusa-test-utils"

medusaIntegrationTestRunner({
testSuite: ({ api, getContainer }) => {
describe("Custom endpoints", () => {
describe("GET /store/custom", () => {
it("returns correct message", async () => {
const response = await api.get(
`/store/custom`
)

expect(response.status).toEqual(200)
expect(response.data).toHaveProperty("message")
expect(response.data.message).toEqual("Hello, World!")
})
})
})
}
})
```

Learn more in [this documentation](https://docs.medusajs.com/learn/debugging-and-testing/testing-tools/integration-tests).
15 changes: 15 additions & 0 deletions paypal-integration/integration-tests/http/health.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
jest.setTimeout(60 * 1000)

medusaIntegrationTestRunner({
inApp: true,
env: {},
testSuite: ({ api }) => {
describe("Ping", () => {
it("ping the server health endpoint", async () => {
const response = await api.get('/health')
expect(response.status).toEqual(200)
})
})
},
})
3 changes: 3 additions & 0 deletions paypal-integration/integration-tests/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const { MetadataStorage } = require("@medusajs/framework/mikro-orm/core")

MetadataStorage.clear()
27 changes: 27 additions & 0 deletions paypal-integration/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { loadEnv } = require("@medusajs/utils");
loadEnv("test", process.cwd());

module.exports = {
transform: {
"^.+\\.[jt]s$": [
"@swc/jest",
{
jsc: {
parser: { syntax: "typescript", decorators: true },
},
},
],
},
testEnvironment: "node",
moduleFileExtensions: ["js", "ts", "json"],
modulePathIgnorePatterns: ["dist/", "<rootDir>/.medusa/"],
setupFiles: ["./integration-tests/setup.js"],
};

if (process.env.TEST_TYPE === "integration:http") {
module.exports.testMatch = ["**/integration-tests/http/*.spec.[jt]s"];
} else if (process.env.TEST_TYPE === "integration:modules") {
module.exports.testMatch = ["**/src/modules/*/__tests__/**/*.[jt]s"];
} else if (process.env.TEST_TYPE === "unit") {
module.exports.testMatch = ["**/src/**/__tests__/**/*.unit.spec.[jt]s"];
}
36 changes: 36 additions & 0 deletions paypal-integration/medusa-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { loadEnv, defineConfig } from '@medusajs/framework/utils'

loadEnv(process.env.NODE_ENV || 'development', process.cwd())

module.exports = defineConfig({
projectConfig: {
databaseUrl: process.env.DATABASE_URL,
http: {
storeCors: process.env.STORE_CORS!,
adminCors: process.env.ADMIN_CORS!,
authCors: process.env.AUTH_CORS!,
jwtSecret: process.env.JWT_SECRET || "supersecret",
cookieSecret: process.env.COOKIE_SECRET || "supersecret",
}
},
modules: [
{
resolve: "@medusajs/medusa/payment",
options: {
providers: [
{
resolve: "./src/modules/paypal",
id: "paypal",
options: {
client_id: process.env.PAYPAL_CLIENT_ID!,
client_secret: process.env.PAYPAL_CLIENT_SECRET!,
environment: process.env.PAYPAL_ENVIRONMENT || "sandbox",
autoCapture: process.env.PAYPAL_AUTO_CAPTURE === "true",
webhook_id: process.env.PAYPAL_WEBHOOK_ID,
},
},
],
},
},
],
})
51 changes: 51 additions & 0 deletions paypal-integration/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name": "paypal-integration",
"version": "0.0.1",
"description": "A starter for Medusa projects.",
"author": "Medusa (https://medusajs.com)",
"license": "MIT",
"keywords": [
"sqlite",
"postgres",
"typescript",
"ecommerce",
"headless",
"medusa"
],
"scripts": {
"build": "medusa build",
"seed": "medusa exec ./src/scripts/seed.ts",
"start": "medusa start",
"dev": "medusa develop",
"test:integration:http": "TEST_TYPE=integration:http NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit",
"test:integration:modules": "TEST_TYPE=integration:modules NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit",
"test:unit": "TEST_TYPE=unit NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit"
},
"dependencies": {
"@medusajs/admin-sdk": "2.12.1",
"@medusajs/cli": "2.12.1",
"@medusajs/framework": "2.12.1",
"@medusajs/medusa": "2.12.1",
"@paypal/paypal-server-sdk": "^2.1.0"
},
"devDependencies": {
"@medusajs/test-utils": "2.12.1",
"@swc/core": "^1.7.28",
"@swc/jest": "^0.2.36",
"@types/jest": "^29.5.13",
"@types/node": "^20.12.11",
"@types/react": "^18.3.2",
"@types/react-dom": "^18.2.25",
"jest": "^29.7.0",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"ts-node": "^10.9.2",
"typescript": "^5.6.2",
"vite": "^5.4.14",
"yalc": "^1.0.0-pre.53"
},
"engines": {
"node": ">=20"
}
}
Loading