fix: fixed company override settings and raffle routes

This commit is contained in:
Samuel Tariku 2025-09-18 22:34:56 +03:00
parent 65df6b9ff1
commit 723ca34660
10 changed files with 145 additions and 83 deletions

View File

@ -351,3 +351,29 @@ SET name = EXCLUDED.name,
is_active = EXCLUDED.is_active, is_active = EXCLUDED.is_active,
created_at = EXCLUDED.created_at, created_at = EXCLUDED.created_at,
updated_at = EXCLUDED.updated_at; updated_at = EXCLUDED.updated_at;
-- Bonus
INSERT INTO user_bonuses (
id,
name,
description,
type,
user_id,
reward_amount,
expires_at
)
VALUES (
1,
'Welcome Bonus',
'Awarded for deposit number (1 / 3)',
'welcome_bonus',
1,
1000,
now() + INTERVAL '1 day'
) ON CONFLICT (id) DO
UPDATE
SET name = EXCLUDED.name,
description = EXCLUDED.description,
type = EXCLUDED.type,
user_id = EXCLUDED.user_id,
reward_amount = EXCLUDED.reward_amount,
expires_at = EXCLUDED.expires_at;

View File

@ -454,7 +454,7 @@ CREATE TABLE IF NOT EXISTS company_settings (
PRIMARY KEY (company_id, key) PRIMARY KEY (company_id, key)
); );
CREATE TABLE user_bonuses ( CREATE TABLE user_bonuses (
id BIGINT NOT NULL, id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL, name TEXT NOT NULL,
description TEXT NOT NULL, description TEXT NOT NULL,
type TEXT NOT NULL, type TEXT NOT NULL,
@ -462,7 +462,7 @@ CREATE TABLE user_bonuses (
reward_amount BIGINT NOT NULL, reward_amount BIGINT NOT NULL,
is_claimed BOOLEAN NOT NULL DEFAULT false, is_claimed BOOLEAN NOT NULL DEFAULT false,
expires_at TIMESTAMP NOT NULL, expires_at TIMESTAMP NOT NULL,
claimed_at TIMESTAMP NOT NULL, claimed_at TIMESTAMP,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
); );

View File

@ -27,7 +27,9 @@ SELECT *
FROM company_settings FROM company_settings
WHERE key = $1; WHERE key = $1;
-- name: GetOverrideSettings :many -- name: GetOverrideSettings :many
SELECT gs.*, SELECT gs.key,
gs.created_at,
gs.updated_at,
COALESCE(cs.value, gs.value) AS value COALESCE(cs.value, gs.value) AS value
FROM global_settings gs FROM global_settings gs
LEFT JOIN company_settings cs ON cs.key = gs.key LEFT JOIN company_settings cs ON cs.key = gs.key

View File

@ -181,7 +181,9 @@ func (q *Queries) GetGlobalSettings(ctx context.Context) ([]GlobalSetting, error
} }
const GetOverrideSettings = `-- name: GetOverrideSettings :many const GetOverrideSettings = `-- name: GetOverrideSettings :many
SELECT gs.key, gs.value, gs.created_at, gs.updated_at, SELECT gs.key,
gs.created_at,
gs.updated_at,
COALESCE(cs.value, gs.value) AS value COALESCE(cs.value, gs.value) AS value
FROM global_settings gs FROM global_settings gs
LEFT JOIN company_settings cs ON cs.key = gs.key LEFT JOIN company_settings cs ON cs.key = gs.key
@ -190,10 +192,9 @@ FROM global_settings gs
type GetOverrideSettingsRow struct { type GetOverrideSettingsRow struct {
Key string `json:"key"` Key string `json:"key"`
Value string `json:"value"`
CreatedAt pgtype.Timestamp `json:"created_at"` CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
Value_2 string `json:"value_2"` Value string `json:"value"`
} }
func (q *Queries) GetOverrideSettings(ctx context.Context, companyID int64) ([]GetOverrideSettingsRow, error) { func (q *Queries) GetOverrideSettings(ctx context.Context, companyID int64) ([]GetOverrideSettingsRow, error) {
@ -207,10 +208,9 @@ func (q *Queries) GetOverrideSettings(ctx context.Context, companyID int64) ([]G
var i GetOverrideSettingsRow var i GetOverrideSettingsRow
if err := rows.Scan( if err := rows.Scan(
&i.Key, &i.Key,
&i.Value,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.Value_2, &i.Value,
); err != nil { ); err != nil {
return nil, err return nil, err
} }

View File

@ -22,6 +22,16 @@ type RaffleStanding struct {
TicketCount int64 TicketCount int64
} }
type RaffleStandingRes struct {
UserID int64 `json:"user_id"`
RaffleID int32 `json:"raffle_id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
PhoneNumber string `json:"phone_number"`
Email string `json:"email"`
TicketCount int64 `json:"ticket_count"`
}
type RaffleWinnerParams struct { type RaffleWinnerParams struct {
RaffleID int32 RaffleID int32
UserID int32 UserID int32

View File

@ -72,6 +72,7 @@ func (s *Service) CreateWelcomeBonus(ctx context.Context, amount domain.Currency
Name: "Welcome Bonus", Name: "Welcome Bonus",
Description: fmt.Sprintf("Awarded for deposit number (%v / %v)", stats.TotalDeposits, settingsList.WelcomeBonusCount), Description: fmt.Sprintf("Awarded for deposit number (%v / %v)", stats.TotalDeposits, settingsList.WelcomeBonusCount),
UserID: userID, UserID: userID,
Type: domain.WelcomeBonus,
RewardAmount: domain.Currency(newBalance), RewardAmount: domain.Currency(newBalance),
ExpiresAt: time.Now().Add(time.Duration(settingsList.WelcomeBonusExpire) * 24 * time.Hour), ExpiresAt: time.Now().Add(time.Duration(settingsList.WelcomeBonusExpire) * 24 * time.Hour),
}) })

View File

@ -19,6 +19,7 @@ func (s *Service) CreateUser(ctx context.Context, User domain.CreateUserReq, is_
// User.BranchID = branchId // User.BranchID = branchId
// User.Role = string(domain.RoleBranchManager) // User.Role = string(domain.RoleBranchManager)
// } // }
hashedPassword, err := hashPassword(User.Password) hashedPassword, err := hashPassword(User.Password)
if err != nil { if err != nil {
return domain.User{}, err return domain.User{}, err

View File

@ -26,71 +26,71 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
spec string spec string
task func() task func()
}{ }{
// { {
// spec: "0 0 * * * *", // Every 1 hour spec: "0 0 * * * *", // Every 1 hour
// task: func() { task: func() {
// mongoLogger.Info("Began fetching upcoming events cron task") mongoLogger.Info("Began fetching upcoming events cron task")
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil { if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
// mongoLogger.Error("Failed to fetch upcoming events", mongoLogger.Error("Failed to fetch upcoming events",
// zap.Error(err), zap.Error(err),
// ) )
// } else { } else {
// mongoLogger.Info("Completed fetching upcoming events without errors") mongoLogger.Info("Completed fetching upcoming events without errors")
// } }
// }, },
// }, },
// { {
// spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events) spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events)
// task: func() { task: func() {
// mongoLogger.Info("Began fetching non live odds cron task") mongoLogger.Info("Began fetching non live odds cron task")
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil { if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
// mongoLogger.Error("Failed to fetch non live odds", mongoLogger.Error("Failed to fetch non live odds",
// zap.Error(err), zap.Error(err),
// ) )
// } else { } else {
// mongoLogger.Info("Completed fetching non live odds without errors") mongoLogger.Info("Completed fetching non live odds without errors")
// } }
// }, },
// }, },
// { {
// spec: "0 */5 * * * *", // Every 5 Minutes spec: "0 */5 * * * *", // Every 5 Minutes
// task: func() { task: func() {
// mongoLogger.Info("Began update all expired events status cron task") mongoLogger.Info("Began update all expired events status cron task")
// if _, err := resultService.CheckAndUpdateExpiredEvents(context.Background()); err != nil { if _, err := resultService.CheckAndUpdateExpiredEvents(context.Background()); err != nil {
// mongoLogger.Error("Failed to update expired events status", mongoLogger.Error("Failed to update expired events status",
// zap.Error(err), zap.Error(err),
// ) )
// } else { } else {
// mongoLogger.Info("Completed expired events without errors") mongoLogger.Info("Completed expired events without errors")
// } }
// }, },
// }, },
// { {
// spec: "0 */15 * * * *", // Every 15 Minutes spec: "0 */15 * * * *", // Every 15 Minutes
// task: func() { task: func() {
// mongoLogger.Info("Began fetching results for upcoming events cron task") mongoLogger.Info("Began fetching results for upcoming events cron task")
// if err := resultService.FetchAndProcessResults(context.Background()); err != nil { if err := resultService.FetchAndProcessResults(context.Background()); err != nil {
// mongoLogger.Error("Failed to process result", mongoLogger.Error("Failed to process result",
// zap.Error(err), zap.Error(err),
// ) )
// } else { } else {
// mongoLogger.Info("Completed processing all event result outcomes without errors") mongoLogger.Info("Completed processing all event result outcomes without errors")
// } }
// }, },
// }, },
// { {
// spec: "0 0 0 * * *", // Every Day spec: "0 0 0 * * *", // Every Day
// task: func() { task: func() {
// mongoLogger.Info("Began Send daily result notification cron task") mongoLogger.Info("Began Send daily result notification cron task")
// if err := resultService.CheckAndSendResultNotifications(context.Background(), time.Now().Add(-24*time.Hour)); err != nil { if err := resultService.CheckAndSendResultNotifications(context.Background(), time.Now().Add(-24*time.Hour)); err != nil {
// mongoLogger.Error("Failed to process result", mongoLogger.Error("Failed to process result",
// zap.Error(err), zap.Error(err),
// ) )
// } else { } else {
// mongoLogger.Info("Completed sending daily result notification without errors") mongoLogger.Info("Completed sending daily result notification without errors")
// } }
// }, },
// }, },
} }
for _, job := range schedule { for _, job := range schedule {

View File

@ -103,6 +103,26 @@ func (h *Handler) GetRafflesOfCompany(c *fiber.Ctx) error {
return response.WriteJSON(c, fiber.StatusOK, "Company Raffles fetched successfully", companyRaffles, nil) return response.WriteJSON(c, fiber.StatusOK, "Company Raffles fetched successfully", companyRaffles, nil)
} }
func (h *Handler) GetTenantRaffles(c *fiber.Ctx) error {
companyID := c.Locals("company_id").(domain.ValidInt64)
if !companyID.Valid {
h.BadRequestLogger().Error("invalid company id")
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
}
companyRaffles, err := h.raffleSvc.GetRafflesOfCompany(c.Context(), int32(companyID.Value))
if err != nil {
h.mongoLoggerSvc.Error("Failed to fetch company raffle",
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch company raffle")
}
return response.WriteJSON(c, fiber.StatusOK, "Company Raffles fetched successfully", companyRaffles, nil)
}
func (h *Handler) GetRaffleStanding(c *fiber.Ctx) error { func (h *Handler) GetRaffleStanding(c *fiber.Ctx) error {
raffleIDStr := c.Params("id") raffleIDStr := c.Params("id")
limitStr := c.Params("limit") limitStr := c.Params("limit")
@ -122,9 +142,10 @@ func (h *Handler) GetRaffleStanding(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch raffle standing") return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch raffle standing")
} }
maskedRaffleStanding := []domain.RaffleStanding{} maskedRaffleStanding := make([]domain.RaffleStandingRes, 0, len(raffleStanding))
for _, standing := range raffleStanding { for _, standing := range raffleStanding {
maskedStanding := domain.RaffleStanding{ maskedStanding := domain.RaffleStandingRes{
UserID: standing.UserID, UserID: standing.UserID,
RaffleID: standing.RaffleID, RaffleID: standing.RaffleID,
FirstName: standing.FirstName, FirstName: standing.FirstName,

View File

@ -60,7 +60,7 @@ func (a *App) initAppRoutes() {
a.fiber.Get("/", func(c *fiber.Ctx) error { a.fiber.Get("/", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{ return c.JSON(fiber.Map{
"message": "Welcome to the FortuneBet API", "message": "Welcome to the FortuneBet API",
"version": "1.0.dev14", "version": "1.0.dev15",
}) })
}) })
@ -198,10 +198,11 @@ func (a *App) initAppRoutes() {
// groupV1.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings) // groupV1.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings)
// Raffle Routes // Raffle Routes
tenant.Get("/raffle/list", h.GetTenantRaffles)
a.fiber.Get("/raffle/standing/:id/:limit", h.GetRaffleStanding) //This needs to be accessible by non-login user
a.fiber.Post("/raffle/create", a.authMiddleware, h.CreateRaffle) a.fiber.Post("/raffle/create", a.authMiddleware, h.CreateRaffle)
a.fiber.Get("/raffle/delete/:id", a.authMiddleware, h.DeleteRaffle) a.fiber.Get("/raffle/delete/:id", a.authMiddleware, h.DeleteRaffle)
a.fiber.Get("/raffle/company/:id", a.authMiddleware, h.GetRafflesOfCompany) a.fiber.Get("/raffle/company/:id", a.authMiddleware, h.GetRafflesOfCompany)
a.fiber.Get("/raffle/standing/:id/:limit", a.authMiddleware, h.GetRaffleStanding)
a.fiber.Get("raffle/winners/:id/:limit", a.authMiddleware, h.GetRaffleWinners) a.fiber.Get("raffle/winners/:id/:limit", a.authMiddleware, h.GetRaffleWinners)
a.fiber.Post("/raffle-ticket/create", a.authMiddleware, h.CreateRaffleTicket) a.fiber.Post("/raffle-ticket/create", a.authMiddleware, h.CreateRaffleTicket)
a.fiber.Get("/raffle-ticket/:id", a.authMiddleware, h.GetUserRaffleTickets) a.fiber.Get("/raffle-ticket/:id", a.authMiddleware, h.GetUserRaffleTickets)
@ -209,9 +210,9 @@ func (a *App) initAppRoutes() {
a.fiber.Get("/raffle-ticket/unsuspend/:id", a.authMiddleware, h.UnSuspendRaffleTicket) a.fiber.Get("/raffle-ticket/unsuspend/:id", a.authMiddleware, h.UnSuspendRaffleTicket)
// Bonus Routes // Bonus Routes
groupV1.Get("/bonus", a.authMiddleware, h.GetBonusesByUserID) tenant.Get("/bonus", a.authMiddleware, h.GetBonusesByUserID)
groupV1.Get("/bonus/stats", a.authMiddleware, h.GetBonusStats) tenant.Get("/bonus/stats", a.authMiddleware, h.GetBonusStats)
groupV1.Post("/bonus/claim/:id", a.authMiddleware, h.ClaimBonus) tenant.Post("/bonus/claim/:id", a.authMiddleware, h.ClaimBonus)
// groupV1.Post("/bonus/create", a.authMiddleware, h.CreateBonusMultiplier) // groupV1.Post("/bonus/create", a.authMiddleware, h.CreateBonusMultiplier)
// groupV1.Put("/bonus/update", a.authMiddleware, h.UpdateBonusMultiplier) // groupV1.Put("/bonus/update", a.authMiddleware, h.UpdateBonusMultiplier)
@ -228,7 +229,7 @@ func (a *App) initAppRoutes() {
groupV1.Get("/customer", a.authMiddleware, a.SuperAdminOnly, h.GetAllCustomers) groupV1.Get("/customer", a.authMiddleware, a.SuperAdminOnly, h.GetAllCustomers)
groupV1.Get("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCustomerByID) groupV1.Get("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCustomerByID)
groupV1.Put("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCustomer) groupV1.Put("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCustomer)
tenant.Get("/customer/:id/bets", a.authMiddleware, h.GetCustomerBets) groupV1.Get("/customer/:id/bets", a.authMiddleware, h.GetCustomerBets)
groupV1.Get("/admin", a.authMiddleware, h.GetAllAdmins) groupV1.Get("/admin", a.authMiddleware, h.GetAllAdmins)
groupV1.Get("/admin/:id", a.authMiddleware, h.GetAdminByID) groupV1.Get("/admin/:id", a.authMiddleware, h.GetAdminByID)
@ -446,8 +447,8 @@ func (a *App) initAppRoutes() {
groupV1.Get("/settings/:key", a.authMiddleware, a.SuperAdminOnly, h.GetGlobalSettingByKey) groupV1.Get("/settings/:key", a.authMiddleware, a.SuperAdminOnly, h.GetGlobalSettingByKey)
groupV1.Put("/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalSettingList) groupV1.Put("/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalSettingList)
tenant.Post("/settings", a.authMiddleware, h.SaveCompanySettingList)
tenant.Get("/settings", a.authMiddleware, h.GetCompanySettingList) tenant.Get("/settings", a.authMiddleware, h.GetCompanySettingList)
tenant.Put("/settings", a.authMiddleware, h.SaveCompanySettingList)
tenant.Delete("/settings/:key", a.authMiddleware, h.DeleteCompanySetting) tenant.Delete("/settings/:key", a.authMiddleware, h.DeleteCompanySetting)
tenant.Delete("/settings", a.authMiddleware, h.DeleteAllCompanySetting) tenant.Delete("/settings", a.authMiddleware, h.DeleteAllCompanySetting)