Skip to content

Commit 4b4bea3

Browse files
committed
feat: setup db seed, xendit, testing transaction for create transaction
1 parent d60eaca commit 4b4bea3

File tree

14 files changed

+772
-13
lines changed

14 files changed

+772
-13
lines changed

.env.example

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,12 @@ CORS_ALLOWED_METHODS="GET,POST,PUT,PATCH,DELETE,OPTIONS"
1313
SMTP_HOST="[email protected]"
1414
SMTP_PASSWORD="123456"
1515
SMTP_PORT="587"
16-
SMTP_EMAIL="smtp.gmail.com"
16+
SMTP_EMAIL="smtp.gmail.com"
17+
18+
# Xendit Payment Gateway Configuration
19+
# Get your API key from: https://dashboard.xendit.co/settings/developers#api-keys
20+
# Use test mode API key for development (starts with xnd_development_)
21+
XENDIT_API_KEY="xnd_development_your_api_key_here"
22+
XENDIT_WEBHOOK_TOKEN="your_webhook_verification_token_here"
23+
XENDIT_SUCCESS_REDIRECT="http://localhost:3000/payment/success"
24+
XENDIT_FAILURE_REDIRECT="http://localhost:3000/payment/failed"

PAYMENT_GATEWAY_GUIDE.md

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
# 🚀 Xendit Payment Gateway Integration - Simple Guide
2+
3+
Integrasi sederhana Xendit Payment Gateway untuk memahami cara kerja payment gateway.
4+
5+
## 📋 Konsep Payment Gateway
6+
7+
```
8+
User → Backend → Xendit → User Bayar → Webhook → Backend Update Status
9+
```
10+
11+
## 🏗️ Struktur Project
12+
13+
```
14+
app/testing_transaction/
15+
├── domain/testing_transaction.go # Model & Interface
16+
├── repository/repository.go # Database operations
17+
├── usecase/usecase.go # Business logic
18+
└── delivery/http/handler.go # HTTP endpoints
19+
20+
pkg/xendit/xendit.go # Xendit SDK wrapper
21+
22+
database/
23+
├── migration/..._table_testing_transaction.sql
24+
└── seeder/..._seed_testing_transaction.sql
25+
```
26+
27+
## 🔧 Setup
28+
29+
### 1. Install Dependencies
30+
```bash
31+
go get github.com/xendit/xendit-go/v6
32+
```
33+
34+
### 2. Setup Xendit Account
35+
1. Daftar di [https://dashboard.xendit.co](https://dashboard.xendit.co)
36+
2. Ambil **API Key** (Test Mode) dari menu **Settings → Developers → API Keys**
37+
3. Copy API key yang dimulai dengan `xnd_development_...`
38+
39+
### 3. Update .env
40+
```env
41+
XENDIT_API_KEY="xnd_development_your_actual_key_here"
42+
XENDIT_WEBHOOK_TOKEN="optional_webhook_token"
43+
XENDIT_SUCCESS_REDIRECT="http://localhost:3000/payment/success"
44+
XENDIT_FAILURE_REDIRECT="http://localhost:3000/payment/failed"
45+
```
46+
47+
### 4. Run Migration
48+
```bash
49+
make migration-up
50+
make seed-up
51+
```
52+
53+
### 5. Start Server
54+
```bash
55+
make run-http
56+
# atau
57+
go run main.go http
58+
```
59+
60+
## 🌐 API Endpoints
61+
62+
### 1. Create Payment (Buat Invoice)
63+
**POST** `/api/v1/public/payments`
64+
65+
Request:
66+
```json
67+
{
68+
"customer_name": "John Doe",
69+
"customer_email": "[email protected]",
70+
"amount": 100000
71+
}
72+
```
73+
74+
Response:
75+
```json
76+
{
77+
"code": 200,
78+
"message": "Payment created successfully",
79+
"data": {
80+
"order_no": "ORDER-1234567890",
81+
"invoice_url": "https://checkout.xendit.co/web/xxxxx",
82+
"amount": 100000,
83+
"status": "pending"
84+
}
85+
}
86+
```
87+
88+
### 2. Get Payment by Order No
89+
**GET** `/api/v1/public/payments/{order_no}`
90+
91+
Response:
92+
```json
93+
{
94+
"code": 200,
95+
"message": "Success",
96+
"data": {
97+
"id": 1,
98+
"order_no": "ORDER-1234567890",
99+
"customer_name": "John Doe",
100+
"customer_email": "[email protected]",
101+
"amount": 100000,
102+
"status": "paid",
103+
"invoice_url": "https://checkout.xendit.co/web/xxxxx",
104+
"payment_method": "BANK_TRANSFER",
105+
"created_at": "2024-01-01T10:00:00Z"
106+
}
107+
}
108+
```
109+
110+
### 3. Get All Payments
111+
**GET** `/api/v1/public/payments`
112+
113+
Response:
114+
```json
115+
{
116+
"code": 200,
117+
"message": "Success",
118+
"data": [
119+
{
120+
"id": 1,
121+
"order_no": "ORDER-1234567890",
122+
"customer_name": "John Doe",
123+
"amount": 100000,
124+
"status": "paid"
125+
}
126+
]
127+
}
128+
```
129+
130+
### 4. Webhook (Otomatis dari Xendit)
131+
**POST** `/api/v1/public/webhooks/xendit`
132+
133+
Xendit akan otomatis hit endpoint ini ketika payment berhasil.
134+
135+
## 🔄 Payment Flow
136+
137+
### 1. User Create Payment
138+
```bash
139+
curl -X POST http://localhost:8000/api/v1/public/payments \
140+
-H "Content-Type: application/json" \
141+
-d '{
142+
"customer_name": "John Doe",
143+
"customer_email": "[email protected]",
144+
"amount": 50000
145+
}'
146+
```
147+
148+
Response akan berisi `invoice_url` yang bisa dibuka untuk bayar.
149+
150+
### 2. User Bayar
151+
- Buka `invoice_url` di browser
152+
- Pilih metode pembayaran (Virtual Account BCA/Mandiri/BNI, QRIS, E-wallet)
153+
- Bayar sesuai instruksi
154+
155+
### 3. Xendit Webhook
156+
Setelah user bayar, Xendit otomatis kirim webhook ke backend:
157+
```
158+
POST /api/v1/public/webhooks/xendit
159+
```
160+
161+
Backend akan update status payment dari `pending``paid`
162+
163+
## 📝 Code Explanation
164+
165+
### 1. Xendit Client (pkg/xendit/xendit.go)
166+
```go
167+
// Wrapper sederhana untuk Xendit SDK
168+
func (c *Client) CreateInvoice(ctx context.Context, orderNo, email string, amount float64, description string) (invoiceURL string, err error)
169+
```
170+
171+
### 2. Usecase (app/testing_transaction/usecase/usecase.go)
172+
173+
**CreatePayment**:
174+
1. Generate order number
175+
2. Panggil Xendit API untuk buat invoice
176+
3. Simpan ke database dengan status `pending`
177+
4. Return invoice URL ke user
178+
179+
**HandleWebhook**:
180+
1. Terima callback dari Xendit
181+
2. Update status payment di database
182+
3. Bisa ditambahkan: kirim email notifikasi, update inventory, dll
183+
184+
### 3. Handler (app/testing_transaction/delivery/http/handler.go)
185+
186+
HTTP handler untuk menerima request dari client dan webhook dari Xendit.
187+
188+
## 🧪 Testing
189+
190+
### Test dengan Postman/cURL
191+
192+
1. **Create Payment**
193+
```bash
194+
curl -X POST http://localhost:8000/api/v1/public/payments \
195+
-H "Content-Type: application/json" \
196+
-d '{"customer_name":"Test User","customer_email":"[email protected]","amount":100000}'
197+
```
198+
199+
2. **Buka invoice_url** yang dikembalikan untuk simulasi pembayaran
200+
201+
3. **Check status payment**
202+
```bash
203+
curl http://localhost:8000/api/v1/public/payments/ORDER-1234567890
204+
```
205+
206+
### Test Webhook di Local
207+
208+
Karena Xendit tidak bisa hit localhost, gunakan salah satu tools:
209+
- **ngrok**: `ngrok http 8000`
210+
- **localtunnel**: `lt --port 8000`
211+
212+
Lalu set webhook URL di Xendit dashboard ke:
213+
```
214+
https://your-ngrok-url.ngrok.io/api/v1/public/webhooks/xendit
215+
```
216+
217+
## 📊 Database Structure
218+
219+
```sql
220+
CREATE TABLE testing_transaction (
221+
id SERIAL PRIMARY KEY,
222+
order_no VARCHAR(100) UNIQUE NOT NULL,
223+
customer_name VARCHAR(255) NOT NULL,
224+
customer_email VARCHAR(255) NOT NULL,
225+
amount NUMERIC(15,2) NOT NULL,
226+
status VARCHAR(50) DEFAULT 'pending', -- pending, paid, expired
227+
invoice_url TEXT,
228+
payment_method VARCHAR(50),
229+
created_at TIMESTAMP DEFAULT NOW(),
230+
updated_at TIMESTAMP
231+
);
232+
```
233+
234+
## 🎯 Key Points
235+
236+
1. **Simple & Clear**: Code dibuat sesederhana mungkin untuk mudah dipahami
237+
2. **Official SDK**: Menggunakan `xendit-go` official SDK, bukan custom HTTP client
238+
3. **Webhook Important**: Webhook adalah cara Xendit memberitahu kita kalau payment berhasil
239+
4. **Async Process**: Payment adalah proses async - user bayar diluar sistem kita
240+
5. **Test Mode**: Gunakan test API key untuk development (tidak ada biaya)
241+
242+
## 🔐 Security Notes
243+
244+
- Jangan commit API key ke git
245+
- Gunakan `.env` untuk menyimpan credentials
246+
- Di production, validate webhook signature dari Xendit
247+
- Gunakan HTTPS untuk webhook endpoint
248+
249+
## 📚 Resources
250+
251+
- [Xendit API Documentation](https://developers.xendit.co/api-reference/)
252+
- [Xendit Go SDK](https://github.com/xendit/xendit-go)
253+
- [Xendit Dashboard](https://dashboard.xendit.co)
254+
255+
## ✅ Next Steps
256+
257+
Setelah memahami basic flow, bisa develop:
258+
1. Integrate dengan event registration yang sudah ada
259+
2. Tambah email notification setelah payment success
260+
3. Implementasi refund/cancellation
261+
4. Add pagination untuk list payments
262+
5. Export payment report
263+
264+
---
265+
266+
**Happy Coding! 🚀**

app/app.go

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,29 @@ import (
44
blogPost "github.com/hammer-code/lms-be/app/blog_post"
55
"github.com/hammer-code/lms-be/app/middlewares"
66
newsletters "github.com/hammer-code/lms-be/app/newsletters"
7+
testingTransaction "github.com/hammer-code/lms-be/app/testing_transaction/delivery/http"
8+
testingTransactionRepo "github.com/hammer-code/lms-be/app/testing_transaction/repository"
9+
testingTransactionUC "github.com/hammer-code/lms-be/app/testing_transaction/usecase"
710
users "github.com/hammer-code/lms-be/app/users"
811
"github.com/hammer-code/lms-be/config"
912
"github.com/hammer-code/lms-be/domain"
1013
pkgDB "github.com/hammer-code/lms-be/pkg/db"
1114
"github.com/hammer-code/lms-be/pkg/jwt"
15+
"github.com/hammer-code/lms-be/pkg/xendit"
1216
"gorm.io/driver/postgres"
1317

1418
events "github.com/hammer-code/lms-be/app/events"
1519
images "github.com/hammer-code/lms-be/app/images"
1620
)
1721

1822
type App struct {
19-
Middleware domain.Middleware
20-
UserHandler domain.UserHandler
21-
NewLetterHandler domain.NewslettterHandler
22-
EventHandler domain.EventHandler
23-
ImageHandler domain.ImageHandler
24-
BlogPostHandler domain.BlogPostHandler
23+
Middleware domain.Middleware
24+
UserHandler domain.UserHandler
25+
NewLetterHandler domain.NewslettterHandler
26+
EventHandler domain.EventHandler
27+
ImageHandler domain.ImageHandler
28+
BlogPostHandler domain.BlogPostHandler
29+
TestingTransactionHandler domain.TestingTransactionHandler
2530
}
2631

2732
func InitApp(
@@ -36,12 +41,16 @@ func InitApp(
3641
dbTx := pkgDB.NewDBTransaction(db)
3742
jwtInstance := jwt.NewJwt(cfg.JWT_SECRET_KEY)
3843

44+
// Xendit client
45+
xenditClient := xendit.NewClient(cfg.XENDIT_API_KEY)
46+
3947
// repository
4048
userRepo := users.InitRepository(dbTx)
4149
newsletterRepo := newsletters.InitRepository(dbTx)
4250
eventRepo := events.InitRepository(dbTx)
4351
imgRepo := images.InitRepository(dbTx)
4452
blogPostRepo := blogPost.InitRepository(dbTx)
53+
testingTransactionRepository := testingTransactionRepo.NewRepository(db)
4554

4655
// Middlewares
4756
middleware := middlewares.InitMiddleware(jwtInstance, userRepo)
@@ -52,20 +61,23 @@ func InitApp(
5261
eventUC := events.InitUsecase(cfg, eventRepo, imgRepo, dbTx)
5362
imgUc := images.InitUsecase(imgRepo, dbTx)
5463
blogPostUc := blogPost.InitUseCase(blogPostRepo, jwtInstance)
64+
testingTransactionUsecase := testingTransactionUC.NewUsecase(testingTransactionRepository, xenditClient)
5565

5666
// handler
5767
userHandler := users.InitHandler(userUsecase)
5868
newsletterHandler := newsletters.InitHandler(newsletterUC, middleware)
5969
eventHandler := events.InitHandler(eventUC)
6070
ImageHandler := images.InitHandler(imgUc)
6171
blogPostHandler := blogPost.InitHandler(blogPostUc)
72+
testingTransactionHandler := testingTransaction.NewHandler(testingTransactionUsecase)
6273

6374
return App{
64-
UserHandler: userHandler,
65-
NewLetterHandler: newsletterHandler,
66-
Middleware: middleware,
67-
EventHandler: eventHandler,
68-
ImageHandler: ImageHandler,
69-
BlogPostHandler: blogPostHandler,
75+
UserHandler: userHandler,
76+
NewLetterHandler: newsletterHandler,
77+
Middleware: middleware,
78+
EventHandler: eventHandler,
79+
ImageHandler: ImageHandler,
80+
BlogPostHandler: blogPostHandler,
81+
TestingTransactionHandler: testingTransactionHandler,
7082
}
7183
}

0 commit comments

Comments
 (0)