wallet security+log file
This commit is contained in:
parent
49d9dafccb
commit
f2ec267347
|
|
@ -297,6 +297,7 @@ ADD CONSTRAINT fk_branch_operations_operations FOREIGN KEY (operation_id) REFERE
|
||||||
ALTER TABLE branch_cashiers
|
ALTER TABLE branch_cashiers
|
||||||
ADD CONSTRAINT fk_branch_cashiers_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
ADD CONSTRAINT fk_branch_cashiers_users FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||||
ADD CONSTRAINT fk_branch_cashiers_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_branch_cashiers_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
ALTER TABLE companies
|
ALTER TABLE companies
|
||||||
ADD CONSTRAINT fk_companies_admin FOREIGN KEY (admin_id) REFERENCES users(id),
|
ADD CONSTRAINT fk_companies_admin FOREIGN KEY (admin_id) REFERENCES users(id),
|
||||||
ADD CONSTRAINT fk_companies_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_companies_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id) ON DELETE CASCADE;
|
||||||
|
|
|
||||||
391
docs/docs.go
391
docs/docs.go
|
|
@ -306,7 +306,6 @@ const docTemplate = `{
|
||||||
},
|
},
|
||||||
"/api/v1/chapa/banks": {
|
"/api/v1/chapa/banks": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Fetch all supported banks from Chapa",
|
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
|
|
@ -316,46 +315,42 @@ const docTemplate = `{
|
||||||
"tags": [
|
"tags": [
|
||||||
"Chapa"
|
"Chapa"
|
||||||
],
|
],
|
||||||
"summary": "Get list of banks",
|
"summary": "fetches chapa supported banks",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/domain.ChapaSupportedBanksResponse"
|
"$ref": "#/definitions/domain.ChapaSupportedBanksResponseWrapper"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
"400": {
|
||||||
}
|
"description": "Bad Request",
|
||||||
},
|
|
||||||
"/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": {
|
"schema": {
|
||||||
"type": "object"
|
"$ref": "#/definitions/domain.Response"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
],
|
"401": {
|
||||||
"responses": {
|
"description": "Unauthorized",
|
||||||
"200": {
|
|
||||||
"description": "ok",
|
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string"
|
"$ref": "#/definitions/domain.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"description": "Unprocessable Entity",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.Response"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -363,11 +358,6 @@ const docTemplate = `{
|
||||||
},
|
},
|
||||||
"/api/v1/chapa/payments/deposit": {
|
"/api/v1/chapa/payments/deposit": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"ApiKeyAuth": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Deposits money into user wallet from user account using Chapa",
|
"description": "Deposits money into user wallet from user account using Chapa",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
|
|
@ -418,40 +408,6 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/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/domain.InitPaymentRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/domain.InitPaymentResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/chapa/payments/verify": {
|
"/api/v1/chapa/payments/verify": {
|
||||||
"post": {
|
"post": {
|
||||||
"consumes": [
|
"consumes": [
|
||||||
|
|
@ -485,38 +441,6 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/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/domain.VerifyTransactionResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/chapa/payments/withdraw": {
|
"/api/v1/chapa/payments/withdraw": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "Initiates a withdrawal transaction using Chapa for the authenticated user.",
|
"description": "Initiates a withdrawal transaction using Chapa for the authenticated user.",
|
||||||
|
|
@ -587,72 +511,6 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/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/domain.TransferRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/domain.CreateTransferResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/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/domain.VerifyTransferResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/virtual-games/recommendations/{userID}": {
|
"/api/v1/virtual-games/recommendations/{userID}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Returns a list of recommended virtual games for a specific user",
|
"description": "Returns a list of recommended virtual games for a specific user",
|
||||||
|
|
@ -4666,17 +4524,18 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain.ChapaSupportedBanksResponse": {
|
"domain.ChapaSupportedBanksResponseWrapper": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"data": {
|
"data": {},
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/domain.ChapaSupportedBank"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"message": {
|
"message": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status_code": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -4770,76 +4629,6 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain.CreateTransferResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {
|
|
||||||
"$ref": "#/definitions/domain.TransferData"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.InitPaymentData": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"checkout_url": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"tx_ref": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.InitPaymentRequest": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"amount": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.InitPaymentResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {
|
|
||||||
"$ref": "#/definitions/domain.InitPaymentData"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"description": "e.g., \"Payment initialized\"",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"description": "\"success\"",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.Odd": {
|
"domain.Odd": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -5167,86 +4956,6 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain.TransactionData": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"amount": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"currency": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"email": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"tx_ref": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.TransferData": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"amount": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"currency": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"reference": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.TransferVerificationData": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"account_name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"bank_code": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"reference": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.UpcomingEvent": {
|
"domain.UpcomingEvent": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -5353,34 +5062,6 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain.VerifyTransactionResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {
|
|
||||||
"$ref": "#/definitions/domain.TransactionData"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.VerifyTransferResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {
|
|
||||||
"$ref": "#/definitions/domain.TransferVerificationData"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.VirtualGame": {
|
"domain.VirtualGame": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,6 @@
|
||||||
},
|
},
|
||||||
"/api/v1/chapa/banks": {
|
"/api/v1/chapa/banks": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Fetch all supported banks from Chapa",
|
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
|
|
@ -308,46 +307,42 @@
|
||||||
"tags": [
|
"tags": [
|
||||||
"Chapa"
|
"Chapa"
|
||||||
],
|
],
|
||||||
"summary": "Get list of banks",
|
"summary": "fetches chapa supported banks",
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/domain.ChapaSupportedBanksResponse"
|
"$ref": "#/definitions/domain.ChapaSupportedBanksResponseWrapper"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
"400": {
|
||||||
}
|
"description": "Bad Request",
|
||||||
},
|
|
||||||
"/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": {
|
"schema": {
|
||||||
"type": "object"
|
"$ref": "#/definitions/domain.Response"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
],
|
"401": {
|
||||||
"responses": {
|
"description": "Unauthorized",
|
||||||
"200": {
|
|
||||||
"description": "ok",
|
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string"
|
"$ref": "#/definitions/domain.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"description": "Unprocessable Entity",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.Response"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.Response"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -355,11 +350,6 @@
|
||||||
},
|
},
|
||||||
"/api/v1/chapa/payments/deposit": {
|
"/api/v1/chapa/payments/deposit": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"ApiKeyAuth": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Deposits money into user wallet from user account using Chapa",
|
"description": "Deposits money into user wallet from user account using Chapa",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
|
|
@ -410,40 +400,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/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/domain.InitPaymentRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/domain.InitPaymentResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/chapa/payments/verify": {
|
"/api/v1/chapa/payments/verify": {
|
||||||
"post": {
|
"post": {
|
||||||
"consumes": [
|
"consumes": [
|
||||||
|
|
@ -477,38 +433,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/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/domain.VerifyTransactionResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/chapa/payments/withdraw": {
|
"/api/v1/chapa/payments/withdraw": {
|
||||||
"post": {
|
"post": {
|
||||||
"description": "Initiates a withdrawal transaction using Chapa for the authenticated user.",
|
"description": "Initiates a withdrawal transaction using Chapa for the authenticated user.",
|
||||||
|
|
@ -579,72 +503,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/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/domain.TransferRequest"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/domain.CreateTransferResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/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/domain.VerifyTransferResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/v1/virtual-games/recommendations/{userID}": {
|
"/api/v1/virtual-games/recommendations/{userID}": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Returns a list of recommended virtual games for a specific user",
|
"description": "Returns a list of recommended virtual games for a specific user",
|
||||||
|
|
@ -4658,17 +4516,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain.ChapaSupportedBanksResponse": {
|
"domain.ChapaSupportedBanksResponseWrapper": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"data": {
|
"data": {},
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/domain.ChapaSupportedBank"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"message": {
|
"message": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status_code": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -4762,76 +4621,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain.CreateTransferResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {
|
|
||||||
"$ref": "#/definitions/domain.TransferData"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.InitPaymentData": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"checkout_url": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"tx_ref": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.InitPaymentRequest": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"amount": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.InitPaymentResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {
|
|
||||||
"$ref": "#/definitions/domain.InitPaymentData"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"description": "e.g., \"Payment initialized\"",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"description": "\"success\"",
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.Odd": {
|
"domain.Odd": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -5159,86 +4948,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain.TransactionData": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"amount": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"currency": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"email": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"tx_ref": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.TransferData": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"amount": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"currency": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"reference": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.TransferVerificationData": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"account_name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"bank_code": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"reference": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.UpcomingEvent": {
|
"domain.UpcomingEvent": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -5345,34 +5054,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"domain.VerifyTransactionResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {
|
|
||||||
"$ref": "#/definitions/domain.TransactionData"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.VerifyTransferResponse": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"data": {
|
|
||||||
"$ref": "#/definitions/domain.TransferVerificationData"
|
|
||||||
},
|
|
||||||
"message": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"domain.VirtualGame": {
|
"domain.VirtualGame": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
||||||
|
|
@ -185,14 +185,15 @@ definitions:
|
||||||
updated_at:
|
updated_at:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
domain.ChapaSupportedBanksResponse:
|
domain.ChapaSupportedBanksResponseWrapper:
|
||||||
properties:
|
properties:
|
||||||
data:
|
data: {}
|
||||||
items:
|
|
||||||
$ref: '#/definitions/domain.ChapaSupportedBank'
|
|
||||||
type: array
|
|
||||||
message:
|
message:
|
||||||
type: string
|
type: string
|
||||||
|
status_code:
|
||||||
|
type: integer
|
||||||
|
success:
|
||||||
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
domain.ChapaTransactionType:
|
domain.ChapaTransactionType:
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -254,52 +255,6 @@ definitions:
|
||||||
- $ref: '#/definitions/domain.OutcomeStatus'
|
- $ref: '#/definitions/domain.OutcomeStatus'
|
||||||
example: 1
|
example: 1
|
||||||
type: object
|
type: object
|
||||||
domain.CreateTransferResponse:
|
|
||||||
properties:
|
|
||||||
data:
|
|
||||||
$ref: '#/definitions/domain.TransferData'
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
status:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
domain.InitPaymentData:
|
|
||||||
properties:
|
|
||||||
checkout_url:
|
|
||||||
type: string
|
|
||||||
tx_ref:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
domain.InitPaymentRequest:
|
|
||||||
properties:
|
|
||||||
amount:
|
|
||||||
type: integer
|
|
||||||
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
|
|
||||||
domain.InitPaymentResponse:
|
|
||||||
properties:
|
|
||||||
data:
|
|
||||||
$ref: '#/definitions/domain.InitPaymentData'
|
|
||||||
message:
|
|
||||||
description: e.g., "Payment initialized"
|
|
||||||
type: string
|
|
||||||
status:
|
|
||||||
description: '"success"'
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
domain.Odd:
|
domain.Odd:
|
||||||
properties:
|
properties:
|
||||||
category:
|
category:
|
||||||
|
|
@ -529,58 +484,6 @@ definitions:
|
||||||
example: 1
|
example: 1
|
||||||
type: integer
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
domain.TransactionData:
|
|
||||||
properties:
|
|
||||||
amount:
|
|
||||||
type: string
|
|
||||||
currency:
|
|
||||||
type: string
|
|
||||||
email:
|
|
||||||
type: string
|
|
||||||
status:
|
|
||||||
type: string
|
|
||||||
tx_ref:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
domain.TransferData:
|
|
||||||
properties:
|
|
||||||
amount:
|
|
||||||
type: string
|
|
||||||
currency:
|
|
||||||
type: string
|
|
||||||
reference:
|
|
||||||
type: string
|
|
||||||
status:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
domain.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
|
|
||||||
domain.TransferVerificationData:
|
|
||||||
properties:
|
|
||||||
account_name:
|
|
||||||
type: string
|
|
||||||
bank_code:
|
|
||||||
type: string
|
|
||||||
reference:
|
|
||||||
type: string
|
|
||||||
status:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
domain.UpcomingEvent:
|
domain.UpcomingEvent:
|
||||||
properties:
|
properties:
|
||||||
awayKitImage:
|
awayKitImage:
|
||||||
|
|
@ -659,24 +562,6 @@ definitions:
|
||||||
description: Veli's user identifier
|
description: Veli's user identifier
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
domain.VerifyTransactionResponse:
|
|
||||||
properties:
|
|
||||||
data:
|
|
||||||
$ref: '#/definitions/domain.TransactionData'
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
status:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
domain.VerifyTransferResponse:
|
|
||||||
properties:
|
|
||||||
data:
|
|
||||||
$ref: '#/definitions/domain.TransferVerificationData'
|
|
||||||
message:
|
|
||||||
type: string
|
|
||||||
status:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
domain.VirtualGame:
|
domain.VirtualGame:
|
||||||
properties:
|
properties:
|
||||||
category:
|
category:
|
||||||
|
|
@ -1752,37 +1637,34 @@ paths:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: Fetch all supported banks from Chapa
|
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/domain.ChapaSupportedBanksResponse'
|
$ref: '#/definitions/domain.ChapaSupportedBanksResponseWrapper'
|
||||||
summary: Get list of banks
|
"400":
|
||||||
tags:
|
description: Bad Request
|
||||||
- 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:
|
schema:
|
||||||
type: string
|
$ref: '#/definitions/domain.Response'
|
||||||
summary: Receive Chapa webhook
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domain.Response'
|
||||||
|
"404":
|
||||||
|
description: Not Found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domain.Response'
|
||||||
|
"422":
|
||||||
|
description: Unprocessable Entity
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domain.Response'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domain.Response'
|
||||||
|
summary: fetches chapa supported banks
|
||||||
tags:
|
tags:
|
||||||
- Chapa
|
- Chapa
|
||||||
/api/v1/chapa/payments/deposit:
|
/api/v1/chapa/payments/deposit:
|
||||||
|
|
@ -1816,33 +1698,9 @@ paths:
|
||||||
description: Internal server error
|
description: Internal server error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/domain.Response'
|
$ref: '#/definitions/domain.Response'
|
||||||
security:
|
|
||||||
- ApiKeyAuth: []
|
|
||||||
summary: Deposit money into user wallet using Chapa
|
summary: Deposit money into user wallet using Chapa
|
||||||
tags:
|
tags:
|
||||||
- Chapa
|
- 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/domain.InitPaymentRequest'
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/domain.InitPaymentResponse'
|
|
||||||
summary: Initialize a payment transaction
|
|
||||||
tags:
|
|
||||||
- Chapa
|
|
||||||
/api/v1/chapa/payments/verify:
|
/api/v1/chapa/payments/verify:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -1864,27 +1722,6 @@ paths:
|
||||||
summary: Verifies Chapa webhook transaction
|
summary: Verifies Chapa webhook transaction
|
||||||
tags:
|
tags:
|
||||||
- Chapa
|
- 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/domain.VerifyTransactionResponse'
|
|
||||||
summary: Verify a payment transaction
|
|
||||||
tags:
|
|
||||||
- Chapa
|
|
||||||
/api/v1/chapa/payments/withdraw:
|
/api/v1/chapa/payments/withdraw:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -1929,49 +1766,6 @@ paths:
|
||||||
summary: Withdraw using Chapa
|
summary: Withdraw using Chapa
|
||||||
tags:
|
tags:
|
||||||
- Chapa
|
- 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/domain.TransferRequest'
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/domain.CreateTransferResponse'
|
|
||||||
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/domain.VerifyTransferResponse'
|
|
||||||
summary: Verify a transfer
|
|
||||||
tags:
|
|
||||||
- Chapa
|
|
||||||
/api/v1/virtual-games/recommendations/{userID}:
|
/api/v1/virtual-games/recommendations/{userID}:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
|
||||||
19
go.mod
19
go.mod
|
|
@ -9,28 +9,28 @@ require (
|
||||||
github.com/gofiber/fiber/v2 v2.52.6
|
github.com/gofiber/fiber/v2 v2.52.6
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/jackc/pgx/v5 v5.7.4
|
github.com/jackc/pgx/v5 v5.7.4
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
|
github.com/shopspring/decimal v1.4.0
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
|
// github.com/stretchr/testify v1.10.0
|
||||||
github.com/swaggo/fiber-swagger v1.3.0
|
github.com/swaggo/fiber-swagger v1.3.0
|
||||||
github.com/swaggo/swag v1.16.4
|
github.com/swaggo/swag v1.16.4
|
||||||
|
github.com/valyala/fasthttp v1.59.0
|
||||||
golang.org/x/crypto v0.36.0
|
golang.org/x/crypto v0.36.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require github.com/gorilla/websocket v1.5.3 // indirect
|
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
// github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
// github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||||
// github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
|
// github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
|
||||||
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||||
|
|
@ -38,7 +38,6 @@ require (
|
||||||
github.com/go-openapi/swag v0.23.1 // indirect
|
github.com/go-openapi/swag v0.23.1 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/gorilla/websocket v1.5.3
|
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||||
|
|
@ -50,13 +49,13 @@ require (
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||||
github.com/shopspring/decimal v1.4.0
|
github.com/stretchr/objx v0.5.2 // indirect
|
||||||
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect
|
github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasthttp v1.59.0
|
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
||||||
golang.org/x/net v0.38.0 // indirect
|
golang.org/x/net v0.38.0 // indirect
|
||||||
golang.org/x/sync v0.12.0 // indirect
|
golang.org/x/sync v0.12.0 // indirect
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -120,6 +120,8 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
|
|
||||||
|
|
@ -221,3 +221,8 @@ type ChapaPaymentUrlResponseWrapper struct {
|
||||||
Data ChapaPaymentUrlResponse `json:"data"`
|
Data ChapaPaymentUrlResponse `json:"data"`
|
||||||
Response
|
Response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ChapaSupportedBanksResponseWrapper struct {
|
||||||
|
Data []ChapaSupportedBank `json:"data"`
|
||||||
|
Response
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,24 @@ var Environment = map[string]string{
|
||||||
|
|
||||||
func NewLogger(env string, lvl slog.Level) *slog.Logger {
|
func NewLogger(env string, lvl slog.Level) *slog.Logger {
|
||||||
var logHandler slog.Handler
|
var logHandler slog.Handler
|
||||||
|
|
||||||
|
err := os.MkdirAll("logs", os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
panic("Failed to create log directory: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.OpenFile("logs/app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
panic("Failed to open log file: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
switch env {
|
switch env {
|
||||||
case "development":
|
case "development":
|
||||||
logHandler = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
|
logHandler = slog.NewTextHandler(file, &slog.HandlerOptions{
|
||||||
Level: lvl,
|
Level: lvl,
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
logHandler = slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
logHandler = slog.NewJSONHandler(file, &slog.HandlerOptions{
|
||||||
Level: lvl,
|
Level: lvl,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,14 @@ import (
|
||||||
type ChapaClient interface {
|
type ChapaClient interface {
|
||||||
IssuePayment(ctx context.Context, payload domain.ChapaTransferPayload) (bool, error)
|
IssuePayment(ctx context.Context, payload domain.ChapaTransferPayload) (bool, error)
|
||||||
InitPayment(ctx context.Context, req domain.InitPaymentRequest) (string, error)
|
InitPayment(ctx context.Context, req domain.InitPaymentRequest) (string, error)
|
||||||
|
FetchBanks() ([]domain.ChapaSupportedBank, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
BaseURL string
|
BaseURL string
|
||||||
SecretKey string
|
SecretKey string
|
||||||
HTTPClient *http.Client
|
HTTPClient *http.Client
|
||||||
|
UserAgent string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(baseURL, secretKey string) *Client {
|
func NewClient(baseURL, secretKey string) *Client {
|
||||||
|
|
@ -27,6 +29,7 @@ func NewClient(baseURL, secretKey string) *Client {
|
||||||
BaseURL: baseURL,
|
BaseURL: baseURL,
|
||||||
SecretKey: secretKey,
|
SecretKey: secretKey,
|
||||||
HTTPClient: http.DefaultClient,
|
HTTPClient: http.DefaultClient,
|
||||||
|
UserAgent: "FortuneBet/1.0",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,3 +99,28 @@ func (c *Client) InitPayment(ctx context.Context, req domain.InitPaymentRequest)
|
||||||
|
|
||||||
return response.Data.CheckoutURL, nil
|
return response.Data.CheckoutURL, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) FetchBanks() ([]domain.ChapaSupportedBank, error) {
|
||||||
|
req, _ := http.NewRequest("GET", c.BaseURL+"/banks", nil)
|
||||||
|
req.Header.Set("Authorization", "Bearer "+c.SecretKey)
|
||||||
|
fmt.Printf("\n\nbase URL is: %s\n\n", c.BaseURL)
|
||||||
|
|
||||||
|
res, err := c.HTTPClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var resp struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data []domain.ChapaSupportedBank `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("\n\nclient fetched banks: %+v\n\n", resp.Data)
|
||||||
|
|
||||||
|
return resp.Data, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,4 +11,5 @@ type ChapaPort interface {
|
||||||
HandleChapaPaymentWebhook(ctx context.Context, req domain.ChapaWebHookPayment) error
|
HandleChapaPaymentWebhook(ctx context.Context, req domain.ChapaWebHookPayment) error
|
||||||
WithdrawUsingChapa(ctx context.Context, userID int64, req domain.ChapaWithdrawRequest) error
|
WithdrawUsingChapa(ctx context.Context, userID int64, req domain.ChapaWithdrawRequest) error
|
||||||
DepositUsingChapa(ctx context.Context, userID int64, req domain.ChapaDepositRequest) (string, error)
|
DepositUsingChapa(ctx context.Context, userID int64, req domain.ChapaDepositRequest) (string, error)
|
||||||
|
GetSupportedBanks() ([]domain.ChapaSupportedBank, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -315,3 +315,37 @@ func (s *Service) DepositUsingChapa(ctx context.Context, userID int64, req domai
|
||||||
|
|
||||||
return paymentURL, nil
|
return paymentURL, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetSupportedBanks() ([]domain.ChapaSupportedBank, error) {
|
||||||
|
banks, err := s.chapaClient.FetchBanks()
|
||||||
|
fmt.Printf("\n\nfetched banks: %+v\n\n", banks)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add formatting logic (same as in original controller)
|
||||||
|
for i := range banks {
|
||||||
|
if banks[i].IsMobilemoney != nil && *(banks[i].IsMobilemoney) == 1 {
|
||||||
|
banks[i].AcctNumberRegex = "/^09[0-9]{8}$/"
|
||||||
|
banks[i].ExampleValue = "0952097177"
|
||||||
|
} else {
|
||||||
|
switch banks[i].AcctLength {
|
||||||
|
case 8:
|
||||||
|
banks[i].ExampleValue = "16967608"
|
||||||
|
case 13:
|
||||||
|
banks[i].ExampleValue = "1000222215735"
|
||||||
|
case 14:
|
||||||
|
banks[i].ExampleValue = "01320089280800"
|
||||||
|
case 16:
|
||||||
|
banks[i].ExampleValue = "1000222215735123"
|
||||||
|
}
|
||||||
|
banks[i].AcctNumberRegex = formatRegex(banks[i].AcctLength)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return banks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatRegex(length int) string {
|
||||||
|
return fmt.Sprintf("/^[0-9]{%d}$/", length)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NFL evaluations
|
// NFL evaluations
|
||||||
func evaluateNFLMoneyLine(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
func EvaluateNFLMoneyLine(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
switch outcome.OddHeader {
|
switch outcome.OddHeader {
|
||||||
case "1":
|
case "1":
|
||||||
if score.Home > score.Away {
|
if score.Home > score.Away {
|
||||||
|
|
@ -25,7 +25,7 @@ func evaluateNFLMoneyLine(outcome domain.BetOutcome, score struct{ Home, Away in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func evaluateNFLSpread(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
func EvaluateNFLSpread(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
handicap, err := strconv.ParseFloat(outcome.OddHandicap, 64)
|
handicap, err := strconv.ParseFloat(outcome.OddHandicap, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid handicap: %s", outcome.OddHandicap)
|
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid handicap: %s", outcome.OddHandicap)
|
||||||
|
|
@ -56,7 +56,7 @@ func evaluateNFLSpread(outcome domain.BetOutcome, score struct{ Home, Away int }
|
||||||
return domain.OUTCOME_STATUS_VOID, nil
|
return domain.OUTCOME_STATUS_VOID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func evaluateNFLTotalPoints(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
func EvaluateNFLTotalPoints(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
totalPoints := float64(score.Home + score.Away)
|
totalPoints := float64(score.Home + score.Away)
|
||||||
threshold, err := strconv.ParseFloat(outcome.OddName, 64)
|
threshold, err := strconv.ParseFloat(outcome.OddName, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -81,8 +81,8 @@ func evaluateNFLTotalPoints(outcome domain.BetOutcome, score struct{ Home, Away
|
||||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
|
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluateRugbyMoneyLine evaluates Rugby money line bets
|
// EvaluateRugbyMoneyLine Evaluates Rugby money line bets
|
||||||
func evaluateRugbyMoneyLine(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
func EvaluateRugbyMoneyLine(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
switch outcome.OddHeader {
|
switch outcome.OddHeader {
|
||||||
case "1":
|
case "1":
|
||||||
if score.Home > score.Away {
|
if score.Home > score.Away {
|
||||||
|
|
@ -99,8 +99,8 @@ func evaluateRugbyMoneyLine(outcome domain.BetOutcome, score struct{ Home, Away
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluateRugbySpread evaluates Rugby spread bets
|
// EvaluateRugbySpread Evaluates Rugby spread bets
|
||||||
func evaluateRugbySpread(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
func EvaluateRugbySpread(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
handicap, err := strconv.ParseFloat(outcome.OddHandicap, 64)
|
handicap, err := strconv.ParseFloat(outcome.OddHandicap, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid handicap: %s", outcome.OddHandicap)
|
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid handicap: %s", outcome.OddHandicap)
|
||||||
|
|
@ -131,8 +131,8 @@ func evaluateRugbySpread(outcome domain.BetOutcome, score struct{ Home, Away int
|
||||||
return domain.OUTCOME_STATUS_VOID, nil
|
return domain.OUTCOME_STATUS_VOID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluateRugbyTotalPoints evaluates Rugby total points bets
|
// EvaluateRugbyTotalPoints Evaluates Rugby total points bets
|
||||||
func evaluateRugbyTotalPoints(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
func EvaluateRugbyTotalPoints(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
totalPoints := float64(score.Home + score.Away)
|
totalPoints := float64(score.Home + score.Away)
|
||||||
threshold, err := strconv.ParseFloat(outcome.OddName, 64)
|
threshold, err := strconv.ParseFloat(outcome.OddName, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -157,8 +157,8 @@ func evaluateRugbyTotalPoints(outcome domain.BetOutcome, score struct{ Home, Awa
|
||||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
|
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluateBaseballMoneyLine evaluates Baseball money line bets
|
// EvaluateBaseballMoneyLine Evaluates Baseball money line bets
|
||||||
func evaluateBaseballMoneyLine(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
func EvaluateBaseballMoneyLine(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
switch outcome.OddHeader {
|
switch outcome.OddHeader {
|
||||||
case "1":
|
case "1":
|
||||||
if score.Home > score.Away {
|
if score.Home > score.Away {
|
||||||
|
|
@ -175,8 +175,8 @@ func evaluateBaseballMoneyLine(outcome domain.BetOutcome, score struct{ Home, Aw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluateBaseballSpread evaluates Baseball spread bets
|
// EvaluateBaseballSpread Evaluates Baseball spread bets
|
||||||
func evaluateBaseballSpread(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
func EvaluateBaseballSpread(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
handicap, err := strconv.ParseFloat(outcome.OddHandicap, 64)
|
handicap, err := strconv.ParseFloat(outcome.OddHandicap, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid handicap: %s", outcome.OddHandicap)
|
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid handicap: %s", outcome.OddHandicap)
|
||||||
|
|
@ -207,8 +207,8 @@ func evaluateBaseballSpread(outcome domain.BetOutcome, score struct{ Home, Away
|
||||||
return domain.OUTCOME_STATUS_VOID, nil
|
return domain.OUTCOME_STATUS_VOID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluateBaseballTotalRuns evaluates Baseball total runs bets
|
// EvaluateBaseballTotalRuns Evaluates Baseball total runs bets
|
||||||
func evaluateBaseballTotalRuns(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
func EvaluateBaseballTotalRuns(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
totalRuns := float64(score.Home + score.Away)
|
totalRuns := float64(score.Home + score.Away)
|
||||||
threshold, err := strconv.ParseFloat(outcome.OddName, 64)
|
threshold, err := strconv.ParseFloat(outcome.OddName, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -233,7 +233,7 @@ func evaluateBaseballTotalRuns(outcome domain.BetOutcome, score struct{ Home, Aw
|
||||||
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
|
return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluateBaseballFirstInning evaluates Baseball first inning bets
|
// EvaluateBaseballFirstInning Evaluates Baseball first inning bets
|
||||||
func EvaluateBaseballFirstInning(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
func EvaluateBaseballFirstInning(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
switch outcome.OddHeader {
|
switch outcome.OddHeader {
|
||||||
case "1":
|
case "1":
|
||||||
|
|
@ -256,7 +256,7 @@ func EvaluateBaseballFirstInning(outcome domain.BetOutcome, score struct{ Home,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluateBaseballFirst5Innings evaluates Baseball first 5 innings bets
|
// EvaluateBaseballFirst5Innings Evaluates Baseball first 5 innings bets
|
||||||
func EvaluateBaseballFirst5Innings(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
func EvaluateBaseballFirst5Innings(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
|
||||||
switch outcome.OddHeader {
|
switch outcome.OddHeader {
|
||||||
case "1":
|
case "1":
|
||||||
|
|
|
||||||
|
|
@ -1,287 +1,288 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
// "bytes"
|
||||||
"encoding/json"
|
// "encoding/json"
|
||||||
|
// "fmt"
|
||||||
|
// "io"
|
||||||
|
// "net/http"
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetBanks godoc
|
// // GetBanks godoc
|
||||||
// @Summary Get list of banks
|
// // @Summary Get list of banks
|
||||||
// @Description Fetch all supported banks from Chapa
|
// // @Description Fetch all supported banks from Chapa
|
||||||
// @Tags Chapa
|
// // @Tags Chapa
|
||||||
// @Accept json
|
// // @Accept json
|
||||||
// @Produce json
|
// // @Produce json
|
||||||
// @Success 200 {object} domain.ChapaSupportedBanksResponse
|
// // @Success 200 {object} domain.ChapaSupportedBanksResponse
|
||||||
// @Router /api/v1/chapa/banks [get]
|
// // @Router /api/v1/chapa/banks [get]
|
||||||
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)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(500).JSON(fiber.Map{"error": "Failed to create request", "details": err.Error()})
|
// return c.Status(500).JSON(fiber.Map{"error": "Failed to create request", "details": err.Error()})
|
||||||
}
|
// }
|
||||||
httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY)
|
// httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY)
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(httpReq)
|
// resp, err := http.DefaultClient.Do(httpReq)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch banks", "details": err.Error()})
|
// return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch banks", "details": err.Error()})
|
||||||
}
|
// }
|
||||||
defer resp.Body.Close()
|
// defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
// body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
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).Type("json").Send(body)
|
// return c.Status(resp.StatusCode).Type("json").Send(body)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// InitializePayment godoc
|
// // InitializePayment godoc
|
||||||
// @Summary Initialize a payment transaction
|
// // @Summary Initialize a payment transaction
|
||||||
// @Description Initiate a payment through Chapa
|
// // @Description Initiate a payment through Chapa
|
||||||
// @Tags Chapa
|
// // @Tags Chapa
|
||||||
// @Accept json
|
// // @Accept json
|
||||||
// @Produce json
|
// // @Produce json
|
||||||
// @Param payload body domain.InitPaymentRequest true "Payment initialization request"
|
// // @Param payload body domain.InitPaymentRequest true "Payment initialization request"
|
||||||
// @Success 200 {object} domain.InitPaymentResponse
|
// // @Success 200 {object} domain.InitPaymentResponse
|
||||||
// @Router /api/v1/chapa/payments/initialize [post]
|
// // @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 {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
"error": "Invalid request body",
|
// "error": "Invalid request body",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Generate and assign a unique transaction reference
|
// // Generate and assign a unique transaction reference
|
||||||
req.TxRef = uuid.New().String()
|
// 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{
|
||||||
"error": "Failed to serialize request",
|
// "error": "Failed to serialize request",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
httpReq, err := http.NewRequest("POST", h.Cfg.CHAPA_BASE_URL+"/transaction/initialize", bytes.NewBuffer(payload))
|
// httpReq, err := http.NewRequest("POST", h.Cfg.CHAPA_BASE_URL+"/transaction/initialize", bytes.NewBuffer(payload))
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(500).JSON(fiber.Map{
|
// return c.Status(500).JSON(fiber.Map{
|
||||||
"error": "Failed to create request",
|
// "error": "Failed to create request",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY)
|
// httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY)
|
||||||
httpReq.Header.Set("Content-Type", "application/json")
|
// httpReq.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(httpReq)
|
// resp, err := http.DefaultClient.Do(httpReq)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(500).JSON(fiber.Map{
|
// return c.Status(500).JSON(fiber.Map{
|
||||||
"error": "Failed to initialize payment",
|
// "error": "Failed to initialize payment",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
defer resp.Body.Close()
|
// defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
// body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(500).JSON(fiber.Map{
|
// return c.Status(500).JSON(fiber.Map{
|
||||||
"error": "Failed to read response",
|
// "error": "Failed to read response",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
return c.Status(resp.StatusCode).Type("json").Send(body)
|
// return c.Status(resp.StatusCode).Type("json").Send(body)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// VerifyTransaction godoc
|
// // VerifyTransaction godoc
|
||||||
// @Summary Verify a payment transaction
|
// // @Summary Verify a payment transaction
|
||||||
// @Description Verify the transaction status from Chapa using tx_ref
|
// // @Description Verify the transaction status from Chapa using tx_ref
|
||||||
// @Tags Chapa
|
// // @Tags Chapa
|
||||||
// @Accept json
|
// // @Accept json
|
||||||
// @Produce json
|
// // @Produce json
|
||||||
// @Param tx_ref path string true "Transaction Reference"
|
// // @Param tx_ref path string true "Transaction Reference"
|
||||||
// @Success 200 {object} domain.VerifyTransactionResponse
|
// // @Success 200 {object} domain.VerifyTransactionResponse
|
||||||
// @Router /api/v1/chapa/payments/verify/{tx_ref} [get]
|
// // @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 == "" {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
"error": "Missing transaction reference",
|
// "error": "Missing transaction reference",
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
url := fmt.Sprintf("%s/transaction/verify/%s", h.Cfg.CHAPA_BASE_URL, txRef)
|
// url := fmt.Sprintf("%s/transaction/verify/%s", h.Cfg.CHAPA_BASE_URL, txRef)
|
||||||
|
|
||||||
httpReq, err := http.NewRequest("GET", url, nil)
|
// httpReq, err := http.NewRequest("GET", url, nil)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(500).JSON(fiber.Map{
|
// return c.Status(500).JSON(fiber.Map{
|
||||||
"error": "Failed to create request",
|
// "error": "Failed to create request",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY)
|
// httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY)
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(httpReq)
|
// resp, err := http.DefaultClient.Do(httpReq)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(500).JSON(fiber.Map{
|
// return c.Status(500).JSON(fiber.Map{
|
||||||
"error": "Failed to verify transaction",
|
// "error": "Failed to verify transaction",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
defer resp.Body.Close()
|
// defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
// body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(500).JSON(fiber.Map{
|
// return c.Status(500).JSON(fiber.Map{
|
||||||
"error": "Failed to read response",
|
// "error": "Failed to read response",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
return c.Status(resp.StatusCode).Type("json").Send(body)
|
// return c.Status(resp.StatusCode).Type("json").Send(body)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// ReceiveWebhook godoc
|
// // ReceiveWebhook godoc
|
||||||
// @Summary Receive Chapa webhook
|
// // @Summary Receive Chapa webhook
|
||||||
// @Description Endpoint to receive webhook payloads from Chapa
|
// // @Description Endpoint to receive webhook payloads from Chapa
|
||||||
// @Tags Chapa
|
// // @Tags Chapa
|
||||||
// @Accept json
|
// // @Accept json
|
||||||
// @Produce json
|
// // @Produce json
|
||||||
// @Param payload body object true "Webhook Payload (dynamic)"
|
// // @Param payload body object true "Webhook Payload (dynamic)"
|
||||||
// @Success 200 {string} string "ok"
|
// // @Success 200 {string} string "ok"
|
||||||
// @Router /api/v1/chapa/payments/callback [post]
|
// // @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 {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
"error": "Invalid webhook data",
|
// "error": "Invalid webhook data",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
h.logger.Info("Chapa webhook received", "payload", payload)
|
// h.logger.Info("Chapa webhook received", "payload", payload)
|
||||||
|
|
||||||
// Optional: you can verify tx_ref here again if needed
|
// // Optional: you can verify tx_ref here again if needed
|
||||||
|
|
||||||
return c.SendStatus(fiber.StatusOK)
|
// return c.SendStatus(fiber.StatusOK)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// CreateTransfer godoc
|
// // CreateTransfer godoc
|
||||||
// @Summary Create a money transfer
|
// // @Summary Create a money transfer
|
||||||
// @Description Initiate a transfer request via Chapa
|
// // @Description Initiate a transfer request via Chapa
|
||||||
// @Tags Chapa
|
// // @Tags Chapa
|
||||||
// @Accept json
|
// // @Accept json
|
||||||
// @Produce json
|
// // @Produce json
|
||||||
// @Param payload body domain.TransferRequest true "Transfer request body"
|
// // @Param payload body domain.TransferRequest true "Transfer request body"
|
||||||
// @Success 200 {object} domain.CreateTransferResponse
|
// // @Success 200 {object} domain.CreateTransferResponse
|
||||||
// @Router /api/v1/chapa/transfers [post]
|
// // @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 {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
"error": "Invalid request",
|
// "error": "Invalid request",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Inject unique transaction reference
|
// // Inject unique transaction reference
|
||||||
req.Reference = uuid.New().String()
|
// 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{
|
||||||
"error": "Failed to serialize request",
|
// "error": "Failed to serialize request",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
httpReq, err := http.NewRequest("POST", h.Cfg.CHAPA_BASE_URL+"/transfers", bytes.NewBuffer(payload))
|
// httpReq, err := http.NewRequest("POST", h.Cfg.CHAPA_BASE_URL+"/transfers", bytes.NewBuffer(payload))
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
"error": "Failed to create HTTP request",
|
// "error": "Failed to create HTTP request",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY)
|
// httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY)
|
||||||
httpReq.Header.Set("Content-Type", "application/json")
|
// httpReq.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(httpReq)
|
// resp, err := http.DefaultClient.Do(httpReq)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
"error": "Transfer request failed",
|
// "error": "Transfer request failed",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
defer resp.Body.Close()
|
// defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
// body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
"error": "Failed to read response",
|
// "error": "Failed to read response",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
return c.Status(resp.StatusCode).Type("json").Send(body)
|
// return c.Status(resp.StatusCode).Type("json").Send(body)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// VerifyTransfer godoc
|
// // VerifyTransfer godoc
|
||||||
// @Summary Verify a transfer
|
// // @Summary Verify a transfer
|
||||||
// @Description Check the status of a money transfer via reference
|
// // @Description Check the status of a money transfer via reference
|
||||||
// @Tags Chapa
|
// // @Tags Chapa
|
||||||
// @Accept json
|
// // @Accept json
|
||||||
// @Produce json
|
// // @Produce json
|
||||||
// @Param transfer_ref path string true "Transfer Reference"
|
// // @Param transfer_ref path string true "Transfer Reference"
|
||||||
// @Success 200 {object} domain.VerifyTransferResponse
|
// // @Success 200 {object} domain.VerifyTransferResponse
|
||||||
// @Router /api/v1/chapa/transfers/verify/{transfer_ref} [get]
|
// // @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 == "" {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
"error": "Missing transfer reference in URL",
|
// "error": "Missing transfer reference in URL",
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
url := fmt.Sprintf("%s/transfers/verify/%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 {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
"error": "Failed to create HTTP request",
|
// "error": "Failed to create HTTP request",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY)
|
// httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY)
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(httpReq)
|
// resp, err := http.DefaultClient.Do(httpReq)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
"error": "Verification request failed",
|
// "error": "Verification request failed",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
defer resp.Body.Close()
|
// defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
// body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
"error": "Failed to read response body",
|
// "error": "Failed to read response body",
|
||||||
"details": err.Error(),
|
// "details": err.Error(),
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
|
|
||||||
return c.Status(resp.StatusCode).Type("json").Send(body)
|
// return c.Status(resp.StatusCode).Type("json").Send(body)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// VerifyChapaPayment godoc
|
// VerifyChapaPayment godoc
|
||||||
// @Summary Verifies Chapa webhook transaction
|
// @Summary Verifies Chapa webhook transaction
|
||||||
|
|
@ -384,7 +385,6 @@ func (h *Handler) WithdrawUsingChapa(c *fiber.Ctx) error {
|
||||||
// @Tags Chapa
|
// @Tags Chapa
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Security ApiKeyAuth
|
|
||||||
// @Param payload body domain.ChapaDepositRequest true "Deposit request payload"
|
// @Param payload body domain.ChapaDepositRequest true "Deposit request payload"
|
||||||
// @Success 200 {object} domain.ChapaPaymentUrlResponseWrapper
|
// @Success 200 {object} domain.ChapaPaymentUrlResponseWrapper
|
||||||
// @Failure 400 {object} domain.Response "Invalid request"
|
// @Failure 400 {object} domain.Response "Invalid request"
|
||||||
|
|
@ -407,7 +407,7 @@ func (h *Handler) DepositUsingChapa(c *fiber.Ctx) error {
|
||||||
return domain.UnProcessableEntityResponse(c)
|
return domain.UnProcessableEntityResponse(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate input in domain/model (you may have a Validate method)
|
// Validate input in domain/domain (you may have a Validate method)
|
||||||
if err := req.Validate(); err != nil {
|
if err := req.Validate(); err != nil {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(domain.Response{
|
return c.Status(fiber.StatusBadRequest).JSON(domain.Response{
|
||||||
Message: err.Error(),
|
Message: err.Error(),
|
||||||
|
|
@ -433,3 +433,32 @@ func (h *Handler) DepositUsingChapa(c *fiber.Ctx) error {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadChapaBanks godoc
|
||||||
|
// @Summary fetches chapa supported banks
|
||||||
|
// @Tags Chapa
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} domain.ChapaSupportedBanksResponseWrapper
|
||||||
|
// @Failure 400,401,404,422,500 {object} domain.Response
|
||||||
|
// @Router /api/v1/chapa/banks [get]
|
||||||
|
func (h *Handler) ReadChapaBanks(c *fiber.Ctx) error {
|
||||||
|
banks, err := h.chapaSvc.GetSupportedBanks()
|
||||||
|
fmt.Printf("\n\nhandler fetched banks: %+v\n\n", banks)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.Response{
|
||||||
|
Message: "Internal server error",
|
||||||
|
Success: false,
|
||||||
|
StatusCode: fiber.StatusInternalServerError,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(domain.ResponseWDataFactory[[]domain.ChapaSupportedBank]{
|
||||||
|
Data: banks,
|
||||||
|
Response: domain.Response{
|
||||||
|
Message: "read successful on chapa supported banks",
|
||||||
|
Success: true,
|
||||||
|
StatusCode: fiber.StatusOK,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
131
internal/web_server/handlers/read_chapa_banks_handler_test.go
Normal file
131
internal/web_server/handlers/read_chapa_banks_handler_test.go
Normal file
|
|
@ -0,0 +1,131 @@
|
||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/mock"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// --- Mock service ---
|
||||||
|
|
||||||
|
type MockChapaService struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockChapaService) GetSupportedBanks() ([]domain.ChapaSupportedBank, error) {
|
||||||
|
args := m.Called()
|
||||||
|
return args.Get(0).([]domain.ChapaSupportedBank), args.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Tests ---
|
||||||
|
|
||||||
|
func (h *Handler) TestReadChapaBanks_Success(t *testing.T) {
|
||||||
|
app := fiber.New()
|
||||||
|
|
||||||
|
mockService := new(MockChapaService)
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
isMobile := 1
|
||||||
|
isRtgs := 1
|
||||||
|
is24hrs := 1
|
||||||
|
|
||||||
|
mockBanks := []domain.ChapaSupportedBank{
|
||||||
|
{
|
||||||
|
Id: 101,
|
||||||
|
Slug: "bank-a",
|
||||||
|
Swift: "BKAETHAA",
|
||||||
|
Name: "Bank A",
|
||||||
|
AcctLength: 13,
|
||||||
|
AcctNumberRegex: "^[0-9]{13}$",
|
||||||
|
ExampleValue: "1000222215735",
|
||||||
|
CountryId: 1,
|
||||||
|
IsMobilemoney: &isMobile,
|
||||||
|
IsActive: 1,
|
||||||
|
IsRtgs: &isRtgs,
|
||||||
|
Active: 1,
|
||||||
|
Is24Hrs: &is24hrs,
|
||||||
|
CreatedAt: now,
|
||||||
|
UpdatedAt: now,
|
||||||
|
Currency: "ETB",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
mockService.On("GetSupportedBanks").Return(mockBanks, nil)
|
||||||
|
|
||||||
|
// handler := handlers.NewChapaHandler(mockService)
|
||||||
|
app.Post("/chapa/banks", h.ReadChapaBanks)
|
||||||
|
|
||||||
|
req := createTestRequest(t, "POST", "/chapa/banks", nil)
|
||||||
|
resp, err := app.Test(req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, fiber.StatusOK, resp.StatusCode)
|
||||||
|
|
||||||
|
var body domain.ResponseWDataFactory[[]domain.ChapaSupportedBank]
|
||||||
|
err = parseJSONBody(resp, &body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.True(t, body.Success)
|
||||||
|
assert.Equal(t, "read successful on chapa supported banks", body.Message)
|
||||||
|
require.Len(t, body.Data, 1)
|
||||||
|
assert.Equal(t, mockBanks[0].Name, body.Data[0].Name)
|
||||||
|
assert.Equal(t, mockBanks[0].AcctNumberRegex, body.Data[0].AcctNumberRegex)
|
||||||
|
|
||||||
|
mockService.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) TestReadChapaBanks_Failure(t *testing.T) {
|
||||||
|
app := fiber.New()
|
||||||
|
|
||||||
|
mockService := new(MockChapaService)
|
||||||
|
mockService.On("GetSupportedBanks").Return(nil, errors.New("chapa service unavailable"))
|
||||||
|
|
||||||
|
// handler := handlers.NewChapaHandler(mockService)
|
||||||
|
app.Post("/chapa/banks", h.ReadChapaBanks)
|
||||||
|
|
||||||
|
req := createTestRequest(t, "POST", "/chapa/banks", nil)
|
||||||
|
resp, err := app.Test(req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, fiber.StatusInternalServerError, resp.StatusCode)
|
||||||
|
|
||||||
|
var body domain.Response
|
||||||
|
err = parseJSONBody(resp, &body)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.False(t, body.Success)
|
||||||
|
assert.Equal(t, "Internal server error", body.Message)
|
||||||
|
mockService.AssertExpectations(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTestRequest(t *testing.T, method, url string, body interface{}) *http.Request {
|
||||||
|
var buf io.Reader
|
||||||
|
if body != nil {
|
||||||
|
b, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
buf = bytes.NewBuffer(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(method, url, buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseJSONBody(resp *http.Response, target interface{}) error {
|
||||||
|
return json.NewDecoder(resp.Body).Decode(target)
|
||||||
|
}
|
||||||
|
|
@ -182,9 +182,10 @@ 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
|
||||||
group.Post("/chapa/payments/verify", h.VerifyChapaPayment)
|
group.Post("/chapa/payments/verify", a.authMiddleware, h.VerifyChapaPayment)
|
||||||
group.Post("/chapa/payments/withdraw", h.WithdrawUsingChapa)
|
group.Post("/chapa/payments/withdraw", a.authMiddleware, h.WithdrawUsingChapa)
|
||||||
group.Post("/chapa/payments/deposit", h.DepositUsingChapa)
|
group.Post("/chapa/payments/deposit", a.authMiddleware, h.DepositUsingChapa)
|
||||||
|
group.Get("/chapa/banks", a.authMiddleware, h.ReadChapaBanks)
|
||||||
|
|
||||||
// group.Post("/chapa/payments/initialize", h.InitializePayment)
|
// group.Post("/chapa/payments/initialize", h.InitializePayment)
|
||||||
// group.Get("/chapa/payments/verify/:tx_ref", h.VerifyTransaction)
|
// group.Get("/chapa/payments/verify/:tx_ref", h.VerifyTransaction)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user