chapa models+swagger+unit_test

This commit is contained in:
Yared Yemane 2025-05-23 16:26:32 +03:00
parent 66a7affeba
commit 991359f805
10 changed files with 1530 additions and 78 deletions

View File

@ -52,15 +52,6 @@ import (
// @BasePath / // @BasePath /
func main() { func main() {
// utils.Init()
// fiberApp := fiber.New()
// fiberApp.Get("/health", func(c *fiber.Ctx) error {
// return c.SendString("Betting service is up and running!")
// })
// router.ChapaRoutes(fiberApp)
cfg, err := config.NewConfig() cfg, err := config.NewConfig()
if err != nil { if err != nil {
slog.Error(" Config error:", "err", err) slog.Error(" Config error:", "err", err)

View File

@ -1,9 +0,0 @@
package main
import "github.com/gofiber/fiber/v2"
func SetupRoutes(app *fiber.App) {
app.Get("/health", func(c *fiber.Ctx) error {
return c.SendString("Betting service is up and running!")
})
}

View File

@ -129,6 +129,267 @@ const docTemplate = `{
} }
} }
}, },
"/api/v1/chapa/banks": {
"get": {
"description": "Fetch all supported banks from Chapa",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Chapa"
],
"summary": "Get list of banks",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.ChapaSupportedBanksResponse"
}
}
}
}
},
"/api/v1/chapa/payments/callback": {
"post": {
"description": "Endpoint to receive webhook payloads from Chapa",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Chapa"
],
"summary": "Receive Chapa webhook",
"parameters": [
{
"description": "Webhook Payload (dynamic)",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"type": "object"
}
}
],
"responses": {
"200": {
"description": "ok",
"schema": {
"type": "string"
}
}
}
}
},
"/api/v1/chapa/payments/initialize": {
"post": {
"description": "Initiate a payment through Chapa",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Chapa"
],
"summary": "Initialize a payment transaction",
"parameters": [
{
"description": "Payment initialization request",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.InitPaymentRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.InitPaymentResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/api/v1/chapa/payments/verify/{tx_ref}": {
"get": {
"description": "Verify the transaction status from Chapa using tx_ref",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Chapa"
],
"summary": "Verify a payment transaction",
"parameters": [
{
"type": "string",
"description": "Transaction Reference",
"name": "tx_ref",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.VerifyTransactionResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/api/v1/chapa/transfers": {
"post": {
"description": "Initiate a transfer request via Chapa",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Chapa"
],
"summary": "Create a money transfer",
"parameters": [
{
"description": "Transfer request body",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.TransferRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.CreateTransferResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/api/v1/chapa/transfers/verify/{transfer_ref}": {
"get": {
"description": "Check the status of a money transfer via reference",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Chapa"
],
"summary": "Verify a transfer",
"parameters": [
{
"type": "string",
"description": "Transfer Reference",
"name": "transfer_ref",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.VerifyTransferResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/auth/login": { "/auth/login": {
"post": { "post": {
"description": "Login customer", "description": "Login customer",
@ -3903,6 +4164,73 @@ const docTemplate = `{
} }
} }
}, },
"handlers.ChapaSupportedBank": {
"type": "object",
"properties": {
"acct_length": {
"type": "integer"
},
"acct_number_regex": {
"type": "string"
},
"active": {
"type": "integer"
},
"country_id": {
"type": "integer"
},
"created_at": {
"type": "string"
},
"currency": {
"type": "string"
},
"example_value": {
"type": "string"
},
"id": {
"type": "integer"
},
"is_24hrs": {
"type": "integer"
},
"is_active": {
"type": "integer"
},
"is_mobilemoney": {
"type": "integer"
},
"is_rtgs": {
"type": "integer"
},
"name": {
"type": "string"
},
"slug": {
"type": "string"
},
"swift": {
"type": "string"
},
"updated_at": {
"type": "string"
}
}
},
"handlers.ChapaSupportedBanksResponse": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/handlers.ChapaSupportedBank"
}
},
"message": {
"type": "string"
}
}
},
"handlers.CheckPhoneEmailExistReq": { "handlers.CheckPhoneEmailExistReq": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -4286,6 +4614,20 @@ const docTemplate = `{
} }
} }
}, },
"handlers.CreateTransferResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/handlers.TransferData"
},
"message": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"handlers.CustomerWalletRes": { "handlers.CustomerWalletRes": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -4328,6 +4670,62 @@ const docTemplate = `{
} }
} }
}, },
"handlers.InitPaymentData": {
"type": "object",
"properties": {
"checkout_url": {
"type": "string"
},
"tx_ref": {
"type": "string"
}
}
},
"handlers.InitPaymentRequest": {
"type": "object",
"properties": {
"amount": {
"type": "string"
},
"callback_url": {
"type": "string"
},
"currency": {
"type": "string"
},
"email": {
"type": "string"
},
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
},
"return_url": {
"type": "string"
},
"tx_ref": {
"type": "string"
}
}
},
"handlers.InitPaymentResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/handlers.InitPaymentData"
},
"message": {
"description": "e.g., \"Payment initialized\"",
"type": "string"
},
"status": {
"description": "\"success\"",
"type": "string"
}
}
},
"handlers.ManagersRes": { "handlers.ManagersRes": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -4505,6 +4903,26 @@ const docTemplate = `{
} }
} }
}, },
"handlers.TransactionData": {
"type": "object",
"properties": {
"amount": {
"type": "string"
},
"currency": {
"type": "string"
},
"email": {
"type": "string"
},
"status": {
"type": "string"
},
"tx_ref": {
"type": "string"
}
}
},
"handlers.TransactionRes": { "handlers.TransactionRes": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -4603,6 +5021,66 @@ const docTemplate = `{
} }
} }
}, },
"handlers.TransferData": {
"type": "object",
"properties": {
"amount": {
"type": "string"
},
"currency": {
"type": "string"
},
"reference": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"handlers.TransferRequest": {
"type": "object",
"properties": {
"account_number": {
"type": "string"
},
"amount": {
"type": "string"
},
"bank_code": {
"type": "string"
},
"currency": {
"type": "string"
},
"reason": {
"type": "string"
},
"recipient_name": {
"type": "string"
},
"reference": {
"type": "string"
}
}
},
"handlers.TransferVerificationData": {
"type": "object",
"properties": {
"account_name": {
"type": "string"
},
"bank_code": {
"type": "string"
},
"reference": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"handlers.TransferWalletRes": { "handlers.TransferWalletRes": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -4734,6 +5212,34 @@ const docTemplate = `{
} }
} }
}, },
"handlers.VerifyTransactionResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/handlers.TransactionData"
},
"message": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"handlers.VerifyTransferResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/handlers.TransferVerificationData"
},
"message": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"handlers.WalletRes": { "handlers.WalletRes": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -121,6 +121,267 @@
} }
} }
}, },
"/api/v1/chapa/banks": {
"get": {
"description": "Fetch all supported banks from Chapa",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Chapa"
],
"summary": "Get list of banks",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.ChapaSupportedBanksResponse"
}
}
}
}
},
"/api/v1/chapa/payments/callback": {
"post": {
"description": "Endpoint to receive webhook payloads from Chapa",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Chapa"
],
"summary": "Receive Chapa webhook",
"parameters": [
{
"description": "Webhook Payload (dynamic)",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"type": "object"
}
}
],
"responses": {
"200": {
"description": "ok",
"schema": {
"type": "string"
}
}
}
}
},
"/api/v1/chapa/payments/initialize": {
"post": {
"description": "Initiate a payment through Chapa",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Chapa"
],
"summary": "Initialize a payment transaction",
"parameters": [
{
"description": "Payment initialization request",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.InitPaymentRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.InitPaymentResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/api/v1/chapa/payments/verify/{tx_ref}": {
"get": {
"description": "Verify the transaction status from Chapa using tx_ref",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Chapa"
],
"summary": "Verify a payment transaction",
"parameters": [
{
"type": "string",
"description": "Transaction Reference",
"name": "tx_ref",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.VerifyTransactionResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/api/v1/chapa/transfers": {
"post": {
"description": "Initiate a transfer request via Chapa",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Chapa"
],
"summary": "Create a money transfer",
"parameters": [
{
"description": "Transfer request body",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/handlers.TransferRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.CreateTransferResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/api/v1/chapa/transfers/verify/{transfer_ref}": {
"get": {
"description": "Check the status of a money transfer via reference",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Chapa"
],
"summary": "Verify a transfer",
"parameters": [
{
"type": "string",
"description": "Transfer Reference",
"name": "transfer_ref",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handlers.VerifyTransferResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/auth/login": { "/auth/login": {
"post": { "post": {
"description": "Login customer", "description": "Login customer",
@ -3895,6 +4156,73 @@
} }
} }
}, },
"handlers.ChapaSupportedBank": {
"type": "object",
"properties": {
"acct_length": {
"type": "integer"
},
"acct_number_regex": {
"type": "string"
},
"active": {
"type": "integer"
},
"country_id": {
"type": "integer"
},
"created_at": {
"type": "string"
},
"currency": {
"type": "string"
},
"example_value": {
"type": "string"
},
"id": {
"type": "integer"
},
"is_24hrs": {
"type": "integer"
},
"is_active": {
"type": "integer"
},
"is_mobilemoney": {
"type": "integer"
},
"is_rtgs": {
"type": "integer"
},
"name": {
"type": "string"
},
"slug": {
"type": "string"
},
"swift": {
"type": "string"
},
"updated_at": {
"type": "string"
}
}
},
"handlers.ChapaSupportedBanksResponse": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/handlers.ChapaSupportedBank"
}
},
"message": {
"type": "string"
}
}
},
"handlers.CheckPhoneEmailExistReq": { "handlers.CheckPhoneEmailExistReq": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -4278,6 +4606,20 @@
} }
} }
}, },
"handlers.CreateTransferResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/handlers.TransferData"
},
"message": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"handlers.CustomerWalletRes": { "handlers.CustomerWalletRes": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -4320,6 +4662,62 @@
} }
} }
}, },
"handlers.InitPaymentData": {
"type": "object",
"properties": {
"checkout_url": {
"type": "string"
},
"tx_ref": {
"type": "string"
}
}
},
"handlers.InitPaymentRequest": {
"type": "object",
"properties": {
"amount": {
"type": "string"
},
"callback_url": {
"type": "string"
},
"currency": {
"type": "string"
},
"email": {
"type": "string"
},
"first_name": {
"type": "string"
},
"last_name": {
"type": "string"
},
"return_url": {
"type": "string"
},
"tx_ref": {
"type": "string"
}
}
},
"handlers.InitPaymentResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/handlers.InitPaymentData"
},
"message": {
"description": "e.g., \"Payment initialized\"",
"type": "string"
},
"status": {
"description": "\"success\"",
"type": "string"
}
}
},
"handlers.ManagersRes": { "handlers.ManagersRes": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -4497,6 +4895,26 @@
} }
} }
}, },
"handlers.TransactionData": {
"type": "object",
"properties": {
"amount": {
"type": "string"
},
"currency": {
"type": "string"
},
"email": {
"type": "string"
},
"status": {
"type": "string"
},
"tx_ref": {
"type": "string"
}
}
},
"handlers.TransactionRes": { "handlers.TransactionRes": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -4595,6 +5013,66 @@
} }
} }
}, },
"handlers.TransferData": {
"type": "object",
"properties": {
"amount": {
"type": "string"
},
"currency": {
"type": "string"
},
"reference": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"handlers.TransferRequest": {
"type": "object",
"properties": {
"account_number": {
"type": "string"
},
"amount": {
"type": "string"
},
"bank_code": {
"type": "string"
},
"currency": {
"type": "string"
},
"reason": {
"type": "string"
},
"recipient_name": {
"type": "string"
},
"reference": {
"type": "string"
}
}
},
"handlers.TransferVerificationData": {
"type": "object",
"properties": {
"account_name": {
"type": "string"
},
"bank_code": {
"type": "string"
},
"reference": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"handlers.TransferWalletRes": { "handlers.TransferWalletRes": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -4726,6 +5204,34 @@
} }
} }
}, },
"handlers.VerifyTransactionResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/handlers.TransactionData"
},
"message": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"handlers.VerifyTransferResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/handlers.TransferVerificationData"
},
"message": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"handlers.WalletRes": { "handlers.WalletRes": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -413,6 +413,50 @@ definitions:
example: 1 example: 1
type: integer type: integer
type: object type: object
handlers.ChapaSupportedBank:
properties:
acct_length:
type: integer
acct_number_regex:
type: string
active:
type: integer
country_id:
type: integer
created_at:
type: string
currency:
type: string
example_value:
type: string
id:
type: integer
is_24hrs:
type: integer
is_active:
type: integer
is_mobilemoney:
type: integer
is_rtgs:
type: integer
name:
type: string
slug:
type: string
swift:
type: string
updated_at:
type: string
type: object
handlers.ChapaSupportedBanksResponse:
properties:
data:
items:
$ref: '#/definitions/handlers.ChapaSupportedBank'
type: array
message:
type: string
type: object
handlers.CheckPhoneEmailExistReq: handlers.CheckPhoneEmailExistReq:
properties: properties:
email: email:
@ -682,6 +726,15 @@ definitions:
example: cash example: cash
type: string type: string
type: object type: object
handlers.CreateTransferResponse:
properties:
data:
$ref: '#/definitions/handlers.TransferData'
message:
type: string
status:
type: string
type: object
handlers.CustomerWalletRes: handlers.CustomerWalletRes:
properties: properties:
company_id: company_id:
@ -712,6 +765,43 @@ definitions:
static_updated_at: static_updated_at:
type: string type: string
type: object type: object
handlers.InitPaymentData:
properties:
checkout_url:
type: string
tx_ref:
type: string
type: object
handlers.InitPaymentRequest:
properties:
amount:
type: string
callback_url:
type: string
currency:
type: string
email:
type: string
first_name:
type: string
last_name:
type: string
return_url:
type: string
tx_ref:
type: string
type: object
handlers.InitPaymentResponse:
properties:
data:
$ref: '#/definitions/handlers.InitPaymentData'
message:
description: e.g., "Payment initialized"
type: string
status:
description: '"success"'
type: string
type: object
handlers.ManagersRes: handlers.ManagersRes:
properties: properties:
created_at: created_at:
@ -835,6 +925,19 @@ definitions:
example: 4.22 example: 4.22
type: number type: number
type: object type: object
handlers.TransactionData:
properties:
amount:
type: string
currency:
type: string
email:
type: string
status:
type: string
tx_ref:
type: string
type: object
handlers.TransactionRes: handlers.TransactionRes:
properties: properties:
account_name: account_name:
@ -904,6 +1007,45 @@ definitions:
example: true example: true
type: boolean type: boolean
type: object type: object
handlers.TransferData:
properties:
amount:
type: string
currency:
type: string
reference:
type: string
status:
type: string
type: object
handlers.TransferRequest:
properties:
account_number:
type: string
amount:
type: string
bank_code:
type: string
currency:
type: string
reason:
type: string
recipient_name:
type: string
reference:
type: string
type: object
handlers.TransferVerificationData:
properties:
account_name:
type: string
bank_code:
type: string
reference:
type: string
status:
type: string
type: object
handlers.TransferWalletRes: handlers.TransferWalletRes:
properties: properties:
amount: amount:
@ -994,6 +1136,24 @@ definitions:
updated_at: updated_at:
type: string type: string
type: object type: object
handlers.VerifyTransactionResponse:
properties:
data:
$ref: '#/definitions/handlers.TransactionData'
message:
type: string
status:
type: string
type: object
handlers.VerifyTransferResponse:
properties:
data:
$ref: '#/definitions/handlers.TransferVerificationData'
message:
type: string
status:
type: string
type: object
handlers.WalletRes: handlers.WalletRes:
properties: properties:
amount: amount:
@ -1206,6 +1366,177 @@ paths:
summary: Create Admin summary: Create Admin
tags: tags:
- admin - admin
/api/v1/chapa/banks:
get:
consumes:
- application/json
description: Fetch all supported banks from Chapa
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.ChapaSupportedBanksResponse'
summary: Get list of banks
tags:
- Chapa
/api/v1/chapa/payments/callback:
post:
consumes:
- application/json
description: Endpoint to receive webhook payloads from Chapa
parameters:
- description: Webhook Payload (dynamic)
in: body
name: payload
required: true
schema:
type: object
produces:
- application/json
responses:
"200":
description: ok
schema:
type: string
summary: Receive Chapa webhook
tags:
- Chapa
/api/v1/chapa/payments/initialize:
post:
consumes:
- application/json
description: Initiate a payment through Chapa
parameters:
- description: Payment initialization request
in: body
name: payload
required: true
schema:
$ref: '#/definitions/handlers.InitPaymentRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.InitPaymentResponse'
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
"500":
description: Internal Server Error
schema:
additionalProperties:
type: string
type: object
summary: Initialize a payment transaction
tags:
- Chapa
/api/v1/chapa/payments/verify/{tx_ref}:
get:
consumes:
- application/json
description: Verify the transaction status from Chapa using tx_ref
parameters:
- description: Transaction Reference
in: path
name: tx_ref
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.VerifyTransactionResponse'
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
"500":
description: Internal Server Error
schema:
additionalProperties:
type: string
type: object
summary: Verify a payment transaction
tags:
- Chapa
/api/v1/chapa/transfers:
post:
consumes:
- application/json
description: Initiate a transfer request via Chapa
parameters:
- description: Transfer request body
in: body
name: payload
required: true
schema:
$ref: '#/definitions/handlers.TransferRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.CreateTransferResponse'
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
"500":
description: Internal Server Error
schema:
additionalProperties:
type: string
type: object
summary: Create a money transfer
tags:
- Chapa
/api/v1/chapa/transfers/verify/{transfer_ref}:
get:
consumes:
- application/json
description: Check the status of a money transfer via reference
parameters:
- description: Transfer Reference
in: path
name: transfer_ref
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handlers.VerifyTransferResponse'
"400":
description: Bad Request
schema:
additionalProperties:
type: string
type: object
"500":
description: Internal Server Error
schema:
additionalProperties:
type: string
type: object
summary: Verify a transfer
tags:
- Chapa
/auth/login: /auth/login:
post: post:
consumes: consumes:

View File

@ -1,2 +0,0 @@
package models

View File

@ -1,19 +0,0 @@
package utils
// import (
// "log"
// "os"
// "github.com/SamuelTariku/FortuneBet-Backend/internal/models"
// )
// func Init() {
// if err != nil {
// log.Println("No .env file found")
// }
// models.ChapaSecret = os.Getenv("CHAPA_SECRET_KEY")
// models.ChapaBaseURL = os.Getenv("CHAPA_BASE_URL")
// if models.ChapaBaseURL == "" {
// models.ChapaBaseURL = "https://api.chapa.co/v1"
// }
// }

View File

@ -7,36 +7,18 @@ import (
"io" "io"
"net/http" "net/http"
// "github.com/SamuelTariku/FortuneBet-Backend/internal/config"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/google/uuid"
) )
var ( // GetBanks godoc
ChapaSecret string // @Summary Get list of banks
ChapaBaseURL string // @Description Fetch all supported banks from Chapa
) // @Tags Chapa
// @Accept json
type InitPaymentRequest struct { // @Produce json
Amount string `json:"amount"` // @Success 200 {object} ChapaSupportedBanksResponse
Currency string `json:"currency"` // @Router /api/v1/chapa/banks [get]
Email string `json:"email"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
TxRef string `json:"tx_ref"`
CallbackURL string `json:"callback_url"`
ReturnURL string `json:"return_url"`
}
type TransferRequest struct {
AccountNumber string `json:"account_number"`
BankCode string `json:"bank_code"`
Amount string `json:"amount"`
Currency string `json:"currency"`
Reference string `json:"reference"`
Reason string `json:"reason"`
RecipientName string `json:"recipient_name"`
}
func (h *Handler) GetBanks(c *fiber.Ctx) error { func (h *Handler) GetBanks(c *fiber.Ctx) error {
httpReq, err := http.NewRequest("GET", h.Cfg.CHAPA_BASE_URL+"/banks", nil) httpReq, err := http.NewRequest("GET", h.Cfg.CHAPA_BASE_URL+"/banks", nil)
// log.Printf("\n\nbase url is: %v\n\n", h.Cfg.CHAPA_BASE_URL) // log.Printf("\n\nbase url is: %v\n\n", h.Cfg.CHAPA_BASE_URL)
@ -56,9 +38,20 @@ func (h *Handler) GetBanks(c *fiber.Ctx) error {
return c.Status(500).JSON(fiber.Map{"error": "Failed to read response", "details": err.Error()}) return c.Status(500).JSON(fiber.Map{"error": "Failed to read response", "details": err.Error()})
} }
return c.Status(resp.StatusCode).Send(body) return c.Status(resp.StatusCode).Type("json").Send(body)
} }
// InitializePayment godoc
// @Summary Initialize a payment transaction
// @Description Initiate a payment through Chapa
// @Tags Chapa
// @Accept json
// @Produce json
// @Param payload body InitPaymentRequest true "Payment initialization request"
// @Success 200 {object} InitPaymentResponse
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/chapa/payments/initialize [post]
func (h *Handler) InitializePayment(c *fiber.Ctx) error { func (h *Handler) InitializePayment(c *fiber.Ctx) error {
var req InitPaymentRequest var req InitPaymentRequest
if err := c.BodyParser(&req); err != nil { if err := c.BodyParser(&req); err != nil {
@ -68,6 +61,9 @@ func (h *Handler) InitializePayment(c *fiber.Ctx) error {
}) })
} }
// Generate and assign a unique transaction reference
req.TxRef = uuid.New().String()
payload, err := json.Marshal(req) payload, err := json.Marshal(req)
if err != nil { if err != nil {
return c.Status(500).JSON(fiber.Map{ return c.Status(500).JSON(fiber.Map{
@ -103,9 +99,20 @@ func (h *Handler) InitializePayment(c *fiber.Ctx) error {
}) })
} }
return c.Status(resp.StatusCode).Send(body) return c.Status(resp.StatusCode).Type("json").Send(body)
} }
// VerifyTransaction godoc
// @Summary Verify a payment transaction
// @Description Verify the transaction status from Chapa using tx_ref
// @Tags Chapa
// @Accept json
// @Produce json
// @Param tx_ref path string true "Transaction Reference"
// @Success 200 {object} VerifyTransactionResponse
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/chapa/payments/verify/{tx_ref} [get]
func (h *Handler) VerifyTransaction(c *fiber.Ctx) error { func (h *Handler) VerifyTransaction(c *fiber.Ctx) error {
txRef := c.Params("tx_ref") txRef := c.Params("tx_ref")
if txRef == "" { if txRef == "" {
@ -142,9 +149,18 @@ func (h *Handler) VerifyTransaction(c *fiber.Ctx) error {
}) })
} }
return c.Status(resp.StatusCode).Send(body) return c.Status(resp.StatusCode).Type("json").Send(body)
} }
// ReceiveWebhook godoc
// @Summary Receive Chapa webhook
// @Description Endpoint to receive webhook payloads from Chapa
// @Tags Chapa
// @Accept json
// @Produce json
// @Param payload body object true "Webhook Payload (dynamic)"
// @Success 200 {string} string "ok"
// @Router /api/v1/chapa/payments/callback [post]
func (h *Handler) ReceiveWebhook(c *fiber.Ctx) error { func (h *Handler) ReceiveWebhook(c *fiber.Ctx) error {
var payload map[string]interface{} var payload map[string]interface{}
if err := c.BodyParser(&payload); err != nil { if err := c.BodyParser(&payload); err != nil {
@ -161,6 +177,17 @@ func (h *Handler) ReceiveWebhook(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusOK) return c.SendStatus(fiber.StatusOK)
} }
// CreateTransfer godoc
// @Summary Create a money transfer
// @Description Initiate a transfer request via Chapa
// @Tags Chapa
// @Accept json
// @Produce json
// @Param payload body TransferRequest true "Transfer request body"
// @Success 200 {object} CreateTransferResponse
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/chapa/transfers [post]
func (h *Handler) CreateTransfer(c *fiber.Ctx) error { func (h *Handler) CreateTransfer(c *fiber.Ctx) error {
var req TransferRequest var req TransferRequest
if err := c.BodyParser(&req); err != nil { if err := c.BodyParser(&req); err != nil {
@ -170,6 +197,9 @@ func (h *Handler) CreateTransfer(c *fiber.Ctx) error {
}) })
} }
// Inject unique transaction reference
req.Reference = uuid.New().String()
payload, err := json.Marshal(req) payload, err := json.Marshal(req)
if err != nil { if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
@ -206,9 +236,20 @@ func (h *Handler) CreateTransfer(c *fiber.Ctx) error {
}) })
} }
return c.Status(resp.StatusCode).Send(body) return c.Status(resp.StatusCode).Type("json").Send(body)
} }
// VerifyTransfer godoc
// @Summary Verify a transfer
// @Description Check the status of a money transfer via reference
// @Tags Chapa
// @Accept json
// @Produce json
// @Param transfer_ref path string true "Transfer Reference"
// @Success 200 {object} VerifyTransferResponse
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /api/v1/chapa/transfers/verify/{transfer_ref} [get]
func (h *Handler) VerifyTransfer(c *fiber.Ctx) error { func (h *Handler) VerifyTransfer(c *fiber.Ctx) error {
transferRef := c.Params("transfer_ref") transferRef := c.Params("transfer_ref")
if transferRef == "" { if transferRef == "" {
@ -217,7 +258,7 @@ func (h *Handler) VerifyTransfer(c *fiber.Ctx) error {
}) })
} }
url := fmt.Sprintf("%s/transfers/%s", h.Cfg.CHAPA_BASE_URL, transferRef) url := fmt.Sprintf("%s/transfers/verify/%s", h.Cfg.CHAPA_BASE_URL, transferRef)
httpReq, err := http.NewRequest("GET", url, nil) httpReq, err := http.NewRequest("GET", url, nil)
if err != nil { if err != nil {
@ -246,5 +287,5 @@ func (h *Handler) VerifyTransfer(c *fiber.Ctx) error {
}) })
} }
return c.Status(resp.StatusCode).Send(body) return c.Status(resp.StatusCode).Type("json").Send(body)
} }

View File

@ -0,0 +1,107 @@
package handlers
import "time"
var (
ChapaSecret string
ChapaBaseURL string
)
type InitPaymentRequest struct {
Amount string `json:"amount"`
Currency string `json:"currency"`
Email string `json:"email"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
TxRef string `json:"tx_ref"`
CallbackURL string `json:"callback_url"`
ReturnURL string `json:"return_url"`
}
type TransferRequest struct {
AccountNumber string `json:"account_number"`
BankCode string `json:"bank_code"`
Amount string `json:"amount"`
Currency string `json:"currency"`
Reference string `json:"reference"`
Reason string `json:"reason"`
RecipientName string `json:"recipient_name"`
}
type ChapaSupportedBank struct {
Id int64 `json:"id"`
Slug string `json:"slug"`
Swift string `json:"swift"`
Name string `json:"name"`
AcctLength int `json:"acct_length"`
AcctNumberRegex string `json:"acct_number_regex"`
ExampleValue string `json:"example_value"`
CountryId int `json:"country_id"`
IsMobilemoney *int `json:"is_mobilemoney"`
IsActive int `json:"is_active"`
IsRtgs *int `json:"is_rtgs"`
Active int `json:"active"`
Is24Hrs *int `json:"is_24hrs"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Currency string `json:"currency"`
}
type ChapaSupportedBanksResponse struct {
Message string `json:"message"`
Data []ChapaSupportedBank `json:"data"`
}
type InitPaymentData struct {
TxRef string `json:"tx_ref"`
CheckoutURL string `json:"checkout_url"`
}
type InitPaymentResponse struct {
Status string `json:"status"` // "success"
Message string `json:"message"` // e.g., "Payment initialized"
Data InitPaymentData `json:"data"`
}
type WebhookPayload map[string]interface{}
type TransactionData struct {
TxRef string `json:"tx_ref"`
Status string `json:"status"`
Amount string `json:"amount"`
Currency string `json:"currency"`
CustomerEmail string `json:"email"`
}
type VerifyTransactionResponse struct {
Status string `json:"status"`
Message string `json:"message"`
Data TransactionData `json:"data"`
}
type TransferData struct {
Reference string `json:"reference"`
Status string `json:"status"`
Amount string `json:"amount"`
Currency string `json:"currency"`
}
type CreateTransferResponse struct {
Status string `json:"status"`
Message string `json:"message"`
Data TransferData `json:"data"`
}
type TransferVerificationData struct {
Reference string `json:"reference"`
Status string `json:"status"`
BankCode string `json:"bank_code"`
AccountName string `json:"account_name"`
}
type VerifyTransferResponse struct {
Status string `json:"status"`
Message string `json:"message"`
Data TransferVerificationData `json:"data"`
}

View File

@ -167,12 +167,12 @@ func (a *App) initAppRoutes() {
a.fiber.Post("/transfer/refill/:id", a.authMiddleware, h.RefillWallet) a.fiber.Post("/transfer/refill/:id", a.authMiddleware, h.RefillWallet)
//Chapa Routes //Chapa Routes
a.fiber.Post("/api/v1/chapa/payments/initialize", a.authMiddleware, h.InitializePayment) a.fiber.Post("/api/v1/chapa/payments/initialize", h.InitializePayment)
a.fiber.Get("/api/v1/chapa/payments/verify/:tx_ref", a.authMiddleware, h.VerifyTransaction) a.fiber.Get("/api/v1/chapa/payments/verify/:tx_ref", h.VerifyTransaction)
a.fiber.Post("/api/v1/chapa/payments/callback", a.authMiddleware, h.ReceiveWebhook) a.fiber.Post("/api/v1/chapa/payments/callback", h.ReceiveWebhook)
a.fiber.Get("/api/v1/chapa/banks", a.authMiddleware, h.GetBanks) a.fiber.Get("/api/v1/chapa/banks", h.GetBanks)
a.fiber.Post("/api/v1/chapa/transfers", a.authMiddleware, h.CreateTransfer) a.fiber.Post("/api/v1/chapa/transfers", h.CreateTransfer)
a.fiber.Get("/api/v1/chapa/transfers/:transfer_ref", a.authMiddleware, h.VerifyTransfer) a.fiber.Get("/api/v1/chapa/transfers/verify/:transfer_ref", h.VerifyTransfer)
// Transactions /transactions // Transactions /transactions
a.fiber.Post("/transaction", a.authMiddleware, h.CreateTransaction) a.fiber.Post("/transaction", a.authMiddleware, h.CreateTransaction)