fix: added wallet type to wallet and other minor fixes
This commit is contained in:
parent
972d62d568
commit
65bd5ab3f5
|
|
@ -133,6 +133,7 @@ CREATE TABLE IF NOT EXISTS wallets (
|
||||||
is_bettable BOOLEAN NOT NULL,
|
is_bettable BOOLEAN NOT NULL,
|
||||||
is_transferable BOOLEAN NOT NULL,
|
is_transferable BOOLEAN NOT NULL,
|
||||||
user_id BIGINT NOT NULL,
|
user_id BIGINT NOT NULL,
|
||||||
|
type VARCHAR(255) NOT NULL,
|
||||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
|
@ -335,12 +336,16 @@ CREATE TABLE flags (
|
||||||
reason TEXT,
|
reason TEXT,
|
||||||
flagged_at TIMESTAMP DEFAULT NOW(),
|
flagged_at TIMESTAMP DEFAULT NOW(),
|
||||||
resolved BOOLEAN DEFAULT FALSE,
|
resolved BOOLEAN DEFAULT FALSE,
|
||||||
|
|
||||||
-- either bet or odd is flagged (not at the same time)
|
-- either bet or odd is flagged (not at the same time)
|
||||||
CHECK (
|
CHECK (
|
||||||
(bet_id IS NOT NULL AND odd_id IS NULL)
|
(
|
||||||
OR
|
bet_id IS NOT NULL
|
||||||
(bet_id IS NULL AND odd_id IS NOT NULL)
|
AND odd_id IS NULL
|
||||||
|
)
|
||||||
|
OR (
|
||||||
|
bet_id IS NULL
|
||||||
|
AND odd_id IS NOT NULL
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
-- Views
|
-- Views
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,7 @@ VALUES ('addis_ababa', 'Addis Ababa'),
|
||||||
('meki', 'Meki'),
|
('meki', 'Meki'),
|
||||||
('negele_borana', 'Negele Borana'),
|
('negele_borana', 'Negele Borana'),
|
||||||
('alaba_kulito', 'Alaba Kulito'),
|
('alaba_kulito', 'Alaba Kulito'),
|
||||||
('alamata 14,', 'Alamata 14,'),
|
('alamata,', 'Alamata,'),
|
||||||
('030', '030'),
|
|
||||||
('chiro', 'Chiro'),
|
('chiro', 'Chiro'),
|
||||||
('tepi', 'Tepi'),
|
('tepi', 'Tepi'),
|
||||||
('durame', 'Durame'),
|
('durame', 'Durame'),
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@ INSERT INTO wallets (
|
||||||
is_withdraw,
|
is_withdraw,
|
||||||
is_bettable,
|
is_bettable,
|
||||||
is_transferable,
|
is_transferable,
|
||||||
user_id
|
user_id,
|
||||||
|
type
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3, $4)
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
-- name: CreateCustomerWallet :one
|
-- name: CreateCustomerWallet :one
|
||||||
INSERT INTO customer_wallets (
|
INSERT INTO customer_wallets (
|
||||||
|
|
|
||||||
|
|
@ -674,6 +674,7 @@ type Wallet struct {
|
||||||
IsBettable bool `json:"is_bettable"`
|
IsBettable bool `json:"is_bettable"`
|
||||||
IsTransferable bool `json:"is_transferable"`
|
IsTransferable bool `json:"is_transferable"`
|
||||||
UserID int64 `json:"user_id"`
|
UserID int64 `json:"user_id"`
|
||||||
|
Type string `json:"type"`
|
||||||
IsActive bool `json:"is_active"`
|
IsActive bool `json:"is_active"`
|
||||||
CreatedAt pgtype.Timestamp `json:"created_at"`
|
CreatedAt pgtype.Timestamp `json:"created_at"`
|
||||||
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
UpdatedAt pgtype.Timestamp `json:"updated_at"`
|
||||||
|
|
|
||||||
|
|
@ -46,17 +46,19 @@ INSERT INTO wallets (
|
||||||
is_withdraw,
|
is_withdraw,
|
||||||
is_bettable,
|
is_bettable,
|
||||||
is_transferable,
|
is_transferable,
|
||||||
user_id
|
user_id,
|
||||||
|
type
|
||||||
)
|
)
|
||||||
VALUES ($1, $2, $3, $4)
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
RETURNING id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at, currency, bonus_balance, cash_balance
|
RETURNING id, balance, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, currency, bonus_balance, cash_balance
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateWalletParams struct {
|
type CreateWalletParams struct {
|
||||||
IsWithdraw bool `json:"is_withdraw"`
|
IsWithdraw bool `json:"is_withdraw"`
|
||||||
IsBettable bool `json:"is_bettable"`
|
IsBettable bool `json:"is_bettable"`
|
||||||
IsTransferable bool `json:"is_transferable"`
|
IsTransferable bool `json:"is_transferable"`
|
||||||
UserID int64 `json:"user_id"`
|
UserID int64 `json:"user_id"`
|
||||||
|
Type string `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateWallet(ctx context.Context, arg CreateWalletParams) (Wallet, error) {
|
func (q *Queries) CreateWallet(ctx context.Context, arg CreateWalletParams) (Wallet, error) {
|
||||||
|
|
@ -65,6 +67,7 @@ func (q *Queries) CreateWallet(ctx context.Context, arg CreateWalletParams) (Wal
|
||||||
arg.IsBettable,
|
arg.IsBettable,
|
||||||
arg.IsTransferable,
|
arg.IsTransferable,
|
||||||
arg.UserID,
|
arg.UserID,
|
||||||
|
arg.Type,
|
||||||
)
|
)
|
||||||
var i Wallet
|
var i Wallet
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
|
|
@ -74,6 +77,7 @@ func (q *Queries) CreateWallet(ctx context.Context, arg CreateWalletParams) (Wal
|
||||||
&i.IsBettable,
|
&i.IsBettable,
|
||||||
&i.IsTransferable,
|
&i.IsTransferable,
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
|
&i.Type,
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
|
@ -184,7 +188,7 @@ func (q *Queries) GetAllCustomerWallet(ctx context.Context) ([]CustomerWalletDet
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetAllWallets = `-- name: GetAllWallets :many
|
const GetAllWallets = `-- name: GetAllWallets :many
|
||||||
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at, currency, bonus_balance, cash_balance
|
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, currency, bonus_balance, cash_balance
|
||||||
FROM wallets
|
FROM wallets
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|
@ -204,6 +208,7 @@ func (q *Queries) GetAllWallets(ctx context.Context) ([]Wallet, error) {
|
||||||
&i.IsBettable,
|
&i.IsBettable,
|
||||||
&i.IsTransferable,
|
&i.IsTransferable,
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
|
&i.Type,
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
|
@ -314,7 +319,7 @@ func (q *Queries) GetCustomerWallet(ctx context.Context, customerID int64) (Cust
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetWalletByID = `-- name: GetWalletByID :one
|
const GetWalletByID = `-- name: GetWalletByID :one
|
||||||
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at, currency, bonus_balance, cash_balance
|
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, currency, bonus_balance, cash_balance
|
||||||
FROM wallets
|
FROM wallets
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`
|
`
|
||||||
|
|
@ -329,6 +334,7 @@ func (q *Queries) GetWalletByID(ctx context.Context, id int64) (Wallet, error) {
|
||||||
&i.IsBettable,
|
&i.IsBettable,
|
||||||
&i.IsTransferable,
|
&i.IsTransferable,
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
|
&i.Type,
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
|
@ -340,7 +346,7 @@ func (q *Queries) GetWalletByID(ctx context.Context, id int64) (Wallet, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetWalletByUserID = `-- name: GetWalletByUserID :many
|
const GetWalletByUserID = `-- name: GetWalletByUserID :many
|
||||||
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at, currency, bonus_balance, cash_balance
|
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, type, is_active, created_at, updated_at, currency, bonus_balance, cash_balance
|
||||||
FROM wallets
|
FROM wallets
|
||||||
WHERE user_id = $1
|
WHERE user_id = $1
|
||||||
`
|
`
|
||||||
|
|
@ -361,6 +367,7 @@ func (q *Queries) GetWalletByUserID(ctx context.Context, userID int64) ([]Wallet
|
||||||
&i.IsBettable,
|
&i.IsBettable,
|
||||||
&i.IsTransferable,
|
&i.IsTransferable,
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
|
&i.Type,
|
||||||
&i.IsActive,
|
&i.IsActive,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.UpdatedAt,
|
&i.UpdatedAt,
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ type CreateBetOutcomeReq struct {
|
||||||
type CreateBetReq struct {
|
type CreateBetReq struct {
|
||||||
Outcomes []CreateBetOutcomeReq `json:"outcomes" validate:"required"`
|
Outcomes []CreateBetOutcomeReq `json:"outcomes" validate:"required"`
|
||||||
Amount float32 `json:"amount" validate:"required,gt=0" example:"100.0"`
|
Amount float32 `json:"amount" validate:"required,gt=0" example:"100.0"`
|
||||||
BranchID *int64 `json:"branch_id,omitempty" validate:"required" example:"1"`
|
BranchID *int64 `json:"branch_id,omitempty" example:"1"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateBetWithFastCodeReq struct {
|
type CreateBetWithFastCodeReq struct {
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,9 @@ type UpdateCompany struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateCompanyReq struct {
|
type CreateCompanyReq struct {
|
||||||
Name string `json:"name" example:"CompanyName"`
|
Name string `json:"name" example:"CompanyName"`
|
||||||
AdminID int64 `json:"admin_id" example:"1"`
|
AdminID int64 `json:"admin_id" example:"1"`
|
||||||
|
DeductedPercentage float32 `json:"deducted_percentage" example:"0.1" validate:"lt=1"`
|
||||||
}
|
}
|
||||||
type UpdateCompanyReq struct {
|
type UpdateCompanyReq struct {
|
||||||
Name *string `json:"name,omitempty" example:"CompanyName"`
|
Name *string `json:"name,omitempty" example:"CompanyName"`
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ type OtpProvider string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TwilioSms OtpProvider = "twilio"
|
TwilioSms OtpProvider = "twilio"
|
||||||
AfroMessage OtpProvider = "aformessage"
|
AfroMessage OtpProvider = "afro_message"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Otp struct {
|
type Otp struct {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ type Wallet struct {
|
||||||
IsTransferable bool
|
IsTransferable bool
|
||||||
IsActive bool
|
IsActive bool
|
||||||
UserID int64
|
UserID int64
|
||||||
|
Type WalletType
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time
|
||||||
CreatedAt time.Time
|
CreatedAt time.Time
|
||||||
}
|
}
|
||||||
|
|
@ -63,6 +64,7 @@ type CreateWallet struct {
|
||||||
IsBettable bool
|
IsBettable bool
|
||||||
IsTransferable bool
|
IsTransferable bool
|
||||||
UserID int64
|
UserID int64
|
||||||
|
Type WalletType
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateCustomerWallet struct {
|
type CreateCustomerWallet struct {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ func convertDBWallet(wallet dbgen.Wallet) domain.Wallet {
|
||||||
IsTransferable: wallet.IsTransferable,
|
IsTransferable: wallet.IsTransferable,
|
||||||
IsActive: wallet.IsActive,
|
IsActive: wallet.IsActive,
|
||||||
UserID: wallet.UserID,
|
UserID: wallet.UserID,
|
||||||
|
Type: domain.WalletType(wallet.Type),
|
||||||
UpdatedAt: wallet.UpdatedAt.Time,
|
UpdatedAt: wallet.UpdatedAt.Time,
|
||||||
CreatedAt: wallet.CreatedAt.Time,
|
CreatedAt: wallet.CreatedAt.Time,
|
||||||
}
|
}
|
||||||
|
|
@ -28,6 +29,7 @@ func convertCreateWallet(wallet domain.CreateWallet) dbgen.CreateWalletParams {
|
||||||
IsBettable: wallet.IsBettable,
|
IsBettable: wallet.IsBettable,
|
||||||
IsTransferable: wallet.IsTransferable,
|
IsTransferable: wallet.IsTransferable,
|
||||||
UserID: wallet.UserID,
|
UserID: wallet.UserID,
|
||||||
|
Type: string(wallet.Type),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,4 +277,3 @@ func (s *Store) GetTotalWallets(ctx context.Context, filter domain.ReportFilter)
|
||||||
|
|
||||||
return total, nil
|
return total, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,11 @@ func (s *Service) SendOtp(ctx context.Context, sentTo string, otpFor domain.OtpF
|
||||||
switch medium {
|
switch medium {
|
||||||
case domain.OtpMediumSms:
|
case domain.OtpMediumSms:
|
||||||
switch provider {
|
switch provider {
|
||||||
case "twilio":
|
case domain.TwilioSms:
|
||||||
if err := s.SendTwilioSMSOTP(ctx, sentTo, message, provider); err != nil {
|
if err := s.SendTwilioSMSOTP(ctx, sentTo, message, provider); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "afromessage":
|
case domain.AfroMessage:
|
||||||
if err := s.SendAfroMessageSMSOTP(ctx, sentTo, message, provider); err != nil {
|
if err := s.SendAfroMessageSMSOTP(ctx, sentTo, message, provider); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +107,7 @@ func (s *Service) SendTwilioSMSOTP(ctx context.Context, receiverPhone, message s
|
||||||
|
|
||||||
_, err := client.Api.CreateMessage(params)
|
_, err := client.Api.CreateMessage(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s", "Error sending SMS message: %s" + err.Error())
|
return fmt.Errorf("%s", "Error sending SMS message: %s"+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -126,11 +126,29 @@ func (s *Service) DeductFromWallet(ctx context.Context, id int64, amount domain.
|
||||||
if wallet.Balance < amount {
|
if wallet.Balance < amount {
|
||||||
// Send Wallet low to admin
|
// Send Wallet low to admin
|
||||||
if walletType == domain.CompanyWalletType || walletType == domain.BranchWalletType {
|
if walletType == domain.CompanyWalletType || walletType == domain.BranchWalletType {
|
||||||
s.SendAdminWalletLowNotification(ctx, wallet, amount)
|
s.SendAdminWalletInsufficientNotification(ctx, wallet, amount)
|
||||||
}
|
}
|
||||||
return domain.Transfer{}, ErrBalanceInsufficient
|
return domain.Transfer{}, ErrBalanceInsufficient
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if wallet.Type == domain.BranchWalletType || wallet.Type == domain.CompanyWalletType {
|
||||||
|
var thresholds []float32
|
||||||
|
|
||||||
|
if wallet.Type == domain.CompanyWalletType {
|
||||||
|
thresholds = []float32{100000, 50000, 25000, 10000, 5000, 3000, 1000, 500}
|
||||||
|
} else {
|
||||||
|
thresholds = []float32{5000, 3000, 1000, 500}
|
||||||
|
}
|
||||||
|
|
||||||
|
balance := wallet.Balance.Float32()
|
||||||
|
for _, threshold := range thresholds {
|
||||||
|
if balance < threshold {
|
||||||
|
s.SendAdminWalletLowNotification(ctx, wallet)
|
||||||
|
break // only send once per check
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = s.walletStore.UpdateBalance(ctx, id, wallet.Balance-amount)
|
err = s.walletStore.UpdateBalance(ctx, id, wallet.Balance-amount)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -197,30 +215,28 @@ func (s *Service) UpdateWalletActive(ctx context.Context, id int64, isActive boo
|
||||||
return s.walletStore.UpdateWalletActive(ctx, id, isActive)
|
return s.walletStore.UpdateWalletActive(ctx, id, isActive)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) SendAdminWalletLowNotification(ctx context.Context, adminWallet domain.Wallet, amount domain.Currency) error {
|
func (s *Service) SendAdminWalletLowNotification(ctx context.Context, adminWallet domain.Wallet) error {
|
||||||
// Send notification to admin team
|
// Send notification to admin team
|
||||||
adminNotification := &domain.Notification{
|
adminNotification := &domain.Notification{
|
||||||
RecipientID: adminWallet.UserID,
|
RecipientID: adminWallet.UserID,
|
||||||
Type: domain.NOTIFICATION_TYPE_ADMIN_ALERT,
|
Type: domain.NOTIFICATION_TYPE_ADMIN_ALERT,
|
||||||
Level: domain.NotificationLevelError,
|
Level: domain.NotificationLevelWarning,
|
||||||
Reciever: domain.NotificationRecieverSideAdmin,
|
Reciever: domain.NotificationRecieverSideAdmin,
|
||||||
DeliveryChannel: domain.DeliveryChannelEmail, // Or any preferred admin channel
|
DeliveryChannel: domain.DeliveryChannelEmail, // Or any preferred admin channel
|
||||||
Payload: domain.NotificationPayload{
|
Payload: domain.NotificationPayload{
|
||||||
Headline: "CREDIT WARNING: System Running Out of Funds",
|
Headline: "CREDIT WARNING: System Running Out of Funds",
|
||||||
Message: fmt.Sprintf(
|
Message: fmt.Sprintf(
|
||||||
"Wallet ID %d has insufficient balance for transfer. Current balance: %.2f, Attempted transfer: %.2f",
|
"Wallet ID %d is running low. Current balance: %.2f",
|
||||||
adminWallet.ID,
|
adminWallet.ID,
|
||||||
adminWallet.Balance.Float32(),
|
adminWallet.Balance.Float32(),
|
||||||
amount.Float32(),
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
Priority: 1, // High priority for admin alerts
|
Priority: 1, // High priority for admin alerts
|
||||||
Metadata: fmt.Appendf(nil, `{
|
Metadata: fmt.Appendf(nil, `{
|
||||||
"wallet_id": %d,
|
"wallet_id": %d,
|
||||||
"balance": %d,
|
"balance": %d,
|
||||||
"required_amount": %d,
|
|
||||||
"notification_type": "admin_alert"
|
"notification_type": "admin_alert"
|
||||||
}`, adminWallet.ID, adminWallet.Balance, amount),
|
}`, adminWallet.ID, adminWallet.Balance),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get admin recipients and send to all
|
// Get admin recipients and send to all
|
||||||
|
|
@ -240,3 +256,85 @@ func (s *Service) SendAdminWalletLowNotification(ctx context.Context, adminWalle
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) SendAdminWalletInsufficientNotification(ctx context.Context, adminWallet domain.Wallet, amount domain.Currency) error {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Send notification to admin team
|
||||||
|
adminNotification := &domain.Notification{
|
||||||
|
RecipientID: adminWallet.UserID,
|
||||||
|
Type: domain.NOTIFICATION_TYPE_ADMIN_ALERT,
|
||||||
|
Level: domain.NotificationLevelError,
|
||||||
|
Reciever: domain.NotificationRecieverSideAdmin,
|
||||||
|
DeliveryChannel: domain.DeliveryChannelEmail, // Or any preferred admin channel
|
||||||
|
Payload: domain.NotificationPayload{
|
||||||
|
Headline: "CREDIT Error: Admin Wallet insufficient to process customer request",
|
||||||
|
Message: fmt.Sprintf(
|
||||||
|
"Wallet ID %d. Transaction Amount %.2f. Current balance: %.2f",
|
||||||
|
adminWallet.ID,
|
||||||
|
amount.Float32(),
|
||||||
|
adminWallet.Balance.Float32(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Priority: 1, // High priority for admin alerts
|
||||||
|
Metadata: fmt.Appendf(nil, `{
|
||||||
|
"wallet_id": %d,
|
||||||
|
"balance": %d,
|
||||||
|
"transaction amount": %.2f,
|
||||||
|
"notification_type": "admin_alert"
|
||||||
|
}`, adminWallet.ID, adminWallet.Balance, amount.Float32()),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get admin recipients and send to all
|
||||||
|
adminRecipients, err := s.notificationStore.ListRecipientIDs(ctx, domain.NotificationRecieverSideAdmin)
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Error("failed to get admin recipients", "error", err)
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
for _, adminID := range adminRecipients {
|
||||||
|
adminNotification.RecipientID = adminID
|
||||||
|
if err := s.notificationStore.SendNotification(ctx, adminNotification); err != nil {
|
||||||
|
s.logger.Error("failed to send admin notification",
|
||||||
|
"admin_id", adminID,
|
||||||
|
"error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) SendCustomerWalletInsufficientNotification(ctx context.Context, customerWallet domain.Wallet, amount domain.Currency) error {
|
||||||
|
// Send notification to admin team
|
||||||
|
adminNotification := &domain.Notification{
|
||||||
|
RecipientID: customerWallet.UserID,
|
||||||
|
Type: domain.NOTIFICATION_TYPE_WALLET,
|
||||||
|
Level: domain.NotificationLevelError,
|
||||||
|
Reciever: domain.NotificationRecieverSideAdmin,
|
||||||
|
DeliveryChannel: domain.DeliveryChannelEmail, // Or any preferred admin channel
|
||||||
|
Payload: domain.NotificationPayload{
|
||||||
|
Headline: "CREDIT Error: Admin Wallet insufficient to process customer request",
|
||||||
|
Message: fmt.Sprintf(
|
||||||
|
"Wallet ID %d. Transaction Amount %.2f. Current balance: %.2f",
|
||||||
|
customerWallet.ID,
|
||||||
|
amount.Float32(),
|
||||||
|
customerWallet.Balance.Float32(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Priority: 1, // High priority for admin alerts
|
||||||
|
Metadata: fmt.Appendf(nil, `{
|
||||||
|
"wallet_id": %d,
|
||||||
|
"balance": %d,
|
||||||
|
"transaction amount": %.2f,
|
||||||
|
"notification_type": "admin_alert"
|
||||||
|
}`, customerWallet.ID, customerWallet.Balance, amount.Float32()),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.notificationStore.SendNotification(ctx, adminNotification); err != nil {
|
||||||
|
s.logger.Error("failed to send customer notification",
|
||||||
|
"admin_id", customerWallet.UserID,
|
||||||
|
"error", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,22 +24,22 @@ 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() {
|
||||||
if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||||
log.Printf("FetchUpcomingEvents error: %v", err)
|
// log.Printf("FetchUpcomingEvents error: %v", err)
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
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() {
|
||||||
if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||||
log.Printf("FetchNonLiveOdds error: %v", err)
|
// log.Printf("FetchNonLiveOdds error: %v", err)
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
spec: "0 */5 * * * *", // Every 5 Minutes
|
spec: "0 */5 * * * *", // Every 5 Minutes
|
||||||
task: func() {
|
task: func() {
|
||||||
|
|
@ -114,10 +114,10 @@ func SetupReportCronJobs(ctx context.Context, reportService *report.Service) {
|
||||||
spec string
|
spec string
|
||||||
period string
|
period string
|
||||||
}{
|
}{
|
||||||
{
|
// {
|
||||||
spec: "*/300 * * * * *", // Every 5 minutes (300 seconds)
|
// spec: "*/300 * * * * *", // Every 5 minutes (300 seconds)
|
||||||
period: "5min",
|
// period: "5min",
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
spec: "0 0 0 * * *", // Daily at midnight
|
spec: "0 0 0 * * *", // Daily at midnight
|
||||||
period: "daily",
|
period: "daily",
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import (
|
||||||
|
|
||||||
// loginCustomerReq represents the request body for the LoginCustomer endpoint.
|
// loginCustomerReq represents the request body for the LoginCustomer endpoint.
|
||||||
type loginCustomerReq struct {
|
type loginCustomerReq struct {
|
||||||
Email string `json:"email" validate:"email" example:"john.doe@example.com"`
|
Email string `json:"email" validate:"required_without=PhoneNumber" example:"john.doe@example.com"`
|
||||||
PhoneNumber string `json:"phone_number" validate:"required_without=Email" example:"1234567890"`
|
PhoneNumber string `json:"phone_number" validate:"required_without=Email" example:"1234567890"`
|
||||||
Password string `json:"password" validate:"required" example:"password123"`
|
Password string `json:"password" validate:"required" example:"password123"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,21 +73,28 @@ func (h *Handler) GetDashboardReport(c *fiber.Ctx) error {
|
||||||
func parseReportFilter(c *fiber.Ctx) (domain.ReportFilter, error) {
|
func parseReportFilter(c *fiber.Ctx) (domain.ReportFilter, error) {
|
||||||
var filter domain.ReportFilter
|
var filter domain.ReportFilter
|
||||||
var err error
|
var err error
|
||||||
|
role := c.Locals("role").(domain.Role)
|
||||||
|
|
||||||
|
if c.Query("company_id") != "" && role == domain.RoleSuperAdmin {
|
||||||
|
|
||||||
if c.Query("company_id") != "" {
|
|
||||||
companyID, err := strconv.ParseInt(c.Query("company_id"), 10, 64)
|
companyID, err := strconv.ParseInt(c.Query("company_id"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.ReportFilter{}, fmt.Errorf("invalid company_id: %w", err)
|
return domain.ReportFilter{}, fmt.Errorf("invalid company_id: %w", err)
|
||||||
}
|
}
|
||||||
filter.CompanyID = domain.ValidInt64{Value: companyID, Valid: true}
|
filter.CompanyID = domain.ValidInt64{Value: companyID, Valid: true}
|
||||||
|
} else {
|
||||||
|
filter.CompanyID = c.Locals("company_id").(domain.ValidInt64)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Query("branch_id") != "" {
|
if c.Query("branch_id") != "" && role == domain.RoleSuperAdmin {
|
||||||
branchID, err := strconv.ParseInt(c.Query("branch_id"), 10, 64)
|
branchID, err := strconv.ParseInt(c.Query("branch_id"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.ReportFilter{}, fmt.Errorf("invalid branch_id: %w", err)
|
return domain.ReportFilter{}, fmt.Errorf("invalid branch_id: %w", err)
|
||||||
}
|
}
|
||||||
filter.BranchID = domain.ValidInt64{Value: branchID, Valid: true}
|
filter.BranchID = domain.ValidInt64{Value: branchID, Valid: true}
|
||||||
|
} else {
|
||||||
|
filter.BranchID = c.Locals("branch_id").(domain.ValidInt64)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Query("user_id") != "" {
|
if c.Query("user_id") != "" {
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,89 @@ func (h *Handler) GetShopBetByBetID(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Shop bet fetched successfully", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Shop bet fetched successfully", res, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAllShopBets godoc
|
||||||
|
// @Summary Gets all shop bets
|
||||||
|
// @Description Gets all the shop bets
|
||||||
|
// @Tags bet
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {array} domain.ShopBetRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Router /api/v1/shop/bet [get]
|
||||||
|
func (h *Handler) GetAllShopBets(c *fiber.Ctx) error {
|
||||||
|
// 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.mongoLoggerSvc.Info("invalid created_before format",
|
||||||
|
zap.String("time", createdBeforeQuery),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid created_before format")
|
||||||
|
}
|
||||||
|
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.mongoLoggerSvc.Info("invalid created_after format",
|
||||||
|
zap.String("created_after", createdAfterQuery),
|
||||||
|
zap.Int("status_code", fiber.StatusBadRequest),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid created_after format")
|
||||||
|
}
|
||||||
|
createdAfter = domain.ValidTime{
|
||||||
|
Value: createdAfterParsed,
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bets, err := h.transactionSvc.GetAllShopBet(c.Context(), domain.ShopBetFilter{
|
||||||
|
Query: searchString,
|
||||||
|
CreatedBefore: createdBefore,
|
||||||
|
CreatedAfter: createdAfter,
|
||||||
|
CompanyID: companyID,
|
||||||
|
BranchID: branchID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to get all bets",
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve bets፡"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make([]domain.ShopBetRes, len(bets))
|
||||||
|
for i, bet := range bets {
|
||||||
|
res[i] = domain.ConvertShopBetDetail(bet)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.WriteJSON(c, fiber.StatusOK, "All bets retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
|
|
||||||
// CashoutBet godoc
|
// CashoutBet godoc
|
||||||
// @Summary Cashout bet at branch
|
// @Summary Cashout bet at branch
|
||||||
// @Description Cashout bet at branch
|
// @Description Cashout bet at branch
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,7 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
|
||||||
// TODO: Remove later
|
// TODO: Remove later
|
||||||
_, err = h.walletSvc.AddToWallet(
|
_, err = h.walletSvc.AddToWallet(
|
||||||
c.Context(), newWallet.RegularID, domain.ToCurrency(10000.0), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
|
c.Context(), newWallet.RegularID, domain.ToCurrency(10000.0), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
|
||||||
"Added 100.0 to wallet only as test for deployment")
|
"Added 10000.0 to wallet only as test for deployment")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.mongoLoggerSvc.Error("Failed to update wallet for user",
|
h.mongoLoggerSvc.Error("Failed to update wallet for user",
|
||||||
|
|
@ -417,20 +417,121 @@ type UserProfileRes struct {
|
||||||
LastLogin time.Time `json:"last_login"`
|
LastLogin time.Time `json:"last_login"`
|
||||||
SuspendedAt time.Time `json:"suspended_at"`
|
SuspendedAt time.Time `json:"suspended_at"`
|
||||||
Suspended bool `json:"suspended"`
|
Suspended bool `json:"suspended"`
|
||||||
|
ReferralCode string `json:"referral_code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserProfile godoc
|
type CustomerProfileRes 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 domain.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"`
|
||||||
|
LastLogin time.Time `json:"last_login"`
|
||||||
|
SuspendedAt time.Time `json:"suspended_at"`
|
||||||
|
Suspended bool `json:"suspended"`
|
||||||
|
ReferralCode string `json:"referral_code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CustomerProfile godoc
|
||||||
// @Summary Get user profile
|
// @Summary Get user profile
|
||||||
// @Description Get user profile
|
// @Description Get user profile
|
||||||
// @Tags user
|
// @Tags user
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} UserProfileRes
|
// @Success 200 {object} CustomerProfileRes
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Security Bearer
|
// @Security Bearer
|
||||||
// @Router /api/v1/user/profile [get]
|
// @Router /api/v1/user/customer-profile [get]
|
||||||
func (h *Handler) UserProfile(c *fiber.Ctx) error {
|
func (h *Handler) CustomerProfile(c *fiber.Ctx) error {
|
||||||
|
|
||||||
|
userID, ok := c.Locals("user_id").(int64)
|
||||||
|
if !ok || userID == 0 {
|
||||||
|
h.mongoLoggerSvc.Error("Invalid user ID in context",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification")
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := h.userSvc.GetUserByID(c.Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to get user profile",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user profile:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
lastLogin, err := h.authSvc.GetLastLogin(c.Context(), user.ID)
|
||||||
|
if err != nil {
|
||||||
|
if err != authentication.ErrRefreshTokenNotFound {
|
||||||
|
h.mongoLoggerSvc.Error("Failed to get user last login",
|
||||||
|
zap.Int64("userID", userID),
|
||||||
|
zap.Int("status_code", fiber.StatusInternalServerError),
|
||||||
|
zap.Error(err),
|
||||||
|
zap.Time("timestamp", time.Now()),
|
||||||
|
)
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user last login:"+err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
lastLogin = &user.CreatedAt
|
||||||
|
}
|
||||||
|
res := CustomerProfileRes{
|
||||||
|
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 profile retrieved successfully", res, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AdminProfileRes 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 domain.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"`
|
||||||
|
LastLogin time.Time `json:"last_login"`
|
||||||
|
SuspendedAt time.Time `json:"suspended_at"`
|
||||||
|
Suspended bool `json:"suspended"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdminProfile godoc
|
||||||
|
// @Summary Get user profile
|
||||||
|
// @Description Get user profile
|
||||||
|
// @Tags user
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} AdminProfileRes
|
||||||
|
// @Failure 400 {object} response.APIResponse
|
||||||
|
// @Failure 500 {object} response.APIResponse
|
||||||
|
// @Security Bearer
|
||||||
|
// @Router /api/v1/user/admin-profile [get]
|
||||||
|
func (h *Handler) AdminProfile(c *fiber.Ctx) error {
|
||||||
|
|
||||||
userID, ok := c.Locals("user_id").(int64)
|
userID, ok := c.Locals("user_id").(int64)
|
||||||
if !ok || userID == 0 {
|
if !ok || userID == 0 {
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,8 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Post("/user/register", h.RegisterUser)
|
groupV1.Post("/user/register", h.RegisterUser)
|
||||||
groupV1.Post("/user/sendRegisterCode", h.SendRegisterCode)
|
groupV1.Post("/user/sendRegisterCode", h.SendRegisterCode)
|
||||||
groupV1.Post("/user/checkPhoneEmailExist", h.CheckPhoneEmailExist)
|
groupV1.Post("/user/checkPhoneEmailExist", h.CheckPhoneEmailExist)
|
||||||
groupV1.Get("/user/profile", a.authMiddleware, h.UserProfile)
|
groupV1.Get("/user/customer-profile", a.authMiddleware, h.CustomerProfile)
|
||||||
|
groupV1.Get("/user/admin-profile", a.authMiddleware, h.AdminProfile)
|
||||||
groupV1.Get("/user/single/:id", a.authMiddleware, h.GetUserByID)
|
groupV1.Get("/user/single/:id", a.authMiddleware, h.GetUserByID)
|
||||||
groupV1.Delete("/user/delete/:id", a.authMiddleware, h.DeleteUser)
|
groupV1.Delete("/user/delete/:id", a.authMiddleware, h.DeleteUser)
|
||||||
groupV1.Post("/user/suspend", a.authMiddleware, h.UpdateUserSuspend)
|
groupV1.Post("/user/suspend", a.authMiddleware, h.UpdateUserSuspend)
|
||||||
|
|
@ -174,6 +175,7 @@ func (a *App) initAppRoutes() {
|
||||||
groupV1.Delete("/branch/:id", a.authMiddleware, h.DeleteBranch)
|
groupV1.Delete("/branch/:id", a.authMiddleware, h.DeleteBranch)
|
||||||
|
|
||||||
groupV1.Get("/search/branch", a.authMiddleware, h.SearchBranch)
|
groupV1.Get("/search/branch", a.authMiddleware, h.SearchBranch)
|
||||||
|
|
||||||
groupV1.Get("/branchLocation", a.authMiddleware, h.GetAllBranchLocations)
|
groupV1.Get("/branchLocation", a.authMiddleware, h.GetAllBranchLocations)
|
||||||
|
|
||||||
groupV1.Get("/branch/:id/cashiers", a.authMiddleware, h.GetBranchCashiers)
|
groupV1.Get("/branch/:id/cashiers", a.authMiddleware, h.GetBranchCashiers)
|
||||||
|
|
@ -287,6 +289,7 @@ func (a *App) initAppRoutes() {
|
||||||
|
|
||||||
// Transactions /shop/transactions
|
// Transactions /shop/transactions
|
||||||
groupV1.Post("/shop/bet", a.authMiddleware, a.CompanyOnly, h.CreateShopBet)
|
groupV1.Post("/shop/bet", a.authMiddleware, a.CompanyOnly, h.CreateShopBet)
|
||||||
|
groupV1.Get("/shop/bet", a.authMiddleware, a.CompanyOnly, h.GetAllShopBets)
|
||||||
groupV1.Get("/shop/bet/:id", a.authMiddleware, a.CompanyOnly, h.GetShopBetByBetID)
|
groupV1.Get("/shop/bet/:id", a.authMiddleware, a.CompanyOnly, h.GetShopBetByBetID)
|
||||||
groupV1.Post("/shop/bet/:id/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutBet)
|
groupV1.Post("/shop/bet/:id/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutBet)
|
||||||
groupV1.Post("/shop/bet/:id/generate", a.authMiddleware, a.CompanyOnly, h.CashoutBet)
|
groupV1.Post("/shop/bet/:id/generate", a.authMiddleware, a.CompanyOnly, h.CashoutBet)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user