diff --git a/cmd/main.go b/cmd/main.go index 6eedda0..0045fca 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -52,15 +52,6 @@ import ( // @BasePath / 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() if err != nil { slog.Error(" Config error:", "err", err) diff --git a/cmd/router.go b/cmd/router.go deleted file mode 100644 index 5c95681..0000000 --- a/cmd/router.go +++ /dev/null @@ -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!") - }) -} diff --git a/docs/docs.go b/docs/docs.go index 72da21c..f9b5d61 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -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": { "post": { "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": { "type": "object", "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": { "type": "object", "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": { "type": "object", "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": { "type": "object", "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": { "type": "object", "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": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 123e78f..b01b99e 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -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": { "post": { "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": { "type": "object", "properties": { @@ -4278,6 +4606,20 @@ } } }, + "handlers.CreateTransferResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/handlers.TransferData" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, "handlers.CustomerWalletRes": { "type": "object", "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": { "type": "object", "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": { "type": "object", "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": { "type": "object", "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": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index e76a984..4219293 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -413,6 +413,50 @@ definitions: example: 1 type: integer 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: properties: email: @@ -682,6 +726,15 @@ definitions: example: cash type: string type: object + handlers.CreateTransferResponse: + properties: + data: + $ref: '#/definitions/handlers.TransferData' + message: + type: string + status: + type: string + type: object handlers.CustomerWalletRes: properties: company_id: @@ -712,6 +765,43 @@ definitions: static_updated_at: type: string 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: properties: created_at: @@ -835,6 +925,19 @@ definitions: example: 4.22 type: number 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: properties: account_name: @@ -904,6 +1007,45 @@ definitions: example: true type: boolean 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: properties: amount: @@ -994,6 +1136,24 @@ definitions: updated_at: type: string 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: properties: amount: @@ -1206,6 +1366,177 @@ paths: summary: Create Admin tags: - 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: post: consumes: diff --git a/internal/models/models.chapa.go b/internal/models/models.chapa.go deleted file mode 100644 index d6a05a4..0000000 --- a/internal/models/models.chapa.go +++ /dev/null @@ -1,2 +0,0 @@ -package models - diff --git a/internal/utils/utils.chapa.go b/internal/utils/utils.chapa.go deleted file mode 100644 index 5005d3a..0000000 --- a/internal/utils/utils.chapa.go +++ /dev/null @@ -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" -// } -// } diff --git a/internal/web_server/handlers/chapa.go b/internal/web_server/handlers/chapa.go index 9165226..1f80787 100644 --- a/internal/web_server/handlers/chapa.go +++ b/internal/web_server/handlers/chapa.go @@ -7,36 +7,18 @@ import ( "io" "net/http" - // "github.com/SamuelTariku/FortuneBet-Backend/internal/config" "github.com/gofiber/fiber/v2" + "github.com/google/uuid" ) -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"` -} - +// GetBanks godoc +// @Summary Get list of banks +// @Description Fetch all supported banks from Chapa +// @Tags Chapa +// @Accept json +// @Produce json +// @Success 200 {object} ChapaSupportedBanksResponse +// @Router /api/v1/chapa/banks [get] func (h *Handler) GetBanks(c *fiber.Ctx) error { 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) @@ -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(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 { var req InitPaymentRequest 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) if err != nil { 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 { txRef := c.Params("tx_ref") 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 { var payload map[string]interface{} if err := c.BodyParser(&payload); err != nil { @@ -161,6 +177,17 @@ func (h *Handler) ReceiveWebhook(c *fiber.Ctx) error { 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 { var req TransferRequest 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) if err != nil { 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 { transferRef := c.Params("transfer_ref") 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) 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) } diff --git a/internal/web_server/handlers/models.chapa.go b/internal/web_server/handlers/models.chapa.go new file mode 100644 index 0000000..f829b53 --- /dev/null +++ b/internal/web_server/handlers/models.chapa.go @@ -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"` +} diff --git a/internal/web_server/routes.go b/internal/web_server/routes.go index 6319bc6..20e84f5 100644 --- a/internal/web_server/routes.go +++ b/internal/web_server/routes.go @@ -167,12 +167,12 @@ func (a *App) initAppRoutes() { a.fiber.Post("/transfer/refill/:id", a.authMiddleware, h.RefillWallet) //Chapa Routes - a.fiber.Post("/api/v1/chapa/payments/initialize", a.authMiddleware, h.InitializePayment) - a.fiber.Get("/api/v1/chapa/payments/verify/:tx_ref", a.authMiddleware, h.VerifyTransaction) - a.fiber.Post("/api/v1/chapa/payments/callback", a.authMiddleware, h.ReceiveWebhook) - a.fiber.Get("/api/v1/chapa/banks", a.authMiddleware, h.GetBanks) - a.fiber.Post("/api/v1/chapa/transfers", a.authMiddleware, h.CreateTransfer) - a.fiber.Get("/api/v1/chapa/transfers/:transfer_ref", a.authMiddleware, h.VerifyTransfer) + a.fiber.Post("/api/v1/chapa/payments/initialize", h.InitializePayment) + a.fiber.Get("/api/v1/chapa/payments/verify/:tx_ref", h.VerifyTransaction) + a.fiber.Post("/api/v1/chapa/payments/callback", h.ReceiveWebhook) + a.fiber.Get("/api/v1/chapa/banks", h.GetBanks) + a.fiber.Post("/api/v1/chapa/transfers", h.CreateTransfer) + a.fiber.Get("/api/v1/chapa/transfers/verify/:transfer_ref", h.VerifyTransfer) // Transactions /transactions a.fiber.Post("/transaction", a.authMiddleware, h.CreateTransaction)