fix: refactored the transactions into shop_transactions
This commit is contained in:
parent
f27a75eb66
commit
d678b4e9d3
|
|
@ -119,7 +119,6 @@ func main() {
|
|||
logger,
|
||||
)
|
||||
|
||||
transactionSvc := transaction.NewService(store)
|
||||
branchSvc := branch.NewService(store)
|
||||
companySvc := company.NewService(store)
|
||||
leagueSvc := league.New(store)
|
||||
|
|
@ -153,6 +152,7 @@ func main() {
|
|||
cfg.FIXER_API_KEY,
|
||||
cfg.FIXER_BASE_URL,
|
||||
)
|
||||
transactionSvc := transaction.NewService(store, *branchSvc)
|
||||
|
||||
reportSvc := report.NewService(
|
||||
bet.BetStore(store),
|
||||
|
|
@ -167,6 +167,8 @@ func main() {
|
|||
logger,
|
||||
)
|
||||
|
||||
|
||||
|
||||
go httpserver.SetupReportCronJobs(context.Background(), reportSvc)
|
||||
|
||||
bankRepository := repository.NewBankRepository(store)
|
||||
|
|
|
|||
|
|
@ -172,28 +172,45 @@ CREATE TABLE IF NOT EXISTS shop_transactions (
|
|||
id BIGSERIAL PRIMARY KEY,
|
||||
amount BIGINT NOT NULL,
|
||||
branch_id BIGINT NOT NULL,
|
||||
company_id BIGINT,
|
||||
cashier_id BIGINT,
|
||||
cashier_name VARCHAR(255),
|
||||
bet_id BIGINT,
|
||||
number_of_outcomes BIGINT,
|
||||
type BIGINT,
|
||||
payment_option BIGINT,
|
||||
full_name VARCHAR(255),
|
||||
phone_number VARCHAR(255),
|
||||
company_id BIGINT NOT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
type BIGINT NOT NULL,
|
||||
full_name VARCHAR(255) NOT NULL,
|
||||
phone_number VARCHAR(255) NOT NULL,
|
||||
payment_option BIGINT NOT NULL,
|
||||
bank_code VARCHAR(255),
|
||||
beneficiary_name VARCHAR(255),
|
||||
account_name VARCHAR(255),
|
||||
account_number VARCHAR(255),
|
||||
reference_number VARCHAR(255),
|
||||
verified BOOLEAN NOT NULL DEFAULT false,
|
||||
approved_by BIGINT,
|
||||
approver_name VARCHAR(255),
|
||||
branch_location VARCHAR(255),
|
||||
branch_name VARCHAR(255),
|
||||
verified BOOLEAN DEFAULT false NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS shop_bets (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
shop_transaction_id BIGINT NOT NULL,
|
||||
cashout_id VARCHAR(255) NOT NULL,
|
||||
cashed_out_by BIGINT,
|
||||
bet_id BIGINT NOT NULL,
|
||||
number_of_outcomes BIGINT NOT NULL,
|
||||
cashed_out BOOLEAN DEFAULT FALSE NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(shop_transaction_id),
|
||||
UNIQUE(bet_id),
|
||||
UNIQUE(cashout_id)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS shop_deposits (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
shop_transaction_id BIGINT NOT NULL,
|
||||
customer_id BIGINT NOT NULL,
|
||||
wallet_transfer_id BIGINT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(shop_transaction_id)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS branches (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
|
|
@ -318,7 +335,7 @@ SELECT branches.*,
|
|||
wallets.is_active AS wallet_is_active
|
||||
FROM branches
|
||||
LEFT JOIN users ON branches.branch_manager_id = users.id
|
||||
LEFT JOin wallets ON wallets.id = branches.wallet_id;
|
||||
LEFT JOIN wallets ON wallets.id = branches.wallet_id;
|
||||
CREATE TABLE IF NOT EXISTS supported_operations (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
|
|
@ -362,6 +379,54 @@ SELECT wt.*,
|
|||
users.phone_number
|
||||
FROM wallet_transfer wt
|
||||
LEFT JOIN users ON users.id = wt.cashier_id;
|
||||
CREATE VIEW shop_transaction_detail AS
|
||||
SELECT st.*,
|
||||
cr.first_name AS creator_first_name,
|
||||
cr.last_name AS creator_last_name,
|
||||
cr.phone_number AS creator_phone_number,
|
||||
ap.first_name AS approver_first_name,
|
||||
ap.last_name AS approver_last_name,
|
||||
ap.phone_number AS approver_phone_number,
|
||||
branches.name AS branch_name,
|
||||
branches.location AS branch_location
|
||||
FROM shop_transactions st
|
||||
LEFT JOIN users cr ON cr.id = st.user_id
|
||||
LEFT JOIN users ap ON ap.id = st.approved_by
|
||||
LEFT JOIN branches ON branches.id = st.branch_id;
|
||||
CREATE VIEW shop_bet_detail AS
|
||||
SELECT sb.*,
|
||||
st.full_name AS customer_full_name,
|
||||
st.phone_number AS customer_phone_number,
|
||||
st.branch_id,
|
||||
st.company_id,
|
||||
st.amount,
|
||||
st.verified AS transaction_verified,
|
||||
bets.status,
|
||||
bets.total_odds,
|
||||
JSON_AGG(bet_outcomes.*) AS outcomes
|
||||
FROM shop_bets AS sb
|
||||
JOIN shop_transactions st ON st.id = sb.shop_transaction_id
|
||||
JOIN bets ON bets.id = sb.bet_id
|
||||
LEFT JOIN bet_outcomes ON bet_outcomes.bet_id = sb.bet_id
|
||||
GROUP BY sb.id,
|
||||
st.full_name,
|
||||
st.phone_number,
|
||||
st.branch_id,
|
||||
st.company_id,
|
||||
st.amount,
|
||||
st.verified,
|
||||
bets.status,
|
||||
bets.total_odds;
|
||||
CREATE VIEW shop_deposit_detail AS
|
||||
SELECT sd.*,
|
||||
st.full_name,
|
||||
st.phone_number,
|
||||
st.branch_id,
|
||||
st.company_id,
|
||||
st.amount,
|
||||
st.verified AS transaction_verified
|
||||
FROM shop_deposits AS sd
|
||||
JOIN shop_transactions st ON st.id = sd.shop_transaction_id;
|
||||
-- Foreign Keys
|
||||
ALTER TABLE users
|
||||
ADD CONSTRAINT unique_email UNIQUE (email),
|
||||
|
|
@ -384,8 +449,13 @@ ADD CONSTRAINT fk_wallet_transfer_receiver_wallet FOREIGN KEY (receiver_wallet_i
|
|||
ADD CONSTRAINT fk_wallet_transfer_cashier FOREIGN KEY (cashier_id) REFERENCES users(id);
|
||||
ALTER TABLE shop_transactions
|
||||
ADD CONSTRAINT fk_shop_transactions_branches FOREIGN KEY (branch_id) REFERENCES branches(id),
|
||||
ADD CONSTRAINT fk_shop_transactions_cashiers FOREIGN KEY (cashier_id) REFERENCES users(id),
|
||||
ADD CONSTRAINT fk_shop_transactions_bets FOREIGN KEY (bet_id) REFERENCES bets(id);
|
||||
ADD CONSTRAINT fk_shop_transactions_users FOREIGN KEY (user_id) REFERENCES users(id);
|
||||
ALTER TABLE shop_bets
|
||||
ADD CONSTRAINT fk_shop_bet_transactions FOREIGN KEY (shop_transaction_id) REFERENCES shop_transactions(id),
|
||||
ADD CONSTRAINT fk_shop_bet_bets FOREIGN KEY (bet_id) REFERENCES bets(id);
|
||||
ALTER TABLE shop_deposits
|
||||
ADD CONSTRAINT fk_shop_deposit_transactions FOREIGN KEY (shop_transaction_id) REFERENCES shop_transactions(id),
|
||||
ADD CONSTRAINT fk_shop_deposit_customers FOREIGN KEY (customer_id) REFERENCES users(id);
|
||||
ALTER TABLE branches
|
||||
ADD CONSTRAINT fk_branches_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id),
|
||||
ADD CONSTRAINT fk_branches_manager FOREIGN KEY (branch_manager_id) REFERENCES users(id);
|
||||
|
|
|
|||
169
db/query/shop_transactions.sql
Normal file
169
db/query/shop_transactions.sql
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
-- name: CreateShopTransaction :one
|
||||
INSERT INTO shop_transactions (
|
||||
amount,
|
||||
branch_id,
|
||||
company_id,
|
||||
user_id,
|
||||
type,
|
||||
full_name,
|
||||
phone_number,
|
||||
payment_option,
|
||||
bank_code,
|
||||
beneficiary_name,
|
||||
account_name,
|
||||
account_number,
|
||||
reference_number
|
||||
)
|
||||
VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10,
|
||||
$11,
|
||||
$12,
|
||||
$13
|
||||
)
|
||||
RETURNING *;
|
||||
-- name: GetAllShopTransactions :many
|
||||
SELECT *
|
||||
FROM shop_transaction_detail
|
||||
wHERE (
|
||||
branch_id = sqlc.narg('branch_id')
|
||||
OR sqlc.narg('branch_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
company_id = sqlc.narg('company_id')
|
||||
OR sqlc.narg('company_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
user_id = sqlc.narg('user_id')
|
||||
OR sqlc.narg('user_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
full_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR phone_number ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR sqlc.narg('query') IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at > sqlc.narg('created_before')
|
||||
OR sqlc.narg('created_before') IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at < sqlc.narg('created_after')
|
||||
OR sqlc.narg('created_after') IS NULL
|
||||
);
|
||||
-- name: GetShopTransactionByID :one
|
||||
SELECT *
|
||||
FROM shop_transaction_detail
|
||||
WHERE id = $1;
|
||||
-- name: GetShopTransactionByBranch :many
|
||||
SELECT *
|
||||
FROM shop_transaction_detail
|
||||
WHERE branch_id = $1;
|
||||
-- name: UpdateShopTransactionVerified :exec
|
||||
UPDATE shop_transactions
|
||||
SET verified = $2,
|
||||
approved_by = $3,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1;
|
||||
-- name: CreateShopBet :one
|
||||
INSERT INTO shop_bets (
|
||||
shop_transaction_id,
|
||||
cashout_id,
|
||||
bet_id,
|
||||
number_of_outcomes
|
||||
)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING *;
|
||||
-- name: GetAllShopBets :many
|
||||
SELECT *
|
||||
FROM shop_bet_detail
|
||||
WHERE (
|
||||
full_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR phone_number ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR sqlc.narg('query') IS NULL
|
||||
)
|
||||
AND (
|
||||
branch_id = sqlc.narg('branch_id')
|
||||
OR sqlc.narg('branch_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
company_id = sqlc.narg('company_id')
|
||||
OR sqlc.narg('company_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at > sqlc.narg('created_before')
|
||||
OR sqlc.narg('created_before') IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at < sqlc.narg('created_after')
|
||||
OR sqlc.narg('created_after') IS NULL
|
||||
);
|
||||
-- name: GetShopBetByID :one
|
||||
SELECT *
|
||||
FROM shop_bet_detail
|
||||
WHERE id = $1;
|
||||
-- name: GetShopBetByBetID :one
|
||||
SELECT *
|
||||
FROM shop_bet_detail
|
||||
WHERE bet_id = $1;
|
||||
-- name: GetShopBetByShopTransactionID :one
|
||||
SELECT *
|
||||
FROM shop_bet_detail
|
||||
WHERE shop_transaction_id = $1;
|
||||
-- name: UpdateShopBetCashOut :exec
|
||||
UPDATE shop_bets
|
||||
SET cashed_out = $2,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1;
|
||||
-- name: UpdateShopBetCashoutID :exec
|
||||
UPDATE shop_bets
|
||||
SET cashout_id = $2,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1;
|
||||
-- name: CreateShopDeposit :one
|
||||
INSERT INTO shop_deposits (
|
||||
shop_transaction_id,
|
||||
customer_id,
|
||||
wallet_transfer_id
|
||||
)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING *;
|
||||
-- name: GetAllShopDeposit :many
|
||||
SELECT *
|
||||
FROM shop_deposit_detail
|
||||
WHERE (
|
||||
full_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR phone_number ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR sqlc.narg('query') IS NULL
|
||||
)
|
||||
AND (
|
||||
branch_id = sqlc.narg('branch_id')
|
||||
OR sqlc.narg('branch_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
company_id = sqlc.narg('company_id')
|
||||
OR sqlc.narg('company_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at > sqlc.narg('created_before')
|
||||
OR sqlc.narg('created_before') IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at < sqlc.narg('created_after')
|
||||
OR sqlc.narg('created_after') IS NULL
|
||||
);
|
||||
-- name: GetShopDepositByID :one
|
||||
SELECT *
|
||||
FROM shop_deposit_detail
|
||||
WHERE id = $1;
|
||||
-- name: GetShopDepositByShopTransactionID :one
|
||||
SELECT *
|
||||
FROM shop_deposit_detail
|
||||
WHERE shop_transaction_id = $1;
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
-- name: CreateShopTransaction :one
|
||||
INSERT INTO shop_transactions (
|
||||
amount,
|
||||
branch_id,
|
||||
cashier_id,
|
||||
bet_id,
|
||||
type,
|
||||
payment_option,
|
||||
full_name,
|
||||
phone_number,
|
||||
bank_code,
|
||||
beneficiary_name,
|
||||
account_name,
|
||||
account_number,
|
||||
reference_number,
|
||||
number_of_outcomes,
|
||||
branch_name,
|
||||
branch_location,
|
||||
company_id,
|
||||
cashier_name
|
||||
)
|
||||
VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10,
|
||||
$11,
|
||||
$12,
|
||||
$13,
|
||||
$14,
|
||||
$15,
|
||||
$16,
|
||||
$17,
|
||||
$18
|
||||
)
|
||||
RETURNING *;
|
||||
-- name: GetAllShopTransactions :many
|
||||
SELECT *
|
||||
FROM shop_transactions
|
||||
wHERE (
|
||||
branch_id = sqlc.narg('branch_id')
|
||||
OR sqlc.narg('branch_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
company_id = sqlc.narg('company_id')
|
||||
OR sqlc.narg('company_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
cashier_id = sqlc.narg('cashier_id')
|
||||
OR sqlc.narg('cashier_id') IS NULL
|
||||
)
|
||||
AND (
|
||||
full_name ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR phone_number ILIKE '%' || sqlc.narg('query') || '%'
|
||||
OR sqlc.narg('query') IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at > sqlc.narg('created_before')
|
||||
OR sqlc.narg('created_before') IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at < sqlc.narg('created_after')
|
||||
OR sqlc.narg('created_after') IS NULL
|
||||
);
|
||||
-- name: GetShopTransactionByID :one
|
||||
SELECT *
|
||||
FROM shop_transactions
|
||||
WHERE id = $1;
|
||||
-- name: GetShopTransactionByBranch :many
|
||||
SELECT *
|
||||
FROM shop_transactions
|
||||
WHERE branch_id = $1;
|
||||
-- name: UpdateShopTransactionVerified :exec
|
||||
UPDATE shop_transactions
|
||||
SET verified = $2,
|
||||
approved_by = $3,
|
||||
approver_name = $4,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1;
|
||||
106
gen/db/models.go
106
gen/db/models.go
|
|
@ -392,33 +392,113 @@ type Setting struct {
|
|||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ShopBet struct {
|
||||
ID int64 `json:"id"`
|
||||
ShopTransactionID int64 `json:"shop_transaction_id"`
|
||||
CashoutID string `json:"cashout_id"`
|
||||
CashedOutBy pgtype.Int8 `json:"cashed_out_by"`
|
||||
BetID int64 `json:"bet_id"`
|
||||
NumberOfOutcomes int64 `json:"number_of_outcomes"`
|
||||
CashedOut bool `json:"cashed_out"`
|
||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ShopBetDetail struct {
|
||||
ID int64 `json:"id"`
|
||||
ShopTransactionID int64 `json:"shop_transaction_id"`
|
||||
CashoutID string `json:"cashout_id"`
|
||||
CashedOutBy pgtype.Int8 `json:"cashed_out_by"`
|
||||
BetID int64 `json:"bet_id"`
|
||||
NumberOfOutcomes int64 `json:"number_of_outcomes"`
|
||||
CashedOut bool `json:"cashed_out"`
|
||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
CustomerFullName string `json:"customer_full_name"`
|
||||
CustomerPhoneNumber string `json:"customer_phone_number"`
|
||||
BranchID int64 `json:"branch_id"`
|
||||
CompanyID int64 `json:"company_id"`
|
||||
Amount int64 `json:"amount"`
|
||||
TransactionVerified bool `json:"transaction_verified"`
|
||||
Status int32 `json:"status"`
|
||||
TotalOdds float32 `json:"total_odds"`
|
||||
Outcomes []BetOutcome `json:"outcomes"`
|
||||
}
|
||||
|
||||
type ShopDeposit struct {
|
||||
ID int64 `json:"id"`
|
||||
ShopTransactionID int64 `json:"shop_transaction_id"`
|
||||
CustomerID int64 `json:"customer_id"`
|
||||
WalletTransferID int64 `json:"wallet_transfer_id"`
|
||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ShopDepositDetail struct {
|
||||
ID int64 `json:"id"`
|
||||
ShopTransactionID int64 `json:"shop_transaction_id"`
|
||||
CustomerID int64 `json:"customer_id"`
|
||||
WalletTransferID int64 `json:"wallet_transfer_id"`
|
||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
FullName string `json:"full_name"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
BranchID int64 `json:"branch_id"`
|
||||
CompanyID int64 `json:"company_id"`
|
||||
Amount int64 `json:"amount"`
|
||||
TransactionVerified bool `json:"transaction_verified"`
|
||||
}
|
||||
|
||||
type ShopTransaction struct {
|
||||
ID int64 `json:"id"`
|
||||
Amount int64 `json:"amount"`
|
||||
BranchID int64 `json:"branch_id"`
|
||||
CompanyID pgtype.Int8 `json:"company_id"`
|
||||
CashierID pgtype.Int8 `json:"cashier_id"`
|
||||
CashierName pgtype.Text `json:"cashier_name"`
|
||||
BetID pgtype.Int8 `json:"bet_id"`
|
||||
NumberOfOutcomes pgtype.Int8 `json:"number_of_outcomes"`
|
||||
Type pgtype.Int8 `json:"type"`
|
||||
PaymentOption pgtype.Int8 `json:"payment_option"`
|
||||
FullName pgtype.Text `json:"full_name"`
|
||||
PhoneNumber pgtype.Text `json:"phone_number"`
|
||||
CompanyID int64 `json:"company_id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
Type int64 `json:"type"`
|
||||
FullName string `json:"full_name"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
PaymentOption int64 `json:"payment_option"`
|
||||
BankCode pgtype.Text `json:"bank_code"`
|
||||
BeneficiaryName pgtype.Text `json:"beneficiary_name"`
|
||||
AccountName pgtype.Text `json:"account_name"`
|
||||
AccountNumber pgtype.Text `json:"account_number"`
|
||||
ReferenceNumber pgtype.Text `json:"reference_number"`
|
||||
Verified bool `json:"verified"`
|
||||
ApprovedBy pgtype.Int8 `json:"approved_by"`
|
||||
ApproverName pgtype.Text `json:"approver_name"`
|
||||
BranchLocation pgtype.Text `json:"branch_location"`
|
||||
BranchName pgtype.Text `json:"branch_name"`
|
||||
Verified bool `json:"verified"`
|
||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ShopTransactionDetail struct {
|
||||
ID int64 `json:"id"`
|
||||
Amount int64 `json:"amount"`
|
||||
BranchID int64 `json:"branch_id"`
|
||||
CompanyID int64 `json:"company_id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
Type int64 `json:"type"`
|
||||
FullName string `json:"full_name"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
PaymentOption int64 `json:"payment_option"`
|
||||
BankCode pgtype.Text `json:"bank_code"`
|
||||
BeneficiaryName pgtype.Text `json:"beneficiary_name"`
|
||||
AccountName pgtype.Text `json:"account_name"`
|
||||
AccountNumber pgtype.Text `json:"account_number"`
|
||||
ReferenceNumber pgtype.Text `json:"reference_number"`
|
||||
ApprovedBy pgtype.Int8 `json:"approved_by"`
|
||||
Verified bool `json:"verified"`
|
||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||
CreatorFirstName pgtype.Text `json:"creator_first_name"`
|
||||
CreatorLastName pgtype.Text `json:"creator_last_name"`
|
||||
CreatorPhoneNumber pgtype.Text `json:"creator_phone_number"`
|
||||
ApproverFirstName pgtype.Text `json:"approver_first_name"`
|
||||
ApproverLastName pgtype.Text `json:"approver_last_name"`
|
||||
ApproverPhoneNumber pgtype.Text `json:"approver_phone_number"`
|
||||
BranchName pgtype.Text `json:"branch_name"`
|
||||
BranchLocation pgtype.Text `json:"branch_location"`
|
||||
}
|
||||
|
||||
type SupportedOperation struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
|
|
|||
711
gen/db/shop_transactions.sql.go
Normal file
711
gen/db/shop_transactions.sql.go
Normal file
|
|
@ -0,0 +1,711 @@
|
|||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.29.0
|
||||
// source: shop_transactions.sql
|
||||
|
||||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const CreateShopBet = `-- name: CreateShopBet :one
|
||||
INSERT INTO shop_bets (
|
||||
shop_transaction_id,
|
||||
cashout_id,
|
||||
bet_id,
|
||||
number_of_outcomes
|
||||
)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at
|
||||
`
|
||||
|
||||
type CreateShopBetParams struct {
|
||||
ShopTransactionID int64 `json:"shop_transaction_id"`
|
||||
CashoutID string `json:"cashout_id"`
|
||||
BetID int64 `json:"bet_id"`
|
||||
NumberOfOutcomes int64 `json:"number_of_outcomes"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateShopBet(ctx context.Context, arg CreateShopBetParams) (ShopBet, error) {
|
||||
row := q.db.QueryRow(ctx, CreateShopBet,
|
||||
arg.ShopTransactionID,
|
||||
arg.CashoutID,
|
||||
arg.BetID,
|
||||
arg.NumberOfOutcomes,
|
||||
)
|
||||
var i ShopBet
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ShopTransactionID,
|
||||
&i.CashoutID,
|
||||
&i.CashedOutBy,
|
||||
&i.BetID,
|
||||
&i.NumberOfOutcomes,
|
||||
&i.CashedOut,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const CreateShopDeposit = `-- name: CreateShopDeposit :one
|
||||
INSERT INTO shop_deposits (
|
||||
shop_transaction_id,
|
||||
customer_id,
|
||||
wallet_transfer_id
|
||||
)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING id, shop_transaction_id, customer_id, wallet_transfer_id, created_at, updated_at
|
||||
`
|
||||
|
||||
type CreateShopDepositParams struct {
|
||||
ShopTransactionID int64 `json:"shop_transaction_id"`
|
||||
CustomerID int64 `json:"customer_id"`
|
||||
WalletTransferID int64 `json:"wallet_transfer_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateShopDeposit(ctx context.Context, arg CreateShopDepositParams) (ShopDeposit, error) {
|
||||
row := q.db.QueryRow(ctx, CreateShopDeposit, arg.ShopTransactionID, arg.CustomerID, arg.WalletTransferID)
|
||||
var i ShopDeposit
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ShopTransactionID,
|
||||
&i.CustomerID,
|
||||
&i.WalletTransferID,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const CreateShopTransaction = `-- name: CreateShopTransaction :one
|
||||
INSERT INTO shop_transactions (
|
||||
amount,
|
||||
branch_id,
|
||||
company_id,
|
||||
user_id,
|
||||
type,
|
||||
full_name,
|
||||
phone_number,
|
||||
payment_option,
|
||||
bank_code,
|
||||
beneficiary_name,
|
||||
account_name,
|
||||
account_number,
|
||||
reference_number
|
||||
)
|
||||
VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
$6,
|
||||
$7,
|
||||
$8,
|
||||
$9,
|
||||
$10,
|
||||
$11,
|
||||
$12,
|
||||
$13
|
||||
)
|
||||
RETURNING id, amount, branch_id, company_id, user_id, type, full_name, phone_number, payment_option, bank_code, beneficiary_name, account_name, account_number, reference_number, approved_by, verified, created_at, updated_at
|
||||
`
|
||||
|
||||
type CreateShopTransactionParams struct {
|
||||
Amount int64 `json:"amount"`
|
||||
BranchID int64 `json:"branch_id"`
|
||||
CompanyID int64 `json:"company_id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
Type int64 `json:"type"`
|
||||
FullName string `json:"full_name"`
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
PaymentOption int64 `json:"payment_option"`
|
||||
BankCode pgtype.Text `json:"bank_code"`
|
||||
BeneficiaryName pgtype.Text `json:"beneficiary_name"`
|
||||
AccountName pgtype.Text `json:"account_name"`
|
||||
AccountNumber pgtype.Text `json:"account_number"`
|
||||
ReferenceNumber pgtype.Text `json:"reference_number"`
|
||||
}
|
||||
|
||||
func (q *Queries) CreateShopTransaction(ctx context.Context, arg CreateShopTransactionParams) (ShopTransaction, error) {
|
||||
row := q.db.QueryRow(ctx, CreateShopTransaction,
|
||||
arg.Amount,
|
||||
arg.BranchID,
|
||||
arg.CompanyID,
|
||||
arg.UserID,
|
||||
arg.Type,
|
||||
arg.FullName,
|
||||
arg.PhoneNumber,
|
||||
arg.PaymentOption,
|
||||
arg.BankCode,
|
||||
arg.BeneficiaryName,
|
||||
arg.AccountName,
|
||||
arg.AccountNumber,
|
||||
arg.ReferenceNumber,
|
||||
)
|
||||
var i ShopTransaction
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Amount,
|
||||
&i.BranchID,
|
||||
&i.CompanyID,
|
||||
&i.UserID,
|
||||
&i.Type,
|
||||
&i.FullName,
|
||||
&i.PhoneNumber,
|
||||
&i.PaymentOption,
|
||||
&i.BankCode,
|
||||
&i.BeneficiaryName,
|
||||
&i.AccountName,
|
||||
&i.AccountNumber,
|
||||
&i.ReferenceNumber,
|
||||
&i.ApprovedBy,
|
||||
&i.Verified,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetAllShopBets = `-- name: GetAllShopBets :many
|
||||
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, outcomes
|
||||
FROM shop_bet_detail
|
||||
WHERE (
|
||||
full_name ILIKE '%' || $1 || '%'
|
||||
OR phone_number ILIKE '%' || $1 || '%'
|
||||
OR $1 IS NULL
|
||||
)
|
||||
AND (
|
||||
branch_id = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
AND (
|
||||
company_id = $3
|
||||
OR $3 IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at > $4
|
||||
OR $4 IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at < $5
|
||||
OR $5 IS NULL
|
||||
)
|
||||
`
|
||||
|
||||
type GetAllShopBetsParams struct {
|
||||
Query pgtype.Text `json:"query"`
|
||||
BranchID pgtype.Int8 `json:"branch_id"`
|
||||
CompanyID pgtype.Int8 `json:"company_id"`
|
||||
CreatedBefore pgtype.Timestamp `json:"created_before"`
|
||||
CreatedAfter pgtype.Timestamp `json:"created_after"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetAllShopBets(ctx context.Context, arg GetAllShopBetsParams) ([]ShopBetDetail, error) {
|
||||
rows, err := q.db.Query(ctx, GetAllShopBets,
|
||||
arg.Query,
|
||||
arg.BranchID,
|
||||
arg.CompanyID,
|
||||
arg.CreatedBefore,
|
||||
arg.CreatedAfter,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ShopBetDetail
|
||||
for rows.Next() {
|
||||
var i ShopBetDetail
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.ShopTransactionID,
|
||||
&i.CashoutID,
|
||||
&i.CashedOutBy,
|
||||
&i.BetID,
|
||||
&i.NumberOfOutcomes,
|
||||
&i.CashedOut,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CustomerFullName,
|
||||
&i.CustomerPhoneNumber,
|
||||
&i.BranchID,
|
||||
&i.CompanyID,
|
||||
&i.Amount,
|
||||
&i.TransactionVerified,
|
||||
&i.Status,
|
||||
&i.TotalOdds,
|
||||
&i.Outcomes,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetAllShopDeposit = `-- name: GetAllShopDeposit :many
|
||||
SELECT id, shop_transaction_id, customer_id, wallet_transfer_id, created_at, updated_at, full_name, phone_number, branch_id, company_id, amount, transaction_verified
|
||||
FROM shop_deposit_detail
|
||||
WHERE (
|
||||
full_name ILIKE '%' || $1 || '%'
|
||||
OR phone_number ILIKE '%' || $1 || '%'
|
||||
OR $1 IS NULL
|
||||
)
|
||||
AND (
|
||||
branch_id = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
AND (
|
||||
company_id = $3
|
||||
OR $3 IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at > $4
|
||||
OR $4 IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at < $5
|
||||
OR $5 IS NULL
|
||||
)
|
||||
`
|
||||
|
||||
type GetAllShopDepositParams struct {
|
||||
Query pgtype.Text `json:"query"`
|
||||
BranchID pgtype.Int8 `json:"branch_id"`
|
||||
CompanyID pgtype.Int8 `json:"company_id"`
|
||||
CreatedBefore pgtype.Timestamp `json:"created_before"`
|
||||
CreatedAfter pgtype.Timestamp `json:"created_after"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetAllShopDeposit(ctx context.Context, arg GetAllShopDepositParams) ([]ShopDepositDetail, error) {
|
||||
rows, err := q.db.Query(ctx, GetAllShopDeposit,
|
||||
arg.Query,
|
||||
arg.BranchID,
|
||||
arg.CompanyID,
|
||||
arg.CreatedBefore,
|
||||
arg.CreatedAfter,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ShopDepositDetail
|
||||
for rows.Next() {
|
||||
var i ShopDepositDetail
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.ShopTransactionID,
|
||||
&i.CustomerID,
|
||||
&i.WalletTransferID,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.FullName,
|
||||
&i.PhoneNumber,
|
||||
&i.BranchID,
|
||||
&i.CompanyID,
|
||||
&i.Amount,
|
||||
&i.TransactionVerified,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetAllShopTransactions = `-- name: GetAllShopTransactions :many
|
||||
SELECT id, amount, branch_id, company_id, user_id, type, full_name, phone_number, payment_option, bank_code, beneficiary_name, account_name, account_number, reference_number, approved_by, verified, created_at, updated_at, creator_first_name, creator_last_name, creator_phone_number, approver_first_name, approver_last_name, approver_phone_number, branch_name, branch_location
|
||||
FROM shop_transaction_detail
|
||||
wHERE (
|
||||
branch_id = $1
|
||||
OR $1 IS NULL
|
||||
)
|
||||
AND (
|
||||
company_id = $2
|
||||
OR $2 IS NULL
|
||||
)
|
||||
AND (
|
||||
user_id = $3
|
||||
OR $3 IS NULL
|
||||
)
|
||||
AND (
|
||||
full_name ILIKE '%' || $4 || '%'
|
||||
OR phone_number ILIKE '%' || $4 || '%'
|
||||
OR $4 IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at > $5
|
||||
OR $5 IS NULL
|
||||
)
|
||||
AND (
|
||||
created_at < $6
|
||||
OR $6 IS NULL
|
||||
)
|
||||
`
|
||||
|
||||
type GetAllShopTransactionsParams struct {
|
||||
BranchID pgtype.Int8 `json:"branch_id"`
|
||||
CompanyID pgtype.Int8 `json:"company_id"`
|
||||
UserID pgtype.Int8 `json:"user_id"`
|
||||
Query pgtype.Text `json:"query"`
|
||||
CreatedBefore pgtype.Timestamp `json:"created_before"`
|
||||
CreatedAfter pgtype.Timestamp `json:"created_after"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetAllShopTransactions(ctx context.Context, arg GetAllShopTransactionsParams) ([]ShopTransactionDetail, error) {
|
||||
rows, err := q.db.Query(ctx, GetAllShopTransactions,
|
||||
arg.BranchID,
|
||||
arg.CompanyID,
|
||||
arg.UserID,
|
||||
arg.Query,
|
||||
arg.CreatedBefore,
|
||||
arg.CreatedAfter,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ShopTransactionDetail
|
||||
for rows.Next() {
|
||||
var i ShopTransactionDetail
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Amount,
|
||||
&i.BranchID,
|
||||
&i.CompanyID,
|
||||
&i.UserID,
|
||||
&i.Type,
|
||||
&i.FullName,
|
||||
&i.PhoneNumber,
|
||||
&i.PaymentOption,
|
||||
&i.BankCode,
|
||||
&i.BeneficiaryName,
|
||||
&i.AccountName,
|
||||
&i.AccountNumber,
|
||||
&i.ReferenceNumber,
|
||||
&i.ApprovedBy,
|
||||
&i.Verified,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CreatorFirstName,
|
||||
&i.CreatorLastName,
|
||||
&i.CreatorPhoneNumber,
|
||||
&i.ApproverFirstName,
|
||||
&i.ApproverLastName,
|
||||
&i.ApproverPhoneNumber,
|
||||
&i.BranchName,
|
||||
&i.BranchLocation,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetShopBetByBetID = `-- name: GetShopBetByBetID :one
|
||||
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, outcomes
|
||||
FROM shop_bet_detail
|
||||
WHERE bet_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetShopBetByBetID(ctx context.Context, betID int64) (ShopBetDetail, error) {
|
||||
row := q.db.QueryRow(ctx, GetShopBetByBetID, betID)
|
||||
var i ShopBetDetail
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ShopTransactionID,
|
||||
&i.CashoutID,
|
||||
&i.CashedOutBy,
|
||||
&i.BetID,
|
||||
&i.NumberOfOutcomes,
|
||||
&i.CashedOut,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CustomerFullName,
|
||||
&i.CustomerPhoneNumber,
|
||||
&i.BranchID,
|
||||
&i.CompanyID,
|
||||
&i.Amount,
|
||||
&i.TransactionVerified,
|
||||
&i.Status,
|
||||
&i.TotalOdds,
|
||||
&i.Outcomes,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetShopBetByID = `-- name: GetShopBetByID :one
|
||||
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, outcomes
|
||||
FROM shop_bet_detail
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetShopBetByID(ctx context.Context, id int64) (ShopBetDetail, error) {
|
||||
row := q.db.QueryRow(ctx, GetShopBetByID, id)
|
||||
var i ShopBetDetail
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ShopTransactionID,
|
||||
&i.CashoutID,
|
||||
&i.CashedOutBy,
|
||||
&i.BetID,
|
||||
&i.NumberOfOutcomes,
|
||||
&i.CashedOut,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CustomerFullName,
|
||||
&i.CustomerPhoneNumber,
|
||||
&i.BranchID,
|
||||
&i.CompanyID,
|
||||
&i.Amount,
|
||||
&i.TransactionVerified,
|
||||
&i.Status,
|
||||
&i.TotalOdds,
|
||||
&i.Outcomes,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetShopBetByShopTransactionID = `-- name: GetShopBetByShopTransactionID :one
|
||||
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, outcomes
|
||||
FROM shop_bet_detail
|
||||
WHERE shop_transaction_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetShopBetByShopTransactionID(ctx context.Context, shopTransactionID int64) (ShopBetDetail, error) {
|
||||
row := q.db.QueryRow(ctx, GetShopBetByShopTransactionID, shopTransactionID)
|
||||
var i ShopBetDetail
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ShopTransactionID,
|
||||
&i.CashoutID,
|
||||
&i.CashedOutBy,
|
||||
&i.BetID,
|
||||
&i.NumberOfOutcomes,
|
||||
&i.CashedOut,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CustomerFullName,
|
||||
&i.CustomerPhoneNumber,
|
||||
&i.BranchID,
|
||||
&i.CompanyID,
|
||||
&i.Amount,
|
||||
&i.TransactionVerified,
|
||||
&i.Status,
|
||||
&i.TotalOdds,
|
||||
&i.Outcomes,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetShopDepositByID = `-- name: GetShopDepositByID :one
|
||||
SELECT id, shop_transaction_id, customer_id, wallet_transfer_id, created_at, updated_at, full_name, phone_number, branch_id, company_id, amount, transaction_verified
|
||||
FROM shop_deposit_detail
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetShopDepositByID(ctx context.Context, id int64) (ShopDepositDetail, error) {
|
||||
row := q.db.QueryRow(ctx, GetShopDepositByID, id)
|
||||
var i ShopDepositDetail
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ShopTransactionID,
|
||||
&i.CustomerID,
|
||||
&i.WalletTransferID,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.FullName,
|
||||
&i.PhoneNumber,
|
||||
&i.BranchID,
|
||||
&i.CompanyID,
|
||||
&i.Amount,
|
||||
&i.TransactionVerified,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetShopDepositByShopTransactionID = `-- name: GetShopDepositByShopTransactionID :one
|
||||
SELECT id, shop_transaction_id, customer_id, wallet_transfer_id, created_at, updated_at, full_name, phone_number, branch_id, company_id, amount, transaction_verified
|
||||
FROM shop_deposit_detail
|
||||
WHERE shop_transaction_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetShopDepositByShopTransactionID(ctx context.Context, shopTransactionID int64) (ShopDepositDetail, error) {
|
||||
row := q.db.QueryRow(ctx, GetShopDepositByShopTransactionID, shopTransactionID)
|
||||
var i ShopDepositDetail
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ShopTransactionID,
|
||||
&i.CustomerID,
|
||||
&i.WalletTransferID,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.FullName,
|
||||
&i.PhoneNumber,
|
||||
&i.BranchID,
|
||||
&i.CompanyID,
|
||||
&i.Amount,
|
||||
&i.TransactionVerified,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetShopTransactionByBranch = `-- name: GetShopTransactionByBranch :many
|
||||
SELECT id, amount, branch_id, company_id, user_id, type, full_name, phone_number, payment_option, bank_code, beneficiary_name, account_name, account_number, reference_number, approved_by, verified, created_at, updated_at, creator_first_name, creator_last_name, creator_phone_number, approver_first_name, approver_last_name, approver_phone_number, branch_name, branch_location
|
||||
FROM shop_transaction_detail
|
||||
WHERE branch_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetShopTransactionByBranch(ctx context.Context, branchID int64) ([]ShopTransactionDetail, error) {
|
||||
rows, err := q.db.Query(ctx, GetShopTransactionByBranch, branchID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ShopTransactionDetail
|
||||
for rows.Next() {
|
||||
var i ShopTransactionDetail
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.Amount,
|
||||
&i.BranchID,
|
||||
&i.CompanyID,
|
||||
&i.UserID,
|
||||
&i.Type,
|
||||
&i.FullName,
|
||||
&i.PhoneNumber,
|
||||
&i.PaymentOption,
|
||||
&i.BankCode,
|
||||
&i.BeneficiaryName,
|
||||
&i.AccountName,
|
||||
&i.AccountNumber,
|
||||
&i.ReferenceNumber,
|
||||
&i.ApprovedBy,
|
||||
&i.Verified,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CreatorFirstName,
|
||||
&i.CreatorLastName,
|
||||
&i.CreatorPhoneNumber,
|
||||
&i.ApproverFirstName,
|
||||
&i.ApproverLastName,
|
||||
&i.ApproverPhoneNumber,
|
||||
&i.BranchName,
|
||||
&i.BranchLocation,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const GetShopTransactionByID = `-- name: GetShopTransactionByID :one
|
||||
SELECT id, amount, branch_id, company_id, user_id, type, full_name, phone_number, payment_option, bank_code, beneficiary_name, account_name, account_number, reference_number, approved_by, verified, created_at, updated_at, creator_first_name, creator_last_name, creator_phone_number, approver_first_name, approver_last_name, approver_phone_number, branch_name, branch_location
|
||||
FROM shop_transaction_detail
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetShopTransactionByID(ctx context.Context, id int64) (ShopTransactionDetail, error) {
|
||||
row := q.db.QueryRow(ctx, GetShopTransactionByID, id)
|
||||
var i ShopTransactionDetail
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Amount,
|
||||
&i.BranchID,
|
||||
&i.CompanyID,
|
||||
&i.UserID,
|
||||
&i.Type,
|
||||
&i.FullName,
|
||||
&i.PhoneNumber,
|
||||
&i.PaymentOption,
|
||||
&i.BankCode,
|
||||
&i.BeneficiaryName,
|
||||
&i.AccountName,
|
||||
&i.AccountNumber,
|
||||
&i.ReferenceNumber,
|
||||
&i.ApprovedBy,
|
||||
&i.Verified,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.CreatorFirstName,
|
||||
&i.CreatorLastName,
|
||||
&i.CreatorPhoneNumber,
|
||||
&i.ApproverFirstName,
|
||||
&i.ApproverLastName,
|
||||
&i.ApproverPhoneNumber,
|
||||
&i.BranchName,
|
||||
&i.BranchLocation,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const UpdateShopBetCashOut = `-- name: UpdateShopBetCashOut :exec
|
||||
UPDATE shop_bets
|
||||
SET cashed_out = $2,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
type UpdateShopBetCashOutParams struct {
|
||||
ID int64 `json:"id"`
|
||||
CashedOut bool `json:"cashed_out"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateShopBetCashOut(ctx context.Context, arg UpdateShopBetCashOutParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateShopBetCashOut, arg.ID, arg.CashedOut)
|
||||
return err
|
||||
}
|
||||
|
||||
const UpdateShopBetCashoutID = `-- name: UpdateShopBetCashoutID :exec
|
||||
UPDATE shop_bets
|
||||
SET cashout_id = $2,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
type UpdateShopBetCashoutIDParams struct {
|
||||
ID int64 `json:"id"`
|
||||
CashoutID string `json:"cashout_id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateShopBetCashoutID(ctx context.Context, arg UpdateShopBetCashoutIDParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateShopBetCashoutID, arg.ID, arg.CashoutID)
|
||||
return err
|
||||
}
|
||||
|
||||
const UpdateShopTransactionVerified = `-- name: UpdateShopTransactionVerified :exec
|
||||
UPDATE shop_transactions
|
||||
SET verified = $2,
|
||||
approved_by = $3,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $1
|
||||
`
|
||||
|
||||
type UpdateShopTransactionVerifiedParams struct {
|
||||
ID int64 `json:"id"`
|
||||
Verified bool `json:"verified"`
|
||||
ApprovedBy pgtype.Int8 `json:"approved_by"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateShopTransactionVerified(ctx context.Context, arg UpdateShopTransactionVerifiedParams) error {
|
||||
_, err := q.db.Exec(ctx, UpdateShopTransactionVerified, arg.ID, arg.Verified, arg.ApprovedBy)
|
||||
return err
|
||||
}
|
||||
|
|
@ -106,7 +106,6 @@ type CreateBetOutcomeReq struct {
|
|||
type CreateBetReq struct {
|
||||
Outcomes []CreateBetOutcomeReq `json:"outcomes"`
|
||||
Amount float32 `json:"amount" example:"100.0"`
|
||||
Status OutcomeStatus `json:"status" example:"1"`
|
||||
FullName string `json:"full_name" example:"John"`
|
||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||
BranchID *int64 `json:"branch_id,omitempty" example:"1"`
|
||||
|
|
|
|||
125
internal/domain/shop_bet.go
Normal file
125
internal/domain/shop_bet.go
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type ShopBet struct {
|
||||
ID int64
|
||||
ShopTransactionID int64
|
||||
CashoutID string
|
||||
CashedOut bool
|
||||
BetID int64
|
||||
NumberOfOutcomes int64
|
||||
}
|
||||
|
||||
type ShopBetFilter struct {
|
||||
CompanyID ValidInt64
|
||||
BranchID ValidInt64
|
||||
Query ValidString
|
||||
CreatedBefore ValidTime
|
||||
CreatedAfter ValidTime
|
||||
}
|
||||
|
||||
type CreateShopBet struct {
|
||||
ShopTransactionID int64
|
||||
CashoutID string
|
||||
BetID int64
|
||||
NumberOfOutcomes int64
|
||||
}
|
||||
|
||||
type ShopBetDetail struct {
|
||||
ID int64
|
||||
ShopTransactionID int64
|
||||
TotalOdds float32
|
||||
BranchID int64
|
||||
CompanyID int64
|
||||
FullName string
|
||||
PhoneNumber string
|
||||
CashoutID string
|
||||
CashedOut bool
|
||||
BetID int64
|
||||
NumberOfOutcomes int64
|
||||
Status OutcomeStatus
|
||||
Amount Currency
|
||||
Outcomes []BetOutcome
|
||||
TransactionVerified bool
|
||||
UpdatedAt time.Time
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type ShopBetReq struct {
|
||||
Outcomes []CreateBetOutcomeReq `json:"outcomes"`
|
||||
Amount float32 `json:"amount" example:"100.0"`
|
||||
BetID int64 `json:"bet_id" example:"1"`
|
||||
PaymentOption PaymentOption `json:"payment_option" example:"1"`
|
||||
FullName string `json:"full_name" example:"John Smith"`
|
||||
PhoneNumber string `json:"phone_number" example:"0911111111"`
|
||||
BankCode string `json:"bank_code"`
|
||||
BeneficiaryName string `json:"beneficiary_name"`
|
||||
AccountName string `json:"account_name"`
|
||||
AccountNumber string `json:"account_number"`
|
||||
ReferenceNumber string `json:"reference_number"`
|
||||
BranchID *int64 `json:"branch_id,omitempty" example:"1"`
|
||||
}
|
||||
|
||||
type CashoutReq struct {
|
||||
CashoutID string `json:"cashout_id" example:"1234"`
|
||||
PaymentOption PaymentOption `json:"payment_option" example:"1"`
|
||||
BankCode string `json:"bank_code"`
|
||||
BeneficiaryName string `json:"beneficiary_name"`
|
||||
AccountName string `json:"account_name"`
|
||||
AccountNumber string `json:"account_number"`
|
||||
ReferenceNumber string `json:"reference_number"`
|
||||
BranchID *int64 `json:"branch_id,omitempty" example:"1"`
|
||||
}
|
||||
|
||||
type ShopBetRes struct {
|
||||
ID int64 `json:"id"`
|
||||
ShopTransactionID int64 `json:"shop_transaction_id"`
|
||||
TotalOdds float32 `json:"total_odds" example:"4.22"`
|
||||
BranchID int64 `json:"branch_id" example:"2"`
|
||||
CompanyID int64 `json:"company_id" example:"2"`
|
||||
FullName string `json:"full_name" example:"John"`
|
||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||
CashoutID string `json:"cashout_id" example:"21234"`
|
||||
CashedOut bool `json:"cashed_out" example:"false"`
|
||||
BetID int64 `json:"bet_id" example:"1"`
|
||||
NumberOfOutcomes int64 `json:"number_of_outcomes" example:"1"`
|
||||
Status OutcomeStatus `json:"status" example:"1"`
|
||||
Amount Currency `json:"amount" example:"100.0"`
|
||||
Outcomes []BetOutcome `json:"outcomes"`
|
||||
TransactionVerified bool `json:"transaction_verified" example:"true"`
|
||||
UpdatedAt time.Time `json:"updated_at" example:"2025-04-08T12:00:00Z"`
|
||||
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
|
||||
}
|
||||
|
||||
func ConvertShopBet(shopBet ShopBet) ShopBetRes {
|
||||
return ShopBetRes{
|
||||
ID: shopBet.ID,
|
||||
ShopTransactionID: shopBet.ShopTransactionID,
|
||||
CashoutID: shopBet.CashoutID,
|
||||
CashedOut: shopBet.CashedOut,
|
||||
BetID: shopBet.BetID,
|
||||
NumberOfOutcomes: shopBet.NumberOfOutcomes,
|
||||
}
|
||||
}
|
||||
func ConvertShopBetDetail(shopBet ShopBetDetail) ShopBetRes {
|
||||
return ShopBetRes{
|
||||
ID: shopBet.ID,
|
||||
ShopTransactionID: shopBet.ShopTransactionID,
|
||||
TotalOdds: shopBet.TotalOdds,
|
||||
BranchID: shopBet.BranchID,
|
||||
CompanyID: shopBet.CompanyID,
|
||||
FullName: shopBet.FullName,
|
||||
PhoneNumber: shopBet.PhoneNumber,
|
||||
CashoutID: shopBet.CashoutID,
|
||||
CashedOut: shopBet.CashedOut,
|
||||
BetID: shopBet.BetID,
|
||||
NumberOfOutcomes: shopBet.NumberOfOutcomes,
|
||||
Status: shopBet.Status,
|
||||
Amount: shopBet.Amount,
|
||||
Outcomes: shopBet.Outcomes,
|
||||
TransactionVerified: shopBet.TransactionVerified,
|
||||
UpdatedAt: shopBet.UpdatedAt,
|
||||
CreatedAt: shopBet.UpdatedAt,
|
||||
}
|
||||
}
|
||||
68
internal/domain/shop_deposit.go
Normal file
68
internal/domain/shop_deposit.go
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type ShopDeposit struct {
|
||||
ID int64
|
||||
ShopTransactionID int64
|
||||
CustomerID int64
|
||||
WalletTransferID int64
|
||||
}
|
||||
type CreateShopDeposit struct {
|
||||
ShopTransactionID int64
|
||||
CustomerID int64
|
||||
WalletTransferID int64
|
||||
}
|
||||
|
||||
type ShopDepositFilter struct {
|
||||
CompanyID ValidInt64
|
||||
BranchID ValidInt64
|
||||
Query ValidString
|
||||
CreatedBefore ValidTime
|
||||
CreatedAfter ValidTime
|
||||
}
|
||||
|
||||
type ShopDepositDetail struct {
|
||||
ID int64
|
||||
ShopTransactionID int64
|
||||
CustomerID int64
|
||||
WalletTransferID int64
|
||||
FullName string
|
||||
PhoneNumber string
|
||||
Amount Currency
|
||||
BranchID int64
|
||||
CompanyID int64
|
||||
TransactionVerified bool
|
||||
UpdatedAt time.Time
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type ShopDepositReq struct {
|
||||
CustomerID int64 `json:"customer_id" example:"1"`
|
||||
Amount float32 `json:"amount" example:"100.0"`
|
||||
PaymentOption PaymentOption `json:"payment_option" example:"1"`
|
||||
FullName string `json:"full_name" example:"John Smith"`
|
||||
PhoneNumber string `json:"phone_number" example:"0911111111"`
|
||||
BankCode string `json:"bank_code"`
|
||||
BeneficiaryName string `json:"beneficiary_name"`
|
||||
AccountName string `json:"account_name"`
|
||||
AccountNumber string `json:"account_number"`
|
||||
ReferenceNumber string `json:"reference_number"`
|
||||
BranchID *int64 `json:"branch_id,omitempty" example:"1"`
|
||||
}
|
||||
|
||||
type ShopDepositRes struct {
|
||||
ID int64 `json:"id"`
|
||||
ShopTransactionID int64 `json:"shop_transaction_id"`
|
||||
CustomerID int64 `json:"customer_id"`
|
||||
WalletTransferID int64 `json:"wallet_transfer_id"`
|
||||
}
|
||||
|
||||
func ConvertShopDeposit(shopDeposit ShopDeposit) ShopDepositRes {
|
||||
return ShopDepositRes{
|
||||
ID: shopDeposit.ID,
|
||||
ShopTransactionID: shopDeposit.ShopTransactionID,
|
||||
CustomerID: shopDeposit.CustomerID,
|
||||
WalletTransferID: shopDeposit.WalletTransferID,
|
||||
}
|
||||
}
|
||||
189
internal/domain/shop_transaction.go
Normal file
189
internal/domain/shop_transaction.go
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type ShopTransactionType int
|
||||
|
||||
const (
|
||||
TRANSACTION_CASHOUT ShopTransactionType = iota
|
||||
TRANSACTION_DEPOSIT
|
||||
TRANSACTION_BET
|
||||
)
|
||||
|
||||
type PaymentOption int64
|
||||
|
||||
const (
|
||||
CASH_TRANSACTION PaymentOption = iota
|
||||
TELEBIRR_TRANSACTION
|
||||
ARIFPAY_TRANSACTION
|
||||
BANK
|
||||
)
|
||||
|
||||
// ShopTransaction only represents branch transactions
|
||||
// This is only used for statistic data
|
||||
type ShopTransaction struct {
|
||||
ID int64
|
||||
Amount Currency
|
||||
BranchID int64
|
||||
CompanyID int64
|
||||
UserID int64
|
||||
Type ShopTransactionType
|
||||
PaymentOption PaymentOption
|
||||
FullName string
|
||||
PhoneNumber string
|
||||
// Payment Details for bank
|
||||
BankCode ValidString
|
||||
BeneficiaryName ValidString
|
||||
AccountName ValidString
|
||||
AccountNumber ValidString
|
||||
ReferenceNumber ValidString
|
||||
Verified bool
|
||||
ApprovedBy ValidInt64
|
||||
UpdatedAt time.Time
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type ShopTransactionRes struct {
|
||||
ID int64 `json:"id" example:"1"`
|
||||
Amount float32 `json:"amount" example:"100.0"`
|
||||
BranchID int64 `json:"branch_id" example:"1"`
|
||||
BranchName string `json:"branch_name" example:"Branch Name"`
|
||||
BranchLocation string `json:"branch_location" example:"Branch Location"`
|
||||
CompanyID int64 `json:"company_id" example:"1"`
|
||||
UserID int64 `json:"user_id" example:"1"`
|
||||
CreatorFirstName string `json:"creator_first_name" example:"John"`
|
||||
CreatorLastName string `json:"creator_last_name" example:"Smith"`
|
||||
CreatorPhoneNumber string `json:"creator_phone_number" example:"0911111111"`
|
||||
CashierName string `json:"cashier_name" example:"John Smith"`
|
||||
Type int64 `json:"type" example:"1"`
|
||||
PaymentOption PaymentOption `json:"payment_option" example:"1"`
|
||||
FullName string `json:"full_name" example:"John Smith"`
|
||||
PhoneNumber string `json:"phone_number" example:"0911111111"`
|
||||
BankCode string `json:"bank_code"`
|
||||
BeneficiaryName string `json:"beneficiary_name"`
|
||||
AccountName string `json:"account_name"`
|
||||
AccountNumber string `json:"account_number"`
|
||||
ReferenceNumber string `json:"reference_number"`
|
||||
Verified bool `json:"verified" example:"true"`
|
||||
ApprovedBy int64 `json:"approved_by" example:"1"`
|
||||
ApproverFirstName string `json:"approver_first_name" example:"John"`
|
||||
ApproverLastName string `json:"approver_last_name" example:"Smith"`
|
||||
ApproverPhoneNumber string `json:"approver_phone_number" example:"0911111111"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type ShopTransactionDetail struct {
|
||||
ID int64
|
||||
Amount Currency
|
||||
BranchID int64
|
||||
BranchName string
|
||||
BranchLocation string
|
||||
CompanyID int64
|
||||
UserID int64
|
||||
CreatorFirstName string
|
||||
CreatorLastName string
|
||||
CreatorPhoneNumber string
|
||||
Type ShopTransactionType
|
||||
PaymentOption PaymentOption
|
||||
FullName string
|
||||
PhoneNumber string
|
||||
// Payment Details for bank
|
||||
BankCode ValidString
|
||||
BeneficiaryName ValidString
|
||||
AccountName ValidString
|
||||
AccountNumber ValidString
|
||||
ReferenceNumber ValidString
|
||||
Verified bool
|
||||
ApprovedBy ValidInt64
|
||||
ApproverFirstName ValidString
|
||||
ApproverLastName ValidString
|
||||
ApproverPhoneNumber ValidString
|
||||
UpdatedAt time.Time
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type ShopTransactionFilter struct {
|
||||
CompanyID ValidInt64
|
||||
BranchID ValidInt64
|
||||
UserID ValidInt64
|
||||
Query ValidString
|
||||
CreatedBefore ValidTime
|
||||
CreatedAfter ValidTime
|
||||
}
|
||||
type CreateShopTransaction struct {
|
||||
Amount Currency
|
||||
BranchID int64
|
||||
CompanyID int64
|
||||
UserID int64
|
||||
Type ShopTransactionType
|
||||
PaymentOption PaymentOption
|
||||
FullName string
|
||||
PhoneNumber string
|
||||
// Payment Details for bank
|
||||
BankCode ValidString
|
||||
BeneficiaryName ValidString
|
||||
AccountName ValidString
|
||||
AccountNumber ValidString
|
||||
ReferenceNumber ValidString
|
||||
Verified bool
|
||||
ApprovedBy ValidInt64
|
||||
}
|
||||
|
||||
func ConvertShopTransaction(transaction ShopTransaction) ShopTransactionRes {
|
||||
newTransaction := ShopTransactionRes{
|
||||
ID: transaction.ID,
|
||||
Amount: transaction.Amount.Float32(),
|
||||
BranchID: transaction.BranchID,
|
||||
CompanyID: transaction.CompanyID,
|
||||
UserID: transaction.UserID,
|
||||
Type: int64(transaction.Type),
|
||||
PaymentOption: transaction.PaymentOption,
|
||||
FullName: transaction.FullName,
|
||||
PhoneNumber: transaction.PhoneNumber,
|
||||
BankCode: transaction.BankCode.Value,
|
||||
BeneficiaryName: transaction.BeneficiaryName.Value,
|
||||
AccountName: transaction.AccountName.Value,
|
||||
AccountNumber: transaction.AccountNumber.Value,
|
||||
ReferenceNumber: transaction.ReferenceNumber.Value,
|
||||
Verified: transaction.Verified,
|
||||
ApprovedBy: transaction.ApprovedBy.Value,
|
||||
CreatedAt: transaction.CreatedAt,
|
||||
UpdatedAt: transaction.UpdatedAt,
|
||||
}
|
||||
|
||||
return newTransaction
|
||||
}
|
||||
|
||||
func ConvertShopTransactionDetail(transaction ShopTransactionDetail) ShopTransactionRes {
|
||||
newTransaction := ShopTransactionRes{
|
||||
ID: transaction.ID,
|
||||
Amount: transaction.Amount.Float32(),
|
||||
BranchID: transaction.BranchID,
|
||||
BranchName: transaction.BranchName,
|
||||
BranchLocation: transaction.BranchLocation,
|
||||
CompanyID: transaction.CompanyID,
|
||||
UserID: transaction.UserID,
|
||||
CreatorFirstName: transaction.CreatorFirstName,
|
||||
CreatorLastName: transaction.CreatorLastName,
|
||||
CreatorPhoneNumber: transaction.CreatorPhoneNumber,
|
||||
Type: int64(transaction.Type),
|
||||
PaymentOption: transaction.PaymentOption,
|
||||
FullName: transaction.FullName,
|
||||
PhoneNumber: transaction.PhoneNumber,
|
||||
BankCode: transaction.BankCode.Value,
|
||||
BeneficiaryName: transaction.BeneficiaryName.Value,
|
||||
AccountName: transaction.AccountName.Value,
|
||||
AccountNumber: transaction.AccountNumber.Value,
|
||||
ReferenceNumber: transaction.ReferenceNumber.Value,
|
||||
Verified: transaction.Verified,
|
||||
ApprovedBy: transaction.ApprovedBy.Value,
|
||||
ApproverFirstName: transaction.ApproverFirstName.Value,
|
||||
ApproverLastName: transaction.ApproverLastName.Value,
|
||||
ApproverPhoneNumber: transaction.ApproverPhoneNumber.Value,
|
||||
CreatedAt: transaction.CreatedAt,
|
||||
UpdatedAt: transaction.UpdatedAt,
|
||||
}
|
||||
|
||||
return newTransaction
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
package domain
|
||||
|
||||
import "time"
|
||||
|
||||
type ShopTransactionType int
|
||||
|
||||
const (
|
||||
TRANSACTION_CASHOUT ShopTransactionType = iota
|
||||
TRANSACTION_DEPOSIT
|
||||
)
|
||||
|
||||
type PaymentOption int64
|
||||
|
||||
const (
|
||||
CASH_TRANSACTION PaymentOption = iota
|
||||
TELEBIRR_TRANSACTION
|
||||
ARIFPAY_TRANSACTION
|
||||
BANK
|
||||
)
|
||||
|
||||
// ShopTransaction only represents branch transactions
|
||||
// This is only used for statistic data
|
||||
type ShopTransaction struct {
|
||||
ID int64
|
||||
Amount Currency
|
||||
BranchID int64
|
||||
BranchName string
|
||||
BranchLocation string
|
||||
CompanyID int64
|
||||
CashierID int64
|
||||
CashierName string
|
||||
BetID int64
|
||||
NumberOfOutcomes int64
|
||||
Type ShopTransactionType
|
||||
PaymentOption PaymentOption
|
||||
FullName string
|
||||
PhoneNumber string
|
||||
// Payment Details for bank
|
||||
BankCode string
|
||||
BeneficiaryName string
|
||||
AccountName string
|
||||
AccountNumber string
|
||||
ReferenceNumber string
|
||||
Verified bool
|
||||
ApprovedBy ValidInt64
|
||||
ApproverName ValidString
|
||||
UpdatedAt time.Time
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type ShopTransactionFilter struct {
|
||||
CompanyID ValidInt64
|
||||
BranchID ValidInt64
|
||||
CashierID ValidInt64
|
||||
Query ValidString
|
||||
CreatedBefore ValidTime
|
||||
CreatedAfter ValidTime
|
||||
}
|
||||
type CreateShopTransaction struct {
|
||||
Amount Currency
|
||||
BranchID int64
|
||||
CashierID int64
|
||||
BetID int64
|
||||
NumberOfOutcomes int64
|
||||
Type ShopTransactionType
|
||||
PaymentOption PaymentOption
|
||||
FullName string
|
||||
PhoneNumber string
|
||||
BankCode string
|
||||
BeneficiaryName string
|
||||
AccountName string
|
||||
AccountNumber string
|
||||
ReferenceNumber string
|
||||
BranchName string
|
||||
BranchLocation string
|
||||
CompanyID int64
|
||||
CashierName string
|
||||
}
|
||||
155
internal/repository/shop_bet.go
Normal file
155
internal/repository/shop_bet.go
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func convertDBShopBet(bet dbgen.ShopBet) domain.ShopBet {
|
||||
return domain.ShopBet{
|
||||
ID: bet.ID,
|
||||
ShopTransactionID: bet.ShopTransactionID,
|
||||
CashoutID: bet.CashoutID,
|
||||
CashedOut: bet.CashedOut,
|
||||
BetID: bet.BetID,
|
||||
NumberOfOutcomes: bet.NumberOfOutcomes,
|
||||
}
|
||||
}
|
||||
|
||||
func convertDBShopBetDetail(bet dbgen.ShopBetDetail) domain.ShopBetDetail {
|
||||
var outcomes []domain.BetOutcome = make([]domain.BetOutcome, 0, len(bet.Outcomes))
|
||||
|
||||
for _, outcome := range bet.Outcomes {
|
||||
outcomes = append(outcomes, convertDBBetOutcomes(outcome))
|
||||
}
|
||||
return domain.ShopBetDetail{
|
||||
ID: bet.ID,
|
||||
ShopTransactionID: bet.ShopTransactionID,
|
||||
TotalOdds: bet.TotalOdds,
|
||||
BranchID: bet.BranchID,
|
||||
CompanyID: bet.CompanyID,
|
||||
FullName: bet.CustomerFullName,
|
||||
PhoneNumber: bet.CustomerPhoneNumber,
|
||||
CashoutID: bet.CashoutID,
|
||||
CashedOut: bet.CashedOut,
|
||||
BetID: bet.BetID,
|
||||
NumberOfOutcomes: bet.NumberOfOutcomes,
|
||||
Status: domain.OutcomeStatus(bet.Status),
|
||||
Amount: domain.Currency(bet.Amount),
|
||||
Outcomes: outcomes,
|
||||
TransactionVerified: bet.TransactionVerified,
|
||||
UpdatedAt: bet.UpdatedAt.Time,
|
||||
CreatedAt: bet.CreatedAt.Time,
|
||||
}
|
||||
}
|
||||
|
||||
func convertCreateShopBet(bet domain.CreateShopBet) dbgen.CreateShopBetParams {
|
||||
return dbgen.CreateShopBetParams{
|
||||
ShopTransactionID: bet.ShopTransactionID,
|
||||
CashoutID: bet.CashoutID,
|
||||
BetID: bet.BetID,
|
||||
NumberOfOutcomes: bet.NumberOfOutcomes,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) CreateShopBet(ctx context.Context, bet domain.CreateShopBet) (domain.ShopBet, error) {
|
||||
newShopBet, err := s.queries.CreateShopBet(ctx, convertCreateShopBet(bet))
|
||||
|
||||
if err != nil {
|
||||
return domain.ShopBet{}, err
|
||||
}
|
||||
|
||||
return convertDBShopBet(newShopBet), err
|
||||
}
|
||||
|
||||
func (s *Store) GetAllShopBet(ctx context.Context, filter domain.ShopBetFilter) ([]domain.ShopBetDetail, error) {
|
||||
bets, err := s.queries.GetAllShopBets(ctx, dbgen.GetAllShopBetsParams{
|
||||
BranchID: pgtype.Int8{
|
||||
Int64: filter.BranchID.Value,
|
||||
Valid: filter.BranchID.Valid,
|
||||
},
|
||||
CompanyID: pgtype.Int8{
|
||||
Int64: filter.CompanyID.Value,
|
||||
Valid: filter.CompanyID.Valid,
|
||||
},
|
||||
Query: pgtype.Text{
|
||||
String: filter.Query.Value,
|
||||
Valid: filter.Query.Valid,
|
||||
},
|
||||
CreatedBefore: pgtype.Timestamp{
|
||||
Time: filter.CreatedBefore.Value,
|
||||
Valid: filter.CreatedBefore.Valid,
|
||||
},
|
||||
CreatedAfter: pgtype.Timestamp{
|
||||
Time: filter.CreatedAfter.Value,
|
||||
Valid: filter.CreatedAfter.Valid,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []domain.ShopBetDetail = make([]domain.ShopBetDetail, 0, len(bets))
|
||||
for _, bet := range bets {
|
||||
result = append(result, convertDBShopBetDetail(bet))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetShopBetByID(ctx context.Context, id int64) (domain.ShopBetDetail, error) {
|
||||
bet, err := s.queries.GetShopBetByID(ctx, id)
|
||||
if err != nil {
|
||||
return domain.ShopBetDetail{}, err
|
||||
}
|
||||
return convertDBShopBetDetail(bet), nil
|
||||
}
|
||||
|
||||
func (s *Store) GetShopBetByBetID(ctx context.Context, betID int64) (domain.ShopBetDetail, error) {
|
||||
bet, err := s.queries.GetShopBetByBetID(ctx, betID)
|
||||
if err != nil {
|
||||
return domain.ShopBetDetail{}, err
|
||||
}
|
||||
return convertDBShopBetDetail(bet), nil
|
||||
}
|
||||
func (s *Store) GetShopBetByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopBetDetail, error) {
|
||||
bet, err := s.queries.GetShopBetByShopTransactionID(ctx, shopTransactionID)
|
||||
if err != nil {
|
||||
return domain.ShopBetDetail{}, err
|
||||
}
|
||||
return convertDBShopBetDetail(bet), nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateShopBetCashOut(ctx context.Context, id int64, cashedOut bool) error {
|
||||
err := s.queries.UpdateShopBetCashOut(ctx, dbgen.UpdateShopBetCashOutParams{
|
||||
ID: id,
|
||||
CashedOut: cashedOut,
|
||||
})
|
||||
if err != nil {
|
||||
domain.MongoDBLogger.Error("failed to update cashout",
|
||||
zap.Int64("id", id),
|
||||
zap.Bool("cashed_out", cashedOut),
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Store) UpdateShopBetCashoutID(ctx context.Context, id int64, cashoutID string) error {
|
||||
err := s.queries.UpdateShopBetCashoutID(ctx, dbgen.UpdateShopBetCashoutIDParams{
|
||||
ID: id,
|
||||
CashoutID: cashoutID,
|
||||
})
|
||||
if err != nil {
|
||||
domain.MongoDBLogger.Error("failed to update cashout_id",
|
||||
zap.Int64("id", id),
|
||||
zap.String("cashout_id", cashoutID),
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
return err
|
||||
}
|
||||
104
internal/repository/shop_deposit.go
Normal file
104
internal/repository/shop_deposit.go
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
func convertShopDeposit(deposit dbgen.ShopDeposit) domain.ShopDeposit {
|
||||
return domain.ShopDeposit{
|
||||
ID: deposit.ID,
|
||||
ShopTransactionID: deposit.ShopTransactionID,
|
||||
CustomerID: deposit.CustomerID,
|
||||
WalletTransferID: deposit.WalletTransferID,
|
||||
}
|
||||
}
|
||||
|
||||
func convertShopDepositDetail(deposit dbgen.ShopDepositDetail) domain.ShopDepositDetail {
|
||||
return domain.ShopDepositDetail{
|
||||
ID: deposit.ID,
|
||||
ShopTransactionID: deposit.ShopTransactionID,
|
||||
CustomerID: deposit.CustomerID,
|
||||
WalletTransferID: deposit.WalletTransferID,
|
||||
FullName: deposit.FullName,
|
||||
PhoneNumber: deposit.PhoneNumber,
|
||||
Amount: domain.Currency(deposit.Amount),
|
||||
BranchID: deposit.BranchID,
|
||||
CompanyID: deposit.CompanyID,
|
||||
TransactionVerified: deposit.TransactionVerified,
|
||||
UpdatedAt: deposit.UpdatedAt.Time,
|
||||
CreatedAt: deposit.CreatedAt.Time,
|
||||
}
|
||||
}
|
||||
func convertCreateShopDeposit(deposit domain.CreateShopDeposit) dbgen.CreateShopDepositParams {
|
||||
return dbgen.CreateShopDepositParams{
|
||||
ShopTransactionID: deposit.ShopTransactionID,
|
||||
CustomerID: deposit.CustomerID,
|
||||
WalletTransferID: deposit.WalletTransferID,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) CreateShopDeposit(ctx context.Context, deposit domain.CreateShopDeposit) (domain.ShopDeposit, error) {
|
||||
newShopDeposit, err := s.queries.CreateShopDeposit(ctx, convertCreateShopDeposit(deposit))
|
||||
|
||||
if err != nil {
|
||||
return domain.ShopDeposit{}, err
|
||||
}
|
||||
return convertShopDeposit(newShopDeposit), nil
|
||||
}
|
||||
|
||||
func (s *Store) GetAllShopDeposit(ctx context.Context, filter domain.ShopDepositFilter) ([]domain.ShopDepositDetail, error) {
|
||||
deposits, err := s.queries.GetAllShopDeposit(ctx, dbgen.GetAllShopDepositParams{
|
||||
BranchID: pgtype.Int8{
|
||||
Int64: filter.BranchID.Value,
|
||||
Valid: filter.BranchID.Valid,
|
||||
},
|
||||
CompanyID: pgtype.Int8{
|
||||
Int64: filter.CompanyID.Value,
|
||||
Valid: filter.CompanyID.Valid,
|
||||
},
|
||||
Query: pgtype.Text{
|
||||
String: filter.Query.Value,
|
||||
Valid: filter.Query.Valid,
|
||||
},
|
||||
CreatedBefore: pgtype.Timestamp{
|
||||
Time: filter.CreatedBefore.Value,
|
||||
Valid: filter.CreatedBefore.Valid,
|
||||
},
|
||||
CreatedAfter: pgtype.Timestamp{
|
||||
Time: filter.CreatedAfter.Value,
|
||||
Valid: filter.CreatedAfter.Valid,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []domain.ShopDepositDetail = make([]domain.ShopDepositDetail, 0, len(deposits))
|
||||
|
||||
for _, deposit := range deposits {
|
||||
result = append(result, convertShopDepositDetail(deposit))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetShopDepositByID(ctx context.Context, id int64) (domain.ShopDepositDetail, error) {
|
||||
deposit, err := s.queries.GetShopDepositByID(ctx, id)
|
||||
if err != nil {
|
||||
return domain.ShopDepositDetail{}, err
|
||||
}
|
||||
|
||||
return convertShopDepositDetail(deposit), err
|
||||
}
|
||||
|
||||
func (s *Store) GetShopDepositByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopDepositDetail, error) {
|
||||
deposit, err := s.queries.GetShopDepositByShopTransactionID(ctx, shopTransactionID)
|
||||
if err != nil {
|
||||
return domain.ShopDepositDetail{}, err
|
||||
}
|
||||
|
||||
return convertShopDepositDetail(deposit), err
|
||||
}
|
||||
|
|
@ -14,18 +14,31 @@ func convertDBShopTransaction(transaction dbgen.ShopTransaction) domain.ShopTran
|
|||
ID: transaction.ID,
|
||||
Amount: domain.Currency(transaction.Amount),
|
||||
BranchID: transaction.BranchID,
|
||||
CashierID: transaction.CashierID.Int64,
|
||||
BetID: transaction.BetID.Int64,
|
||||
NumberOfOutcomes: transaction.NumberOfOutcomes.Int64,
|
||||
Type: domain.ShopTransactionType(transaction.Type.Int64),
|
||||
PaymentOption: domain.PaymentOption(transaction.PaymentOption.Int64),
|
||||
FullName: transaction.FullName.String,
|
||||
PhoneNumber: transaction.PhoneNumber.String,
|
||||
BankCode: transaction.BankCode.String,
|
||||
BeneficiaryName: transaction.BeneficiaryName.String,
|
||||
AccountName: transaction.AccountName.String,
|
||||
AccountNumber: transaction.AccountNumber.String,
|
||||
ReferenceNumber: transaction.ReferenceNumber.String,
|
||||
UserID: transaction.UserID,
|
||||
Type: domain.ShopTransactionType(transaction.Type),
|
||||
PaymentOption: domain.PaymentOption(transaction.PaymentOption),
|
||||
FullName: transaction.FullName,
|
||||
PhoneNumber: transaction.PhoneNumber,
|
||||
BankCode: domain.ValidString{
|
||||
Value: transaction.BankCode.String,
|
||||
Valid: transaction.BankCode.Valid,
|
||||
},
|
||||
BeneficiaryName: domain.ValidString{
|
||||
Value: transaction.BeneficiaryName.String,
|
||||
Valid: transaction.BeneficiaryName.Valid,
|
||||
},
|
||||
AccountName: domain.ValidString{
|
||||
Value: transaction.AccountName.String,
|
||||
Valid: transaction.AccountName.Valid,
|
||||
},
|
||||
AccountNumber: domain.ValidString{
|
||||
Value: transaction.AccountName.String,
|
||||
Valid: transaction.AccountNumber.Valid,
|
||||
},
|
||||
ReferenceNumber: domain.ValidString{
|
||||
Value: transaction.ReferenceNumber.String,
|
||||
Valid: transaction.ReferenceNumber.Valid,
|
||||
},
|
||||
ApprovedBy: domain.ValidInt64{
|
||||
Value: transaction.ApprovedBy.Int64,
|
||||
Valid: transaction.ApprovedBy.Valid,
|
||||
|
|
@ -33,59 +46,105 @@ func convertDBShopTransaction(transaction dbgen.ShopTransaction) domain.ShopTran
|
|||
CreatedAt: transaction.CreatedAt.Time,
|
||||
UpdatedAt: transaction.UpdatedAt.Time,
|
||||
Verified: transaction.Verified,
|
||||
BranchName: transaction.BranchName.String,
|
||||
BranchLocation: transaction.BranchLocation.String,
|
||||
CashierName: transaction.CashierName.String,
|
||||
CompanyID: transaction.CompanyID.Int64,
|
||||
ApproverName: domain.ValidString{
|
||||
Value: transaction.ApproverName.String,
|
||||
Valid: transaction.ApprovedBy.Valid,
|
||||
},
|
||||
CompanyID: transaction.CompanyID,
|
||||
}
|
||||
}
|
||||
|
||||
func convertCreateTransaction(transaction domain.CreateShopTransaction) dbgen.CreateShopTransactionParams {
|
||||
func convertDBShopTransactionDetail(transaction dbgen.ShopTransactionDetail) domain.ShopTransactionDetail {
|
||||
return domain.ShopTransactionDetail{
|
||||
ID: transaction.ID,
|
||||
Amount: domain.Currency(transaction.Amount),
|
||||
BranchID: transaction.BranchID,
|
||||
UserID: transaction.UserID,
|
||||
CreatorFirstName: transaction.CreatorFirstName.String,
|
||||
CreatorLastName: transaction.CreatorLastName.String,
|
||||
CreatorPhoneNumber: transaction.CreatorPhoneNumber.String,
|
||||
Type: domain.ShopTransactionType(transaction.Type),
|
||||
PaymentOption: domain.PaymentOption(transaction.PaymentOption),
|
||||
FullName: transaction.FullName,
|
||||
PhoneNumber: transaction.PhoneNumber,
|
||||
BankCode: domain.ValidString{
|
||||
Value: transaction.BankCode.String,
|
||||
Valid: transaction.BankCode.Valid,
|
||||
},
|
||||
BeneficiaryName: domain.ValidString{
|
||||
Value: transaction.BeneficiaryName.String,
|
||||
Valid: transaction.BeneficiaryName.Valid,
|
||||
},
|
||||
AccountName: domain.ValidString{
|
||||
Value: transaction.AccountName.String,
|
||||
Valid: transaction.AccountName.Valid,
|
||||
},
|
||||
AccountNumber: domain.ValidString{
|
||||
Value: transaction.AccountName.String,
|
||||
Valid: transaction.AccountNumber.Valid,
|
||||
},
|
||||
ReferenceNumber: domain.ValidString{
|
||||
Value: transaction.ReferenceNumber.String,
|
||||
Valid: transaction.ReferenceNumber.Valid,
|
||||
},
|
||||
ApprovedBy: domain.ValidInt64{
|
||||
Value: transaction.ApprovedBy.Int64,
|
||||
Valid: transaction.ApprovedBy.Valid,
|
||||
},
|
||||
ApproverFirstName: domain.ValidString{
|
||||
Value: transaction.ApproverFirstName.String,
|
||||
Valid: transaction.ApproverFirstName.Valid,
|
||||
},
|
||||
ApproverLastName: domain.ValidString{
|
||||
Value: transaction.ApproverLastName.String,
|
||||
Valid: transaction.ApproverLastName.Valid,
|
||||
},
|
||||
ApproverPhoneNumber: domain.ValidString{
|
||||
Value: transaction.ApproverPhoneNumber.String,
|
||||
Valid: transaction.ApproverPhoneNumber.Valid,
|
||||
},
|
||||
CreatedAt: transaction.CreatedAt.Time,
|
||||
UpdatedAt: transaction.UpdatedAt.Time,
|
||||
Verified: transaction.Verified,
|
||||
CompanyID: transaction.CompanyID,
|
||||
BranchName: transaction.BranchName.String,
|
||||
BranchLocation: transaction.BranchLocation.String,
|
||||
}
|
||||
}
|
||||
|
||||
func convertCreateShopTransaction(transaction domain.CreateShopTransaction) dbgen.CreateShopTransactionParams {
|
||||
return dbgen.CreateShopTransactionParams{
|
||||
Amount: int64(transaction.Amount),
|
||||
BranchID: transaction.BranchID,
|
||||
CashierID: pgtype.Int8{Int64: transaction.CashierID, Valid: true},
|
||||
BetID: pgtype.Int8{Int64: transaction.BetID, Valid: true},
|
||||
Type: pgtype.Int8{Int64: int64(transaction.Type), Valid: true},
|
||||
PaymentOption: pgtype.Int8{Int64: int64(transaction.PaymentOption), Valid: true},
|
||||
FullName: pgtype.Text{String: transaction.FullName, Valid: transaction.FullName != ""},
|
||||
PhoneNumber: pgtype.Text{String: transaction.PhoneNumber, Valid: transaction.PhoneNumber != ""},
|
||||
BankCode: pgtype.Text{String: transaction.BankCode, Valid: transaction.BankCode != ""},
|
||||
BeneficiaryName: pgtype.Text{String: transaction.BeneficiaryName, Valid: transaction.BeneficiaryName != ""},
|
||||
AccountName: pgtype.Text{String: transaction.AccountName, Valid: transaction.AccountName != ""},
|
||||
AccountNumber: pgtype.Text{String: transaction.AccountNumber, Valid: transaction.AccountNumber != ""},
|
||||
ReferenceNumber: pgtype.Text{String: transaction.ReferenceNumber, Valid: transaction.ReferenceNumber != ""},
|
||||
NumberOfOutcomes: pgtype.Int8{Int64: transaction.NumberOfOutcomes, Valid: true},
|
||||
BranchName: pgtype.Text{String: transaction.BranchName, Valid: transaction.BranchName != ""},
|
||||
BranchLocation: pgtype.Text{String: transaction.BranchLocation, Valid: transaction.BranchLocation != ""},
|
||||
CashierName: pgtype.Text{String: transaction.CashierName, Valid: transaction.CashierName != ""},
|
||||
CompanyID: pgtype.Int8{Int64: transaction.CompanyID, Valid: true},
|
||||
UserID: transaction.UserID,
|
||||
Type: int64(transaction.Type),
|
||||
PaymentOption: int64(transaction.PaymentOption),
|
||||
FullName: transaction.FullName,
|
||||
PhoneNumber: transaction.PhoneNumber,
|
||||
CompanyID: transaction.CompanyID,
|
||||
BankCode: pgtype.Text{String: transaction.BankCode.Value, Valid: transaction.BankCode.Valid},
|
||||
BeneficiaryName: pgtype.Text{String: transaction.BeneficiaryName.Value, Valid: transaction.BeneficiaryName.Valid},
|
||||
AccountName: pgtype.Text{String: transaction.AccountName.Value, Valid: transaction.AccountName.Valid},
|
||||
AccountNumber: pgtype.Text{String: transaction.AccountNumber.Value, Valid: transaction.AccountNumber.Valid},
|
||||
ReferenceNumber: pgtype.Text{String: transaction.ReferenceNumber.Value, Valid: transaction.ReferenceNumber.Valid},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) CreateShopTransaction(ctx context.Context, transaction domain.CreateShopTransaction) (domain.ShopTransaction, error) {
|
||||
|
||||
newTransaction, err := s.queries.CreateShopTransaction(ctx, convertCreateTransaction(transaction))
|
||||
newTransaction, err := s.queries.CreateShopTransaction(ctx, convertCreateShopTransaction(transaction))
|
||||
if err != nil {
|
||||
return domain.ShopTransaction{}, err
|
||||
}
|
||||
return convertDBShopTransaction(newTransaction), err
|
||||
}
|
||||
|
||||
func (s *Store) GetShopTransactionByID(ctx context.Context, id int64) (domain.ShopTransaction, error) {
|
||||
func (s *Store) GetShopTransactionByID(ctx context.Context, id int64) (domain.ShopTransactionDetail, error) {
|
||||
transaction, err := s.queries.GetShopTransactionByID(ctx, id)
|
||||
if err != nil {
|
||||
return domain.ShopTransaction{}, err
|
||||
return domain.ShopTransactionDetail{}, err
|
||||
}
|
||||
|
||||
return convertDBShopTransaction(transaction), nil
|
||||
return convertDBShopTransactionDetail(transaction), nil
|
||||
}
|
||||
|
||||
func (s *Store) GetAllShopTransactions(ctx context.Context, filter domain.ShopTransactionFilter) ([]domain.ShopTransaction, error) {
|
||||
func (s *Store) GetAllShopTransactions(ctx context.Context, filter domain.ShopTransactionFilter) ([]domain.ShopTransactionDetail, error) {
|
||||
transaction, err := s.queries.GetAllShopTransactions(ctx, dbgen.GetAllShopTransactionsParams{
|
||||
BranchID: pgtype.Int8{
|
||||
Int64: filter.BranchID.Value,
|
||||
|
|
@ -95,9 +154,9 @@ func (s *Store) GetAllShopTransactions(ctx context.Context, filter domain.ShopTr
|
|||
Int64: filter.CompanyID.Value,
|
||||
Valid: filter.CompanyID.Valid,
|
||||
},
|
||||
CashierID: pgtype.Int8{
|
||||
Int64: filter.CashierID.Value,
|
||||
Valid: filter.CashierID.Valid,
|
||||
UserID: pgtype.Int8{
|
||||
Int64: filter.UserID.Value,
|
||||
Valid: filter.UserID.Valid,
|
||||
},
|
||||
Query: pgtype.Text{
|
||||
String: filter.Query.Value,
|
||||
|
|
@ -117,22 +176,22 @@ func (s *Store) GetAllShopTransactions(ctx context.Context, filter domain.ShopTr
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var result []domain.ShopTransaction = make([]domain.ShopTransaction, 0, len(transaction))
|
||||
for _, ticket := range transaction {
|
||||
result = append(result, convertDBShopTransaction(ticket))
|
||||
var result []domain.ShopTransactionDetail = make([]domain.ShopTransactionDetail, 0, len(transaction))
|
||||
for _, tAction := range transaction {
|
||||
result = append(result, convertDBShopTransactionDetail(tAction))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
func (s *Store) GetShopTransactionByBranch(ctx context.Context, id int64) ([]domain.ShopTransaction, error) {
|
||||
func (s *Store) GetShopTransactionByBranch(ctx context.Context, id int64) ([]domain.ShopTransactionDetail, error) {
|
||||
transaction, err := s.queries.GetShopTransactionByBranch(ctx, id)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []domain.ShopTransaction = make([]domain.ShopTransaction, 0, len(transaction))
|
||||
var result []domain.ShopTransactionDetail = make([]domain.ShopTransactionDetail, 0, len(transaction))
|
||||
for _, ticket := range transaction {
|
||||
result = append(result, convertDBShopTransaction(ticket))
|
||||
result = append(result, convertDBShopTransactionDetail(ticket))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
|
@ -145,14 +204,11 @@ func (s *Store) UpdateShopTransactionVerified(ctx context.Context, id int64, ver
|
|||
Valid: true,
|
||||
},
|
||||
Verified: verified,
|
||||
ApproverName: pgtype.Text{
|
||||
String: approverName,
|
||||
Valid: true,
|
||||
},
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
// GetTransactionTotals returns total deposits and withdrawals
|
||||
func (s *Store) GetTransactionTotals(ctx context.Context, filter domain.ReportFilter) (deposits, withdrawals domain.Currency, err error) {
|
||||
query := `SELECT
|
||||
|
|
@ -172,7 +228,7 @@ func (s *Store) GetTransactionTotals(ctx context.Context, filter domain.ReportFi
|
|||
args = append(args, filter.BranchID.Value)
|
||||
argPos++
|
||||
} else if filter.UserID.Valid {
|
||||
query += fmt.Sprintf(" WHERE cashier_id = $%d", argPos)
|
||||
query += fmt.Sprintf(" WHERE user_id = $%d", argPos)
|
||||
args = append(args, filter.UserID.Value)
|
||||
argPos++
|
||||
}
|
||||
|
|
@ -252,7 +252,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
|
|||
newBet := domain.CreateBet{
|
||||
Amount: domain.ToCurrency(req.Amount),
|
||||
TotalOdds: totalOdds,
|
||||
Status: req.Status,
|
||||
Status: domain.OUTCOME_STATUS_PENDING,
|
||||
FullName: req.FullName,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
CashoutID: cashoutID,
|
||||
|
|
|
|||
|
|
@ -8,11 +8,23 @@ import (
|
|||
|
||||
type TransactionStore interface {
|
||||
CreateShopTransaction(ctx context.Context, transaction domain.CreateShopTransaction) (domain.ShopTransaction, error)
|
||||
GetShopTransactionByID(ctx context.Context, id int64) (domain.ShopTransaction, error)
|
||||
GetAllShopTransactions(ctx context.Context, filter domain.ShopTransactionFilter) ([]domain.ShopTransaction, error)
|
||||
GetShopTransactionByBranch(ctx context.Context, id int64) ([]domain.ShopTransaction, error)
|
||||
GetAllShopTransactions(ctx context.Context, filter domain.ShopTransactionFilter) ([]domain.ShopTransactionDetail, error)
|
||||
GetShopTransactionByID(ctx context.Context, id int64) (domain.ShopTransactionDetail, error)
|
||||
GetShopTransactionByBranch(ctx context.Context, id int64) ([]domain.ShopTransactionDetail, error)
|
||||
UpdateShopTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64, approverName string) error
|
||||
|
||||
GetTransactionTotals(ctx context.Context, filter domain.ReportFilter) (deposits, withdrawals domain.Currency, err error)
|
||||
GetBranchTransactionTotals(ctx context.Context, filter domain.ReportFilter) (map[int64]domain.BranchTransactions, error)
|
||||
|
||||
CreateShopBet(ctx context.Context, bet domain.CreateShopBet) (domain.ShopBet, error)
|
||||
GetAllShopBet(ctx context.Context, filter domain.ShopBetFilter) ([]domain.ShopBetDetail, error)
|
||||
GetShopBetByID(ctx context.Context, id int64) (domain.ShopBetDetail, error)
|
||||
GetShopBetByBetID(ctx context.Context, betID int64) (domain.ShopBetDetail, error)
|
||||
GetShopBetByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopBetDetail, error)
|
||||
UpdateShopBetCashOut(ctx context.Context, id int64, cashedOut bool) error
|
||||
UpdateShopBetCashoutID(ctx context.Context, id int64, cashoutID string) error
|
||||
|
||||
CreateShopDeposit(ctx context.Context, deposit domain.CreateShopDeposit) (domain.ShopDeposit, error)
|
||||
GetAllShopDeposit(ctx context.Context, filter domain.ShopDepositFilter) ([]domain.ShopDepositDetail, error)
|
||||
GetShopDepositByID(ctx context.Context, id int64) (domain.ShopDepositDetail, error)
|
||||
GetShopDepositByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopDepositDetail, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,32 +2,91 @@ package transaction
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrBranchRequiredForRole = errors.New("branch_id is required to be passed for this role")
|
||||
ErrInvalidBranchID = errors.New("invalid branch id")
|
||||
ErrUnauthorizedCompanyID = errors.New("unauthorized company id")
|
||||
ErrUnauthorizedBranchManager = errors.New("unauthorized branch manager")
|
||||
ErrCustomerRoleNotAuthorized = errors.New("customer role not authorized")
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
transactionStore TransactionStore
|
||||
branchSvc branch.Service
|
||||
betSvc bet.Service
|
||||
walletSvc wallet.Service
|
||||
}
|
||||
|
||||
func NewService(transactionStore TransactionStore) *Service {
|
||||
func NewService(transactionStore TransactionStore, branchSvc branch.Service, betSvc bet.Service, walletSvc wallet.Service) *Service {
|
||||
return &Service{
|
||||
transactionStore: transactionStore,
|
||||
branchSvc: branchSvc,
|
||||
betSvc: betSvc,
|
||||
walletSvc: walletSvc,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) CreateShopTransaction(ctx context.Context, transaction domain.CreateShopTransaction) (domain.ShopTransaction, error) {
|
||||
return s.transactionStore.CreateShopTransaction(ctx, transaction)
|
||||
}
|
||||
func (s *Service) GetShopTransactionByID(ctx context.Context, id int64) (domain.ShopTransaction, error) {
|
||||
func (s *Service) GetShopTransactionByID(ctx context.Context, id int64) (domain.ShopTransactionDetail, error) {
|
||||
return s.transactionStore.GetShopTransactionByID(ctx, id)
|
||||
}
|
||||
func (s *Service) GetAllShopTransactions(ctx context.Context, filter domain.ShopTransactionFilter) ([]domain.ShopTransaction, error) {
|
||||
func (s *Service) GetAllShopTransactions(ctx context.Context, filter domain.ShopTransactionFilter) ([]domain.ShopTransactionDetail, error) {
|
||||
return s.transactionStore.GetAllShopTransactions(ctx, filter)
|
||||
}
|
||||
func (s *Service) GetShopTransactionByBranch(ctx context.Context, id int64) ([]domain.ShopTransaction, error) {
|
||||
func (s *Service) GetShopTransactionByBranch(ctx context.Context, id int64) ([]domain.ShopTransactionDetail, error) {
|
||||
return s.transactionStore.GetShopTransactionByBranch(ctx, id)
|
||||
}
|
||||
func (s *Service) UpdateShopTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64, approverName string) error {
|
||||
return s.transactionStore.UpdateShopTransactionVerified(ctx, id, verified, approvedBy, approverName)
|
||||
}
|
||||
|
||||
func (s *Service) GetBranchByRole(ctx context.Context, branchID *int64, role domain.Role, userID int64, userCompanyID domain.ValidInt64) (*int64, *int64, error) {
|
||||
// var branchID int64
|
||||
// var companyID int64
|
||||
|
||||
if role == domain.RoleAdmin || role == domain.RoleBranchManager || role == domain.RoleSuperAdmin {
|
||||
if branchID == nil {
|
||||
// h.logger.Error("CashoutReq Branch ID is required for this user role")
|
||||
return nil, nil, ErrBranchRequiredForRole
|
||||
}
|
||||
branch, err := s.branchSvc.GetBranchByID(ctx, *branchID)
|
||||
if err != nil {
|
||||
// h.logger.Error("CashoutReq no branches")
|
||||
return nil, nil, ErrInvalidBetID
|
||||
}
|
||||
|
||||
// Check if the user has access to the company
|
||||
if role != domain.RoleSuperAdmin {
|
||||
if !userCompanyID.Valid || userCompanyID.Value != branch.CompanyID {
|
||||
return nil, nil, ErrUnauthorizedCompanyID
|
||||
}
|
||||
}
|
||||
|
||||
if role == domain.RoleBranchManager {
|
||||
if branch.BranchManagerID != userID {
|
||||
return nil, nil, ErrUnauthorizedBranchManager
|
||||
}
|
||||
}
|
||||
|
||||
return &branch.ID, &branch.CompanyID, nil
|
||||
} else if role == domain.RoleCashier {
|
||||
branch, err := s.branchSvc.GetBranchByCashier(ctx, userID)
|
||||
if err != nil {
|
||||
// h.logger.Error("CashoutReq failed, branch id invalid")
|
||||
return nil, nil, ErrInvalidBranchID
|
||||
}
|
||||
return &branch.ID, &branch.CompanyID, nil
|
||||
} else {
|
||||
return nil, nil, ErrCustomerRoleNotAuthorized
|
||||
}
|
||||
}
|
||||
|
|
|
|||
207
internal/services/transaction/shop_bet.go
Normal file
207
internal/services/transaction/shop_bet.go
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidBetID = errors.New("invalid bet id")
|
||||
ErrUserHasNotWonBet = errors.New("user has not won bet")
|
||||
ErrUserHasAlreadyCashoutOut = errors.New("user has already cashout")
|
||||
ErrTransactionNotVerified = errors.New("transaction hasn't been verified")
|
||||
)
|
||||
|
||||
func (s *Service) GenerateCashoutID() (string, error) {
|
||||
const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
const length int = 13
|
||||
charLen := big.NewInt(int64(len(chars)))
|
||||
result := make([]byte, length)
|
||||
|
||||
for i := 0; i < length; i++ {
|
||||
index, err := rand.Int(rand.Reader, charLen)
|
||||
if err != nil {
|
||||
// s.mongoLogger.Error("failed to generate random index for cashout ID",
|
||||
// zap.Int("position", i),
|
||||
// zap.Error(err),
|
||||
// )
|
||||
return "", err
|
||||
}
|
||||
result[i] = chars[index.Int64()]
|
||||
}
|
||||
|
||||
return string(result), nil
|
||||
}
|
||||
|
||||
func (s *Service) CreateShopBet(ctx context.Context, userID int64, role domain.Role, userCompanyID domain.ValidInt64, req domain.ShopBetReq) (domain.ShopBet, error) {
|
||||
|
||||
branchID, companyID, err := s.GetBranchByRole(ctx, req.BranchID, role, userID, userCompanyID)
|
||||
|
||||
if err != nil {
|
||||
return domain.ShopBet{}, err
|
||||
}
|
||||
|
||||
cashoutID, err := s.GenerateCashoutID()
|
||||
|
||||
if err != nil {
|
||||
return domain.ShopBet{}, err
|
||||
}
|
||||
|
||||
newBet, err := s.betSvc.PlaceBet(ctx, domain.CreateBetReq{
|
||||
Outcomes: req.Outcomes,
|
||||
Amount: req.Amount,
|
||||
FullName: req.FullName,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
BranchID: branchID,
|
||||
}, userID, role)
|
||||
|
||||
if err != nil {
|
||||
return domain.ShopBet{}, err
|
||||
}
|
||||
|
||||
newTransaction, err := s.CreateShopTransaction(ctx, domain.CreateShopTransaction{
|
||||
Amount: domain.ToCurrency(req.Amount),
|
||||
BranchID: *branchID,
|
||||
CompanyID: *companyID,
|
||||
UserID: userID,
|
||||
Type: domain.TRANSACTION_BET,
|
||||
FullName: req.FullName,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
PaymentOption: req.PaymentOption,
|
||||
BankCode: domain.ValidString{
|
||||
Value: req.BankCode,
|
||||
Valid: req.BankCode != "",
|
||||
},
|
||||
BeneficiaryName: domain.ValidString{
|
||||
Value: req.BeneficiaryName,
|
||||
Valid: req.BeneficiaryName != "",
|
||||
},
|
||||
AccountName: domain.ValidString{
|
||||
Value: req.AccountName,
|
||||
Valid: req.AccountName != "",
|
||||
},
|
||||
AccountNumber: domain.ValidString{
|
||||
Value: req.AccountNumber,
|
||||
Valid: req.AccountNumber != "",
|
||||
},
|
||||
ReferenceNumber: domain.ValidString{
|
||||
Value: req.ReferenceNumber,
|
||||
Valid: req.ReferenceNumber != "",
|
||||
},
|
||||
Verified: false,
|
||||
ApprovedBy: domain.ValidInt64{
|
||||
Value: userID,
|
||||
Valid: true,
|
||||
},
|
||||
})
|
||||
|
||||
return s.transactionStore.CreateShopBet(ctx, domain.CreateShopBet{
|
||||
ShopTransactionID: newTransaction.ID,
|
||||
CashoutID: cashoutID,
|
||||
BetID: newBet.ID,
|
||||
NumberOfOutcomes: int64(len(req.Outcomes)),
|
||||
})
|
||||
}
|
||||
|
||||
// func (s *Service) CreateShopBet(ctx context.Context, bet domain.CreateShopBet) (domain.ShopBet, error) {
|
||||
// return s.transactionStore.CreateShopBet(ctx, bet)
|
||||
// }
|
||||
|
||||
func (s *Service) CashoutBet(ctx context.Context, betID int64, userID int64, role domain.Role, req domain.CashoutReq) (domain.ShopTransaction, error) {
|
||||
branchID, companyID, err := s.GetBranchByRole(ctx, req.BranchID, role, userID)
|
||||
|
||||
if err != nil {
|
||||
return domain.ShopTransaction{}, nil
|
||||
}
|
||||
|
||||
bet, err := s.GetShopBetByBetID(ctx, betID)
|
||||
if err != nil {
|
||||
// h.logger.Error("CashoutReq failed", "error", err)
|
||||
return domain.ShopTransaction{}, ErrInvalidBetID
|
||||
}
|
||||
|
||||
if bet.Status != domain.OUTCOME_STATUS_WIN {
|
||||
// h.logger.Error("CashoutReq failed, bet has not won")
|
||||
return domain.ShopTransaction{}, ErrUserHasNotWonBet
|
||||
}
|
||||
|
||||
if bet.CashedOut {
|
||||
// s.logger.Error(("Bet has already been cashed out"))
|
||||
return domain.ShopTransaction{}, ErrUserHasAlreadyCashoutOut
|
||||
}
|
||||
|
||||
if !bet.TransactionVerified {
|
||||
return domain.ShopTransaction{}, ErrTransactionNotVerified
|
||||
}
|
||||
|
||||
err = s.UpdateShopBetCashOut(ctx, bet.ID, true)
|
||||
|
||||
if err != nil {
|
||||
return domain.ShopTransaction{}, err
|
||||
}
|
||||
|
||||
return s.CreateShopTransaction(ctx, domain.CreateShopTransaction{
|
||||
Amount: bet.Amount,
|
||||
BranchID: *branchID,
|
||||
CompanyID: *companyID,
|
||||
UserID: userID,
|
||||
Type: domain.TRANSACTION_CASHOUT,
|
||||
FullName: bet.FullName,
|
||||
PhoneNumber: bet.PhoneNumber,
|
||||
PaymentOption: req.PaymentOption,
|
||||
BankCode: domain.ValidString{
|
||||
Value: req.BankCode,
|
||||
Valid: req.BankCode != "",
|
||||
},
|
||||
BeneficiaryName: domain.ValidString{
|
||||
Value: req.BeneficiaryName,
|
||||
Valid: req.BeneficiaryName != "",
|
||||
},
|
||||
AccountName: domain.ValidString{
|
||||
Value: req.AccountName,
|
||||
Valid: req.AccountName != "",
|
||||
},
|
||||
AccountNumber: domain.ValidString{
|
||||
Value: req.AccountNumber,
|
||||
Valid: req.AccountNumber != "",
|
||||
},
|
||||
ReferenceNumber: domain.ValidString{
|
||||
Value: req.ReferenceNumber,
|
||||
Valid: req.ReferenceNumber != "",
|
||||
},
|
||||
Verified: false,
|
||||
ApprovedBy: domain.ValidInt64{
|
||||
Value: userID,
|
||||
Valid: true,
|
||||
},
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func (s *Service) GetAllShopBet(ctx context.Context, filter domain.ShopBetFilter) ([]domain.ShopBetDetail, error) {
|
||||
return s.transactionStore.GetAllShopBet(ctx, filter)
|
||||
}
|
||||
|
||||
func (s *Service) GetShopBetByID(ctx context.Context, id int64) (domain.ShopBetDetail, error) {
|
||||
return s.transactionStore.GetShopBetByBetID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) GetShopBetByBetID(ctx context.Context, betID int64) (domain.ShopBetDetail, error) {
|
||||
return s.transactionStore.GetShopBetByBetID(ctx, betID)
|
||||
}
|
||||
|
||||
func (s *Service) GetShopBetByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopBetDetail, error) {
|
||||
return s.transactionStore.GetShopBetByShopTransactionID(ctx, shopTransactionID)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateShopBetCashOut(ctx context.Context, id int64, cashedOut bool) error {
|
||||
return s.transactionStore.UpdateShopBetCashOut(ctx, id, cashedOut)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateShopBetCashoutID(ctx context.Context, id int64, cashoutID string) error {
|
||||
return s.transactionStore.UpdateShopBetCashoutID(ctx, id, cashoutID)
|
||||
}
|
||||
114
internal/services/transaction/shop_deposit.go
Normal file
114
internal/services/transaction/shop_deposit.go
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
package transaction
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
)
|
||||
|
||||
func (s *Service) CreateShopDeposit(ctx context.Context, userID int64, role domain.Role, req domain.ShopDepositReq) (domain.ShopDeposit, error) {
|
||||
var branchID int64
|
||||
var companyID int64
|
||||
var senderID int64
|
||||
if role == domain.RoleAdmin || role == domain.RoleBranchManager || role == domain.RoleSuperAdmin {
|
||||
if req.BranchID == nil {
|
||||
// h.logger.Error("CashoutReq Branch ID is required for this user role")
|
||||
return domain.ShopDeposit{}, ErrBranchRequiredForRole
|
||||
}
|
||||
branch, err := s.branchSvc.GetBranchByID(ctx, *req.BranchID)
|
||||
if err != nil {
|
||||
// h.logger.Error("CashoutReq no branches")
|
||||
return domain.ShopDeposit{}, ErrInvalidBetID
|
||||
}
|
||||
|
||||
branchID = branch.ID
|
||||
companyID = branch.CompanyID
|
||||
senderID = branch.WalletID
|
||||
} else if role == domain.RoleCashier {
|
||||
branch, err := s.branchSvc.GetBranchByCashier(ctx, userID)
|
||||
if err != nil {
|
||||
// h.logger.Error("CashoutReq failed, branch id invalid")
|
||||
return domain.ShopDeposit{}, ErrInvalidBranchID
|
||||
}
|
||||
branchID = branch.ID
|
||||
companyID = branch.CompanyID
|
||||
senderID = branch.WalletID
|
||||
} else {
|
||||
return domain.ShopDeposit{}, ErrCustomerRoleNotAuthorized
|
||||
}
|
||||
|
||||
customerWallet, err := s.walletSvc.GetCustomerWallet(ctx, req.CustomerID)
|
||||
|
||||
if err != nil {
|
||||
return domain.ShopDeposit{}, err
|
||||
}
|
||||
|
||||
transfer, err := s.walletSvc.TransferToWallet(ctx,
|
||||
senderID, customerWallet.RegularID, domain.ToCurrency(req.Amount), domain.TRANSFER_DIRECT,
|
||||
domain.ValidInt64{Value: userID, Valid: true},
|
||||
fmt.Sprintf("Transferred %v from customer wallet deposit", req.Amount),
|
||||
)
|
||||
|
||||
newTransaction, err := s.CreateShopTransaction(ctx, domain.CreateShopTransaction{
|
||||
Amount: domain.Currency(req.Amount),
|
||||
BranchID: branchID,
|
||||
CompanyID: companyID,
|
||||
UserID: userID,
|
||||
Type: domain.TRANSACTION_DEPOSIT,
|
||||
FullName: req.FullName,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
PaymentOption: req.PaymentOption,
|
||||
BankCode: domain.ValidString{
|
||||
Value: req.BankCode,
|
||||
Valid: req.BankCode != "",
|
||||
},
|
||||
BeneficiaryName: domain.ValidString{
|
||||
Value: req.BeneficiaryName,
|
||||
Valid: req.BeneficiaryName != "",
|
||||
},
|
||||
AccountName: domain.ValidString{
|
||||
Value: req.AccountName,
|
||||
Valid: req.AccountName != "",
|
||||
},
|
||||
AccountNumber: domain.ValidString{
|
||||
Value: req.AccountNumber,
|
||||
Valid: req.AccountNumber != "",
|
||||
},
|
||||
ReferenceNumber: domain.ValidString{
|
||||
Value: req.ReferenceNumber,
|
||||
Valid: req.ReferenceNumber != "",
|
||||
},
|
||||
Verified: false,
|
||||
ApprovedBy: domain.ValidInt64{
|
||||
Value: userID,
|
||||
Valid: true,
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return domain.ShopDeposit{}, err
|
||||
}
|
||||
|
||||
return s.transactionStore.CreateShopDeposit(ctx, domain.CreateShopDeposit{
|
||||
ShopTransactionID: newTransaction.ID,
|
||||
CustomerID: req.CustomerID,
|
||||
WalletTransferID: transfer.ID,
|
||||
})
|
||||
}
|
||||
|
||||
// func (s *Service) CreateShopDeposit(ctx context.Context, deposit domain.CreateShopDeposit) (domain.ShopDeposit, error) {
|
||||
// return s.transactionStore.CreateShopDeposit(ctx, deposit)
|
||||
// }
|
||||
|
||||
func (s *Service) GetAllShopDeposit(ctx context.Context, filter domain.ShopDepositFilter) ([]domain.ShopDepositDetail, error) {
|
||||
return s.transactionStore.GetAllShopDeposit(ctx, filter)
|
||||
}
|
||||
|
||||
func (s *Service) GetShopDepositByID(ctx context.Context, id int64) (domain.ShopDepositDetail, error) {
|
||||
return s.transactionStore.GetShopDepositByID(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) GetShopDepositByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopDepositDetail, error) {
|
||||
return s.transactionStore.GetShopDepositByShopTransactionID(ctx, shopTransactionID)
|
||||
}
|
||||
|
|
@ -115,7 +115,9 @@ func (c *Client) ProcessBet(ctx context.Context, req domain.BetRequest) (*domain
|
|||
return &domain.BetResponse{}, err
|
||||
}
|
||||
|
||||
c.walletSvc.DeductFromWallet(ctx, wallets[0].ID, domain.Currency(req.Amount.Amount), domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT)
|
||||
c.walletSvc.DeductFromWallet(ctx, wallets[0].ID, domain.Currency(req.Amount.Amount), domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT,
|
||||
fmt.Sprintf("Deducting %v from wallet for creating Veli Game Bet", req.Amount.Amount),
|
||||
)
|
||||
|
||||
return &res, err
|
||||
}
|
||||
|
|
@ -156,7 +158,9 @@ func (c *Client) ProcessWin(ctx context.Context, req domain.WinRequest) (*domain
|
|||
return &domain.WinResponse{}, err
|
||||
}
|
||||
|
||||
c.walletSvc.AddToWallet(ctx, wallets[0].ID, domain.Currency(req.Amount.Amount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{})
|
||||
c.walletSvc.AddToWallet(ctx, wallets[0].ID, domain.Currency(req.Amount.Amount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
|
||||
fmt.Sprintf("Adding %v to wallet due to winning Veli Games bet", req.Amount),
|
||||
)
|
||||
|
||||
return &res, err
|
||||
}
|
||||
|
|
@ -199,7 +203,9 @@ func (c *Client) ProcessCancel(ctx context.Context, req domain.CancelRequest) (*
|
|||
return &domain.CancelResponse{}, err
|
||||
}
|
||||
|
||||
c.walletSvc.AddToWallet(ctx, wallets[0].ID, domain.Currency(req.AdjustmentRefund.Amount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{})
|
||||
c.walletSvc.AddToWallet(ctx, wallets[0].ID, domain.Currency(req.AdjustmentRefund.Amount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
|
||||
fmt.Sprintf("Adding %v to wallet due to cancelling virtual game bet", req.AdjustmentRefund.Amount),
|
||||
)
|
||||
return &res, err
|
||||
}
|
||||
|
||||
|
|
|
|||
303
internal/web_server/handlers/shop_handler.go
Normal file
303
internal/web_server/handlers/shop_handler.go
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// CreateShopBet godoc
|
||||
// @Summary Create bet at branch
|
||||
// @Description Create bet at branch
|
||||
// @Tags transaction
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param createBet body domain.ShopBetReq true "create bet"
|
||||
// @Success 200 {object} TransactionRes
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /shop/bet [post]
|
||||
func (h *Handler) CreateShopBet(c *fiber.Ctx) error {
|
||||
|
||||
userID := c.Locals("user_id").(int64)
|
||||
role := c.Locals("role").(domain.Role)
|
||||
company_id := c.Locals("company_id").(domain.ValidInt64)
|
||||
|
||||
var req domain.ShopBetReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
h.logger.Error("CreateBetReq failed to parse request", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||
}
|
||||
|
||||
valErrs, ok := h.validator.Validate(c, req)
|
||||
if !ok {
|
||||
h.logger.Error("CreateBetReq failed v", "error", valErrs)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||
}
|
||||
|
||||
shopBet, err := h.transactionSvc.CreateShopBet(c.Context(), userID, role, company_id, req)
|
||||
|
||||
if err != nil {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to cashout bet", err, nil)
|
||||
}
|
||||
res := domain.ConvertShopBet(shopBet)
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Transaction created successfully", res, nil)
|
||||
}
|
||||
|
||||
// CashoutBet godoc
|
||||
// @Summary Cashout bet at branch
|
||||
// @Description Cashout bet at branch
|
||||
// @Tags transaction
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param createBet body domain.CashoutReq true "cashout bet"
|
||||
// @Success 200 {object} TransactionRes
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /shop/bet/{id}/cashout [post]
|
||||
func (h *Handler) CashoutBet(c *fiber.Ctx) error {
|
||||
|
||||
betIDStr := c.Params("id")
|
||||
|
||||
betID, err := strconv.ParseInt(betIDStr, 10, 64)
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error("CashoutReq invalid bet id", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid bet id", err, nil)
|
||||
}
|
||||
|
||||
userID := c.Locals("user_id").(int64)
|
||||
role := c.Locals("role").(domain.Role)
|
||||
|
||||
var req domain.CashoutReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
h.logger.Error("CashoutReq failed to parse request", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||
}
|
||||
|
||||
valErrs, ok := h.validator.Validate(c, req)
|
||||
if !ok {
|
||||
h.logger.Error("CashoutReq failed v", "error", valErrs)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||
}
|
||||
|
||||
transaction, err := h.transactionSvc.CashoutBet(c.Context(), betID, userID, role, req)
|
||||
|
||||
if err != nil {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to cashout bet", err, nil)
|
||||
}
|
||||
res := domain.ConvertShopTransaction(transaction)
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Transaction created successfully", res, nil)
|
||||
}
|
||||
|
||||
// DepositForCustomer godoc
|
||||
// @Summary Shop deposit into customer wallet
|
||||
// @Description Transfers money from branch wallet to customer wallet
|
||||
// @Tags transaction
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param transferToWallet body domain.ShopDepositReq true "ShopDepositReq"
|
||||
// @Success 200 {object} TransferWalletRes
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /shop/deposit [post]
|
||||
func (h *Handler) DepositForCustomer(c *fiber.Ctx) error {
|
||||
|
||||
// Get sender ID from the cashier
|
||||
userID := c.Locals("user_id").(int64)
|
||||
role := c.Locals("role").(domain.Role)
|
||||
|
||||
var req domain.ShopDepositReq
|
||||
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
h.logger.Error("CreateTransferReq failed", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||
}
|
||||
|
||||
valErrs, ok := h.validator.Validate(c, req)
|
||||
if !ok {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||
}
|
||||
|
||||
deposit, err := h.transactionSvc.CreateShopDeposit(c.Context(), userID, role, req)
|
||||
|
||||
if err != nil {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to create shop deposit", err, nil)
|
||||
}
|
||||
|
||||
res := domain.ConvertShopDeposit(deposit)
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Transfer Successful", res, nil)
|
||||
|
||||
}
|
||||
|
||||
// GetAllTransactions godoc
|
||||
// @Summary Gets all transactions
|
||||
// @Description Gets all the transactions
|
||||
// @Tags transaction
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {array} TransactionRes
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /shop/transaction [get]
|
||||
func (h *Handler) GetAllTransactions(c *fiber.Ctx) error {
|
||||
// Get user_id from middleware
|
||||
// userID := c.Locals("user_id").(int64)
|
||||
// role := c.Locals("role").(domain.Role)
|
||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||
branchID := c.Locals("branch_id").(domain.ValidInt64)
|
||||
|
||||
searchQuery := c.Query("query")
|
||||
searchString := domain.ValidString{
|
||||
Value: searchQuery,
|
||||
Valid: searchQuery != "",
|
||||
}
|
||||
|
||||
createdBeforeQuery := c.Query("created_before")
|
||||
var createdBefore domain.ValidTime
|
||||
if createdBeforeQuery != "" {
|
||||
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
|
||||
if err != nil {
|
||||
h.logger.Error("invalid start_time format", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
|
||||
}
|
||||
createdBefore = domain.ValidTime{
|
||||
Value: createdBeforeParsed,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
createdAfterQuery := c.Query("created_after")
|
||||
var createdAfter domain.ValidTime
|
||||
if createdAfterQuery != "" {
|
||||
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
|
||||
if err != nil {
|
||||
h.logger.Error("invalid start_time format", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
|
||||
}
|
||||
createdAfter = domain.ValidTime{
|
||||
Value: createdAfterParsed,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Check user role and fetch transactions accordingly
|
||||
transactions, err := h.transactionSvc.GetAllShopTransactions(c.Context(), domain.ShopTransactionFilter{
|
||||
CompanyID: companyID,
|
||||
BranchID: branchID,
|
||||
Query: searchString,
|
||||
CreatedBefore: createdBefore,
|
||||
CreatedAfter: createdAfter,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get transactions", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve transactions", err, nil)
|
||||
}
|
||||
|
||||
res := make([]domain.ShopTransactionRes, len(transactions))
|
||||
for i, transaction := range transactions {
|
||||
res[i] = domain.ConvertShopTransactionDetail(transaction)
|
||||
}
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Transactions retrieved successfully", res, nil)
|
||||
|
||||
}
|
||||
|
||||
// GetTransactionByID godoc
|
||||
// @Summary Gets transaction by id
|
||||
// @Description Gets a single transaction by id
|
||||
// @Tags transaction
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "Transaction ID"
|
||||
// @Success 200 {object} TransactionRes
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /shop/transaction/{id} [get]
|
||||
func (h *Handler) GetTransactionByID(c *fiber.Ctx) error {
|
||||
transactionID := c.Params("id")
|
||||
id, err := strconv.ParseInt(transactionID, 10, 64)
|
||||
if err != nil {
|
||||
h.logger.Error("Invalid transaction ID", "transactionID", transactionID, "error", err)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid transaction ID")
|
||||
}
|
||||
|
||||
transaction, err := h.transactionSvc.GetShopTransactionByID(c.Context(), id)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get transaction by ID", "transactionID", id, "error", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve transaction")
|
||||
}
|
||||
|
||||
res := domain.ConvertShopTransactionDetail(transaction)
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Transaction retrieved successfully", res, nil)
|
||||
}
|
||||
|
||||
type UpdateTransactionVerifiedReq struct {
|
||||
Verified bool `json:"verified" example:"true"`
|
||||
}
|
||||
|
||||
// UpdateTransactionVerified godoc
|
||||
// @Summary Updates the verified field of a transaction
|
||||
// @Description Updates the verified status of a transaction
|
||||
// @Tags transaction
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "Transaction ID"
|
||||
// @Param updateVerified body UpdateTransactionVerifiedReq true "Updates Transaction Verification"
|
||||
// @Success 200 {object} response.APIResponse
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /shop/transaction/{id} [put]
|
||||
func (h *Handler) UpdateTransactionVerified(c *fiber.Ctx) error {
|
||||
transactionID := c.Params("id")
|
||||
userID := c.Locals("user_id").(int64)
|
||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||
role := c.Locals("role").(domain.Role)
|
||||
|
||||
id, err := strconv.ParseInt(transactionID, 10, 64)
|
||||
if err != nil {
|
||||
h.logger.Error("Invalid transaction ID", "transactionID", transactionID, "error", err)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid transaction ID")
|
||||
}
|
||||
|
||||
var req UpdateTransactionVerifiedReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
h.logger.Error("Failed to parse UpdateTransactionVerified request", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||
}
|
||||
|
||||
h.logger.Info("Update Transaction Verified", slog.Bool("verified", req.Verified))
|
||||
|
||||
if valErrs, ok := h.validator.Validate(c, req); !ok {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||
}
|
||||
|
||||
transaction, err := h.transactionSvc.GetShopTransactionByID(c.Context(), id)
|
||||
if role != domain.RoleSuperAdmin {
|
||||
if !companyID.Valid || companyID.Value != transaction.CompanyID {
|
||||
h.logger.Error("Failed to parse UpdateTransactionVerified request", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
user, err := h.userSvc.GetUserById(c.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("Invalid user ID", "userID", userID, "error", err)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid user ID")
|
||||
}
|
||||
err = h.transactionSvc.UpdateShopTransactionVerified(c.Context(), id, req.Verified, userID, user.FirstName+" "+user.LastName)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to update transaction verification", "transactionID", id, "error", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update transaction verification")
|
||||
}
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Transaction updated successfully", nil, nil)
|
||||
}
|
||||
|
|
@ -1,498 +0,0 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type ShopTransactionRes struct {
|
||||
ID int64 `json:"id" example:"1"`
|
||||
Amount float32 `json:"amount" example:"100.0"`
|
||||
BranchID int64 `json:"branch_id" example:"1"`
|
||||
BranchName string `json:"branch_name" example:"Branch Name"`
|
||||
BranchLocation string `json:"branch_location" example:"Branch Location"`
|
||||
CompanyID int64 `json:"company_id" example:"1"`
|
||||
CashierID int64 `json:"cashier_id" example:"1"`
|
||||
CashierName string `json:"cashier_name" example:"John Smith"`
|
||||
BetID int64 `json:"bet_id" example:"1"`
|
||||
NumberOfOutcomes int64 `json:"number_of_outcomes" example:"1"`
|
||||
Type int64 `json:"type" example:"1"`
|
||||
PaymentOption domain.PaymentOption `json:"payment_option" example:"1"`
|
||||
FullName string `json:"full_name" example:"John Smith"`
|
||||
PhoneNumber string `json:"phone_number" example:"0911111111"`
|
||||
BankCode string `json:"bank_code"`
|
||||
BeneficiaryName string `json:"beneficiary_name"`
|
||||
AccountName string `json:"account_name"`
|
||||
AccountNumber string `json:"account_number"`
|
||||
ReferenceNumber string `json:"reference_number"`
|
||||
Verified bool `json:"verified" example:"true"`
|
||||
ApprovedBy *int64 `json:"approved_by" example:"1"`
|
||||
ApproverName *string `json:"approver_name" example:"John Smith"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type CashoutReq struct {
|
||||
CashoutID string `json:"cashout_id" example:"191212"`
|
||||
Amount float32 `json:"amount" example:"100.0"`
|
||||
BetID int64 `json:"bet_id" example:"1"`
|
||||
Type int64 `json:"type" example:"1"`
|
||||
PaymentOption domain.PaymentOption `json:"payment_option" example:"1"`
|
||||
FullName string `json:"full_name" example:"John Smith"`
|
||||
PhoneNumber string `json:"phone_number" example:"0911111111"`
|
||||
BankCode string `json:"bank_code"`
|
||||
BeneficiaryName string `json:"beneficiary_name"`
|
||||
AccountName string `json:"account_name"`
|
||||
AccountNumber string `json:"account_number"`
|
||||
ReferenceNumber string `json:"reference_number"`
|
||||
BranchID *int64 `json:"branch_id,omitempty" example:"1"`
|
||||
}
|
||||
|
||||
func convertShopTransaction(transaction domain.ShopTransaction) ShopTransactionRes {
|
||||
newTransaction := ShopTransactionRes{
|
||||
ID: transaction.ID,
|
||||
Amount: transaction.Amount.Float32(),
|
||||
BranchID: transaction.BranchID,
|
||||
BranchName: transaction.BranchName,
|
||||
BranchLocation: transaction.BranchLocation,
|
||||
CompanyID: transaction.CompanyID,
|
||||
CashierID: transaction.CashierID,
|
||||
CashierName: transaction.CashierName,
|
||||
BetID: transaction.BetID,
|
||||
Type: int64(transaction.Type),
|
||||
PaymentOption: transaction.PaymentOption,
|
||||
FullName: transaction.FullName,
|
||||
PhoneNumber: transaction.PhoneNumber,
|
||||
BankCode: transaction.BankCode,
|
||||
BeneficiaryName: transaction.BeneficiaryName,
|
||||
AccountName: transaction.AccountName,
|
||||
AccountNumber: transaction.AccountNumber,
|
||||
ReferenceNumber: transaction.ReferenceNumber,
|
||||
Verified: transaction.Verified,
|
||||
NumberOfOutcomes: transaction.NumberOfOutcomes,
|
||||
CreatedAt: transaction.CreatedAt,
|
||||
UpdatedAt: transaction.UpdatedAt,
|
||||
}
|
||||
|
||||
if transaction.ApprovedBy.Valid {
|
||||
newTransaction.ApprovedBy = &transaction.ApprovedBy.Value
|
||||
newTransaction.ApproverName = &transaction.ApproverName.Value
|
||||
|
||||
}
|
||||
|
||||
return newTransaction
|
||||
}
|
||||
|
||||
// CashoutBet godoc
|
||||
// @Summary Cashout bet at branch
|
||||
// @Description Cashout bet at branch
|
||||
// @Tags transaction
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param createBet body CashoutReq true "cashout bet"
|
||||
// @Success 200 {object} TransactionRes
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /shop/cashout [post]
|
||||
func (h *Handler) CashoutBet(c *fiber.Ctx) error {
|
||||
userID := c.Locals("user_id").(int64)
|
||||
role := c.Locals("role").(domain.Role)
|
||||
// user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
||||
|
||||
// TODO: Make a "Only Company" middleware auth and move this into that
|
||||
if role == domain.RoleCustomer {
|
||||
h.logger.Error("CashoutReq failed due to unauthorized access")
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||
"error": "unauthorized access",
|
||||
})
|
||||
}
|
||||
|
||||
var req CashoutReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
h.logger.Error("CashoutReq failed to parse request", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||
}
|
||||
|
||||
valErrs, ok := h.validator.Validate(c, req)
|
||||
if !ok {
|
||||
h.logger.Error("CashoutReq failed v", "error", valErrs)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||
}
|
||||
|
||||
var branchID int64
|
||||
var branchName string
|
||||
var branchLocation string
|
||||
var companyID int64
|
||||
if role == domain.RoleAdmin || role == domain.RoleBranchManager || role == domain.RoleSuperAdmin {
|
||||
if req.BranchID == nil {
|
||||
h.logger.Error("CashoutReq Branch ID is required for this user role")
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Branch ID is required for this user role", nil, nil)
|
||||
}
|
||||
branch, err := h.branchSvc.GetBranchByID(c.Context(), *req.BranchID)
|
||||
if err != nil {
|
||||
h.logger.Error("CashoutReq no branches")
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "cannot find Branch ID", err, nil)
|
||||
}
|
||||
|
||||
branchID = branch.ID
|
||||
branchName = branch.Name
|
||||
branchLocation = branch.Location
|
||||
companyID = branch.CompanyID
|
||||
} else {
|
||||
branch, err := h.branchSvc.GetBranchByCashier(c.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("CashoutReq failed, branch id invalid")
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Branch ID invalid", err, nil)
|
||||
}
|
||||
branchID = branch.ID
|
||||
branchName = branch.Name
|
||||
branchLocation = branch.Location
|
||||
companyID = branch.CompanyID
|
||||
}
|
||||
|
||||
bet, err := h.betSvc.GetBetByID(c.Context(), req.BetID)
|
||||
if err != nil {
|
||||
h.logger.Error("CashoutReq failed", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Bet ID invalid", err, nil)
|
||||
}
|
||||
|
||||
// if bet.Status != domain.OUTCOME_STATUS_WIN {
|
||||
// h.logger.Error("CashoutReq failed, bet has not won")
|
||||
// return response.WriteJSON(c, fiber.StatusBadRequest, "User has not won bet", err, nil)
|
||||
// }
|
||||
|
||||
if bet.CashedOut {
|
||||
h.logger.Error(("Bet has already been cashed out"))
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "This bet has already been cashed out", err, nil)
|
||||
}
|
||||
|
||||
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("CashoutReq failed, user id invalid", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "User ID invalid", err, nil)
|
||||
}
|
||||
transaction, err := h.transactionSvc.CreateShopTransaction(c.Context(), domain.CreateShopTransaction{
|
||||
BranchID: branchID,
|
||||
CashierID: userID,
|
||||
Amount: domain.ToCurrency(req.Amount),
|
||||
BetID: bet.ID,
|
||||
NumberOfOutcomes: int64(len(bet.Outcomes)),
|
||||
Type: domain.ShopTransactionType(req.Type),
|
||||
PaymentOption: domain.PaymentOption(req.PaymentOption),
|
||||
FullName: req.FullName,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
BankCode: req.BankCode,
|
||||
BeneficiaryName: req.BeneficiaryName,
|
||||
AccountName: req.AccountName,
|
||||
AccountNumber: req.AccountNumber,
|
||||
ReferenceNumber: req.ReferenceNumber,
|
||||
CashierName: user.FirstName + " " + user.LastName,
|
||||
BranchName: branchName,
|
||||
BranchLocation: branchLocation,
|
||||
CompanyID: companyID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error("CashoutReq failed", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Internal Server Error", err, nil)
|
||||
}
|
||||
|
||||
err = h.betSvc.UpdateCashOut(c.Context(), req.BetID, true)
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error("CashoutReq failed", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Internal Server Error", err, nil)
|
||||
}
|
||||
|
||||
res := convertShopTransaction(transaction)
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Transaction created successfully", res, nil)
|
||||
}
|
||||
|
||||
type DepositForCustomerReq struct {
|
||||
Amount float32 `json:"amount" example:"100.0"`
|
||||
PaymentMethod string `json:"payment_method" example:"cash"`
|
||||
BankCode string `json:"bank_code"`
|
||||
BeneficiaryName string `json:"beneficiary_name"`
|
||||
AccountName string `json:"account_name"`
|
||||
AccountNumber string `json:"account_number"`
|
||||
ReferenceNumber string `json:"reference_number"`
|
||||
BranchID *int64 `json:"branch_id,omitempty" example:"1"`
|
||||
}
|
||||
|
||||
// DepositForCustomer godoc
|
||||
// @Summary Shop deposit into customer wallet
|
||||
// @Description Transfers money from branch wallet to customer wallet
|
||||
// @Tags transaction
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param transferToWallet body DepositForCustomerReq true "DepositForCustomer"
|
||||
// @Success 200 {object} TransferWalletRes
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /shop/deposit/:id [post]
|
||||
|
||||
func (h *Handler) DepositForCustomer(c *fiber.Ctx) error {
|
||||
customerIDString := c.Params("id")
|
||||
customerID, err := strconv.ParseInt(customerIDString, 10, 64)
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error("Invalid customer ID", "customerID", customerID, "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil)
|
||||
}
|
||||
|
||||
// Get sender ID from the cashier
|
||||
userID := c.Locals("user_id").(int64)
|
||||
role := c.Locals("role").(domain.Role)
|
||||
|
||||
var req DepositForCustomerReq
|
||||
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
h.logger.Error("CreateTransferReq failed", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||
}
|
||||
|
||||
valErrs, ok := h.validator.Validate(c, req)
|
||||
if !ok {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||
}
|
||||
var senderID int64
|
||||
switch role {
|
||||
case domain.RoleCustomer:
|
||||
h.logger.Error("Unauthorized access", "userID", userID, "role", role)
|
||||
return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
|
||||
case domain.RoleAdmin, domain.RoleSuperAdmin, domain.RoleBranchManager:
|
||||
if req.BranchID == nil {
|
||||
h.logger.Error("CashoutReq Branch ID is required for this user role")
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Branch ID is required for this user role", nil, nil)
|
||||
}
|
||||
branch, err := h.branchSvc.GetBranchByID(c.Context(), *req.BranchID)
|
||||
if err != nil {
|
||||
h.logger.Error("CashoutReq no branches")
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "cannot find Branch ID", err, nil)
|
||||
}
|
||||
|
||||
senderID = branch.WalletID
|
||||
case domain.RoleCashier:
|
||||
cashierBranch, err := h.branchSvc.GetBranchByCashier(c.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get branch", "user ID", userID, "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve cashier branch", err, nil)
|
||||
}
|
||||
senderID = cashierBranch.WalletID
|
||||
default:
|
||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Unknown Role", err, nil)
|
||||
}
|
||||
|
||||
customerWallet, err := h.walletSvc.GetCustomerWallet(c.Context(), customerID)
|
||||
|
||||
if err != nil {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid customer id", err, nil)
|
||||
}
|
||||
|
||||
transfer, err := h.walletSvc.TransferToWallet(c.Context(),
|
||||
senderID, customerWallet.RegularID, domain.ToCurrency(req.Amount), domain.PaymentMethod(req.PaymentMethod),
|
||||
domain.ValidInt64{Value: userID, Valid: true},
|
||||
fmt.Sprintf("Transferred %v from wallet to customer wallet", req.Amount),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
h.mongoLoggerSvc.Error("Failed to transfer money to wallet", zap.Error(err))
|
||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Transfer Failed", err, nil)
|
||||
}
|
||||
|
||||
transaction, err := h.transactionSvc.CreateShopTransaction(c.Context(), domain.CreateShopTransaction{
|
||||
BranchID: branchID,
|
||||
CashierID: userID,
|
||||
Amount: domain.ToCurrency(req.Amount),
|
||||
Type: domain.TRANSACTION_DEPOSIT,
|
||||
PaymentOption: domain.PaymentOption(req.PaymentOption),
|
||||
FullName: req.FullName,
|
||||
PhoneNumber: req.PhoneNumber,
|
||||
BankCode: req.BankCode,
|
||||
BeneficiaryName: req.BeneficiaryName,
|
||||
AccountName: req.AccountName,
|
||||
AccountNumber: req.AccountNumber,
|
||||
ReferenceNumber: req.ReferenceNumber,
|
||||
CashierName: user.FirstName + " " + user.LastName,
|
||||
BranchName: branchName,
|
||||
BranchLocation: branchLocation,
|
||||
CompanyID: companyID,
|
||||
})
|
||||
|
||||
res := convertTransfer(transfer)
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Transfer Successful", res, nil)
|
||||
|
||||
}
|
||||
|
||||
// GetAllTransactions godoc
|
||||
// @Summary Gets all transactions
|
||||
// @Description Gets all the transactions
|
||||
// @Tags transaction
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {array} TransactionRes
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /shop/transaction [get]
|
||||
func (h *Handler) GetAllTransactions(c *fiber.Ctx) error {
|
||||
// Get user_id from middleware
|
||||
// userID := c.Locals("user_id").(int64)
|
||||
// role := c.Locals("role").(domain.Role)
|
||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||
branchID := c.Locals("branch_id").(domain.ValidInt64)
|
||||
|
||||
searchQuery := c.Query("query")
|
||||
searchString := domain.ValidString{
|
||||
Value: searchQuery,
|
||||
Valid: searchQuery != "",
|
||||
}
|
||||
|
||||
createdBeforeQuery := c.Query("created_before")
|
||||
var createdBefore domain.ValidTime
|
||||
if createdBeforeQuery != "" {
|
||||
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
|
||||
if err != nil {
|
||||
h.logger.Error("invalid start_time format", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
|
||||
}
|
||||
createdBefore = domain.ValidTime{
|
||||
Value: createdBeforeParsed,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
createdAfterQuery := c.Query("created_after")
|
||||
var createdAfter domain.ValidTime
|
||||
if createdAfterQuery != "" {
|
||||
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
|
||||
if err != nil {
|
||||
h.logger.Error("invalid start_time format", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
|
||||
}
|
||||
createdAfter = domain.ValidTime{
|
||||
Value: createdAfterParsed,
|
||||
Valid: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Check user role and fetch transactions accordingly
|
||||
transactions, err := h.transactionSvc.GetAllShopTransactions(c.Context(), domain.ShopTransactionFilter{
|
||||
CompanyID: companyID,
|
||||
BranchID: branchID,
|
||||
Query: searchString,
|
||||
CreatedBefore: createdBefore,
|
||||
CreatedAfter: createdAfter,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get transactions", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve transactions", err, nil)
|
||||
}
|
||||
|
||||
res := make([]ShopTransactionRes, len(transactions))
|
||||
for i, transaction := range transactions {
|
||||
res[i] = convertShopTransaction(transaction)
|
||||
}
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Transactions retrieved successfully", res, nil)
|
||||
|
||||
}
|
||||
|
||||
// GetTransactionByID godoc
|
||||
// @Summary Gets transaction by id
|
||||
// @Description Gets a single transaction by id
|
||||
// @Tags transaction
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "Transaction ID"
|
||||
// @Success 200 {object} TransactionRes
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /shop/transaction/{id} [get]
|
||||
func (h *Handler) GetTransactionByID(c *fiber.Ctx) error {
|
||||
transactionID := c.Params("id")
|
||||
id, err := strconv.ParseInt(transactionID, 10, 64)
|
||||
if err != nil {
|
||||
h.logger.Error("Invalid transaction ID", "transactionID", transactionID, "error", err)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid transaction ID")
|
||||
}
|
||||
|
||||
transaction, err := h.transactionSvc.GetShopTransactionByID(c.Context(), id)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get transaction by ID", "transactionID", id, "error", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve transaction")
|
||||
}
|
||||
|
||||
res := convertShopTransaction(transaction)
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Transaction retrieved successfully", res, nil)
|
||||
}
|
||||
|
||||
type UpdateTransactionVerifiedReq struct {
|
||||
Verified bool `json:"verified" example:"true"`
|
||||
}
|
||||
|
||||
// UpdateTransactionVerified godoc
|
||||
// @Summary Updates the verified field of a transaction
|
||||
// @Description Updates the verified status of a transaction
|
||||
// @Tags transaction
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "Transaction ID"
|
||||
// @Param updateVerified body UpdateTransactionVerifiedReq true "Updates Transaction Verification"
|
||||
// @Success 200 {object} response.APIResponse
|
||||
// @Failure 400 {object} response.APIResponse
|
||||
// @Failure 500 {object} response.APIResponse
|
||||
// @Router /shop/transaction/{id} [put]
|
||||
func (h *Handler) UpdateTransactionVerified(c *fiber.Ctx) error {
|
||||
transactionID := c.Params("id")
|
||||
userID := c.Locals("user_id").(int64)
|
||||
companyID := c.Locals("company_id").(domain.ValidInt64)
|
||||
role := c.Locals("role").(domain.Role)
|
||||
|
||||
id, err := strconv.ParseInt(transactionID, 10, 64)
|
||||
if err != nil {
|
||||
h.logger.Error("Invalid transaction ID", "transactionID", transactionID, "error", err)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid transaction ID")
|
||||
}
|
||||
|
||||
var req UpdateTransactionVerifiedReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
h.logger.Error("Failed to parse UpdateTransactionVerified request", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||
}
|
||||
|
||||
h.logger.Info("Update Transaction Verified", slog.Bool("verified", req.Verified))
|
||||
|
||||
if valErrs, ok := h.validator.Validate(c, req); !ok {
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
||||
}
|
||||
|
||||
transaction, err := h.transactionSvc.GetShopTransactionByID(c.Context(), id)
|
||||
if role != domain.RoleSuperAdmin {
|
||||
if !companyID.Valid || companyID.Value != transaction.CompanyID {
|
||||
h.logger.Error("Failed to parse UpdateTransactionVerified request", "error", err)
|
||||
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
user, err := h.userSvc.GetUserById(c.Context(), userID)
|
||||
if err != nil {
|
||||
h.logger.Error("Invalid user ID", "userID", userID, "error", err)
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid user ID")
|
||||
}
|
||||
err = h.transactionSvc.UpdateShopTransactionVerified(c.Context(), id, req.Verified, userID, user.FirstName+" "+user.LastName)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to update transaction verification", "transactionID", id, "error", err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update transaction verification")
|
||||
}
|
||||
|
||||
return response.WriteJSON(c, fiber.StatusOK, "Transaction updated successfully", nil, nil)
|
||||
}
|
||||
|
|
@ -273,7 +273,9 @@ func (a *App) initAppRoutes() {
|
|||
// group.Get("/virtual-games/recommendations/:userID", h.GetRecommendations)
|
||||
|
||||
// Transactions /shop/transactions
|
||||
a.fiber.Post("/shop/cashout", a.authMiddleware, h.CashoutBet)
|
||||
a.fiber.Post("/shop/bet", a.authMiddleware, a.CompanyOnly, h.CreateShopBet)
|
||||
a.fiber.Post("/shop/bet/:id/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutBet)
|
||||
a.fiber.Post("/shop/deposit", a.authMiddleware, a.CompanyOnly, h.DepositForCustomer)
|
||||
a.fiber.Get("/shop/transaction", a.authMiddleware, h.GetAllTransactions)
|
||||
a.fiber.Get("/shop/transaction/:id", a.authMiddleware, h.GetTransactionByID)
|
||||
a.fiber.Put("/shop/transaction/:id", a.authMiddleware, h.UpdateTransactionVerified)
|
||||
|
|
|
|||
5
makefile
5
makefile
|
|
@ -43,7 +43,8 @@ migrations/up:
|
|||
postgres:
|
||||
@echo 'Running postgres db...'
|
||||
docker compose -f docker-compose.yml exec postgres psql -U root -d gh
|
||||
|
||||
postgres_log:
|
||||
docker logs fortunebet-backend-postgres-1
|
||||
.PHONY: swagger
|
||||
swagger:
|
||||
@swag init -g cmd/main.go
|
||||
|
|
@ -51,7 +52,7 @@ swagger:
|
|||
.PHONY: db-up
|
||||
db-up:
|
||||
@docker compose up -d postgres migrate mongo redis
|
||||
|
||||
@docker logs fortunebet-backend-postgres-1 > logs/postgres.log 2>&1 &
|
||||
.PHONY: db-down
|
||||
db-down:
|
||||
@docker compose down
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user