fix: Update integration issues

This commit is contained in:
Samuel Tariku 2025-05-23 12:00:04 +03:00
parent 6a06b399c7
commit 16768ad924
19 changed files with 619 additions and 162 deletions

View File

@ -55,15 +55,6 @@ SELECT branches.*
FROM branch_cashiers FROM branch_cashiers
JOIN branches ON branch_cashiers.branch_id = branches.id JOIN branches ON branch_cashiers.branch_id = branches.id
WHERE branch_cashiers.user_id = $1; WHERE branch_cashiers.user_id = $1;
-- name: GetCashiersByBranch :many
SELECT users.*
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id
WHERE branch_cashiers.branch_id = $1;
-- name: GetAllCashiers :many
SELECT users.*
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id;
-- name: UpdateBranch :one -- name: UpdateBranch :one
UPDATE branches UPDATE branches
SET name = COALESCE(sqlc.narg(name), name), SET name = COALESCE(sqlc.narg(name), name),

15
db/query/cashier.sql Normal file
View File

@ -0,0 +1,15 @@
-- name: GetCashiersByBranch :many
SELECT users.*
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id
WHERE branch_cashiers.branch_id = $1;
-- name: GetAllCashiers :many
SELECT users.*,
branch_id
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id;
-- name: GetCashierByID :one
SELECT users.*,
branch_id
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = $1;

View File

@ -100,11 +100,9 @@ WHERE first_name ILIKE '%' || $1 || '%'
UPDATE users UPDATE users
SET first_name = $1, SET first_name = $1,
last_name = $2, last_name = $2,
email = $3, suspended = $3,
phone_number = $4, updated_at = CURRENT_TIMESTAMP
role = $5, WHERE id = $4;
updated_at = $6
WHERE id = $7;
-- name: UpdateUserCompany :exec -- name: UpdateUserCompany :exec
UPDATE users UPDATE users
SET company_id = $1 SET company_id = $1

View File

@ -190,49 +190,6 @@ func (q *Queries) GetAllBranches(ctx context.Context) ([]BranchDetail, error) {
return items, nil return items, nil
} }
const GetAllCashiers = `-- name: GetAllCashiers :many
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id
`
func (q *Queries) GetAllCashiers(ctx context.Context) ([]User, error) {
rows, err := q.db.Query(ctx, GetAllCashiers)
if err != nil {
return nil, err
}
defer rows.Close()
var items []User
for rows.Next() {
var i User
if err := rows.Scan(
&i.ID,
&i.FirstName,
&i.LastName,
&i.Email,
&i.PhoneNumber,
&i.Role,
&i.Password,
&i.EmailVerified,
&i.PhoneVerified,
&i.CreatedAt,
&i.UpdatedAt,
&i.CompanyID,
&i.SuspendedAt,
&i.Suspended,
&i.ReferralCode,
&i.ReferredBy,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetAllSupportedOperations = `-- name: GetAllSupportedOperations :many const GetAllSupportedOperations = `-- name: GetAllSupportedOperations :many
SELECT id, name, description SELECT id, name, description
FROM supported_operations FROM supported_operations
@ -430,50 +387,6 @@ func (q *Queries) GetBranchOperations(ctx context.Context, branchID int64) ([]Ge
return items, nil return items, nil
} }
const GetCashiersByBranch = `-- name: GetCashiersByBranch :many
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id
WHERE branch_cashiers.branch_id = $1
`
func (q *Queries) GetCashiersByBranch(ctx context.Context, branchID int64) ([]User, error) {
rows, err := q.db.Query(ctx, GetCashiersByBranch, branchID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []User
for rows.Next() {
var i User
if err := rows.Scan(
&i.ID,
&i.FirstName,
&i.LastName,
&i.Email,
&i.PhoneNumber,
&i.Role,
&i.Password,
&i.EmailVerified,
&i.PhoneVerified,
&i.CreatedAt,
&i.UpdatedAt,
&i.CompanyID,
&i.SuspendedAt,
&i.Suspended,
&i.ReferralCode,
&i.ReferredBy,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const SearchBranchByName = `-- name: SearchBranchByName :many const SearchBranchByName = `-- name: SearchBranchByName :many
SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number SELECT id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number
FROM branch_details FROM branch_details

173
gen/db/cashier.sql.go Normal file
View File

@ -0,0 +1,173 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.28.0
// source: cashier.sql
package dbgen
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const GetAllCashiers = `-- name: GetAllCashiers :many
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by,
branch_id
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id
`
type GetAllCashiersRow struct {
ID int64 `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email pgtype.Text `json:"email"`
PhoneNumber pgtype.Text `json:"phone_number"`
Role string `json:"role"`
Password []byte `json:"password"`
EmailVerified bool `json:"email_verified"`
PhoneVerified bool `json:"phone_verified"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
CompanyID pgtype.Int8 `json:"company_id"`
SuspendedAt pgtype.Timestamptz `json:"suspended_at"`
Suspended bool `json:"suspended"`
ReferralCode pgtype.Text `json:"referral_code"`
ReferredBy pgtype.Text `json:"referred_by"`
BranchID int64 `json:"branch_id"`
}
func (q *Queries) GetAllCashiers(ctx context.Context) ([]GetAllCashiersRow, error) {
rows, err := q.db.Query(ctx, GetAllCashiers)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetAllCashiersRow
for rows.Next() {
var i GetAllCashiersRow
if err := rows.Scan(
&i.ID,
&i.FirstName,
&i.LastName,
&i.Email,
&i.PhoneNumber,
&i.Role,
&i.Password,
&i.EmailVerified,
&i.PhoneVerified,
&i.CreatedAt,
&i.UpdatedAt,
&i.CompanyID,
&i.SuspendedAt,
&i.Suspended,
&i.ReferralCode,
&i.ReferredBy,
&i.BranchID,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetCashierByID = `-- name: GetCashierByID :one
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by,
branch_id
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = $1
`
type GetCashierByIDRow struct {
ID int64 `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email pgtype.Text `json:"email"`
PhoneNumber pgtype.Text `json:"phone_number"`
Role string `json:"role"`
Password []byte `json:"password"`
EmailVerified bool `json:"email_verified"`
PhoneVerified bool `json:"phone_verified"`
CreatedAt pgtype.Timestamptz `json:"created_at"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
CompanyID pgtype.Int8 `json:"company_id"`
SuspendedAt pgtype.Timestamptz `json:"suspended_at"`
Suspended bool `json:"suspended"`
ReferralCode pgtype.Text `json:"referral_code"`
ReferredBy pgtype.Text `json:"referred_by"`
BranchID int64 `json:"branch_id"`
}
func (q *Queries) GetCashierByID(ctx context.Context, userID int64) (GetCashierByIDRow, error) {
row := q.db.QueryRow(ctx, GetCashierByID, userID)
var i GetCashierByIDRow
err := row.Scan(
&i.ID,
&i.FirstName,
&i.LastName,
&i.Email,
&i.PhoneNumber,
&i.Role,
&i.Password,
&i.EmailVerified,
&i.PhoneVerified,
&i.CreatedAt,
&i.UpdatedAt,
&i.CompanyID,
&i.SuspendedAt,
&i.Suspended,
&i.ReferralCode,
&i.ReferredBy,
&i.BranchID,
)
return i, err
}
const GetCashiersByBranch = `-- name: GetCashiersByBranch :many
SELECT users.id, users.first_name, users.last_name, users.email, users.phone_number, users.role, users.password, users.email_verified, users.phone_verified, users.created_at, users.updated_at, users.company_id, users.suspended_at, users.suspended, users.referral_code, users.referred_by
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id
WHERE branch_cashiers.branch_id = $1
`
func (q *Queries) GetCashiersByBranch(ctx context.Context, branchID int64) ([]User, error) {
rows, err := q.db.Query(ctx, GetCashiersByBranch, branchID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []User
for rows.Next() {
var i User
if err := rows.Scan(
&i.ID,
&i.FirstName,
&i.LastName,
&i.Email,
&i.PhoneNumber,
&i.Role,
&i.Password,
&i.EmailVerified,
&i.PhoneVerified,
&i.CreatedAt,
&i.UpdatedAt,
&i.CompanyID,
&i.SuspendedAt,
&i.Suspended,
&i.ReferralCode,
&i.ReferredBy,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}

View File

@ -532,20 +532,15 @@ const UpdateUser = `-- name: UpdateUser :exec
UPDATE users UPDATE users
SET first_name = $1, SET first_name = $1,
last_name = $2, last_name = $2,
email = $3, suspended = $3,
phone_number = $4, updated_at = CURRENT_TIMESTAMP
role = $5, WHERE id = $4
updated_at = $6
WHERE id = $7
` `
type UpdateUserParams struct { type UpdateUserParams struct {
FirstName string `json:"first_name"` FirstName string `json:"first_name"`
LastName string `json:"last_name"` LastName string `json:"last_name"`
Email pgtype.Text `json:"email"` Suspended bool `json:"suspended"`
PhoneNumber pgtype.Text `json:"phone_number"`
Role string `json:"role"`
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
ID int64 `json:"id"` ID int64 `json:"id"`
} }
@ -553,10 +548,7 @@ func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) error {
_, err := q.db.Exec(ctx, UpdateUser, _, err := q.db.Exec(ctx, UpdateUser,
arg.FirstName, arg.FirstName,
arg.LastName, arg.LastName,
arg.Email, arg.Suspended,
arg.PhoneNumber,
arg.Role,
arg.UpdatedAt,
arg.ID, arg.ID,
) )
return err return err

View File

@ -62,9 +62,26 @@ type UpdateUserReq struct {
FirstName ValidString FirstName ValidString
LastName ValidString LastName ValidString
Suspended ValidBool Suspended ValidBool
CompanyID ValidInt64
} }
type UpdateUserReferalCode struct { type UpdateUserReferalCode struct {
UserID int64 UserID int64
Code string Code string
} }
type GetCashier struct {
ID int64 `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
PhoneNumber string `json:"phone_number"`
Role Role `json:"role"`
EmailVerified bool `json:"email_verified"`
PhoneVerified bool `json:"phone_verified"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
SuspendedAt time.Time `json:"suspended_at"`
Suspended bool `json:"suspended"`
BranchID int64 `json:"branch_id"`
}

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"database/sql" "database/sql"
"errors" "errors"
"fmt"
"time" "time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
@ -129,14 +130,14 @@ func (s *Store) GetAllUsers(ctx context.Context, filter user.Filter) ([]domain.U
return userList, totalCount, nil return userList, totalCount, nil
} }
func (s *Store) GetAllCashiers(ctx context.Context) ([]domain.User, error) { func (s *Store) GetAllCashiers(ctx context.Context) ([]domain.GetCashier, error) {
users, err := s.queries.GetAllCashiers(ctx) users, err := s.queries.GetAllCashiers(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
userList := make([]domain.User, len(users)) userList := make([]domain.GetCashier, len(users))
for i, user := range users { for i, user := range users {
userList[i] = domain.User{ userList[i] = domain.GetCashier{
ID: user.ID, ID: user.ID,
FirstName: user.FirstName, FirstName: user.FirstName,
LastName: user.LastName, LastName: user.LastName,
@ -154,6 +155,28 @@ func (s *Store) GetAllCashiers(ctx context.Context) ([]domain.User, error) {
return userList, nil return userList, nil
} }
func (s *Store) GetCashierByID(ctx context.Context, cashierID int64) (domain.GetCashier, error) {
user, err := s.queries.GetCashierByID(ctx, cashierID)
if err != nil {
return domain.GetCashier{}, err
}
return domain.GetCashier{
ID: user.ID,
FirstName: user.FirstName,
LastName: user.LastName,
Email: user.Email.String,
PhoneNumber: user.PhoneNumber.String,
Role: domain.Role(user.Role),
EmailVerified: user.EmailVerified,
PhoneVerified: user.PhoneVerified,
CreatedAt: user.CreatedAt.Time,
UpdatedAt: user.UpdatedAt.Time,
SuspendedAt: user.SuspendedAt.Time,
Suspended: user.Suspended,
BranchID: user.BranchID,
}, nil
}
func (s *Store) GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error) { func (s *Store) GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error) {
users, err := s.queries.GetCashiersByBranch(ctx, branchID) users, err := s.queries.GetCashiersByBranch(ctx, branchID)
if err != nil { if err != nil {
@ -210,13 +233,12 @@ func (s *Store) SearchUserByNameOrPhone(ctx context.Context, searchString string
func (s *Store) UpdateUser(ctx context.Context, user domain.UpdateUserReq) error { func (s *Store) UpdateUser(ctx context.Context, user domain.UpdateUserReq) error {
err := s.queries.UpdateUser(ctx, dbgen.UpdateUserParams{ err := s.queries.UpdateUser(ctx, dbgen.UpdateUserParams{
// ID: user.ID, ID: user.UserId,
// FirstName: user.FirstName, FirstName: user.FirstName.Value,
// LastName: user.LastName, LastName: user.LastName.Value,
// Email: user.Email, Suspended: user.Suspended.Value,
// PhoneNumber: user.PhoneNumber,
}) })
fmt.Printf("Updating User %v with values %v", user.UserId, user)
if err != nil { if err != nil {
return err return err
} }

View File

@ -219,6 +219,9 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
} }
newBet.IsShopBet = true newBet.IsShopBet = true
case domain.RoleCustomer: case domain.RoleCustomer:
// Get User Wallet
return domain.CreateBetRes{}, fmt.Errorf("Not yet implemented") return domain.CreateBetRes{}, fmt.Errorf("Not yet implemented")
default: default:
return domain.CreateBetRes{}, fmt.Errorf("Unknown Role Type") return domain.CreateBetRes{}, fmt.Errorf("Unknown Role Type")

View File

@ -71,6 +71,10 @@ func (s *Service) GetCashiersByBranch(ctx context.Context, branchID int64) ([]do
return s.userStore.GetCashiersByBranch(ctx, branchID) return s.userStore.GetCashiersByBranch(ctx, branchID)
} }
func (s *Service) GetAllCashiers(ctx context.Context) ([]domain.User, error) { func (s *Service) GetAllCashiers(ctx context.Context) ([]domain.GetCashier, error) {
return s.userStore.GetAllCashiers(ctx) return s.userStore.GetAllCashiers(ctx)
} }
func (s *Service) GetCashierByID(ctx context.Context, cashierID int64) (domain.GetCashier, error) {
return s.userStore.GetCashierByID(ctx, cashierID)
}

View File

@ -11,7 +11,8 @@ type UserStore interface {
CreateUserWithoutOtp(ctx context.Context, user domain.User, is_company bool) (domain.User, error) CreateUserWithoutOtp(ctx context.Context, user domain.User, is_company bool) (domain.User, error)
GetUserByID(ctx context.Context, id int64) (domain.User, error) GetUserByID(ctx context.Context, id int64) (domain.User, error)
GetAllUsers(ctx context.Context, filter Filter) ([]domain.User, int64, error) GetAllUsers(ctx context.Context, filter Filter) ([]domain.User, int64, error)
GetAllCashiers(ctx context.Context) ([]domain.User, error) GetAllCashiers(ctx context.Context) ([]domain.GetCashier, error)
GetCashierByID(ctx context.Context, cashierID int64) (domain.GetCashier, error)
GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error) GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error)
UpdateUser(ctx context.Context, user domain.UpdateUserReq) error UpdateUser(ctx context.Context, user domain.UpdateUserReq) error
UpdateUserCompany(ctx context.Context, id int64, companyID int64) error UpdateUserCompany(ctx context.Context, id int64, companyID int64) error

View File

@ -13,7 +13,6 @@ type Service struct {
otpStore OtpStore otpStore OtpStore
smsGateway SmsGateway smsGateway SmsGateway
emailGateway EmailGateway emailGateway EmailGateway
} }
func NewService( func NewService(

View File

@ -2,6 +2,7 @@ package handlers
import ( import (
"log/slog" "log/slog"
"strconv"
"time" "time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
@ -129,7 +130,7 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error {
Role: string(domain.RoleAdmin), Role: string(domain.RoleAdmin),
CompanyID: domain.ValidInt64{ CompanyID: domain.ValidInt64{
Value: int64(c.QueryInt("company_id")), Value: int64(c.QueryInt("company_id")),
Valid: true, Valid: false,
}, },
Page: domain.ValidInt{ Page: domain.ValidInt{
Value: c.QueryInt("page", 1) - 1, Value: c.QueryInt("page", 1) - 1,
@ -179,5 +180,154 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error {
} }
return response.WritePaginatedJSON(c, fiber.StatusOK, "Admins retrieved successfully", result, nil, filter.Page.Value, int(total)) return response.WritePaginatedJSON(c, fiber.StatusOK, "Admins retrieved successfully", result, nil, filter.Page.Value, int(total))
}
// GetAdminByID godoc
// @Summary Get admin by id
// @Description Get a single admin by id
// @Tags admin
// @Accept json
// @Produce json
// @Param id path int true "User ID"
// @Success 200 {object} AdminRes
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /admin/{id} [get]
func (h *Handler) GetAdminByID(c *fiber.Ctx) error {
// branchId := int64(12) //c.Locals("branch_id").(int64)
// filter := user.Filter{
// Role: string(domain.RoleUser),
// BranchId: user.ValidBranchId{
// Value: branchId,
// Valid: true,
// },
// Page: c.QueryInt("page", 1),
// PageSize: c.QueryInt("page_size", 10),
// }
// valErrs, ok := validator.Validate(c, filter)
// if !ok {
// return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
// }
userIDstr := c.Params("id")
userID, err := strconv.ParseInt(userIDstr, 10, 64)
if err != nil {
h.logger.Error("failed to fetch user using UserID", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid admin ID", nil, nil)
}
user, err := h.userSvc.GetUserByID(c.Context(), userID)
if err != nil {
h.logger.Error("Get User By ID failed", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get admin", nil, nil)
}
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID)
if err != nil {
if err != authentication.ErrRefreshTokenNotFound {
h.logger.Error("Failed to get user last login", "userID", user.ID, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login")
}
lastLogin = &user.CreatedAt
}
res := AdminRes{
ID: user.ID,
FirstName: user.FirstName,
LastName: user.LastName,
Email: user.Email,
PhoneNumber: user.PhoneNumber,
Role: user.Role,
EmailVerified: user.EmailVerified,
PhoneVerified: user.PhoneVerified,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
SuspendedAt: user.SuspendedAt,
Suspended: user.Suspended,
LastLogin: *lastLogin,
}
return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
}
type updateAdminReq struct {
FirstName string `json:"first_name" example:"John"`
LastName string `json:"last_name" example:"Doe"`
Suspended bool `json:"suspended" example:"false"`
CompanyID *int64 `json:"company_id,omitempty" example:"1"`
}
// UpdateAdmin godoc
// @Summary Update Admin
// @Description Update Admin
// @Tags admin
// @Accept json
// @Produce json
// @Param admin body updateAdminReq true "Update Admin"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /admin/{id} [put]
func (h *Handler) UpdateAdmin(c *fiber.Ctx) error {
var req updateAdminReq
if err := c.BodyParser(&req); err != nil {
h.logger.Error("UpdateAdmin failed", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil)
}
valErrs, ok := h.validator.Validate(c, req)
if !ok {
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
}
AdminIDStr := c.Params("id")
AdminID, err := strconv.ParseInt(AdminIDStr, 10, 64)
if err != nil {
h.logger.Error("UpdateAdmin failed", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Admin ID", nil, nil)
}
var companyID domain.ValidInt64
if req.CompanyID != nil {
companyID = domain.ValidInt64{
Value: *req.CompanyID,
Valid: true,
}
}
err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
UserId: AdminID,
FirstName: domain.ValidString{
Value: req.FirstName,
Valid: req.FirstName != "",
},
LastName: domain.ValidString{
Value: req.LastName,
Valid: req.LastName != "",
},
Suspended: domain.ValidBool{
Value: req.Suspended,
Valid: true,
},
CompanyID: companyID,
},
)
if err != nil {
h.logger.Error("UpdateAdmin failed", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update admin", nil, nil)
}
if req.CompanyID != nil {
_, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{
ID: *req.CompanyID,
AdminID: &AdminID,
})
if err != nil {
h.logger.Error("CreateAdmin failed to update company", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to update company", nil, nil)
}
}
return response.WriteJSON(c, fiber.StatusOK, "Managers updated successfully", nil, nil)
} }

View File

@ -142,7 +142,8 @@ func (h *Handler) CreateBranch(c *fiber.Ctx) error {
checkedCompanyID = *req.CompanyID checkedCompanyID = *req.CompanyID
} else { } else {
IsSelfOwned = false IsSelfOwned = false
checkedCompanyID = companyID.Value //the company id is always valid when its not a super admin checkedCompanyID = companyID.Value
//TODO:check that the company id is always valid when its not a super admin
} }
// Create Branch Wallet // Create Branch Wallet

View File

@ -7,6 +7,7 @@ import (
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
) )
@ -87,6 +88,7 @@ type GetCashierRes struct {
SuspendedAt time.Time `json:"suspended_at"` SuspendedAt time.Time `json:"suspended_at"`
Suspended bool `json:"suspended"` Suspended bool `json:"suspended"`
LastLogin time.Time `json:"last_login"` LastLogin time.Time `json:"last_login"`
BranchID int64 `json:"branch_id"`
} }
// GetAllCashiers godoc // GetAllCashiers godoc
@ -103,22 +105,31 @@ type GetCashierRes struct {
// @Failure 500 {object} response.APIResponse // @Failure 500 {object} response.APIResponse
// @Router /cashiers [get] // @Router /cashiers [get]
func (h *Handler) GetAllCashiers(c *fiber.Ctx) error { func (h *Handler) GetAllCashiers(c *fiber.Ctx) error {
// branchId := int64(12) //c.Locals("branch_id").(int64) role := c.Locals("role").(domain.Role)
// filter := user.Filter{ companyId := c.Locals("company_id").(domain.ValidInt64)
// Role: string(domain.RoleCashier),
// BranchId: user.ValidBranchId{
// Value: branchId,
// Valid: true,
// },
// Page: c.QueryInt("page", 1),
// PageSize: c.QueryInt("page_size", 10),
// }
// valErrs, ok := validator.Validate(c, filter)
// if !ok {
// return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
// }
cashiers, err := h.userSvc.GetAllCashiers(c.Context()) if role != domain.RoleSuperAdmin && !companyId.Valid {
return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID")
}
filter := user.Filter{
Role: string(domain.RoleCashier),
CompanyID: companyId,
Page: domain.ValidInt{
Value: c.QueryInt("page", 1) - 1,
Valid: true,
},
PageSize: domain.ValidInt{
Value: c.QueryInt("page_size", 10),
Valid: true,
},
}
valErrs, ok := h.validator.Validate(c, filter)
if !ok {
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
}
cashiers, total, err := h.userSvc.GetAllUsers(c.Context(), filter)
if err != nil { if err != nil {
h.logger.Error("GetAllCashiers failed", "error", err) h.logger.Error("GetAllCashiers failed", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil)
@ -154,11 +165,80 @@ func (h *Handler) GetAllCashiers(c *fiber.Ctx) error {
}) })
} }
return response.WriteJSON(c, fiber.StatusOK, "Cashiers retrieved successfully", result, nil) return response.WritePaginatedJSON(c, fiber.StatusOK, "Cashiers retrieved successfully", result, nil, filter.Page.Value, int(total))
} }
type updateUserReq struct { // GetCashierByID godoc
// @Summary Get cashier by id
// @Description Get a single cashier by id
// @Tags cashier
// @Accept json
// @Produce json
// @Param id path int true "User ID"
// @Success 200 {object} UserProfileRes
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /cashier/{id} [get]
func (h *Handler) GetCashierByID(c *fiber.Ctx) error {
// branchId := int64(12) //c.Locals("branch_id").(int64)
// filter := user.Filter{
// Role: string(domain.RoleUser),
// BranchId: user.ValidBranchId{
// Value: branchId,
// Valid: true,
// },
// Page: c.QueryInt("page", 1),
// PageSize: c.QueryInt("page_size", 10),
// }
// valErrs, ok := validator.Validate(c, filter)
// if !ok {
// return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
// }
stringID := c.Params("id")
cashierID, err := strconv.ParseInt(stringID, 10, 64)
if err != nil {
h.logger.Error("failed to fetch user using UserID", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashier ID", nil, nil)
}
user, err := h.userSvc.GetCashierByID(c.Context(), cashierID)
if err != nil {
h.logger.Error("Get User By ID failed", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil)
}
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID)
if err != nil {
if err != authentication.ErrRefreshTokenNotFound {
h.logger.Error("Failed to get user last login", "cashierID", user.ID, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login")
}
lastLogin = &user.CreatedAt
}
res := GetCashierRes{
ID: user.ID,
FirstName: user.FirstName,
LastName: user.LastName,
Email: user.Email,
PhoneNumber: user.PhoneNumber,
Role: user.Role,
EmailVerified: user.EmailVerified,
PhoneVerified: user.PhoneVerified,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
SuspendedAt: user.SuspendedAt,
Suspended: user.Suspended,
LastLogin: *lastLogin,
BranchID: user.BranchID,
}
return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
}
type updateCashierReq struct {
FirstName string `json:"first_name" example:"John"` FirstName string `json:"first_name" example:"John"`
LastName string `json:"last_name" example:"Doe"` LastName string `json:"last_name" example:"Doe"`
Suspended bool `json:"suspended" example:"false"` Suspended bool `json:"suspended" example:"false"`
@ -171,7 +251,7 @@ type updateUserReq struct {
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param id path int true "Cashier ID" // @Param id path int true "Cashier ID"
// @Param cashier body updateUserReq true "Update cashier" // @Param cashier body updateCashierReq true "Update cashier"
// @Success 200 {object} response.APIResponse // @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse // @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse // @Failure 401 {object} response.APIResponse
@ -184,7 +264,7 @@ func (h *Handler) UpdateCashier(c *fiber.Ctx) error {
h.logger.Error("UpdateCashier failed", "error", err) h.logger.Error("UpdateCashier failed", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashier ID", nil, nil) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashier ID", nil, nil)
} }
var req updateUserReq var req updateCashierReq
if err := c.BodyParser(&req); err != nil { if err := c.BodyParser(&req); err != nil {
h.logger.Error("UpdateCashier failed", "error", err) h.logger.Error("UpdateCashier failed", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil)

View File

@ -241,7 +241,7 @@ func (h *Handler) UpdateCompany(c *fiber.Ctx) error {
var req UpdateCompanyReq var req UpdateCompanyReq
if err := c.BodyParser(&req); err != nil { if err := c.BodyParser(&req); err != nil {
h.logger.Error("CreateCompanyReq failed", "error", err) h.logger.Error("UpdateCompanyReq failed", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
} }
valErrs, ok := h.validator.Validate(c, req) valErrs, ok := h.validator.Validate(c, req)

View File

@ -109,12 +109,15 @@ type ManagersRes struct {
// @Failure 500 {object} response.APIResponse // @Failure 500 {object} response.APIResponse
// @Router /managers [get] // @Router /managers [get]
func (h *Handler) GetAllManagers(c *fiber.Ctx) error { func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
role := c.Locals("role").(domain.Role)
companyId := c.Locals("company_id").(domain.ValidInt64)
if role != domain.RoleSuperAdmin && !companyId.Valid {
return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID")
}
filter := user.Filter{ filter := user.Filter{
Role: string(domain.RoleBranchManager), Role: string(domain.RoleBranchManager),
CompanyID: domain.ValidInt64{ CompanyID: companyId,
Value: int64(c.QueryInt("company_id")),
Valid: true,
},
Page: domain.ValidInt{ Page: domain.ValidInt{
Value: c.QueryInt("page", 1) - 1, Value: c.QueryInt("page", 1) - 1,
Valid: true, Valid: true,
@ -166,20 +169,97 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
} }
// GetManagerByID godoc
// @Summary Get manager by id
// @Description Get a single manager by id
// @Tags manager
// @Accept json
// @Produce json
// @Param id path int true "User ID"
// @Success 200 {object} ManagerRes
// @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /managers/{id} [get]
func (h *Handler) GetManagerByID(c *fiber.Ctx) error {
// branchId := int64(12) //c.Locals("branch_id").(int64)
// filter := user.Filter{
// Role: string(domain.RoleUser),
// BranchId: user.ValidBranchId{
// Value: branchId,
// Valid: true,
// },
// Page: c.QueryInt("page", 1),
// PageSize: c.QueryInt("page_size", 10),
// }
// valErrs, ok := validator.Validate(c, filter)
// if !ok {
// return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
// }
userIDstr := c.Params("id")
userID, err := strconv.ParseInt(userIDstr, 10, 64)
if err != nil {
h.logger.Error("failed to fetch user using UserID", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid managers ID", nil, nil)
}
user, err := h.userSvc.GetUserByID(c.Context(), userID)
if err != nil {
h.logger.Error("Get User By ID failed", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get managers", nil, nil)
}
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID)
if err != nil {
if err != authentication.ErrRefreshTokenNotFound {
h.logger.Error("Failed to get user last login", "userID", user.ID, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login")
}
lastLogin = &user.CreatedAt
}
res := ManagersRes{
ID: user.ID,
FirstName: user.FirstName,
LastName: user.LastName,
Email: user.Email,
PhoneNumber: user.PhoneNumber,
Role: user.Role,
EmailVerified: user.EmailVerified,
PhoneVerified: user.PhoneVerified,
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
SuspendedAt: user.SuspendedAt,
Suspended: user.Suspended,
LastLogin: *lastLogin,
}
return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
}
type updateManagerReq struct {
FirstName string `json:"first_name" example:"John"`
LastName string `json:"last_name" example:"Doe"`
Suspended bool `json:"suspended" example:"false"`
CompanyID *int64 `json:"company_id,omitempty" example:"1"`
}
// UpdateManagers godoc // UpdateManagers godoc
// @Summary Update Managers // @Summary Update Managers
// @Description Update Managers // @Description Update Managers
// @Tags Managers // @Tags manager
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param Managers body updateUserReq true "Update Managers" // @Param Managers body updateManagerReq true "Update Managers"
// @Success 200 {object} response.APIResponse // @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse // @Failure 400 {object} response.APIResponse
// @Failure 401 {object} response.APIResponse // @Failure 401 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse // @Failure 500 {object} response.APIResponse
// @Router /managers/{id} [put] // @Router /managers/{id} [put]
func (h *Handler) UpdateManagers(c *fiber.Ctx) error { func (h *Handler) UpdateManagers(c *fiber.Ctx) error {
var req updateUserReq var req updateManagerReq
if err := c.BodyParser(&req); err != nil { if err := c.BodyParser(&req); err != nil {
h.logger.Error("UpdateManagers failed", "error", err) h.logger.Error("UpdateManagers failed", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", nil, nil)
@ -196,6 +276,19 @@ func (h *Handler) UpdateManagers(c *fiber.Ctx) error {
h.logger.Error("UpdateManagers failed", "error", err) h.logger.Error("UpdateManagers failed", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Managers ID", nil, nil) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid Managers ID", nil, nil)
} }
var companyID domain.ValidInt64
role := c.Locals("role").(domain.Role)
if req.CompanyID != nil {
if role != domain.RoleSuperAdmin {
h.logger.Error("UpdateManagers failed", "error", err)
return response.WriteJSON(c, fiber.StatusUnauthorized, "This user role cannot modify company ID", nil, nil)
}
companyID = domain.ValidInt64{
Value: *req.CompanyID,
Valid: true,
}
}
err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{ err = h.userSvc.UpdateUser(c.Context(), domain.UpdateUserReq{
UserId: ManagersId, UserId: ManagersId,
FirstName: domain.ValidString{ FirstName: domain.ValidString{
@ -210,6 +303,7 @@ func (h *Handler) UpdateManagers(c *fiber.Ctx) error {
Value: req.Suspended, Value: req.Suspended,
Valid: true, Valid: true,
}, },
CompanyID: companyID,
}, },
) )
if err != nil { if err != nil {

View File

@ -474,13 +474,13 @@ func (h *Handler) GetUserByID(c *fiber.Ctx) error {
userIDstr := c.Params("id") userIDstr := c.Params("id")
userID, err := strconv.ParseInt(userIDstr, 10, 64) userID, err := strconv.ParseInt(userIDstr, 10, 64)
if err != nil { if err != nil {
h.logger.Error("UpdateCashier failed", "error", err) h.logger.Error("failed to fetch user using UserID", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashier ID", nil, nil) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashier ID", nil, nil)
} }
user, err := h.userSvc.GetUserByID(c.Context(), userID) user, err := h.userSvc.GetUserByID(c.Context(), userID)
if err != nil { if err != nil {
h.logger.Error("GetAllCashiers failed", "error", err) h.logger.Error("Get User By ID failed", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil)
} }
@ -510,7 +510,7 @@ func (h *Handler) GetUserByID(c *fiber.Ctx) error {
LastLogin: *lastLogin, LastLogin: *lastLogin,
} }
return response.WriteJSON(c, fiber.StatusOK, "Cashiers retrieved successfully", res, nil) return response.WriteJSON(c, fiber.StatusOK, "User retrieved successfully", res, nil)
} }

View File

@ -90,13 +90,17 @@ func (a *App) initAppRoutes() {
a.fiber.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings) a.fiber.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings)
a.fiber.Get("/cashiers", a.authMiddleware, h.GetAllCashiers) a.fiber.Get("/cashiers", a.authMiddleware, h.GetAllCashiers)
a.fiber.Get("/cashiers/:id", a.authMiddleware, h.GetCashierByID)
a.fiber.Post("/cashiers", a.authMiddleware, h.CreateCashier) a.fiber.Post("/cashiers", a.authMiddleware, h.CreateCashier)
a.fiber.Put("/cashiers/:id", a.authMiddleware, h.UpdateCashier) a.fiber.Put("/cashiers/:id", a.authMiddleware, h.UpdateCashier)
a.fiber.Get("/admin", a.authMiddleware, h.GetAllAdmins) a.fiber.Get("/admin", a.authMiddleware, h.GetAllAdmins)
a.fiber.Get("/admin/:id", a.authMiddleware, h.GetAdminByID)
a.fiber.Post("/admin", a.authMiddleware, h.CreateAdmin) a.fiber.Post("/admin", a.authMiddleware, h.CreateAdmin)
a.fiber.Put("/admin/:id", a.authMiddleware, h.UpdateAdmin)
a.fiber.Get("/managers", a.authMiddleware, h.GetAllManagers) a.fiber.Get("/managers", a.authMiddleware, h.GetAllManagers)
a.fiber.Get("/managers/:id", a.authMiddleware, h.GetManagerByID)
a.fiber.Post("/managers", a.authMiddleware, h.CreateManager) a.fiber.Post("/managers", a.authMiddleware, h.CreateManager)
a.fiber.Put("/managers/:id", a.authMiddleware, h.UpdateManagers) a.fiber.Put("/managers/:id", a.authMiddleware, h.UpdateManagers)
a.fiber.Get("/manager/:id/branch", a.authMiddleware, h.GetBranchByManagerID) a.fiber.Get("/manager/:id/branch", a.authMiddleware, h.GetBranchByManagerID)