From ae571d51a6c4bcd7f3ea242c9868a4f798fdfc90 Mon Sep 17 00:00:00 2001 From: Samuel Tariku Date: Wed, 30 Apr 2025 18:43:46 +0300 Subject: [PATCH] fixed company-id, admin-id optional parameters for creating company and branch --- .vscode/settings.json | 4 +- db/migrations/000001_fortune.up.sql | 57 +++++++++-------- db/query/branch.sql | 13 ++-- db/query/company.sql | 6 +- db/query/transactions.sql | 13 +++- db/query/transfer.sql | 33 +++++++--- db/query/user.sql | 5 ++ gen/db/branch.sql.go | 26 ++++---- gen/db/company.sql.go | 14 ++--- gen/db/models.go | 5 ++ gen/db/transactions.sql.go | 63 ++++++++++++++++--- gen/db/transfer.sql.go | 29 +++++++-- gen/db/user.sql.go | 16 +++++ internal/domain/branch.go | 11 ++-- internal/domain/company.go | 5 +- internal/domain/transaction.go | 10 ++- internal/repository/branch.go | 52 ++++++++++++--- internal/repository/company.go | 30 +++++++-- internal/repository/transaction.go | 24 +++++-- internal/repository/user.go | 14 +++++ internal/services/branch/port.go | 2 +- internal/services/branch/service.go | 4 +- internal/services/company/port.go | 2 +- internal/services/company/service.go | 4 +- internal/services/event/service.go | 9 +-- internal/services/transaction/port.go | 2 +- internal/services/transaction/service.go | 4 +- internal/services/user/port.go | 1 + internal/services/user/user.go | 9 ++- internal/web_server/handlers/admin.go | 22 ++++++- .../web_server/handlers/branch_handler.go | 47 +++++++++++--- .../web_server/handlers/company_handler.go | 29 +++++++-- .../handlers/transaction_handler.go | 46 ++++++++++++-- internal/web_server/middleware.go | 14 +++++ 34 files changed, 480 insertions(+), 145 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f72d738..aa78ae8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,7 @@ { "cSpell.words": [ - "Cashout" + "Cashout", + "narg", + "sqlc" ] } \ No newline at end of file diff --git a/db/migrations/000001_fortune.up.sql b/db/migrations/000001_fortune.up.sql index 7f8eca6..c5eb97a 100644 --- a/db/migrations/000001_fortune.up.sql +++ b/db/migrations/000001_fortune.up.sql @@ -99,18 +99,6 @@ CREATE TABLE IF NOT EXISTS ticket_outcomes ( status INT NOT NULL DEFAULT 0, expires TIMESTAMP NOT NULL ); -CREATE VIEW bet_with_outcomes AS -SELECT bets.*, - JSON_AGG(bet_outcomes.*) AS outcomes -FROM bets - LEFT JOIN bet_outcomes ON bets.id = bet_outcomes.bet_id -GROUP BY bets.id; -CREATE VIEW ticket_with_outcomes AS -SELECT tickets.*, - JSON_AGG(ticket_outcomes.*) AS outcomes -FROM tickets - LEFT JOIN ticket_outcomes ON tickets.id = ticket_outcomes.ticket_id -GROUP BY tickets.id; CREATE TABLE IF NOT EXISTS wallets ( id BIGSERIAL PRIMARY KEY, balance BIGINT NOT NULL DEFAULT 0, @@ -148,7 +136,9 @@ CREATE TABLE IF NOT EXISTS transactions ( id BIGSERIAL PRIMARY KEY, amount BIGINT NOT NULL, branch_id BIGINT NOT NULL, + company_id BIGINT NOT NULL, cashier_id BIGINT NOT NULL, + cashier_name VARCHAR(255) NOT NULL, bet_id BIGINT NOT NULL, number_of_outcomes BIGINT NOT NULL, type BIGINT NOT NULL, @@ -162,6 +152,9 @@ CREATE TABLE IF NOT EXISTS transactions ( reference_number VARCHAR(255) NOT NULL, verified BOOLEAN NOT NULL DEFAULT false, approved_by BIGINT, + approver_name VARCHAR(255), + branch_location VARCHAR(255) NOT NULL, + branch_name VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); @@ -176,17 +169,6 @@ CREATE TABLE IF NOT EXISTS branches ( created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -CREATE VIEW branch_details AS -SELECT branches.*, - CONCAT(users.first_name, ' ', users.last_name) AS manager_name, - users.phone_number AS manager_phone_number -FROM branches - LEFT JOIN users ON branches.branch_manager_id = users.id; -CREATE TABLE IF NOT EXISTS supported_operations ( - id BIGSERIAL PRIMARY KEY, - name VARCHAR(255) NOT NULL, - description VARCHAR(255) NOT NULL -); CREATE TABLE IF NOT EXISTS branch_operations ( id BIGSERIAL PRIMARY KEY, operation_id BIGINT NOT NULL, @@ -250,12 +232,37 @@ CREATE TABLE companies ( admin_id BIGINT NOT NULL, wallet_id BIGINT NOT NULL ); +-- Views CREATE VIEW companies_with_wallets AS SELECT companies.*, wallets.balance, wallets.is_active FROM companies JOIN wallets ON wallets.id = companies.wallet_id; +CREATE VIEW branch_details AS +SELECT branches.*, + CONCAT(users.first_name, ' ', users.last_name) AS manager_name, + users.phone_number AS manager_phone_number +FROM branches + LEFT JOIN users ON branches.branch_manager_id = users.id; +CREATE TABLE IF NOT EXISTS supported_operations ( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + description VARCHAR(255) NOT NULL +); +CREATE VIEW bet_with_outcomes AS +SELECT bets.*, + JSON_AGG(bet_outcomes.*) AS outcomes +FROM bets + LEFT JOIN bet_outcomes ON bets.id = bet_outcomes.bet_id +GROUP BY bets.id; +CREATE VIEW ticket_with_outcomes AS +SELECT tickets.*, + JSON_AGG(ticket_outcomes.*) AS outcomes +FROM tickets + LEFT JOIN ticket_outcomes ON tickets.id = ticket_outcomes.ticket_id +GROUP BY tickets.id; +-- Foreign Keys ALTER TABLE refresh_tokens ADD CONSTRAINT fk_refresh_tokens_users FOREIGN KEY (user_id) REFERENCES users(id); ALTER TABLE bets @@ -279,8 +286,8 @@ ALTER TABLE branches ADD CONSTRAINT fk_branches_wallet FOREIGN KEY (wallet_id) REFERENCES wallets(id), ADD CONSTRAINT fk_branches_manager FOREIGN KEY (branch_manager_id) REFERENCES users(id); ALTER TABLE branch_operations -ADD CONSTRAINT fk_branch_operations_operations FOREIGN KEY (operation_id) REFERENCES supported_operations(id), - ADD CONSTRAINT fk_branch_operations_branches FOREIGN KEY (branch_id) REFERENCES branches(id); +ADD CONSTRAINT fk_branch_operations_operations FOREIGN KEY (operation_id) REFERENCES supported_operations(id) ON DELETE CASCADE, + ADD CONSTRAINT fk_branch_operations_branches FOREIGN KEY (branch_id) REFERENCES branches(id) ON DELETE CASCADE; ALTER TABLE branch_cashiers ADD CONSTRAINT fk_branch_cashiers_users FOREIGN KEY (user_id) REFERENCES users(id), ADD CONSTRAINT fk_branch_cashiers_branches FOREIGN KEY (branch_id) REFERENCES branches(id); diff --git a/db/query/branch.sql b/db/query/branch.sql index 041d0ef..422a612 100644 --- a/db/query/branch.sql +++ b/db/query/branch.sql @@ -24,7 +24,6 @@ RETURNING *; -- name: GetAllBranches :many SELECT * FROM branch_details; - -- name: GetBranchByID :one SELECT * FROM branch_details @@ -67,12 +66,12 @@ FROM branch_cashiers JOIN users ON branch_cashiers.user_id = users.id; -- name: UpdateBranch :one UPDATE branches -SET name = $1, - location = $2, - branch_manager_id = $3, - company_id = $4, - is_self_owned = $5 -WHERE id = $6 +SET name = COALESCE(sqlc.narg(name), name), + location = COALESCE(sqlc.narg(location), location), + branch_manager_id = COALESCE(sqlc.narg(branch_manager_id), branch_manager_id), + company_id = COALESCE(sqlc.narg(company_id), company_id), + is_self_owned = COALESCE(sqlc.narg(is_self_owned), is_self_owned) +WHERE id = $1 RETURNING *; -- name: DeleteBranch :exec DELETE FROM branches diff --git a/db/query/company.sql b/db/query/company.sql index d9ec3a8..35d37c1 100644 --- a/db/query/company.sql +++ b/db/query/company.sql @@ -19,9 +19,9 @@ FROM companies_with_wallets WHERE name ILIKE '%' || $1 || '%'; -- name: UpdateCompany :one UPDATE companies -SET name = $1, - admin_id = $2 -WHERE id = $3 +SET name = COALESCE(sqlc.narg(name), name), + admin_id = COALESCE(sqlc.narg(admin_id), admin_id) +WHERE id = $1 RETURNING *; -- name: DeleteCompany :exec DELETE FROM companies diff --git a/db/query/transactions.sql b/db/query/transactions.sql index a64363f..83e8787 100644 --- a/db/query/transactions.sql +++ b/db/query/transactions.sql @@ -13,7 +13,11 @@ INSERT INTO transactions ( account_name, account_number, reference_number, - number_of_outcomes + number_of_outcomes, + branch_name, + branch_location, + company_id, + cashier_name ) VALUES ( $1, @@ -29,7 +33,11 @@ VALUES ( $11, $12, $13, - $14 + $14, + $15, + $16, + $17, + $18 ) RETURNING *; -- name: GetAllTransactions :many @@ -47,5 +55,6 @@ WHERE branch_id = $1; UPDATE transactions SET verified = $2, approved_by = $3, + approver_name = $4, updated_at = CURRENT_TIMESTAMP WHERE id = $1; \ No newline at end of file diff --git a/db/query/transfer.sql b/db/query/transfer.sql index 62007d6..1272c32 100644 --- a/db/query/transfer.sql +++ b/db/query/transfer.sql @@ -1,14 +1,29 @@ -- name: CreateTransfer :one -INSERT INTO wallet_transfer (amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *; - +INSERT INTO wallet_transfer ( + amount, + type, + receiver_wallet_id, + sender_wallet_id, + cashier_id, + verified, + payment_method + ) +VALUES ($1, $2, $3, $4, $5, $6, $7) +RETURNING *; -- name: GetAllTransfers :many -SELECT * FROM wallet_transfer; - +SELECT * +FROM wallet_transfer; -- name: GetTransfersByWallet :many -SELECT * FROM wallet_transfer WHERE receiver_wallet_id = $1 OR sender_wallet_id = $1; - +SELECT * +FROM wallet_transfer +WHERE receiver_wallet_id = $1 + OR sender_wallet_id = $1; -- name: GetTransferByID :one -SELECT * FROM wallet_transfer WHERE id = $1; - +SELECT * +FROM wallet_transfer +WHERE id = $1; -- name: UpdateTransferVerification :exec -UPDATE wallet_transfer SET verified = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2; +UPDATE wallet_transfer +SET verified = $1, + updated_at = CURRENT_TIMESTAMP +WHERE id = $2; \ No newline at end of file diff --git a/db/query/user.sql b/db/query/user.sql index 1fd2029..c5799e8 100644 --- a/db/query/user.sql +++ b/db/query/user.sql @@ -105,6 +105,11 @@ SET first_name = $1, role = $5, updated_at = $6 WHERE id = $7; +-- name: UpdateUserCompany :exec +UPDATE users +SET company_id = $1 +WHERE id = $2; + -- name: SuspendUser :exec UPDATE users SET suspended = $1, diff --git a/gen/db/branch.sql.go b/gen/db/branch.sql.go index 439d76f..cf16465 100644 --- a/gen/db/branch.sql.go +++ b/gen/db/branch.sql.go @@ -514,32 +514,32 @@ func (q *Queries) SearchBranchByName(ctx context.Context, dollar_1 pgtype.Text) const UpdateBranch = `-- name: UpdateBranch :one UPDATE branches -SET name = $1, - location = $2, - branch_manager_id = $3, - company_id = $4, - is_self_owned = $5 -WHERE id = $6 +SET name = COALESCE($2, name), + location = COALESCE($3, location), + branch_manager_id = COALESCE($4, branch_manager_id), + company_id = COALESCE($5, company_id), + is_self_owned = COALESCE($6, is_self_owned) +WHERE id = $1 RETURNING id, name, location, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at ` type UpdateBranchParams struct { - Name string `json:"name"` - Location string `json:"location"` - BranchManagerID int64 `json:"branch_manager_id"` - CompanyID int64 `json:"company_id"` - IsSelfOwned bool `json:"is_self_owned"` - ID int64 `json:"id"` + ID int64 `json:"id"` + Name pgtype.Text `json:"name"` + Location pgtype.Text `json:"location"` + BranchManagerID pgtype.Int8 `json:"branch_manager_id"` + CompanyID pgtype.Int8 `json:"company_id"` + IsSelfOwned pgtype.Bool `json:"is_self_owned"` } func (q *Queries) UpdateBranch(ctx context.Context, arg UpdateBranchParams) (Branch, error) { row := q.db.QueryRow(ctx, UpdateBranch, + arg.ID, arg.Name, arg.Location, arg.BranchManagerID, arg.CompanyID, arg.IsSelfOwned, - arg.ID, ) var i Branch err := row.Scan( diff --git a/gen/db/company.sql.go b/gen/db/company.sql.go index f9db3aa..13a1940 100644 --- a/gen/db/company.sql.go +++ b/gen/db/company.sql.go @@ -136,20 +136,20 @@ func (q *Queries) SearchCompanyByName(ctx context.Context, dollar_1 pgtype.Text) const UpdateCompany = `-- name: UpdateCompany :one UPDATE companies -SET name = $1, - admin_id = $2 -WHERE id = $3 +SET name = COALESCE($2, name), + admin_id = COALESCE($3, admin_id) +WHERE id = $1 RETURNING id, name, admin_id, wallet_id ` type UpdateCompanyParams struct { - Name string `json:"name"` - AdminID int64 `json:"admin_id"` - ID int64 `json:"id"` + ID int64 `json:"id"` + Name pgtype.Text `json:"name"` + AdminID pgtype.Int8 `json:"admin_id"` } func (q *Queries) UpdateCompany(ctx context.Context, arg UpdateCompanyParams) (Company, error) { - row := q.db.QueryRow(ctx, UpdateCompany, arg.Name, arg.AdminID, arg.ID) + row := q.db.QueryRow(ctx, UpdateCompany, arg.ID, arg.Name, arg.AdminID) var i Company err := row.Scan( &i.ID, diff --git a/gen/db/models.go b/gen/db/models.go index 820d65a..42c5185 100644 --- a/gen/db/models.go +++ b/gen/db/models.go @@ -337,7 +337,9 @@ type Transaction struct { ID int64 `json:"id"` Amount int64 `json:"amount"` BranchID int64 `json:"branch_id"` + CompanyID int64 `json:"company_id"` CashierID int64 `json:"cashier_id"` + CashierName string `json:"cashier_name"` BetID int64 `json:"bet_id"` NumberOfOutcomes int64 `json:"number_of_outcomes"` Type int64 `json:"type"` @@ -351,6 +353,9 @@ type Transaction struct { ReferenceNumber string `json:"reference_number"` Verified bool `json:"verified"` ApprovedBy pgtype.Int8 `json:"approved_by"` + ApproverName pgtype.Text `json:"approver_name"` + BranchLocation string `json:"branch_location"` + BranchName string `json:"branch_name"` CreatedAt pgtype.Timestamp `json:"created_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"` } diff --git a/gen/db/transactions.sql.go b/gen/db/transactions.sql.go index 6c605a5..d3a7418 100644 --- a/gen/db/transactions.sql.go +++ b/gen/db/transactions.sql.go @@ -26,7 +26,11 @@ INSERT INTO transactions ( account_name, account_number, reference_number, - number_of_outcomes + number_of_outcomes, + branch_name, + branch_location, + company_id, + cashier_name ) VALUES ( $1, @@ -42,9 +46,13 @@ VALUES ( $11, $12, $13, - $14 + $14, + $15, + $16, + $17, + $18 ) -RETURNING id, amount, branch_id, cashier_id, bet_id, number_of_outcomes, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, approved_by, created_at, updated_at +RETURNING id, amount, branch_id, company_id, cashier_id, cashier_name, bet_id, number_of_outcomes, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, approved_by, approver_name, branch_location, branch_name, created_at, updated_at ` type CreateTransactionParams struct { @@ -62,6 +70,10 @@ type CreateTransactionParams struct { AccountNumber string `json:"account_number"` ReferenceNumber string `json:"reference_number"` NumberOfOutcomes int64 `json:"number_of_outcomes"` + BranchName string `json:"branch_name"` + BranchLocation string `json:"branch_location"` + CompanyID int64 `json:"company_id"` + CashierName string `json:"cashier_name"` } func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionParams) (Transaction, error) { @@ -80,13 +92,19 @@ func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionPa arg.AccountNumber, arg.ReferenceNumber, arg.NumberOfOutcomes, + arg.BranchName, + arg.BranchLocation, + arg.CompanyID, + arg.CashierName, ) var i Transaction err := row.Scan( &i.ID, &i.Amount, &i.BranchID, + &i.CompanyID, &i.CashierID, + &i.CashierName, &i.BetID, &i.NumberOfOutcomes, &i.Type, @@ -100,6 +118,9 @@ func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionPa &i.ReferenceNumber, &i.Verified, &i.ApprovedBy, + &i.ApproverName, + &i.BranchLocation, + &i.BranchName, &i.CreatedAt, &i.UpdatedAt, ) @@ -107,7 +128,7 @@ func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionPa } const GetAllTransactions = `-- name: GetAllTransactions :many -SELECT id, amount, branch_id, cashier_id, bet_id, number_of_outcomes, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, approved_by, created_at, updated_at +SELECT id, amount, branch_id, company_id, cashier_id, cashier_name, bet_id, number_of_outcomes, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, approved_by, approver_name, branch_location, branch_name, created_at, updated_at FROM transactions ` @@ -124,7 +145,9 @@ func (q *Queries) GetAllTransactions(ctx context.Context) ([]Transaction, error) &i.ID, &i.Amount, &i.BranchID, + &i.CompanyID, &i.CashierID, + &i.CashierName, &i.BetID, &i.NumberOfOutcomes, &i.Type, @@ -138,6 +161,9 @@ func (q *Queries) GetAllTransactions(ctx context.Context) ([]Transaction, error) &i.ReferenceNumber, &i.Verified, &i.ApprovedBy, + &i.ApproverName, + &i.BranchLocation, + &i.BranchName, &i.CreatedAt, &i.UpdatedAt, ); err != nil { @@ -152,7 +178,7 @@ func (q *Queries) GetAllTransactions(ctx context.Context) ([]Transaction, error) } const GetTransactionByBranch = `-- name: GetTransactionByBranch :many -SELECT id, amount, branch_id, cashier_id, bet_id, number_of_outcomes, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, approved_by, created_at, updated_at +SELECT id, amount, branch_id, company_id, cashier_id, cashier_name, bet_id, number_of_outcomes, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, approved_by, approver_name, branch_location, branch_name, created_at, updated_at FROM transactions WHERE branch_id = $1 ` @@ -170,7 +196,9 @@ func (q *Queries) GetTransactionByBranch(ctx context.Context, branchID int64) ([ &i.ID, &i.Amount, &i.BranchID, + &i.CompanyID, &i.CashierID, + &i.CashierName, &i.BetID, &i.NumberOfOutcomes, &i.Type, @@ -184,6 +212,9 @@ func (q *Queries) GetTransactionByBranch(ctx context.Context, branchID int64) ([ &i.ReferenceNumber, &i.Verified, &i.ApprovedBy, + &i.ApproverName, + &i.BranchLocation, + &i.BranchName, &i.CreatedAt, &i.UpdatedAt, ); err != nil { @@ -198,7 +229,7 @@ func (q *Queries) GetTransactionByBranch(ctx context.Context, branchID int64) ([ } const GetTransactionByID = `-- name: GetTransactionByID :one -SELECT id, amount, branch_id, cashier_id, bet_id, number_of_outcomes, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, approved_by, created_at, updated_at +SELECT id, amount, branch_id, company_id, cashier_id, cashier_name, bet_id, number_of_outcomes, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, approved_by, approver_name, branch_location, branch_name, created_at, updated_at FROM transactions WHERE id = $1 ` @@ -210,7 +241,9 @@ func (q *Queries) GetTransactionByID(ctx context.Context, id int64) (Transaction &i.ID, &i.Amount, &i.BranchID, + &i.CompanyID, &i.CashierID, + &i.CashierName, &i.BetID, &i.NumberOfOutcomes, &i.Type, @@ -224,6 +257,9 @@ func (q *Queries) GetTransactionByID(ctx context.Context, id int64) (Transaction &i.ReferenceNumber, &i.Verified, &i.ApprovedBy, + &i.ApproverName, + &i.BranchLocation, + &i.BranchName, &i.CreatedAt, &i.UpdatedAt, ) @@ -234,17 +270,24 @@ const UpdateTransactionVerified = `-- name: UpdateTransactionVerified :exec UPDATE transactions SET verified = $2, approved_by = $3, + approver_name = $4, updated_at = CURRENT_TIMESTAMP WHERE id = $1 ` type UpdateTransactionVerifiedParams struct { - ID int64 `json:"id"` - Verified bool `json:"verified"` - ApprovedBy pgtype.Int8 `json:"approved_by"` + ID int64 `json:"id"` + Verified bool `json:"verified"` + ApprovedBy pgtype.Int8 `json:"approved_by"` + ApproverName pgtype.Text `json:"approver_name"` } func (q *Queries) UpdateTransactionVerified(ctx context.Context, arg UpdateTransactionVerifiedParams) error { - _, err := q.db.Exec(ctx, UpdateTransactionVerified, arg.ID, arg.Verified, arg.ApprovedBy) + _, err := q.db.Exec(ctx, UpdateTransactionVerified, + arg.ID, + arg.Verified, + arg.ApprovedBy, + arg.ApproverName, + ) return err } diff --git a/gen/db/transfer.sql.go b/gen/db/transfer.sql.go index f4d8cc2..9bbf333 100644 --- a/gen/db/transfer.sql.go +++ b/gen/db/transfer.sql.go @@ -12,7 +12,17 @@ import ( ) const CreateTransfer = `-- name: CreateTransfer :one -INSERT INTO wallet_transfer (amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method, created_at, updated_at +INSERT INTO wallet_transfer ( + amount, + type, + receiver_wallet_id, + sender_wallet_id, + cashier_id, + verified, + payment_method + ) +VALUES ($1, $2, $3, $4, $5, $6, $7) +RETURNING id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method, created_at, updated_at ` type CreateTransferParams struct { @@ -52,7 +62,8 @@ func (q *Queries) CreateTransfer(ctx context.Context, arg CreateTransferParams) } const GetAllTransfers = `-- name: GetAllTransfers :many -SELECT id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method, created_at, updated_at FROM wallet_transfer +SELECT id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method, created_at, updated_at +FROM wallet_transfer ` func (q *Queries) GetAllTransfers(ctx context.Context) ([]WalletTransfer, error) { @@ -87,7 +98,9 @@ func (q *Queries) GetAllTransfers(ctx context.Context) ([]WalletTransfer, error) } const GetTransferByID = `-- name: GetTransferByID :one -SELECT id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method, created_at, updated_at FROM wallet_transfer WHERE id = $1 +SELECT id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method, created_at, updated_at +FROM wallet_transfer +WHERE id = $1 ` func (q *Queries) GetTransferByID(ctx context.Context, id int64) (WalletTransfer, error) { @@ -109,7 +122,10 @@ func (q *Queries) GetTransferByID(ctx context.Context, id int64) (WalletTransfer } const GetTransfersByWallet = `-- name: GetTransfersByWallet :many -SELECT id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method, created_at, updated_at FROM wallet_transfer WHERE receiver_wallet_id = $1 OR sender_wallet_id = $1 +SELECT id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, payment_method, created_at, updated_at +FROM wallet_transfer +WHERE receiver_wallet_id = $1 + OR sender_wallet_id = $1 ` func (q *Queries) GetTransfersByWallet(ctx context.Context, receiverWalletID int64) ([]WalletTransfer, error) { @@ -144,7 +160,10 @@ func (q *Queries) GetTransfersByWallet(ctx context.Context, receiverWalletID int } const UpdateTransferVerification = `-- name: UpdateTransferVerification :exec -UPDATE wallet_transfer SET verified = $1, updated_at = CURRENT_TIMESTAMP WHERE id = $2 +UPDATE wallet_transfer +SET verified = $1, + updated_at = CURRENT_TIMESTAMP +WHERE id = $2 ` type UpdateTransferVerificationParams struct { diff --git a/gen/db/user.sql.go b/gen/db/user.sql.go index 7a6fcb8..a595372 100644 --- a/gen/db/user.sql.go +++ b/gen/db/user.sql.go @@ -561,3 +561,19 @@ func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) error { ) return err } + +const UpdateUserCompany = `-- name: UpdateUserCompany :exec +UPDATE users +SET company_id = $1 +WHERE id = $2 +` + +type UpdateUserCompanyParams struct { + CompanyID pgtype.Int8 `json:"company_id"` + ID int64 `json:"id"` +} + +func (q *Queries) UpdateUserCompany(ctx context.Context, arg UpdateUserCompanyParams) error { + _, err := q.db.Exec(ctx, UpdateUserCompany, arg.CompanyID, arg.ID) + return err +} diff --git a/internal/domain/branch.go b/internal/domain/branch.go index 3295dae..fd7bad6 100644 --- a/internal/domain/branch.go +++ b/internal/domain/branch.go @@ -44,11 +44,12 @@ type CreateBranch struct { } type UpdateBranch struct { - Name string - Location string - BranchManagerID int64 - CompanyID int64 - IsSelfOwned bool + ID int64 + Name *string + Location *string + BranchManagerID *int64 + CompanyID *int64 + IsSelfOwned *bool } type CreateSupportedOperation struct { diff --git a/internal/domain/company.go b/internal/domain/company.go index 60d738a..9a05e4c 100644 --- a/internal/domain/company.go +++ b/internal/domain/company.go @@ -26,6 +26,7 @@ type CreateCompany struct { } type UpdateCompany struct { - Name string - AdminID int64 + ID int64 + Name *string + AdminID *int64 } diff --git a/internal/domain/transaction.go b/internal/domain/transaction.go index 781610f..d767600 100644 --- a/internal/domain/transaction.go +++ b/internal/domain/transaction.go @@ -24,7 +24,11 @@ type Transaction struct { ID int64 Amount Currency BranchID int64 + BranchName string + BranchLocation string + CompanyID int64 CashierID int64 + CashierName string BetID int64 NumberOfOutcomes int64 Type TransactionType @@ -39,10 +43,10 @@ type Transaction struct { ReferenceNumber string Verified bool ApprovedBy ValidInt64 + ApproverName ValidString UpdatedAt time.Time CreatedAt time.Time } - type CreateTransaction struct { Amount Currency BranchID int64 @@ -59,4 +63,8 @@ type CreateTransaction struct { AccountName string AccountNumber string ReferenceNumber string + BranchName string + BranchLocation string + CompanyID int64 + CashierName string } diff --git a/internal/repository/branch.go b/internal/repository/branch.go index 6287380..8a98ff8 100644 --- a/internal/repository/branch.go +++ b/internal/repository/branch.go @@ -45,6 +45,46 @@ func convertDBBranch(dbBranch dbgen.Branch) domain.Branch { } } +func convertUpdateBranch(updateBranch domain.UpdateBranch) dbgen.UpdateBranchParams { + + var newUpdateBranch dbgen.UpdateBranchParams + + newUpdateBranch.ID = updateBranch.ID + + if updateBranch.Name != nil { + newUpdateBranch.Name = pgtype.Text{ + String: *updateBranch.Name, + Valid: true, + } + } + if updateBranch.Location != nil { + newUpdateBranch.Location = pgtype.Text{ + String: *updateBranch.Location, + Valid: true, + } + } + if updateBranch.BranchManagerID != nil { + newUpdateBranch.BranchManagerID = pgtype.Int8{ + Int64: *updateBranch.BranchManagerID, + Valid: true, + } + } + if updateBranch.CompanyID != nil { + newUpdateBranch.CompanyID = pgtype.Int8{ + Int64: *updateBranch.CompanyID, + Valid: true, + } + } + if updateBranch.IsSelfOwned != nil { + newUpdateBranch.IsSelfOwned = pgtype.Bool{ + Bool: *updateBranch.IsSelfOwned, + Valid: true, + } + } + + return newUpdateBranch +} + func (s *Store) CreateBranch(ctx context.Context, branch domain.CreateBranch) (domain.Branch, error) { dbBranch, err := s.queries.CreateBranch(ctx, convertCreateBranch(branch)) @@ -111,14 +151,9 @@ func (s *Store) SearchBranchByName(ctx context.Context, name string) ([]domain.B return branches, nil } -func (s *Store) UpdateBranch(ctx context.Context, id int64, branch domain.UpdateBranch) (domain.Branch, error) { - dbBranch, err := s.queries.UpdateBranch(ctx, dbgen.UpdateBranchParams{ - ID: id, - Name: branch.Name, - Location: branch.Location, - BranchManagerID: branch.BranchManagerID, - IsSelfOwned: branch.IsSelfOwned, - }) +func (s *Store) UpdateBranch(ctx context.Context, branch domain.UpdateBranch) (domain.Branch, error) { + + dbBranch, err := s.queries.UpdateBranch(ctx, convertUpdateBranch(branch)) if err != nil { return domain.Branch{}, err } @@ -209,7 +244,6 @@ func (s *Store) GetBranchByCashier(ctx context.Context, userID int64) (domain.Br return convertDBBranch(branch), err } - func (s *Store) DeleteBranchOperation(ctx context.Context, branchID int64, operationID int64) error { err := s.queries.DeleteBranchOperation(ctx, dbgen.DeleteBranchOperationParams{ BranchID: branchID, diff --git a/internal/repository/company.go b/internal/repository/company.go index 0ed64ac..8f3fe1a 100644 --- a/internal/repository/company.go +++ b/internal/repository/company.go @@ -36,6 +36,28 @@ func convertDBCompanyWithWallet(dbCompany dbgen.CompaniesWithWallet) domain.GetC } } +func convertUpdateCompany(updateCompany domain.UpdateCompany) dbgen.UpdateCompanyParams { + var newUpdateCompany dbgen.UpdateCompanyParams + + newUpdateCompany.ID = updateCompany.ID + + if updateCompany.Name != nil { + newUpdateCompany.Name = pgtype.Text{ + String: *updateCompany.Name, + Valid: true, + } + } + + if updateCompany.AdminID != nil { + newUpdateCompany.AdminID = pgtype.Int8{ + Int64: *updateCompany.AdminID, + Valid: true, + } + } + + return newUpdateCompany +} + func (s *Store) CreateCompany(ctx context.Context, company domain.CreateCompany) (domain.Company, error) { dbCompany, err := s.queries.CreateCompany(ctx, convertCreateCompany(company)) if err != nil { @@ -84,12 +106,8 @@ func (s *Store) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany return convertDBCompanyWithWallet(dbCompany), nil } -func (s *Store) UpdateCompany(ctx context.Context, id int64, company domain.UpdateCompany) (domain.Company, error) { - dbCompany, err := s.queries.UpdateCompany(ctx, dbgen.UpdateCompanyParams{ - ID: id, - Name: company.Name, - AdminID: company.AdminID, - }) +func (s *Store) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) { + dbCompany, err := s.queries.UpdateCompany(ctx, convertUpdateCompany(company)) if err != nil { return domain.Company{}, err diff --git a/internal/repository/transaction.go b/internal/repository/transaction.go index e0753b2..da53fc3 100644 --- a/internal/repository/transaction.go +++ b/internal/repository/transaction.go @@ -29,9 +29,17 @@ func convertDBTransaction(transaction dbgen.Transaction) domain.Transaction { Value: transaction.ApprovedBy.Int64, Valid: transaction.ApprovedBy.Valid, }, - CreatedAt: transaction.CreatedAt.Time, - UpdatedAt: transaction.UpdatedAt.Time, - Verified: transaction.Verified, + CreatedAt: transaction.CreatedAt.Time, + UpdatedAt: transaction.UpdatedAt.Time, + Verified: transaction.Verified, + BranchName: transaction.BranchName, + BranchLocation: transaction.BranchLocation, + CashierName: transaction.CashierName, + CompanyID: transaction.CompanyID, + ApproverName: domain.ValidString{ + Value: transaction.ApproverName.String, + Valid: transaction.ApprovedBy.Valid, + }, } } @@ -51,6 +59,10 @@ func convertCreateTransaction(transaction domain.CreateTransaction) dbgen.Create AccountNumber: transaction.AccountNumber, ReferenceNumber: transaction.ReferenceNumber, NumberOfOutcomes: transaction.NumberOfOutcomes, + BranchName: transaction.BranchName, + BranchLocation: transaction.BranchLocation, + CashierName: transaction.CashierName, + CompanyID: transaction.CompanyID, } } @@ -99,7 +111,7 @@ func (s *Store) GetTransactionByBranch(ctx context.Context, id int64) ([]domain. return result, nil } -func (s *Store) UpdateTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64) error { +func (s *Store) UpdateTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64, approverName string) error { err := s.queries.UpdateTransactionVerified(ctx, dbgen.UpdateTransactionVerifiedParams{ ID: id, ApprovedBy: pgtype.Int8{ @@ -107,6 +119,10 @@ func (s *Store) UpdateTransactionVerified(ctx context.Context, id int64, verifie Valid: true, }, Verified: verified, + ApproverName: pgtype.Text{ + String: approverName, + Valid: true, + }, }) return err } diff --git a/internal/repository/user.go b/internal/repository/user.go index dc30506..3c0c910 100644 --- a/internal/repository/user.go +++ b/internal/repository/user.go @@ -216,6 +216,20 @@ func (s *Store) UpdateUser(ctx context.Context, user domain.UpdateUserReq) error } return nil } + +func (s *Store) UpdateUserCompany(ctx context.Context, id int64, companyID int64) error { + err := s.queries.UpdateUserCompany(ctx, dbgen.UpdateUserCompanyParams{ + CompanyID: pgtype.Int8{ + Int64: companyID, + Valid: true, + }, + ID: id, + }) + if err != nil { + return err + } + return nil +} func (s *Store) DeleteUser(ctx context.Context, id int64) error { err := s.queries.DeleteUser(ctx, id) if err != nil { diff --git a/internal/services/branch/port.go b/internal/services/branch/port.go index 53e6b0d..2e9c58c 100644 --- a/internal/services/branch/port.go +++ b/internal/services/branch/port.go @@ -13,7 +13,7 @@ type BranchStore interface { GetBranchByCompanyID(ctx context.Context, companyID int64) ([]domain.BranchDetail, error) GetAllBranches(ctx context.Context) ([]domain.BranchDetail, error) SearchBranchByName(ctx context.Context, name string) ([]domain.BranchDetail, error) - UpdateBranch(ctx context.Context, id int64, branch domain.UpdateBranch) (domain.Branch, error) + UpdateBranch(ctx context.Context, branch domain.UpdateBranch) (domain.Branch, error) DeleteBranch(ctx context.Context, id int64) error CreateBranchOperation(ctx context.Context, branchOperation domain.CreateBranchOperation) error CreateSupportedOperation(ctx context.Context, supportedOperation domain.CreateSupportedOperation) (domain.SupportedOperation, error) diff --git a/internal/services/branch/service.go b/internal/services/branch/service.go index eddd1e9..8c9e4d1 100644 --- a/internal/services/branch/service.go +++ b/internal/services/branch/service.go @@ -57,8 +57,8 @@ func (s *Service) GetAllSupportedOperations(ctx context.Context) ([]domain.Suppo func (s *Service) SearchBranchByName(ctx context.Context, name string) ([]domain.BranchDetail, error) { return s.branchStore.SearchBranchByName(ctx, name) } -func (s *Service) UpdateBranch(ctx context.Context, id int64, branch domain.UpdateBranch) (domain.Branch, error) { - return s.branchStore.UpdateBranch(ctx, id, branch) +func (s *Service) UpdateBranch(ctx context.Context, branch domain.UpdateBranch) (domain.Branch, error) { + return s.branchStore.UpdateBranch(ctx, branch) } func (s *Service) DeleteBranch(ctx context.Context, id int64) error { return s.branchStore.DeleteBranch(ctx, id) diff --git a/internal/services/company/port.go b/internal/services/company/port.go index ad8fb74..7081899 100644 --- a/internal/services/company/port.go +++ b/internal/services/company/port.go @@ -11,6 +11,6 @@ type CompanyStore interface { GetAllCompanies(ctx context.Context) ([]domain.GetCompany, error) SearchCompanyByName(ctx context.Context, name string) ([]domain.GetCompany, error) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany, error) - UpdateCompany(ctx context.Context, id int64, company domain.UpdateCompany) (domain.Company, error) + UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) DeleteCompany(ctx context.Context, id int64) error } diff --git a/internal/services/company/service.go b/internal/services/company/service.go index affc432..6379356 100644 --- a/internal/services/company/service.go +++ b/internal/services/company/service.go @@ -31,8 +31,8 @@ func (s *Service) SearchCompanyByName(ctx context.Context, name string) ([]domai return s.companyStore.SearchCompanyByName(ctx, name) } -func (s *Service) UpdateCompany(ctx context.Context, id int64, company domain.UpdateCompany) (domain.Company, error) { - return s.companyStore.UpdateCompany(ctx, id, company) +func (s *Service) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) { + return s.companyStore.UpdateCompany(ctx, company) } func (s *Service) DeleteCompany(ctx context.Context, id int64) error { return s.companyStore.DeleteCompany(ctx, id) diff --git a/internal/services/event/service.go b/internal/services/event/service.go index 57f44c5..d5e5aa3 100644 --- a/internal/services/event/service.go +++ b/internal/services/event/service.go @@ -99,11 +99,12 @@ func (s *service) FetchLiveEvents(ctx context.Context) error { func (s *service) FetchUpcomingEvents(ctx context.Context) error { sportIDs := []int{1} - var totalPages int = 1 - var page int = 0 - var limit int = 100 - var count int = 0 + for _, sportID := range sportIDs { + var totalPages int = 1 + var page int = 0 + var limit int = 100 + var count int = 0 for page != totalPages { time.Sleep(3 * time.Second) //This will restrict the fetching to 1200 requests per hour diff --git a/internal/services/transaction/port.go b/internal/services/transaction/port.go index 052ce45..d0c500b 100644 --- a/internal/services/transaction/port.go +++ b/internal/services/transaction/port.go @@ -11,5 +11,5 @@ type TransactionStore interface { GetTransactionByID(ctx context.Context, id int64) (domain.Transaction, error) GetAllTransactions(ctx context.Context) ([]domain.Transaction, error) GetTransactionByBranch(ctx context.Context, id int64) ([]domain.Transaction, error) - UpdateTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64) error + UpdateTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64, approverName string) error } diff --git a/internal/services/transaction/service.go b/internal/services/transaction/service.go index 3e965cc..c7504b4 100644 --- a/internal/services/transaction/service.go +++ b/internal/services/transaction/service.go @@ -28,6 +28,6 @@ func (s *Service) GetAllTransactions(ctx context.Context) ([]domain.Transaction, func (s *Service) GetTransactionByBranch(ctx context.Context, id int64) ([]domain.Transaction, error) { return s.transactionStore.GetTransactionByBranch(ctx, id) } -func (s *Service) UpdateTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64) error { - return s.transactionStore.UpdateTransactionVerified(ctx, id, verified, approvedBy) +func (s *Service) UpdateTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64, approverName string) error { + return s.transactionStore.UpdateTransactionVerified(ctx, id, verified, approvedBy, approverName) } diff --git a/internal/services/user/port.go b/internal/services/user/port.go index 588787c..3dfa77e 100644 --- a/internal/services/user/port.go +++ b/internal/services/user/port.go @@ -14,6 +14,7 @@ type UserStore interface { GetAllCashiers(ctx context.Context) ([]domain.User, error) GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error) UpdateUser(ctx context.Context, user domain.UpdateUserReq) error + UpdateUserCompany(ctx context.Context, id int64, companyID int64) error DeleteUser(ctx context.Context, id int64) error CheckPhoneEmailExist(ctx context.Context, phoneNum, email string) (bool, bool, error) GetUserByEmail(ctx context.Context, email string) (domain.User, error) diff --git a/internal/services/user/user.go b/internal/services/user/user.go index 5c141c7..225ecc6 100644 --- a/internal/services/user/user.go +++ b/internal/services/user/user.go @@ -6,9 +6,6 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" ) - - - func (s *Service) SearchUserByNameOrPhone(ctx context.Context, searchString string) ([]domain.User, error) { // Search user return s.userStore.SearchUserByNameOrPhone(ctx, searchString) @@ -18,6 +15,12 @@ func (s *Service) UpdateUser(ctx context.Context, user domain.UpdateUserReq) err // update user return s.userStore.UpdateUser(ctx, user) +} + +func (s *Service) UpdateUserCompany(ctx context.Context, id int64, companyID int64) error { + // update user + return s.userStore.UpdateUserCompany(ctx, id, companyID) + } func (s *Service) GetUserByID(ctx context.Context, id int64) (domain.User, error) { return s.userStore.GetUserByID(ctx, id) diff --git a/internal/web_server/handlers/admin.go b/internal/web_server/handlers/admin.go index 26e2ca7..2b8cdf0 100644 --- a/internal/web_server/handlers/admin.go +++ b/internal/web_server/handlers/admin.go @@ -1,6 +1,7 @@ package handlers import ( + "log/slog" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" @@ -51,6 +52,11 @@ func (h *Handler) CreateAdmin(c *fiber.Ctx) error { Valid: false, } } else { + _, err := h.companySvc.GetCompanyByID(c.Context(), *req.CompanyID) + if err != nil { + h.logger.Error("CreateAdmin company id is invalid", "error", err) + return response.WriteJSON(c, fiber.StatusInternalServerError, "Company ID is invalid", nil, nil) + } companyID = domain.ValidInt64{ Value: *req.CompanyID, Valid: true, @@ -66,11 +72,25 @@ func (h *Handler) CreateAdmin(c *fiber.Ctx) error { Role: string(domain.RoleAdmin), CompanyID: companyID, } - _, err := h.userSvc.CreateUser(c.Context(), user, true) + + h.logger.Info("CreateAdmin", slog.Bool("company id", req.CompanyID == nil)) + newUser, err := h.userSvc.CreateUser(c.Context(), user, true) if err != nil { h.logger.Error("CreateAdmin failed", "error", err) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to create admin", nil, nil) } + + if req.CompanyID != nil { + _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{ + ID: *req.CompanyID, + AdminID: &newUser.ID, + }) + 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, "Admin created successfully", nil, nil) } diff --git a/internal/web_server/handlers/branch_handler.go b/internal/web_server/handlers/branch_handler.go index 254272a..f261c4f 100644 --- a/internal/web_server/handlers/branch_handler.go +++ b/internal/web_server/handlers/branch_handler.go @@ -9,12 +9,20 @@ import ( ) type CreateBranchReq struct { - Name string `json:"name" example:"4-kilo Branch"` - Location string `json:"location" example:"Addis Ababa"` - BranchManagerID int64 `json:"branch_manager_id" example:"1"` - CompanyID int64 `json:"company_id" example:"1"` - IsSelfOwned bool `json:"is_self_owned" example:"false"` - Operations []int64 `json:"operations"` + Name string `json:"name" validate:"required,min=3,max=100" example:"4-kilo Branch"` + Location string `json:"location" validate:"required,min=3,max=100" example:"Addis Ababa"` + BranchManagerID int64 `json:"branch_manager_id" validate:"required,gt=0" example:"1"` + CompanyID *int64 `json:"company_id,omitempty" example:"1"` + IsSelfOwned *bool `json:"is_self_owned,omitempty" example:"false"` + Operations []int64 `json:"operations" validate:"required,dive,gt=0"` +} + +type UpdateBranchReq struct { + Name *string `json:"name,omitempty" example:"4-kilo Branch"` + Location *string `json:"location,omitempty" example:"Addis Ababa"` + BranchManagerID *int64 `json:"branch_manager_id,omitempty" example:"1"` + CompanyID *int64 `json:"company_id,omitempty" example:"1"` + IsSelfOwned *bool `json:"is_self_owned,omitempty" example:"false"` } type CreateSupportedOperationReq struct { @@ -106,6 +114,9 @@ func (h *Handler) CreateBranch(c *fiber.Ctx) error { // return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil) // } + role := c.Locals("role").(domain.Role) + companyID := c.Locals("company_id").(domain.ValidInt64) + var req CreateBranchReq if err := c.BodyParser(&req); err != nil { @@ -117,6 +128,21 @@ func (h *Handler) CreateBranch(c *fiber.Ctx) error { if !ok { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) } + var IsSelfOwned bool + var checkedCompanyID int64 + if role == domain.RoleSuperAdmin { + if req.IsSelfOwned == nil { + return response.WriteJSON(c, fiber.StatusBadRequest, "is_self_owned is required for super admin", nil, nil) + } + if req.CompanyID == nil { + return response.WriteJSON(c, fiber.StatusBadRequest, "company_id is required for super admin", nil, nil) + } + IsSelfOwned = *req.IsSelfOwned + checkedCompanyID = *req.CompanyID + } else { + IsSelfOwned = false + checkedCompanyID = companyID.Value //the company id is always valid when its not a super admin + } // Create Branch Wallet newWallet, err := h.walletSvc.CreateWallet(c.Context(), domain.CreateWallet{ @@ -136,8 +162,8 @@ func (h *Handler) CreateBranch(c *fiber.Ctx) error { Location: req.Location, WalletID: newWallet.ID, BranchManagerID: req.BranchManagerID, - CompanyID: req.CompanyID, - IsSelfOwned: req.IsSelfOwned, + CompanyID: checkedCompanyID, + IsSelfOwned: IsSelfOwned, }) if err != nil { @@ -519,7 +545,7 @@ func (h *Handler) UpdateBranch(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", err, nil) } - var req CreateBranchReq + var req UpdateBranchReq if err := c.BodyParser(&req); err != nil { h.logger.Error("CreateBranchReq failed", "error", err) @@ -530,7 +556,8 @@ func (h *Handler) UpdateBranch(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) } - branch, err := h.branchSvc.UpdateBranch(c.Context(), id, domain.UpdateBranch{ + branch, err := h.branchSvc.UpdateBranch(c.Context(), domain.UpdateBranch{ + ID: id, Name: req.Name, Location: req.Location, BranchManagerID: req.BranchManagerID, diff --git a/internal/web_server/handlers/company_handler.go b/internal/web_server/handlers/company_handler.go index 863cbd7..6e0f713 100644 --- a/internal/web_server/handlers/company_handler.go +++ b/internal/web_server/handlers/company_handler.go @@ -12,6 +12,10 @@ type CreateCompanyReq struct { Name string `json:"name" example:"CompanyName"` AdminID int64 `json:"admin_id" example:"1"` } +type UpdateCompanyReq struct { + Name *string `json:"name,omitempty" example:"CompanyName"` + AdminID *int64 `json:"admin_id,omitempty" example:"1"` +} type CompanyRes struct { ID int64 `json:"id" example:"1"` @@ -71,7 +75,14 @@ func (h *Handler) CreateCompany(c *fiber.Ctx) error { if !ok { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) } - // Create Branch Wallet + + user, err := h.userSvc.GetUserByID(c.Context(), req.AdminID) + if err != nil { + h.logger.Error("Error fetching user", "error", err) + return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get user", err, nil) + } + + // Create Company Wallet newWallet, err := h.walletSvc.CreateWallet(c.Context(), domain.CreateWallet{ IsWithdraw: false, IsBettable: true, @@ -86,7 +97,7 @@ func (h *Handler) CreateCompany(c *fiber.Ctx) error { company, err := h.companySvc.CreateCompany(c.Context(), domain.CreateCompany{ Name: req.Name, - AdminID: req.AdminID, + AdminID: user.ID, WalletID: newWallet.ID, }) @@ -97,6 +108,13 @@ func (h *Handler) CreateCompany(c *fiber.Ctx) error { }) } + err = h.userSvc.UpdateUserCompany(c.Context(), user.ID, company.ID) + if err != nil { + h.logger.Error("CreateCompanyReq failed", "error", err) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Internal server error", + }) + } res := convertCompany(company) return response.WriteJSON(c, fiber.StatusCreated, "Company Created", res, nil) @@ -201,7 +219,7 @@ func (h *Handler) SearchCompany(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param id path int true "Company ID" -// @Param updateCompany body CreateCompanyReq true "Update Company" +// @Param updateCompany body UpdateCompanyReq true "Update Company" // @Success 200 {object} CompanyRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse @@ -215,7 +233,7 @@ func (h *Handler) UpdateCompany(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid company ID", err, nil) } - var req CreateCompanyReq + var req UpdateCompanyReq if err := c.BodyParser(&req); err != nil { h.logger.Error("CreateCompanyReq failed", "error", err) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) @@ -225,7 +243,8 @@ func (h *Handler) UpdateCompany(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) } - company, err := h.companySvc.UpdateCompany(c.Context(), id, domain.UpdateCompany{ + company, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{ + ID: id, Name: req.Name, AdminID: req.AdminID, }) diff --git a/internal/web_server/handlers/transaction_handler.go b/internal/web_server/handlers/transaction_handler.go index 5263803..b9c5d6a 100644 --- a/internal/web_server/handlers/transaction_handler.go +++ b/internal/web_server/handlers/transaction_handler.go @@ -14,7 +14,11 @@ type TransactionRes struct { ID int64 `json:"id" example:"1"` Amount float32 `json:"amount" example:"100.0"` BranchID int64 `json:"branch_id" example:"1"` + BranchName string `json:"branch_name" example:"Branch Name"` + BranchLocation string `json:"branch_location" example:"Branch Location"` + CompanyID int64 `json:"company_id" example:"1"` CashierID int64 `json:"cashier_id" example:"1"` + CashierName string `json:"cashier_name" example:"John Smith"` BetID int64 `json:"bet_id" example:"1"` NumberOfOutcomes int64 `json:"number_of_outcomes" example:"1"` Type int64 `json:"type" example:"1"` @@ -28,6 +32,7 @@ type TransactionRes struct { ReferenceNumber string `json:"reference_number"` Verified bool `json:"verified" example:"true"` ApprovedBy *int64 `json:"approved_by" example:"1"` + ApproverName *string `json:"approver_name" example:"John Smith"` UpdatedAt time.Time `json:"updated_at"` CreatedAt time.Time `json:"created_at"` } @@ -53,7 +58,11 @@ func convertTransaction(transaction domain.Transaction) TransactionRes { ID: transaction.ID, Amount: transaction.Amount.Float32(), BranchID: transaction.BranchID, + BranchName: transaction.BranchName, + BranchLocation: transaction.BranchLocation, + CompanyID: transaction.CompanyID, CashierID: transaction.CashierID, + CashierName: transaction.CashierName, BetID: transaction.BetID, Type: int64(transaction.Type), PaymentOption: transaction.PaymentOption, @@ -72,6 +81,8 @@ func convertTransaction(transaction domain.Transaction) TransactionRes { if transaction.ApprovedBy.Valid { newTransaction.ApprovedBy = &transaction.ApprovedBy.Value + newTransaction.ApproverName = &transaction.ApproverName.Value + } return newTransaction @@ -114,6 +125,9 @@ func (h *Handler) CreateTransaction(c *fiber.Ctx) error { } var branchID int64 + var branchName string + var branchLocation string + var companyID int64 if role == domain.RoleAdmin || role == domain.RoleBranchManager || role == domain.RoleSuperAdmin { if req.BranchID == nil { h.logger.Error("CreateTransactionReq Branch ID is required for this user role") @@ -126,7 +140,9 @@ func (h *Handler) CreateTransaction(c *fiber.Ctx) error { } branchID = branch.ID - + branchName = branch.Name + branchLocation = branch.Location + companyID = branch.CompanyID } else { branch, err := h.branchSvc.GetBranchByCashier(c.Context(), userID) if err != nil { @@ -134,6 +150,9 @@ func (h *Handler) CreateTransaction(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusBadRequest, "Branch ID invalid", err, nil) } branchID = branch.ID + branchName = branch.Name + branchLocation = branch.Location + companyID = branch.CompanyID } bet, err := h.betSvc.GetBetByID(c.Context(), req.BetID) @@ -152,6 +171,8 @@ func (h *Handler) CreateTransaction(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusBadRequest, "This bet has already been cashed out", err, nil) } + user, err := h.userSvc.GetUserByID(c.Context(), userID) + transaction, err := h.transactionSvc.CreateTransaction(c.Context(), domain.CreateTransaction{ BranchID: branchID, CashierID: userID, @@ -167,6 +188,10 @@ func (h *Handler) CreateTransaction(c *fiber.Ctx) error { AccountName: req.AccountName, AccountNumber: req.AccountNumber, ReferenceNumber: req.ReferenceNumber, + CashierName: user.FirstName + " " + user.LastName, + BranchName: branchName, + BranchLocation: branchLocation, + CompanyID: companyID, }) if err != nil { @@ -289,7 +314,8 @@ type UpdateTransactionVerifiedReq struct { func (h *Handler) UpdateTransactionVerified(c *fiber.Ctx) error { transactionID := c.Params("id") userID := c.Locals("user_id").(int64) - // companyID := c.Locals("company_id").(domain.ValidInt64) + companyID := c.Locals("company_id").(domain.ValidInt64) + role := c.Locals("role").(domain.Role) id, err := strconv.ParseInt(transactionID, 10, 64) if err != nil { @@ -309,8 +335,20 @@ func (h *Handler) UpdateTransactionVerified(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) } - // TODO: make it so that only people within the company can verify a transaction - err = h.transactionSvc.UpdateTransactionVerified(c.Context(), id, req.Verified, userID) + transaction, err := h.transactionSvc.GetTransactionByID(c.Context(), id) + if role != domain.RoleSuperAdmin { + if !companyID.Valid || companyID.Value != transaction.CompanyID { + h.logger.Error("Failed to parse UpdateTransactionVerified request", "error", err) + return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) + } + } + + user, err := h.userSvc.GetUserById(c.Context(), userID) + if err != nil { + h.logger.Error("Invalid user ID", "userID", userID, "error", err) + return fiber.NewError(fiber.StatusBadRequest, "Invalid user ID") + } + err = h.transactionSvc.UpdateTransactionVerified(c.Context(), id, req.Verified, userID, user.FirstName+" "+user.LastName) if err != nil { h.logger.Error("Failed to update transaction verification", "transactionID", id, "error", err) return fiber.NewError(fiber.StatusInternalServerError, "Failed to update transaction verification") diff --git a/internal/web_server/middleware.go b/internal/web_server/middleware.go index 5b48396..c7c90d5 100644 --- a/internal/web_server/middleware.go +++ b/internal/web_server/middleware.go @@ -41,6 +41,12 @@ func (a *App) authMiddleware(c *fiber.Ctx) error { // refreshToken = c.Cookies("refresh_token", "") // return fiber.NewError(fiber.StatusUnauthorized, "Refresh token missing") + + } + // Asserting to make sure that there is no company role without a valid company id + if claim.Role != domain.RoleSuperAdmin && !claim.CompanyID.Valid { + fmt.Println("Company Role without Company ID") + return fiber.NewError(fiber.StatusInternalServerError, "Company Role without Company ID") } c.Locals("user_id", claim.UserId) c.Locals("role", claim.Role) @@ -57,3 +63,11 @@ func (a *App) SuperAdminOnly(c *fiber.Ctx) error { } return c.Next() } + +func (a *App) CompanyOnly(c *fiber.Ctx) error { + userRole := c.Locals("role").(domain.Role) + if userRole == domain.RoleCustomer { + return fiber.NewError(fiber.StatusUnauthorized, "Invalid access token") + } + return c.Next() +}