From 3ef1a71795d5f2b1f313a7d8267ee619b831e5ef Mon Sep 17 00:00:00 2001 From: Ademola Personal Date: Wed, 18 Jun 2025 11:16:34 +0100 Subject: [PATCH 1/2] feat: add new migration files for UUID extension, user_wallets, security_events, kyc, transactions, sessions, and audit logging --- .../20250618100321_initial_setup.sql | 166 +++++++++++++++ .../20250618100355_authentication.sql | 66 ++++++ .../20250618100431_country_compliance.sql | 77 +++++++ .../20250618100620_kyc_kyb_documents.sql | 129 ++++++++++++ .../20250618100638_wallet_payment.sql | 111 ++++++++++ .../20250618100648_payroll_management.sql | 81 ++++++++ ...50618100705_invoice_contact_management.sql | 125 +++++++++++ .../20250618100726_timesheet_management.sql | 58 ++++++ db/migrations/20250618100748_transactions.sql | 80 +++++++ .../20250618100806_hr_management.sql | 102 +++++++++ .../20250618100847_tax_managment.sql | 80 +++++++ .../20250618100857_notification_roles.sql | 95 +++++++++ .../20250618100913_system_configurations.sql | 90 ++++++++ .../20250618100943_audit_logging.sql | 41 ++++ .../20250618101017_api_integration.sql | 75 +++++++ .../20250618101030_functions_triggers.sql | 196 ++++++++++++++++++ .../00001_create_extension_uuid.sql | 0 .../00002_create_users_table.sql | 0 .../00009_create_sessions_table.sql | 0 .../00010_create_kyc_table.sql | 0 .../20250321122619_user_device.sql | 0 .../20250321123506_otp.sql | 0 .../20250321140031_transactions.sql | 0 .../20250502134941_security.sql | 0 .../20250502134956_wallet.sql | 0 25 files changed, 1572 insertions(+) create mode 100644 db/migrations/20250618100321_initial_setup.sql create mode 100644 db/migrations/20250618100355_authentication.sql create mode 100644 db/migrations/20250618100431_country_compliance.sql create mode 100644 db/migrations/20250618100620_kyc_kyb_documents.sql create mode 100644 db/migrations/20250618100638_wallet_payment.sql create mode 100644 db/migrations/20250618100648_payroll_management.sql create mode 100644 db/migrations/20250618100705_invoice_contact_management.sql create mode 100644 db/migrations/20250618100726_timesheet_management.sql create mode 100644 db/migrations/20250618100748_transactions.sql create mode 100644 db/migrations/20250618100806_hr_management.sql create mode 100644 db/migrations/20250618100847_tax_managment.sql create mode 100644 db/migrations/20250618100857_notification_roles.sql create mode 100644 db/migrations/20250618100913_system_configurations.sql create mode 100644 db/migrations/20250618100943_audit_logging.sql create mode 100644 db/migrations/20250618101017_api_integration.sql create mode 100644 db/migrations/20250618101030_functions_triggers.sql rename db/{migrations => old_migration}/00001_create_extension_uuid.sql (100%) rename db/{migrations => old_migration}/00002_create_users_table.sql (100%) rename db/{migrations => old_migration}/00009_create_sessions_table.sql (100%) rename db/{migrations => old_migration}/00010_create_kyc_table.sql (100%) rename db/{migrations => old_migration}/20250321122619_user_device.sql (100%) rename db/{migrations => old_migration}/20250321123506_otp.sql (100%) rename db/{migrations => old_migration}/20250321140031_transactions.sql (100%) rename db/{migrations => old_migration}/20250502134941_security.sql (100%) rename db/{migrations => old_migration}/20250502134956_wallet.sql (100%) diff --git a/db/migrations/20250618100321_initial_setup.sql b/db/migrations/20250618100321_initial_setup.sql new file mode 100644 index 0000000..4e4d9c4 --- /dev/null +++ b/db/migrations/20250618100321_initial_setup.sql @@ -0,0 +1,166 @@ +-- +goose Up +-- Create UUID extension if not exists +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; + +-- Core User and Account Management +CREATE TABLE users ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + email VARCHAR(255) UNIQUE NOT NULL, + password_hash VARCHAR(255), + auth_provider VARCHAR(50), + provider_id VARCHAR(255), + email_verified BOOLEAN DEFAULT FALSE, + email_verified_at TIMESTAMPTZ, + account_type VARCHAR(50) NOT NULL, + account_status VARCHAR(50) DEFAULT 'pending', + two_factor_enabled BOOLEAN DEFAULT FALSE, + two_factor_method VARCHAR(50), + user_login_type VARCHAR(50), + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + last_login_at TIMESTAMPTZ, + deleted_at TIMESTAMPTZ +); + +CREATE TABLE personal_users ( + id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE, + first_name VARCHAR(255), + last_name VARCHAR(255), + profile_picture VARCHAR(255), + phone_number VARCHAR(50), + phone_number_verified BOOLEAN DEFAULT FALSE, + phone_number_verified_at TIMESTAMPTZ, + nationality VARCHAR(255), + residential_country VARCHAR(255), + user_address VARCHAR(255), + user_city VARCHAR(255), + user_postal_code VARCHAR(255), + gender VARCHAR(50), + date_of_birth DATE, + job_role VARCHAR(255), + personal_account_type VARCHAR(50), + employment_type VARCHAR(50), + tax_id VARCHAR(255), + default_payment_currency VARCHAR(50), + default_payment_method VARCHAR(50), + hourly_rate DECIMAL(18, 2), + specialization VARCHAR(255), + kyc_status VARCHAR(50) DEFAULT 'pending', + kyc_verified_at TIMESTAMPTZ, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE companies ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + owner_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + company_name VARCHAR(255) NOT NULL, + company_email VARCHAR(255), + company_phone VARCHAR(50), + company_size VARCHAR(50), + company_industry VARCHAR(255), + company_description TEXT, + company_headquarters VARCHAR(255), + company_logo VARCHAR(255), + company_website VARCHAR(255), + primary_contact_name VARCHAR(255), + primary_contact_email VARCHAR(255), + primary_contact_phone VARCHAR(50), + company_address VARCHAR(255), + company_city VARCHAR(255), + company_postal_code VARCHAR(255), + company_country VARCHAR(255), + company_registration_number VARCHAR(255), + registration_country VARCHAR(255), + tax_id VARCHAR(255), + incorporation_date DATE, + account_status VARCHAR(50) DEFAULT 'pending', + kyb_status VARCHAR(50) DEFAULT 'pending', + kyb_verified_at TIMESTAMPTZ, + kyb_verification_method VARCHAR(50), + kyb_verification_provider VARCHAR(255), + kyb_rejection_reason TEXT, + legal_entity_type VARCHAR(50), + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE company_users ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + role VARCHAR(50) NOT NULL, + department VARCHAR(100), + job_title VARCHAR(255), + is_administrator BOOLEAN DEFAULT FALSE, + can_manage_payroll BOOLEAN DEFAULT FALSE, + can_manage_invoices BOOLEAN DEFAULT FALSE, + can_manage_employees BOOLEAN DEFAULT FALSE, + can_manage_company_settings BOOLEAN DEFAULT FALSE, + can_manage_bank_accounts BOOLEAN DEFAULT FALSE, + can_manage_wallets BOOLEAN DEFAULT FALSE, + permissions JSONB, + is_active BOOLEAN DEFAULT TRUE, + added_by UUID REFERENCES users(id), + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(company_id, user_id) +); + +CREATE TABLE company_staff_profiles ( + id UUID PRIMARY KEY REFERENCES company_users(id) ON DELETE CASCADE, + first_name VARCHAR(255), + last_name VARCHAR(255), + profile_picture VARCHAR(255), + phone_number VARCHAR(50), + email VARCHAR(255), + department VARCHAR(100), + job_title VARCHAR(255), + reports_to UUID REFERENCES company_users(id), + hire_date DATE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE company_employees ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + user_id UUID REFERENCES users(id) ON DELETE SET NULL, + employee_id VARCHAR(100), + department VARCHAR(100), + position VARCHAR(100), + employment_status VARCHAR(50) DEFAULT 'active', + employment_type VARCHAR(50), + start_date DATE, + end_date DATE, + manager_id UUID REFERENCES company_users(id), + salary_amount DECIMAL(18, 6), + salary_currency VARCHAR(10), + salary_frequency VARCHAR(50), + hourly_rate DECIMAL(18, 6), + payment_method VARCHAR(50), + payment_split JSONB, + tax_information JSONB, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(company_id, employee_id) +); + +-- Create indexes for better performance +CREATE INDEX idx_users_email ON users(email); +CREATE INDEX idx_users_account_type ON users(account_type); +CREATE INDEX idx_users_account_status ON users(account_status); +CREATE INDEX idx_companies_owner_id ON companies(owner_id); +CREATE INDEX idx_company_users_company_id ON company_users(company_id); +CREATE INDEX idx_company_users_user_id ON company_users(user_id); +CREATE INDEX idx_company_employees_company_id ON company_employees(company_id); +CREATE INDEX idx_company_employees_user_id ON company_employees(user_id); + +-- +goose Down +DROP TABLE IF EXISTS company_employees CASCADE; +DROP TABLE IF EXISTS company_staff_profiles CASCADE; +DROP TABLE IF EXISTS company_users CASCADE; +DROP TABLE IF EXISTS companies CASCADE; +DROP TABLE IF EXISTS personal_users CASCADE; +DROP TABLE IF EXISTS users CASCADE; +DROP EXTENSION IF EXISTS "uuid-ossp"; \ No newline at end of file diff --git a/db/migrations/20250618100355_authentication.sql b/db/migrations/20250618100355_authentication.sql new file mode 100644 index 0000000..964e742 --- /dev/null +++ b/db/migrations/20250618100355_authentication.sql @@ -0,0 +1,66 @@ +-- +goose Up +-- Authentication tables +CREATE TABLE sessions ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + refresh_token VARCHAR(1024), + user_agent TEXT, + client_ip VARCHAR(45), + last_used_at TIMESTAMPTZ DEFAULT NOW(), + web_oauth_client_id TEXT, + oauth_access_token TEXT, + oauth_id_token TEXT, + user_login_type VARCHAR(100), + mfa_verified BOOLEAN DEFAULT FALSE, + is_blocked BOOLEAN DEFAULT FALSE, + expires_at TIMESTAMPTZ, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE user_devices ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + device_token VARCHAR(255), + platform VARCHAR(50), + device_type VARCHAR(100), + device_model VARCHAR(100), + os_name VARCHAR(50), + os_version VARCHAR(50), + push_notification_token VARCHAR(255), + is_active BOOLEAN DEFAULT TRUE, + is_verified BOOLEAN DEFAULT FALSE, + last_used_at TIMESTAMPTZ DEFAULT NOW(), + app_version VARCHAR(50), + client_ip VARCHAR(45), + expires_at TIMESTAMPTZ, + is_revoked BOOLEAN DEFAULT FALSE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE security_events ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID REFERENCES users(id) ON DELETE SET NULL, + company_id UUID REFERENCES companies(id) ON DELETE SET NULL, + event_type VARCHAR(100) NOT NULL, + severity VARCHAR(50) NOT NULL, + ip_address VARCHAR(45), + user_agent TEXT, + metadata JSONB, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Create indexes +CREATE INDEX idx_sessions_user_id ON sessions(user_id); +CREATE INDEX idx_sessions_expires_at ON sessions(expires_at); +CREATE INDEX idx_user_devices_user_id ON user_devices(user_id); +CREATE INDEX idx_user_devices_device_token ON user_devices(device_token); +CREATE INDEX idx_security_events_user_id ON security_events(user_id); +CREATE INDEX idx_security_events_company_id ON security_events(company_id); +CREATE INDEX idx_security_events_event_type ON security_events(event_type); +CREATE INDEX idx_security_events_created_at ON security_events(created_at); + +-- +goose Down +DROP TABLE IF EXISTS security_events CASCADE; +DROP TABLE IF EXISTS user_devices CASCADE; +DROP TABLE IF EXISTS sessions CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618100431_country_compliance.sql b/db/migrations/20250618100431_country_compliance.sql new file mode 100644 index 0000000..0865068 --- /dev/null +++ b/db/migrations/20250618100431_country_compliance.sql @@ -0,0 +1,77 @@ +-- +goose Up +-- Country Management and Compliance +CREATE TABLE supported_countries ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + country_code VARCHAR(3) UNIQUE NOT NULL, + country_name VARCHAR(100) NOT NULL, + region VARCHAR(50), + currency_code VARCHAR(3), + currency_symbol VARCHAR(5), + is_active BOOLEAN DEFAULT TRUE, + is_high_risk BOOLEAN DEFAULT FALSE, + requires_enhanced_kyc BOOLEAN DEFAULT FALSE, + requires_enhanced_kyb BOOLEAN DEFAULT FALSE, + timezone VARCHAR(50), + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE kyc_country_requirements ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + country_id UUID NOT NULL REFERENCES supported_countries(id) ON DELETE CASCADE, + document_type VARCHAR(50) NOT NULL, + is_required BOOLEAN DEFAULT TRUE, + requirement_description TEXT, + acceptable_document_formats VARCHAR(255), + verification_level VARCHAR(50), + additional_attributes JSONB, + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE kyb_country_requirements ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + country_id UUID NOT NULL REFERENCES supported_countries(id) ON DELETE CASCADE, + document_type VARCHAR(50) NOT NULL, + business_type VARCHAR(50), + is_required BOOLEAN DEFAULT TRUE, + requirement_description TEXT, + acceptable_document_formats VARCHAR(255), + verification_level VARCHAR(50), + additional_attributes JSONB, + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE compliance_rules ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + country_id UUID NOT NULL REFERENCES supported_countries(id) ON DELETE CASCADE, + rule_type VARCHAR(50) NOT NULL, + entity_type VARCHAR(50) NOT NULL, + threshold_amount DECIMAL(18, 6), + threshold_currency VARCHAR(3), + rule_description TEXT, + regulatory_reference VARCHAR(255), + action_required VARCHAR(50), + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Create indexes +CREATE INDEX idx_supported_countries_country_code ON supported_countries(country_code); +CREATE INDEX idx_supported_countries_is_active ON supported_countries(is_active); +CREATE INDEX idx_kyc_country_requirements_country_id ON kyc_country_requirements(country_id); +CREATE INDEX idx_kyc_country_requirements_document_type ON kyc_country_requirements(document_type); +CREATE INDEX idx_kyb_country_requirements_country_id ON kyb_country_requirements(country_id); +CREATE INDEX idx_kyb_country_requirements_document_type ON kyb_country_requirements(document_type); +CREATE INDEX idx_compliance_rules_country_id ON compliance_rules(country_id); +CREATE INDEX idx_compliance_rules_rule_type ON compliance_rules(rule_type); + +-- +goose Down +DROP TABLE IF EXISTS compliance_rules CASCADE; +DROP TABLE IF EXISTS kyb_country_requirements CASCADE; +DROP TABLE IF EXISTS kyc_country_requirements CASCADE; +DROP TABLE IF EXISTS supported_countries CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618100620_kyc_kyb_documents.sql b/db/migrations/20250618100620_kyc_kyb_documents.sql new file mode 100644 index 0000000..e4f2729 --- /dev/null +++ b/db/migrations/20250618100620_kyc_kyb_documents.sql @@ -0,0 +1,129 @@ +-- +goose Up +-- KYC/KYB Management +CREATE TABLE kyc_documents ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + country_id UUID NOT NULL REFERENCES supported_countries(id) ON DELETE CASCADE, + document_type VARCHAR(50) NOT NULL, + document_number VARCHAR(100), + document_country VARCHAR(100), + issue_date DATE, + expiry_date DATE, + document_url VARCHAR(255), + ipfs_hash VARCHAR(255), + verification_status VARCHAR(50) DEFAULT 'pending', + verification_level VARCHAR(50), + verification_notes TEXT, + verified_by UUID REFERENCES users(id), + verified_at TIMESTAMPTZ, + rejection_reason TEXT, + metadata JSONB, + meets_requirements BOOLEAN DEFAULT FALSE, + requirement_id UUID REFERENCES kyc_country_requirements(id), + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE kyb_documents ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + country_id UUID NOT NULL REFERENCES supported_countries(id) ON DELETE CASCADE, + document_type VARCHAR(50) NOT NULL, + document_number VARCHAR(100), + document_country VARCHAR(100), + issue_date DATE, + expiry_date DATE, + document_url VARCHAR(255), + ipfs_hash VARCHAR(255), + verification_status VARCHAR(50) DEFAULT 'pending', + verification_level VARCHAR(50), + verification_notes TEXT, + verified_by UUID REFERENCES users(id), + verified_at TIMESTAMPTZ, + rejection_reason TEXT, + metadata JSONB, + meets_requirements BOOLEAN DEFAULT FALSE, + requirement_id UUID REFERENCES kyb_country_requirements(id), + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE kyc_verification_attempts ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + verification_provider VARCHAR(100) NOT NULL, + verification_reference VARCHAR(255), + verification_status VARCHAR(50) DEFAULT 'pending', + verification_result VARCHAR(50), + response_data JSONB, + error_message TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE kyb_verification_attempts ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + verification_provider VARCHAR(100) NOT NULL, + verification_reference VARCHAR(255), + verification_status VARCHAR(50) DEFAULT 'pending', + verification_result VARCHAR(50), + response_data JSONB, + error_message TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE user_country_kyc_status ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + country_id UUID NOT NULL REFERENCES supported_countries(id) ON DELETE CASCADE, + verification_status VARCHAR(50) DEFAULT 'pending', + verification_level VARCHAR(50), + verification_date TIMESTAMPTZ, + expiry_date TIMESTAMPTZ, + rejection_reason TEXT, + notes TEXT, + risk_rating VARCHAR(20), + restricted_features JSONB, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(user_id, country_id) +); + +CREATE TABLE company_country_kyb_status ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + country_id UUID NOT NULL REFERENCES supported_countries(id) ON DELETE CASCADE, + verification_status VARCHAR(50) DEFAULT 'pending', + verification_level VARCHAR(50), + verification_date TIMESTAMPTZ, + expiry_date TIMESTAMPTZ, + rejection_reason TEXT, + notes TEXT, + risk_rating VARCHAR(20), + restricted_features JSONB, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(company_id, country_id) +); + +-- Create indexes +CREATE INDEX idx_kyc_documents_user_id ON kyc_documents(user_id); +CREATE INDEX idx_kyc_documents_country_id ON kyc_documents(country_id); +CREATE INDEX idx_kyc_documents_verification_status ON kyc_documents(verification_status); +CREATE INDEX idx_kyb_documents_company_id ON kyb_documents(company_id); +CREATE INDEX idx_kyb_documents_country_id ON kyb_documents(country_id); +CREATE INDEX idx_kyb_documents_verification_status ON kyb_documents(verification_status); +CREATE INDEX idx_kyc_verification_attempts_user_id ON kyc_verification_attempts(user_id); +CREATE INDEX idx_kyb_verification_attempts_company_id ON kyb_verification_attempts(company_id); +CREATE INDEX idx_user_country_kyc_status_user_id ON user_country_kyc_status(user_id); +CREATE INDEX idx_company_country_kyb_status_company_id ON company_country_kyb_status(company_id); + +-- +goose Down +DROP TABLE IF EXISTS company_country_kyb_status CASCADE; +DROP TABLE IF EXISTS user_country_kyc_status CASCADE; +DROP TABLE IF EXISTS kyb_verification_attempts CASCADE; +DROP TABLE IF EXISTS kyc_verification_attempts CASCADE; +DROP TABLE IF EXISTS kyb_documents CASCADE; +DROP TABLE IF EXISTS kyc_documents CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618100638_wallet_payment.sql b/db/migrations/20250618100638_wallet_payment.sql new file mode 100644 index 0000000..a295115 --- /dev/null +++ b/db/migrations/20250618100638_wallet_payment.sql @@ -0,0 +1,111 @@ +-- +goose Up +-- Wallet and Payment Infrastructure +CREATE TABLE supported_networks ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + name VARCHAR(100) UNIQUE NOT NULL, + chain_id INTEGER UNIQUE NOT NULL, + network_type VARCHAR(50) NOT NULL, + currency_symbol VARCHAR(10) NOT NULL, + block_explorer_url VARCHAR(255), + rpc_url VARCHAR(255), + is_evm_compatible BOOLEAN DEFAULT FALSE, + is_active BOOLEAN DEFAULT TRUE, + transaction_speed VARCHAR(50), + average_block_time INTEGER, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE supported_tokens ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + network_id UUID NOT NULL REFERENCES supported_networks(id) ON DELETE CASCADE, + name VARCHAR(100) NOT NULL, + symbol VARCHAR(20) NOT NULL, + decimals INTEGER NOT NULL DEFAULT 18, + contract_address VARCHAR(255), + token_type VARCHAR(50) NOT NULL, + logo_url VARCHAR(255), + is_stablecoin BOOLEAN DEFAULT FALSE, + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(network_id, symbol, contract_address) +); + +CREATE TABLE user_wallets ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + wallet_address VARCHAR(255) NOT NULL, + wallet_type VARCHAR(50) NOT NULL, + chain_id INTEGER NOT NULL, + is_default BOOLEAN DEFAULT FALSE, + is_verified BOOLEAN DEFAULT FALSE, + verification_method VARCHAR(50), + verified_at TIMESTAMPTZ, + nickname VARCHAR(100), + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(user_id, wallet_address, chain_id) +); + +CREATE TABLE company_wallets ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + wallet_address VARCHAR(255) NOT NULL, + wallet_type VARCHAR(50) NOT NULL, + chain_id INTEGER NOT NULL, + is_default BOOLEAN DEFAULT FALSE, + multisig_config JSONB, + required_approvals INTEGER DEFAULT 1, + wallet_name VARCHAR(100), + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(company_id, wallet_address, chain_id) +); + +CREATE TABLE bank_accounts ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID REFERENCES users(id) ON DELETE CASCADE, + company_id UUID REFERENCES companies(id) ON DELETE CASCADE, + account_number VARCHAR(255) NOT NULL, + account_holder_name VARCHAR(255) NOT NULL, + bank_name VARCHAR(255) NOT NULL, + bank_code VARCHAR(100), + routing_number VARCHAR(100), + swift_code VARCHAR(50), + iban VARCHAR(100), + account_type VARCHAR(50) NOT NULL, + currency VARCHAR(3) NOT NULL, + country VARCHAR(100) NOT NULL, + is_default BOOLEAN DEFAULT FALSE, + is_verified BOOLEAN DEFAULT FALSE, + verification_method VARCHAR(50), + verified_at TIMESTAMPTZ, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + CONSTRAINT chk_bank_account_owner CHECK ( + (user_id IS NOT NULL AND company_id IS NULL) OR + (user_id IS NULL AND company_id IS NOT NULL) + ) +); + +-- Create indexes +CREATE INDEX idx_supported_networks_chain_id ON supported_networks(chain_id); +CREATE INDEX idx_supported_networks_is_active ON supported_networks(is_active); +CREATE INDEX idx_supported_tokens_network_id ON supported_tokens(network_id); +CREATE INDEX idx_supported_tokens_symbol ON supported_tokens(symbol); +CREATE INDEX idx_user_wallets_user_id ON user_wallets(user_id); +CREATE INDEX idx_user_wallets_wallet_address ON user_wallets(wallet_address); +CREATE INDEX idx_user_wallets_chain_id ON user_wallets(chain_id); +CREATE INDEX idx_company_wallets_company_id ON company_wallets(company_id); +CREATE INDEX idx_company_wallets_wallet_address ON company_wallets(wallet_address); +CREATE INDEX idx_bank_accounts_user_id ON bank_accounts(user_id); +CREATE INDEX idx_bank_accounts_company_id ON bank_accounts(company_id); +CREATE INDEX idx_bank_accounts_currency ON bank_accounts(currency); + +-- +goose Down +DROP TABLE IF EXISTS bank_accounts CASCADE; +DROP TABLE IF EXISTS company_wallets CASCADE; +DROP TABLE IF EXISTS user_wallets CASCADE; +DROP TABLE IF EXISTS supported_tokens CASCADE; +DROP TABLE IF EXISTS supported_networks CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618100648_payroll_management.sql b/db/migrations/20250618100648_payroll_management.sql new file mode 100644 index 0000000..1a96581 --- /dev/null +++ b/db/migrations/20250618100648_payroll_management.sql @@ -0,0 +1,81 @@ +-- +goose Up +-- Payroll Management +CREATE TABLE payroll_periods ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + period_name VARCHAR(100) NOT NULL, + frequency VARCHAR(50) NOT NULL, + start_date DATE NOT NULL, + end_date DATE NOT NULL, + payment_date DATE NOT NULL, + status VARCHAR(50) DEFAULT 'draft', + is_recurring BOOLEAN DEFAULT FALSE, + next_period_id UUID, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Add self-referencing foreign key for next_period_id +ALTER TABLE payroll_periods ADD CONSTRAINT fk_next_period_id + FOREIGN KEY (next_period_id) REFERENCES payroll_periods(id); + +CREATE TABLE payrolls ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + period_id UUID NOT NULL REFERENCES payroll_periods(id) ON DELETE CASCADE, + name VARCHAR(255) NOT NULL, + description TEXT, + total_amount DECIMAL(24, 6) DEFAULT 0, + base_currency VARCHAR(10) NOT NULL, + status VARCHAR(50) DEFAULT 'draft', + execution_type VARCHAR(50) DEFAULT 'manual', + scheduled_execution_time TIMESTAMPTZ, + executed_at TIMESTAMPTZ, + smart_contract_address VARCHAR(255), + chain_id INTEGER, + transaction_hash VARCHAR(255), + created_by UUID NOT NULL REFERENCES users(id), + approved_by UUID REFERENCES users(id), + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE payroll_items ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + payroll_id UUID NOT NULL REFERENCES payrolls(id) ON DELETE CASCADE, + employee_id UUID NOT NULL REFERENCES company_employees(id) ON DELETE CASCADE, + base_amount DECIMAL(18, 6) NOT NULL, + base_currency VARCHAR(10) NOT NULL, + payment_amount DECIMAL(18, 6) NOT NULL, + payment_currency VARCHAR(10) NOT NULL, + exchange_rate DECIMAL(24, 12) DEFAULT 1, + payment_method VARCHAR(50) NOT NULL, + payment_split JSONB, + status VARCHAR(50) DEFAULT 'pending', + transaction_hash VARCHAR(255), + recipient_wallet_address VARCHAR(255), + recipient_bank_account_id UUID REFERENCES bank_accounts(id), + notes TEXT, + timesheet_id UUID, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Create indexes +CREATE INDEX idx_payroll_periods_company_id ON payroll_periods(company_id); +CREATE INDEX idx_payroll_periods_start_date ON payroll_periods(start_date); +CREATE INDEX idx_payroll_periods_end_date ON payroll_periods(end_date); +CREATE INDEX idx_payroll_periods_status ON payroll_periods(status); +CREATE INDEX idx_payrolls_company_id ON payrolls(company_id); +CREATE INDEX idx_payrolls_period_id ON payrolls(period_id); +CREATE INDEX idx_payrolls_status ON payrolls(status); +CREATE INDEX idx_payrolls_created_by ON payrolls(created_by); +CREATE INDEX idx_payroll_items_payroll_id ON payroll_items(payroll_id); +CREATE INDEX idx_payroll_items_employee_id ON payroll_items(employee_id); +CREATE INDEX idx_payroll_items_status ON payroll_items(status); +CREATE INDEX idx_payroll_items_timesheet_id ON payroll_items(timesheet_id); + +-- +goose Down +DROP TABLE IF EXISTS payroll_items CASCADE; +DROP TABLE IF EXISTS payrolls CASCADE; +DROP TABLE IF EXISTS payroll_periods CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618100705_invoice_contact_management.sql b/db/migrations/20250618100705_invoice_contact_management.sql new file mode 100644 index 0000000..b5c83f7 --- /dev/null +++ b/db/migrations/20250618100705_invoice_contact_management.sql @@ -0,0 +1,125 @@ +-- +goose Up +-- Invoice and Contract Management +CREATE TABLE invoices ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + invoice_number VARCHAR(100) UNIQUE NOT NULL, + issuer_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + recipient_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + title VARCHAR(255) NOT NULL, + description TEXT, + issue_date DATE NOT NULL, + due_date DATE NOT NULL, + total_amount DECIMAL(18, 6) NOT NULL, + currency VARCHAR(10) NOT NULL, + status VARCHAR(50) DEFAULT 'draft', + payment_method VARCHAR(50), + recipient_wallet_address VARCHAR(255), + recipient_bank_account_id UUID REFERENCES bank_accounts(id), + transaction_hash VARCHAR(255), + payment_date TIMESTAMPTZ, + rejection_reason TEXT, + ipfs_hash VARCHAR(255), + smart_contract_address VARCHAR(255), + chain_id INTEGER, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE invoice_items ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + invoice_id UUID NOT NULL REFERENCES invoices(id) ON DELETE CASCADE, + description TEXT NOT NULL, + quantity DECIMAL(10, 2) NOT NULL DEFAULT 1, + unit_price DECIMAL(18, 6) NOT NULL, + amount DECIMAL(18, 6) NOT NULL, + tax_rate DECIMAL(5, 2) DEFAULT 0, + tax_amount DECIMAL(18, 6) DEFAULT 0, + discount_percentage DECIMAL(5, 2) DEFAULT 0, + discount_amount DECIMAL(18, 6) DEFAULT 0, + total_amount DECIMAL(18, 6) NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE contract_templates ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + creator_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + company_id UUID REFERENCES companies(id) ON DELETE CASCADE, + name VARCHAR(255) NOT NULL, + description TEXT, + template_type VARCHAR(50) NOT NULL, + template_content JSONB NOT NULL, + is_public BOOLEAN DEFAULT FALSE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE contracts ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + template_id UUID REFERENCES contract_templates(id), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + employee_id UUID REFERENCES company_employees(id) ON DELETE CASCADE, + freelancer_id UUID REFERENCES users(id) ON DELETE CASCADE, + contract_title VARCHAR(255) NOT NULL, + contract_type VARCHAR(50) NOT NULL, + start_date DATE NOT NULL, + end_date DATE, + status VARCHAR(50) DEFAULT 'draft', + payment_terms JSONB, + contract_document_url VARCHAR(255), + ipfs_hash VARCHAR(255), + smart_contract_address VARCHAR(255), + chain_id INTEGER, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + CONSTRAINT chk_contract_party CHECK ( + (employee_id IS NOT NULL AND freelancer_id IS NULL) OR + (employee_id IS NULL AND freelancer_id IS NOT NULL) + ) +); + +CREATE TABLE payment_requests ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + creator_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + recipient_id UUID REFERENCES users(id) ON DELETE CASCADE, + company_id UUID REFERENCES companies(id) ON DELETE CASCADE, + request_title VARCHAR(255) NOT NULL, + description TEXT, + amount DECIMAL(18, 6) NOT NULL, + currency VARCHAR(10) NOT NULL, + status VARCHAR(50) DEFAULT 'pending', + expiry_date TIMESTAMPTZ, + payment_link VARCHAR(255), + qr_code_url VARCHAR(255), + payment_method VARCHAR(50), + recipient_wallet_address VARCHAR(255), + recipient_bank_account_id UUID REFERENCES bank_accounts(id), + transaction_hash VARCHAR(255), + paid_at TIMESTAMPTZ, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Create indexes +CREATE INDEX idx_invoices_invoice_number ON invoices(invoice_number); +CREATE INDEX idx_invoices_issuer_id ON invoices(issuer_id); +CREATE INDEX idx_invoices_recipient_id ON invoices(recipient_id); +CREATE INDEX idx_invoices_status ON invoices(status); +CREATE INDEX idx_invoices_due_date ON invoices(due_date); +CREATE INDEX idx_invoice_items_invoice_id ON invoice_items(invoice_id); +CREATE INDEX idx_contract_templates_creator_id ON contract_templates(creator_id); +CREATE INDEX idx_contract_templates_company_id ON contract_templates(company_id); +CREATE INDEX idx_contracts_template_id ON contracts(template_id); +CREATE INDEX idx_contracts_company_id ON contracts(company_id); +CREATE INDEX idx_contracts_employee_id ON contracts(employee_id); +CREATE INDEX idx_contracts_freelancer_id ON contracts(freelancer_id); +CREATE INDEX idx_payment_requests_creator_id ON payment_requests(creator_id); +CREATE INDEX idx_payment_requests_recipient_id ON payment_requests(recipient_id); +CREATE INDEX idx_payment_requests_status ON payment_requests(status); + +-- +goose Down +DROP TABLE IF EXISTS payment_requests CASCADE; +DROP TABLE IF EXISTS contracts CASCADE; +DROP TABLE IF EXISTS contract_templates CASCADE; +DROP TABLE IF EXISTS invoice_items CASCADE; +DROP TABLE IF EXISTS invoices CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618100726_timesheet_management.sql b/db/migrations/20250618100726_timesheet_management.sql new file mode 100644 index 0000000..a2bee17 --- /dev/null +++ b/db/migrations/20250618100726_timesheet_management.sql @@ -0,0 +1,58 @@ +-- +goose Up +-- Timesheet Management +CREATE TABLE timesheets ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + employee_id UUID NOT NULL REFERENCES company_employees(id) ON DELETE CASCADE, + period_id UUID REFERENCES payroll_periods(id) ON DELETE SET NULL, + status VARCHAR(50) DEFAULT 'draft', + total_hours DECIMAL(8, 2) DEFAULT 0, + billable_hours DECIMAL(8, 2) DEFAULT 0, + overtime_hours DECIMAL(8, 2) DEFAULT 0, + hourly_rate DECIMAL(18, 6), + rate_currency VARCHAR(10), + total_amount DECIMAL(18, 6) DEFAULT 0, + submitted_at TIMESTAMPTZ, + approved_at TIMESTAMPTZ, + approved_by UUID REFERENCES users(id), + rejection_reason TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE timesheet_entries ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + timesheet_id UUID NOT NULL REFERENCES timesheets(id) ON DELETE CASCADE, + date DATE NOT NULL, + start_time TIME, + end_time TIME, + hours DECIMAL(5, 2) NOT NULL, + is_billable BOOLEAN DEFAULT TRUE, + is_overtime BOOLEAN DEFAULT FALSE, + project VARCHAR(255), + task VARCHAR(255), + description TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Add the foreign key reference from payroll_items to timesheets +ALTER TABLE payroll_items ADD CONSTRAINT fk_payroll_items_timesheet_id + FOREIGN KEY (timesheet_id) REFERENCES timesheets(id); + +-- Create indexes +CREATE INDEX idx_timesheets_company_id ON timesheets(company_id); +CREATE INDEX idx_timesheets_employee_id ON timesheets(employee_id); +CREATE INDEX idx_timesheets_period_id ON timesheets(period_id); +CREATE INDEX idx_timesheets_status ON timesheets(status); +CREATE INDEX idx_timesheets_submitted_at ON timesheets(submitted_at); +CREATE INDEX idx_timesheet_entries_timesheet_id ON timesheet_entries(timesheet_id); +CREATE INDEX idx_timesheet_entries_date ON timesheet_entries(date); +CREATE INDEX idx_timesheet_entries_project ON timesheet_entries(project); + +-- +goose Down +-- Remove the foreign key constraint from payroll_items +ALTER TABLE payroll_items DROP CONSTRAINT IF EXISTS fk_payroll_items_timesheet_id; + +DROP TABLE IF EXISTS timesheet_entries CASCADE; +DROP TABLE IF EXISTS timesheets CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618100748_transactions.sql b/db/migrations/20250618100748_transactions.sql new file mode 100644 index 0000000..1490a0a --- /dev/null +++ b/db/migrations/20250618100748_transactions.sql @@ -0,0 +1,80 @@ +-- +goose Up +-- Transaction Management +CREATE TABLE wallet_transactions ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + wallet_address VARCHAR(255) NOT NULL, + transaction_hash VARCHAR(255) UNIQUE NOT NULL, + chain_id INTEGER NOT NULL, + block_number BIGINT, + from_address VARCHAR(255) NOT NULL, + to_address VARCHAR(255) NOT NULL, + token_address VARCHAR(255), + token_symbol VARCHAR(20), + amount DECIMAL(36, 18) NOT NULL, + transaction_type VARCHAR(50) NOT NULL, + transaction_status VARCHAR(50) DEFAULT 'pending', + gas_price DECIMAL(36, 18), + gas_used BIGINT, + transaction_fee DECIMAL(36, 18), + reference_type VARCHAR(50), + reference_id UUID, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE fiat_transactions ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + bank_account_id UUID NOT NULL REFERENCES bank_accounts(id) ON DELETE CASCADE, + transaction_reference VARCHAR(255) UNIQUE NOT NULL, + transaction_type VARCHAR(50) NOT NULL, + amount DECIMAL(18, 6) NOT NULL, + currency VARCHAR(3) NOT NULL, + status VARCHAR(50) DEFAULT 'pending', + payment_provider VARCHAR(100), + payment_method VARCHAR(50), + provider_reference VARCHAR(255), + provider_fee DECIMAL(18, 6) DEFAULT 0, + reference_type VARCHAR(50), + reference_id UUID, + metadata JSONB, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE exchange_rates ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + base_currency VARCHAR(10) NOT NULL, + quote_currency VARCHAR(10) NOT NULL, + rate DECIMAL(24, 12) NOT NULL, + source VARCHAR(100) NOT NULL, + timestamp TIMESTAMPTZ NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(base_currency, quote_currency, timestamp, source) +); + +-- Create indexes +CREATE INDEX idx_wallet_transactions_wallet_address ON wallet_transactions(wallet_address); +CREATE INDEX idx_wallet_transactions_transaction_hash ON wallet_transactions(transaction_hash); +CREATE INDEX idx_wallet_transactions_chain_id ON wallet_transactions(chain_id); +CREATE INDEX idx_wallet_transactions_from_address ON wallet_transactions(from_address); +CREATE INDEX idx_wallet_transactions_to_address ON wallet_transactions(to_address); +CREATE INDEX idx_wallet_transactions_transaction_type ON wallet_transactions(transaction_type); +CREATE INDEX idx_wallet_transactions_reference ON wallet_transactions(reference_type, reference_id); +CREATE INDEX idx_wallet_transactions_created_at ON wallet_transactions(created_at); + +CREATE INDEX idx_fiat_transactions_bank_account_id ON fiat_transactions(bank_account_id); +CREATE INDEX idx_fiat_transactions_transaction_reference ON fiat_transactions(transaction_reference); +CREATE INDEX idx_fiat_transactions_transaction_type ON fiat_transactions(transaction_type); +CREATE INDEX idx_fiat_transactions_status ON fiat_transactions(status); +CREATE INDEX idx_fiat_transactions_reference ON fiat_transactions(reference_type, reference_id); +CREATE INDEX idx_fiat_transactions_created_at ON fiat_transactions(created_at); + +CREATE INDEX idx_exchange_rates_base_currency ON exchange_rates(base_currency); +CREATE INDEX idx_exchange_rates_quote_currency ON exchange_rates(quote_currency); +CREATE INDEX idx_exchange_rates_timestamp ON exchange_rates(timestamp); +CREATE INDEX idx_exchange_rates_base_quote ON exchange_rates(base_currency, quote_currency); + +-- +goose Down +DROP TABLE IF EXISTS exchange_rates CASCADE; +DROP TABLE IF EXISTS fiat_transactions CASCADE; +DROP TABLE IF EXISTS wallet_transactions CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618100806_hr_management.sql b/db/migrations/20250618100806_hr_management.sql new file mode 100644 index 0000000..4d02f4a --- /dev/null +++ b/db/migrations/20250618100806_hr_management.sql @@ -0,0 +1,102 @@ +-- +goose Up +-- HR Management (Leave, Expenses) +CREATE TABLE leave_types ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + name VARCHAR(100) NOT NULL, + description TEXT, + is_paid BOOLEAN DEFAULT TRUE, + accrual_rate DECIMAL(5, 2) DEFAULT 0, + accrual_period VARCHAR(20) DEFAULT 'monthly', + maximum_balance DECIMAL(5, 2), + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(company_id, name) +); + +CREATE TABLE leave_balances ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + employee_id UUID NOT NULL REFERENCES company_employees(id) ON DELETE CASCADE, + leave_type_id UUID NOT NULL REFERENCES leave_types(id) ON DELETE CASCADE, + balance DECIMAL(6, 2) DEFAULT 0, + accrued DECIMAL(6, 2) DEFAULT 0, + used DECIMAL(6, 2) DEFAULT 0, + last_accrual_date DATE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(employee_id, leave_type_id) +); + +CREATE TABLE leave_requests ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + employee_id UUID NOT NULL REFERENCES company_employees(id) ON DELETE CASCADE, + leave_type_id UUID NOT NULL REFERENCES leave_types(id) ON DELETE CASCADE, + start_date DATE NOT NULL, + end_date DATE NOT NULL, + days DECIMAL(5, 2) NOT NULL, + reason TEXT, + status VARCHAR(50) DEFAULT 'pending', + approved_by UUID REFERENCES users(id), + approved_at TIMESTAMPTZ, + rejected_reason TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + CONSTRAINT chk_leave_dates CHECK (end_date >= start_date), + CONSTRAINT chk_leave_days CHECK (days > 0) +); + +CREATE TABLE expense_categories ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + name VARCHAR(100) NOT NULL, + description TEXT, + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(company_id, name) +); + +CREATE TABLE expenses ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + category_id UUID NOT NULL REFERENCES expense_categories(id) ON DELETE CASCADE, + amount DECIMAL(18, 6) NOT NULL, + currency VARCHAR(10) NOT NULL, + expense_date DATE NOT NULL, + description TEXT, + receipt_url VARCHAR(255), + ipfs_hash VARCHAR(255), + status VARCHAR(50) DEFAULT 'pending', + payment_transaction_id UUID, + approved_by UUID REFERENCES users(id), + approved_at TIMESTAMPTZ, + rejected_reason TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + CONSTRAINT chk_expense_amount CHECK (amount > 0) +); + +-- Create indexes +CREATE INDEX idx_leave_types_company_id ON leave_types(company_id); +CREATE INDEX idx_leave_types_is_active ON leave_types(is_active); +CREATE INDEX idx_leave_balances_employee_id ON leave_balances(employee_id); +CREATE INDEX idx_leave_balances_leave_type_id ON leave_balances(leave_type_id); +CREATE INDEX idx_leave_requests_employee_id ON leave_requests(employee_id); +CREATE INDEX idx_leave_requests_leave_type_id ON leave_requests(leave_type_id); +CREATE INDEX idx_leave_requests_status ON leave_requests(status); +CREATE INDEX idx_leave_requests_start_date ON leave_requests(start_date); +CREATE INDEX idx_expense_categories_company_id ON expense_categories(company_id); +CREATE INDEX idx_expenses_user_id ON expenses(user_id); +CREATE INDEX idx_expenses_company_id ON expenses(company_id); +CREATE INDEX idx_expenses_category_id ON expenses(category_id); +CREATE INDEX idx_expenses_status ON expenses(status); +CREATE INDEX idx_expenses_expense_date ON expenses(expense_date); + +-- +goose Down +DROP TABLE IF EXISTS expenses CASCADE; +DROP TABLE IF EXISTS expense_categories CASCADE; +DROP TABLE IF EXISTS leave_requests CASCADE; +DROP TABLE IF EXISTS leave_balances CASCADE; +DROP TABLE IF EXISTS leave_types CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618100847_tax_managment.sql b/db/migrations/20250618100847_tax_managment.sql new file mode 100644 index 0000000..638b50c --- /dev/null +++ b/db/migrations/20250618100847_tax_managment.sql @@ -0,0 +1,80 @@ +-- +goose Up +-- Tax Management +CREATE TABLE tax_rates ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + country_id UUID NOT NULL REFERENCES supported_countries(id) ON DELETE CASCADE, + region VARCHAR(100), + tax_type VARCHAR(50) NOT NULL, + rate DECIMAL(6, 3) NOT NULL, + effective_date DATE NOT NULL, + expiry_date DATE, + description TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + CONSTRAINT chk_tax_rate CHECK (rate >= 0 AND rate <= 100), + CONSTRAINT chk_tax_dates CHECK (expiry_date IS NULL OR expiry_date > effective_date) +); + +CREATE TABLE tax_calculations ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID REFERENCES users(id) ON DELETE CASCADE, + company_id UUID REFERENCES companies(id) ON DELETE CASCADE, + reference_type VARCHAR(50) NOT NULL, + reference_id UUID NOT NULL, + tax_rate_id UUID NOT NULL REFERENCES tax_rates(id) ON DELETE CASCADE, + taxable_amount DECIMAL(18, 6) NOT NULL, + tax_amount DECIMAL(18, 6) NOT NULL, + calculation_date DATE NOT NULL, + tax_period VARCHAR(20) NOT NULL, + status VARCHAR(50) DEFAULT 'calculated', + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + CONSTRAINT chk_tax_calculation_amounts CHECK ( + taxable_amount >= 0 AND tax_amount >= 0 + ), + CONSTRAINT chk_tax_calculation_entity CHECK ( + (user_id IS NOT NULL AND company_id IS NULL) OR + (user_id IS NULL AND company_id IS NOT NULL) + ) +); + +CREATE TABLE tax_documents ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID REFERENCES users(id) ON DELETE CASCADE, + company_id UUID REFERENCES companies(id) ON DELETE CASCADE, + country_id UUID NOT NULL REFERENCES supported_countries(id) ON DELETE CASCADE, + document_type VARCHAR(50) NOT NULL, + tax_year INTEGER NOT NULL, + document_url VARCHAR(255), + ipfs_hash VARCHAR(255), + status VARCHAR(50) DEFAULT 'draft', + expires_at DATE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + CONSTRAINT chk_tax_document_entity CHECK ( + (user_id IS NOT NULL AND company_id IS NULL) OR + (user_id IS NULL AND company_id IS NOT NULL) + ), + CONSTRAINT chk_tax_year CHECK (tax_year >= 2000 AND tax_year <= 2100) +); + +-- Create indexes +CREATE INDEX idx_tax_rates_country_id ON tax_rates(country_id); +CREATE INDEX idx_tax_rates_tax_type ON tax_rates(tax_type); +CREATE INDEX idx_tax_rates_effective_date ON tax_rates(effective_date); +CREATE INDEX idx_tax_rates_expiry_date ON tax_rates(expiry_date); +CREATE INDEX idx_tax_calculations_user_id ON tax_calculations(user_id); +CREATE INDEX idx_tax_calculations_company_id ON tax_calculations(company_id); +CREATE INDEX idx_tax_calculations_reference ON tax_calculations(reference_type, reference_id); +CREATE INDEX idx_tax_calculations_tax_rate_id ON tax_calculations(tax_rate_id); +CREATE INDEX idx_tax_calculations_calculation_date ON tax_calculations(calculation_date); +CREATE INDEX idx_tax_documents_user_id ON tax_documents(user_id); +CREATE INDEX idx_tax_documents_company_id ON tax_documents(company_id); +CREATE INDEX idx_tax_documents_country_id ON tax_documents(country_id); +CREATE INDEX idx_tax_documents_tax_year ON tax_documents(tax_year); +CREATE INDEX idx_tax_documents_document_type ON tax_documents(document_type); + +-- +goose Down +DROP TABLE IF EXISTS tax_documents CASCADE; +DROP TABLE IF EXISTS tax_calculations CASCADE; +DROP TABLE IF EXISTS tax_rates CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618100857_notification_roles.sql b/db/migrations/20250618100857_notification_roles.sql new file mode 100644 index 0000000..f3d4ff7 --- /dev/null +++ b/db/migrations/20250618100857_notification_roles.sql @@ -0,0 +1,95 @@ +-- +goose Up +-- Notification System +CREATE TABLE notification_templates ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + template_name VARCHAR(100) UNIQUE NOT NULL, + template_type VARCHAR(50) NOT NULL, + subject VARCHAR(255), + content TEXT NOT NULL, + variables JSONB, + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE notifications ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + template_id UUID REFERENCES notification_templates(id) ON DELETE SET NULL, + notification_type VARCHAR(50) NOT NULL, + title VARCHAR(255) NOT NULL, + content TEXT NOT NULL, + reference_type VARCHAR(50), + reference_id UUID, + is_read BOOLEAN DEFAULT FALSE, + read_at TIMESTAMPTZ, + delivery_status VARCHAR(50) DEFAULT 'pending', + priority VARCHAR(20) DEFAULT 'normal', + created_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Roles and Permissions +CREATE TABLE permissions ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + permission_key VARCHAR(100) UNIQUE NOT NULL, + description TEXT, + category VARCHAR(100) NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE roles ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID REFERENCES companies(id) ON DELETE CASCADE, + role_name VARCHAR(100) NOT NULL, + description TEXT, + is_system_role BOOLEAN DEFAULT FALSE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(company_id, role_name) +); + +CREATE TABLE role_permissions ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE, + permission_id UUID NOT NULL REFERENCES permissions(id) ON DELETE CASCADE, + created_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(role_id, permission_id) +); + +CREATE TABLE user_roles ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE, + company_id UUID REFERENCES companies(id) ON DELETE CASCADE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(user_id, role_id, company_id) +); + +-- Create indexes +CREATE INDEX idx_notification_templates_template_type ON notification_templates(template_type); +CREATE INDEX idx_notification_templates_is_active ON notification_templates(is_active); +CREATE INDEX idx_notifications_user_id ON notifications(user_id); +CREATE INDEX idx_notifications_template_id ON notifications(template_id); +CREATE INDEX idx_notifications_notification_type ON notifications(notification_type); +CREATE INDEX idx_notifications_is_read ON notifications(is_read); +CREATE INDEX idx_notifications_reference ON notifications(reference_type, reference_id); +CREATE INDEX idx_notifications_created_at ON notifications(created_at); +CREATE INDEX idx_permissions_permission_key ON permissions(permission_key); +CREATE INDEX idx_permissions_category ON permissions(category); +CREATE INDEX idx_roles_company_id ON roles(company_id); +CREATE INDEX idx_roles_is_system_role ON roles(is_system_role); +CREATE INDEX idx_role_permissions_role_id ON role_permissions(role_id); +CREATE INDEX idx_role_permissions_permission_id ON role_permissions(permission_id); +CREATE INDEX idx_user_roles_user_id ON user_roles(user_id); +CREATE INDEX idx_user_roles_role_id ON user_roles(role_id); +CREATE INDEX idx_user_roles_company_id ON user_roles(company_id); + +-- +goose Down +DROP TABLE IF EXISTS user_roles CASCADE; +DROP TABLE IF EXISTS role_permissions CASCADE; +DROP TABLE IF EXISTS roles CASCADE; +DROP TABLE IF EXISTS permissions CASCADE; +DROP TABLE IF EXISTS notifications CASCADE; +DROP TABLE IF EXISTS notification_templates CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618100913_system_configurations.sql b/db/migrations/20250618100913_system_configurations.sql new file mode 100644 index 0000000..1dc2eac --- /dev/null +++ b/db/migrations/20250618100913_system_configurations.sql @@ -0,0 +1,90 @@ +-- +goose Up +-- System Configuration +CREATE TABLE system_settings ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + setting_key VARCHAR(100) UNIQUE NOT NULL, + setting_value TEXT, + data_type VARCHAR(50) NOT NULL DEFAULT 'string', + description TEXT, + is_sensitive BOOLEAN DEFAULT FALSE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE company_settings ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + setting_key VARCHAR(100) NOT NULL, + setting_value TEXT, + data_type VARCHAR(50) NOT NULL DEFAULT 'string', + description TEXT, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(company_id, setting_key) +); + +CREATE TABLE user_settings ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + setting_key VARCHAR(100) NOT NULL, + setting_value TEXT, + data_type VARCHAR(50) NOT NULL DEFAULT 'string', + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(user_id, setting_key) +); + +-- Feature Flags +CREATE TABLE feature_flags ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + flag_key VARCHAR(100) UNIQUE NOT NULL, + description TEXT, + is_enabled BOOLEAN DEFAULT FALSE, + rollout_percentage INTEGER DEFAULT 0, + conditions JSONB, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + CONSTRAINT chk_rollout_percentage CHECK (rollout_percentage >= 0 AND rollout_percentage <= 100) +); + +CREATE TABLE user_feature_flags ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + flag_key VARCHAR(100) NOT NULL, + is_enabled BOOLEAN NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(user_id, flag_key) +); + +CREATE TABLE company_feature_flags ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + flag_key VARCHAR(100) NOT NULL, + is_enabled BOOLEAN NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + UNIQUE(company_id, flag_key) +); + +-- Create indexes +CREATE INDEX idx_system_settings_setting_key ON system_settings(setting_key); +CREATE INDEX idx_system_settings_data_type ON system_settings(data_type); +CREATE INDEX idx_company_settings_company_id ON company_settings(company_id); +CREATE INDEX idx_company_settings_setting_key ON company_settings(setting_key); +CREATE INDEX idx_user_settings_user_id ON user_settings(user_id); +CREATE INDEX idx_user_settings_setting_key ON user_settings(setting_key); +CREATE INDEX idx_feature_flags_flag_key ON feature_flags(flag_key); +CREATE INDEX idx_feature_flags_is_enabled ON feature_flags(is_enabled); +CREATE INDEX idx_user_feature_flags_user_id ON user_feature_flags(user_id); +CREATE INDEX idx_user_feature_flags_flag_key ON user_feature_flags(flag_key); +CREATE INDEX idx_company_feature_flags_company_id ON company_feature_flags(company_id); +CREATE INDEX idx_company_feature_flags_flag_key ON company_feature_flags(flag_key); + +-- +goose Down +DROP TABLE IF EXISTS company_feature_flags CASCADE; +DROP TABLE IF EXISTS user_feature_flags CASCADE; +DROP TABLE IF EXISTS feature_flags CASCADE; +DROP TABLE IF EXISTS user_settings CASCADE; +DROP TABLE IF EXISTS company_settings CASCADE; +DROP TABLE IF EXISTS system_settings CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618100943_audit_logging.sql b/db/migrations/20250618100943_audit_logging.sql new file mode 100644 index 0000000..a523c66 --- /dev/null +++ b/db/migrations/20250618100943_audit_logging.sql @@ -0,0 +1,41 @@ +-- +goose Up +-- Audit and Logging +CREATE TABLE audit_logs ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID REFERENCES users(id) ON DELETE SET NULL, + company_id UUID REFERENCES companies(id) ON DELETE SET NULL, + action VARCHAR(100) NOT NULL, + entity_type VARCHAR(100) NOT NULL, + entity_id UUID NOT NULL, + previous_state JSONB, + new_state JSONB, + ip_address VARCHAR(45), + user_agent TEXT, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE activity_logs ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + activity_type VARCHAR(100) NOT NULL, + description TEXT, + metadata JSONB, + ip_address VARCHAR(45), + user_agent TEXT, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +-- Create indexes +CREATE INDEX idx_audit_logs_user_id ON audit_logs(user_id); +CREATE INDEX idx_audit_logs_company_id ON audit_logs(company_id); +CREATE INDEX idx_audit_logs_action ON audit_logs(action); +CREATE INDEX idx_audit_logs_entity_type ON audit_logs(entity_type); +CREATE INDEX idx_audit_logs_entity_id ON audit_logs(entity_id); +CREATE INDEX idx_audit_logs_created_at ON audit_logs(created_at); +CREATE INDEX idx_activity_logs_user_id ON activity_logs(user_id); +CREATE INDEX idx_activity_logs_activity_type ON activity_logs(activity_type); +CREATE INDEX idx_activity_logs_created_at ON activity_logs(created_at); + +-- +goose Down +DROP TABLE IF EXISTS activity_logs CASCADE; +DROP TABLE IF EXISTS audit_logs CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618101017_api_integration.sql b/db/migrations/20250618101017_api_integration.sql new file mode 100644 index 0000000..75f5f33 --- /dev/null +++ b/db/migrations/20250618101017_api_integration.sql @@ -0,0 +1,75 @@ +-- +goose Up +-- API and Integration +CREATE TABLE api_keys ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID REFERENCES users(id) ON DELETE CASCADE, + company_id UUID REFERENCES companies(id) ON DELETE CASCADE, + api_key_hash VARCHAR(255) UNIQUE NOT NULL, + name VARCHAR(100) NOT NULL, + permissions JSONB, + expires_at TIMESTAMPTZ, + is_active BOOLEAN DEFAULT TRUE, + last_used_at TIMESTAMPTZ, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + CONSTRAINT chk_api_key_owner CHECK ( + (user_id IS NOT NULL AND company_id IS NULL) OR + (user_id IS NULL AND company_id IS NOT NULL) + ) +); + +CREATE TABLE integration_connections ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID REFERENCES users(id) ON DELETE CASCADE, + company_id UUID REFERENCES companies(id) ON DELETE CASCADE, + integration_type VARCHAR(100) NOT NULL, + provider VARCHAR(100) NOT NULL, + access_token TEXT, + refresh_token TEXT, + token_expires_at TIMESTAMPTZ, + connection_data JSONB, + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + CONSTRAINT chk_integration_owner CHECK ( + (user_id IS NOT NULL AND company_id IS NULL) OR + (user_id IS NULL AND company_id IS NOT NULL) + ) +); + +CREATE TABLE webhooks ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID REFERENCES users(id) ON DELETE CASCADE, + company_id UUID REFERENCES companies(id) ON DELETE CASCADE, + webhook_url VARCHAR(255) NOT NULL, + event_types VARCHAR[] NOT NULL, + secret_key VARCHAR(255) NOT NULL, + description TEXT, + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMPTZ DEFAULT NOW(), + updated_at TIMESTAMPTZ DEFAULT NOW(), + CONSTRAINT chk_webhook_owner CHECK ( + (user_id IS NOT NULL AND company_id IS NULL) OR + (user_id IS NULL AND company_id IS NOT NULL) + ) +); + +-- Create indexes +CREATE INDEX idx_api_keys_user_id ON api_keys(user_id); +CREATE INDEX idx_api_keys_company_id ON api_keys(company_id); +CREATE INDEX idx_api_keys_api_key_hash ON api_keys(api_key_hash); +CREATE INDEX idx_api_keys_is_active ON api_keys(is_active); +CREATE INDEX idx_api_keys_expires_at ON api_keys(expires_at); +CREATE INDEX idx_integration_connections_user_id ON integration_connections(user_id); +CREATE INDEX idx_integration_connections_company_id ON integration_connections(company_id); +CREATE INDEX idx_integration_connections_integration_type ON integration_connections(integration_type); +CREATE INDEX idx_integration_connections_provider ON integration_connections(provider); +CREATE INDEX idx_integration_connections_is_active ON integration_connections(is_active); +CREATE INDEX idx_webhooks_user_id ON webhooks(user_id); +CREATE INDEX idx_webhooks_company_id ON webhooks(company_id); +CREATE INDEX idx_webhooks_is_active ON webhooks(is_active); + +-- +goose Down +DROP TABLE IF EXISTS webhooks CASCADE; +DROP TABLE IF EXISTS integration_connections CASCADE; +DROP TABLE IF EXISTS api_keys CASCADE; \ No newline at end of file diff --git a/db/migrations/20250618101030_functions_triggers.sql b/db/migrations/20250618101030_functions_triggers.sql new file mode 100644 index 0000000..bee6fcf --- /dev/null +++ b/db/migrations/20250618101030_functions_triggers.sql @@ -0,0 +1,196 @@ +-- +goose Up +-- Functions and Triggers + +-- Function to update the updated_at timestamp +CREATE OR REPLACE FUNCTION update_updated_at_column() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = NOW(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Function to generate invoice numbers +CREATE OR REPLACE FUNCTION generate_invoice_number() +RETURNS TRIGGER AS $$ +BEGIN + IF NEW.invoice_number IS NULL THEN + NEW.invoice_number := 'INV-' || EXTRACT(YEAR FROM NOW()) || '-' || + LPAD(NEXTVAL('invoice_number_seq')::TEXT, 6, '0'); + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Create sequence for invoice numbers +CREATE SEQUENCE IF NOT EXISTS invoice_number_seq START 1; + +-- Function to validate payment split percentages +CREATE OR REPLACE FUNCTION validate_payment_split() +RETURNS TRIGGER AS $$ +DECLARE + split_total DECIMAL(5,2) := 0; + split_item JSONB; +BEGIN + IF NEW.payment_split IS NOT NULL THEN + FOR split_item IN SELECT jsonb_array_elements(NEW.payment_split) + LOOP + split_total := split_total + (split_item->>'percentage')::DECIMAL(5,2); + END LOOP; + + IF split_total != 100.00 THEN + RAISE EXCEPTION 'Payment split percentages must total 100, got %', split_total; + END IF; + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Function to update timesheet totals +CREATE OR REPLACE FUNCTION update_timesheet_totals() +RETURNS TRIGGER AS $$ +DECLARE + timesheet_record RECORD; +BEGIN + -- Get the timesheet ID from either NEW or OLD record + IF TG_OP = 'DELETE' THEN + SELECT id INTO timesheet_record FROM timesheets WHERE id = OLD.timesheet_id; + ELSE + SELECT id INTO timesheet_record FROM timesheets WHERE id = NEW.timesheet_id; + END IF; + + -- Update timesheet totals + UPDATE timesheets SET + total_hours = ( + SELECT COALESCE(SUM(hours), 0) + FROM timesheet_entries + WHERE timesheet_id = timesheet_record.id + ), + billable_hours = ( + SELECT COALESCE(SUM(hours), 0) + FROM timesheet_entries + WHERE timesheet_id = timesheet_record.id AND is_billable = true + ), + overtime_hours = ( + SELECT COALESCE(SUM(hours), 0) + FROM timesheet_entries + WHERE timesheet_id = timesheet_record.id AND is_overtime = true + ), + updated_at = NOW() + WHERE id = timesheet_record.id; + + RETURN COALESCE(NEW, OLD); +END; +$$ LANGUAGE plpgsql; + +-- Create updated_at triggers for all tables that have updated_at columns +CREATE TRIGGER trigger_users_updated_at BEFORE UPDATE ON users + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_personal_users_updated_at BEFORE UPDATE ON personal_users + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_companies_updated_at BEFORE UPDATE ON companies + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_company_users_updated_at BEFORE UPDATE ON company_users + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_company_staff_profiles_updated_at BEFORE UPDATE ON company_staff_profiles + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_company_employees_updated_at BEFORE UPDATE ON company_employees + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_user_devices_updated_at BEFORE UPDATE ON user_devices + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_supported_countries_updated_at BEFORE UPDATE ON supported_countries + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_kyc_country_requirements_updated_at BEFORE UPDATE ON kyc_country_requirements + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_kyb_country_requirements_updated_at BEFORE UPDATE ON kyb_country_requirements + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_compliance_rules_updated_at BEFORE UPDATE ON compliance_rules + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_kyc_documents_updated_at BEFORE UPDATE ON kyc_documents + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_kyb_documents_updated_at BEFORE UPDATE ON kyb_documents + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_supported_networks_updated_at BEFORE UPDATE ON supported_networks + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_supported_tokens_updated_at BEFORE UPDATE ON supported_tokens + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_user_wallets_updated_at BEFORE UPDATE ON user_wallets + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_company_wallets_updated_at BEFORE UPDATE ON company_wallets + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_bank_accounts_updated_at BEFORE UPDATE ON bank_accounts + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +-- Create invoice number generation trigger +CREATE TRIGGER trigger_generate_invoice_number BEFORE INSERT ON invoices + FOR EACH ROW EXECUTE FUNCTION generate_invoice_number(); + +-- Create payment split validation triggers +CREATE TRIGGER trigger_validate_payroll_payment_split BEFORE INSERT OR UPDATE ON payroll_items + FOR EACH ROW EXECUTE FUNCTION validate_payment_split(); + +CREATE TRIGGER trigger_validate_employee_payment_split BEFORE INSERT OR UPDATE ON company_employees + FOR EACH ROW EXECUTE FUNCTION validate_payment_split(); + +-- Create timesheet totals update triggers +CREATE TRIGGER trigger_update_timesheet_totals_insert AFTER INSERT ON timesheet_entries + FOR EACH ROW EXECUTE FUNCTION update_timesheet_totals(); + +CREATE TRIGGER trigger_update_timesheet_totals_update AFTER UPDATE ON timesheet_entries + FOR EACH ROW EXECUTE FUNCTION update_timesheet_totals(); + +CREATE TRIGGER trigger_update_timesheet_totals_delete AFTER DELETE ON timesheet_entries + FOR EACH ROW EXECUTE FUNCTION update_timesheet_totals(); + +-- +goose Down +-- Drop all triggers +DROP TRIGGER IF EXISTS trigger_update_timesheet_totals_delete ON timesheet_entries; +DROP TRIGGER IF EXISTS trigger_update_timesheet_totals_update ON timesheet_entries; +DROP TRIGGER IF EXISTS trigger_update_timesheet_totals_insert ON timesheet_entries; +DROP TRIGGER IF EXISTS trigger_validate_employee_payment_split ON company_employees; +DROP TRIGGER IF EXISTS trigger_validate_payroll_payment_split ON payroll_items; +DROP TRIGGER IF EXISTS trigger_generate_invoice_number ON invoices; +DROP TRIGGER IF EXISTS trigger_bank_accounts_updated_at ON bank_accounts; +DROP TRIGGER IF EXISTS trigger_company_wallets_updated_at ON company_wallets; +DROP TRIGGER IF EXISTS trigger_user_wallets_updated_at ON user_wallets; +DROP TRIGGER IF EXISTS trigger_supported_tokens_updated_at ON supported_tokens; +DROP TRIGGER IF EXISTS trigger_supported_networks_updated_at ON supported_networks; +DROP TRIGGER IF EXISTS trigger_kyb_documents_updated_at ON kyb_documents; +DROP TRIGGER IF EXISTS trigger_kyc_documents_updated_at ON kyc_documents; +DROP TRIGGER IF EXISTS trigger_compliance_rules_updated_at ON compliance_rules; +DROP TRIGGER IF EXISTS trigger_kyb_country_requirements_updated_at ON kyb_country_requirements; +DROP TRIGGER IF EXISTS trigger_kyc_country_requirements_updated_at ON kyc_country_requirements; +DROP TRIGGER IF EXISTS trigger_supported_countries_updated_at ON supported_countries; +DROP TRIGGER IF EXISTS trigger_user_devices_updated_at ON user_devices; +DROP TRIGGER IF EXISTS trigger_company_employees_updated_at ON company_employees; +DROP TRIGGER IF EXISTS trigger_company_staff_profiles_updated_at ON company_staff_profiles; +DROP TRIGGER IF EXISTS trigger_company_users_updated_at ON company_users; +DROP TRIGGER IF EXISTS trigger_companies_updated_at ON companies; +DROP TRIGGER IF EXISTS trigger_personal_users_updated_at ON personal_users; +DROP TRIGGER IF EXISTS trigger_users_updated_at ON users; + +-- Drop functions +DROP FUNCTION IF EXISTS update_timesheet_totals(); +DROP FUNCTION IF EXISTS validate_payment_split(); +DROP FUNCTION IF EXISTS generate_invoice_number(); +DROP FUNCTION IF EXISTS update_updated_at_column(); + +-- Drop sequence +DROP SEQUENCE IF EXISTS invoice_number_seq; \ No newline at end of file diff --git a/db/migrations/00001_create_extension_uuid.sql b/db/old_migration/00001_create_extension_uuid.sql similarity index 100% rename from db/migrations/00001_create_extension_uuid.sql rename to db/old_migration/00001_create_extension_uuid.sql diff --git a/db/migrations/00002_create_users_table.sql b/db/old_migration/00002_create_users_table.sql similarity index 100% rename from db/migrations/00002_create_users_table.sql rename to db/old_migration/00002_create_users_table.sql diff --git a/db/migrations/00009_create_sessions_table.sql b/db/old_migration/00009_create_sessions_table.sql similarity index 100% rename from db/migrations/00009_create_sessions_table.sql rename to db/old_migration/00009_create_sessions_table.sql diff --git a/db/migrations/00010_create_kyc_table.sql b/db/old_migration/00010_create_kyc_table.sql similarity index 100% rename from db/migrations/00010_create_kyc_table.sql rename to db/old_migration/00010_create_kyc_table.sql diff --git a/db/migrations/20250321122619_user_device.sql b/db/old_migration/20250321122619_user_device.sql similarity index 100% rename from db/migrations/20250321122619_user_device.sql rename to db/old_migration/20250321122619_user_device.sql diff --git a/db/migrations/20250321123506_otp.sql b/db/old_migration/20250321123506_otp.sql similarity index 100% rename from db/migrations/20250321123506_otp.sql rename to db/old_migration/20250321123506_otp.sql diff --git a/db/migrations/20250321140031_transactions.sql b/db/old_migration/20250321140031_transactions.sql similarity index 100% rename from db/migrations/20250321140031_transactions.sql rename to db/old_migration/20250321140031_transactions.sql diff --git a/db/migrations/20250502134941_security.sql b/db/old_migration/20250502134941_security.sql similarity index 100% rename from db/migrations/20250502134941_security.sql rename to db/old_migration/20250502134941_security.sql diff --git a/db/migrations/20250502134956_wallet.sql b/db/old_migration/20250502134956_wallet.sql similarity index 100% rename from db/migrations/20250502134956_wallet.sql rename to db/old_migration/20250502134956_wallet.sql From f2834593deef12101c526c06ee71774c3fd9cec6 Mon Sep 17 00:00:00 2001 From: Ademola Personal Date: Wed, 18 Jun 2025 12:48:18 +0100 Subject: [PATCH 2/2] refactor: remove obsolete migration files and clean up Makefile --- Makefile | 2 +- .../20250618101030_functions_triggers.sql | 88 +- db/mock/store.go | 957 ------------ .../00001_create_extension_uuid.sql | 6 - db/old_migration/00002_create_users_table.sql | 43 - .../00009_create_sessions_table.sql | 32 - db/old_migration/00010_create_kyc_table.sql | 19 - .../20250321122619_user_device.sql | 44 - db/old_migration/20250321123506_otp.sql | 63 - .../20250321140031_transactions.sql | 21 - db/old_migration/20250502134941_security.sql | 16 - db/old_migration/20250502134956_wallet.sql | 14 - db/query/audit.sql | 158 ++ db/query/auth.sql | 181 +++ db/query/companies.sql | 283 ++++ db/query/compliance.sql | 295 ++++ db/query/invoices.sql | 253 ++++ db/query/notifications.sql | 256 ++++ db/query/otp_verifications.sql | 70 - db/query/payroll.sql | 276 ++++ db/query/security_events.sql | 20 - db/query/sessions.sql | 126 -- db/query/settings.sql | 237 +++ db/query/timesheets.sql | 219 +++ db/query/transactions.sql | 278 +++- db/query/user_device.sql | 167 --- db/query/user_wallets.sql | 22 - db/query/users.sql | 383 ++--- db/query/wallet.sql | 178 +++ db/sqlc/audit.sql.go | 778 ++++++++++ db/sqlc/auth.sql.go | 714 +++++++++ db/sqlc/companies.sql.go | 1172 +++++++++++++++ db/sqlc/compliance.sql.go | 1250 ++++++++++++++++ db/sqlc/invoices.sql.go | 1255 ++++++++++++++++ db/sqlc/models.go | 1109 ++++++++++++-- db/sqlc/notifications.sql.go | 1126 ++++++++++++++ db/sqlc/otp_verifications.sql.go | 304 ---- db/sqlc/payroll.sql.go | 1330 +++++++++++++++++ db/sqlc/querier.go | 161 +- db/sqlc/security_events.sql.go | 143 -- db/sqlc/seed.go | 928 ------------ db/sqlc/sessions.sql.go | 510 ------- db/sqlc/settings.sql.go | 996 ++++++++++++ db/sqlc/store.go | 46 - db/sqlc/timesheets.sql.go | 974 ++++++++++++ db/sqlc/transactions.sql.go | 1306 ++++++++++++++-- db/sqlc/user_device.sql.go | 633 -------- db/sqlc/user_wallets.sql.go | 149 -- db/sqlc/users.sql.go | 1277 ++++++---------- db/sqlc/wallet.sql.go | 870 +++++++++++ go.mod | 3 +- go.sum | 14 +- 52 files changed, 15879 insertions(+), 5876 deletions(-) delete mode 100644 db/mock/store.go delete mode 100644 db/old_migration/00001_create_extension_uuid.sql delete mode 100644 db/old_migration/00002_create_users_table.sql delete mode 100644 db/old_migration/00009_create_sessions_table.sql delete mode 100644 db/old_migration/00010_create_kyc_table.sql delete mode 100644 db/old_migration/20250321122619_user_device.sql delete mode 100644 db/old_migration/20250321123506_otp.sql delete mode 100644 db/old_migration/20250321140031_transactions.sql delete mode 100644 db/old_migration/20250502134941_security.sql delete mode 100644 db/old_migration/20250502134956_wallet.sql create mode 100644 db/query/audit.sql create mode 100644 db/query/auth.sql create mode 100644 db/query/companies.sql create mode 100644 db/query/compliance.sql create mode 100644 db/query/invoices.sql create mode 100644 db/query/notifications.sql delete mode 100644 db/query/otp_verifications.sql create mode 100644 db/query/payroll.sql delete mode 100644 db/query/security_events.sql delete mode 100644 db/query/sessions.sql create mode 100644 db/query/settings.sql create mode 100644 db/query/timesheets.sql delete mode 100644 db/query/user_device.sql delete mode 100644 db/query/user_wallets.sql create mode 100644 db/query/wallet.sql create mode 100644 db/sqlc/audit.sql.go create mode 100644 db/sqlc/auth.sql.go create mode 100644 db/sqlc/companies.sql.go create mode 100644 db/sqlc/compliance.sql.go create mode 100644 db/sqlc/invoices.sql.go create mode 100644 db/sqlc/notifications.sql.go delete mode 100644 db/sqlc/otp_verifications.sql.go create mode 100644 db/sqlc/payroll.sql.go delete mode 100644 db/sqlc/security_events.sql.go delete mode 100644 db/sqlc/seed.go delete mode 100644 db/sqlc/sessions.sql.go create mode 100644 db/sqlc/settings.sql.go delete mode 100644 db/sqlc/store.go create mode 100644 db/sqlc/timesheets.sql.go delete mode 100644 db/sqlc/user_device.sql.go delete mode 100644 db/sqlc/user_wallets.sql.go create mode 100644 db/sqlc/wallet.sql.go diff --git a/Makefile b/Makefile index ed63f0a..a03598d 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ dockerlogs: docker logs defi dropdb: - docker exec -it defi dropdb $(DB_NAME) + docker exec -it defi dropdb $(DB_NAME) # Migration commands (using goose) migrate-create: diff --git a/db/migrations/20250618101030_functions_triggers.sql b/db/migrations/20250618101030_functions_triggers.sql index bee6fcf..721a3b9 100644 --- a/db/migrations/20250618101030_functions_triggers.sql +++ b/db/migrations/20250618101030_functions_triggers.sql @@ -1,33 +1,35 @@ -- +goose Up -- Functions and Triggers --- Function to update the updated_at timestamp +-- +goose StatementBegin CREATE OR REPLACE FUNCTION update_updated_at_column() -RETURNS TRIGGER AS $$ +RETURNS TRIGGER AS ' BEGIN NEW.updated_at = NOW(); RETURN NEW; END; -$$ LANGUAGE plpgsql; +' LANGUAGE plpgsql; +-- +goose StatementEnd --- Function to generate invoice numbers +-- +goose StatementBegin CREATE OR REPLACE FUNCTION generate_invoice_number() -RETURNS TRIGGER AS $$ +RETURNS TRIGGER AS ' BEGIN IF NEW.invoice_number IS NULL THEN - NEW.invoice_number := 'INV-' || EXTRACT(YEAR FROM NOW()) || '-' || - LPAD(NEXTVAL('invoice_number_seq')::TEXT, 6, '0'); + NEW.invoice_number := ''INV-'' || EXTRACT(YEAR FROM NOW()) || ''-'' || + LPAD(NEXTVAL(''invoice_number_seq'')::TEXT, 6, ''0''); END IF; RETURN NEW; END; -$$ LANGUAGE plpgsql; +' LANGUAGE plpgsql; +-- +goose StatementEnd -- Create sequence for invoice numbers CREATE SEQUENCE IF NOT EXISTS invoice_number_seq START 1; --- Function to validate payment split percentages +-- +goose StatementBegin CREATE OR REPLACE FUNCTION validate_payment_split() -RETURNS TRIGGER AS $$ +RETURNS TRIGGER AS ' DECLARE split_total DECIMAL(5,2) := 0; split_item JSONB; @@ -35,31 +37,30 @@ BEGIN IF NEW.payment_split IS NOT NULL THEN FOR split_item IN SELECT jsonb_array_elements(NEW.payment_split) LOOP - split_total := split_total + (split_item->>'percentage')::DECIMAL(5,2); + split_total := split_total + (split_item->>''percentage'')::DECIMAL(5,2); END LOOP; IF split_total != 100.00 THEN - RAISE EXCEPTION 'Payment split percentages must total 100, got %', split_total; + RAISE EXCEPTION ''Payment split percentages must total 100, got %'', split_total; END IF; END IF; RETURN NEW; END; -$$ LANGUAGE plpgsql; +' LANGUAGE plpgsql; +-- +goose StatementEnd --- Function to update timesheet totals +-- +goose StatementBegin CREATE OR REPLACE FUNCTION update_timesheet_totals() -RETURNS TRIGGER AS $$ +RETURNS TRIGGER AS ' DECLARE timesheet_record RECORD; BEGIN - -- Get the timesheet ID from either NEW or OLD record - IF TG_OP = 'DELETE' THEN + IF TG_OP = ''DELETE'' THEN SELECT id INTO timesheet_record FROM timesheets WHERE id = OLD.timesheet_id; ELSE SELECT id INTO timesheet_record FROM timesheets WHERE id = NEW.timesheet_id; END IF; - -- Update timesheet totals UPDATE timesheets SET total_hours = ( SELECT COALESCE(SUM(hours), 0) @@ -81,7 +82,8 @@ BEGIN RETURN COALESCE(NEW, OLD); END; -$$ LANGUAGE plpgsql; +' LANGUAGE plpgsql; +-- +goose StatementEnd -- Create updated_at triggers for all tables that have updated_at columns CREATE TRIGGER trigger_users_updated_at BEFORE UPDATE ON users @@ -138,6 +140,42 @@ CREATE TRIGGER trigger_company_wallets_updated_at BEFORE UPDATE ON company_walle CREATE TRIGGER trigger_bank_accounts_updated_at BEFORE UPDATE ON bank_accounts FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); +CREATE TRIGGER trigger_payroll_periods_updated_at BEFORE UPDATE ON payroll_periods + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_payrolls_updated_at BEFORE UPDATE ON payrolls + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_payroll_items_updated_at BEFORE UPDATE ON payroll_items + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_invoices_updated_at BEFORE UPDATE ON invoices + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_invoice_items_updated_at BEFORE UPDATE ON invoice_items + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_contracts_updated_at BEFORE UPDATE ON contracts + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_contract_templates_updated_at BEFORE UPDATE ON contract_templates + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_payment_requests_updated_at BEFORE UPDATE ON payment_requests + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_timesheets_updated_at BEFORE UPDATE ON timesheets + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_timesheet_entries_updated_at BEFORE UPDATE ON timesheet_entries + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_wallet_transactions_updated_at BEFORE UPDATE ON wallet_transactions + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + +CREATE TRIGGER trigger_fiat_transactions_updated_at BEFORE UPDATE ON fiat_transactions + FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); + -- Create invoice number generation trigger CREATE TRIGGER trigger_generate_invoice_number BEFORE INSERT ON invoices FOR EACH ROW EXECUTE FUNCTION generate_invoice_number(); @@ -167,6 +205,18 @@ DROP TRIGGER IF EXISTS trigger_update_timesheet_totals_insert ON timesheet_entri DROP TRIGGER IF EXISTS trigger_validate_employee_payment_split ON company_employees; DROP TRIGGER IF EXISTS trigger_validate_payroll_payment_split ON payroll_items; DROP TRIGGER IF EXISTS trigger_generate_invoice_number ON invoices; +DROP TRIGGER IF EXISTS trigger_fiat_transactions_updated_at ON fiat_transactions; +DROP TRIGGER IF EXISTS trigger_wallet_transactions_updated_at ON wallet_transactions; +DROP TRIGGER IF EXISTS trigger_timesheet_entries_updated_at ON timesheet_entries; +DROP TRIGGER IF EXISTS trigger_timesheets_updated_at ON timesheets; +DROP TRIGGER IF EXISTS trigger_payment_requests_updated_at ON payment_requests; +DROP TRIGGER IF EXISTS trigger_contract_templates_updated_at ON contract_templates; +DROP TRIGGER IF EXISTS trigger_contracts_updated_at ON contracts; +DROP TRIGGER IF EXISTS trigger_invoice_items_updated_at ON invoice_items; +DROP TRIGGER IF EXISTS trigger_invoices_updated_at ON invoices; +DROP TRIGGER IF EXISTS trigger_payroll_items_updated_at ON payroll_items; +DROP TRIGGER IF EXISTS trigger_payrolls_updated_at ON payrolls; +DROP TRIGGER IF EXISTS trigger_payroll_periods_updated_at ON payroll_periods; DROP TRIGGER IF EXISTS trigger_bank_accounts_updated_at ON bank_accounts; DROP TRIGGER IF EXISTS trigger_company_wallets_updated_at ON company_wallets; DROP TRIGGER IF EXISTS trigger_user_wallets_updated_at ON user_wallets; diff --git a/db/mock/store.go b/db/mock/store.go deleted file mode 100644 index ed04267..0000000 --- a/db/mock/store.go +++ /dev/null @@ -1,957 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/demola234/defifundr/db/sqlc (interfaces: Store) - -// Package mockdb is a generated GoMock package. -package mockdb - -import ( - context "context" - reflect "reflect" - time "time" - - sqlc "github.com/demola234/defifundr/db/sqlc" - gomock "github.com/golang/mock/gomock" - uuid "github.com/google/uuid" - pgtype "github.com/jackc/pgx/v5/pgtype" -) - -// MockStore is a mock of Store interface. -type MockStore struct { - ctrl *gomock.Controller - recorder *MockStoreMockRecorder -} - -// MockStoreMockRecorder is the mock recorder for MockStore. -type MockStoreMockRecorder struct { - mock *MockStore -} - -// NewMockStore creates a new mock instance. -func NewMockStore(ctrl *gomock.Controller) *MockStore { - mock := &MockStore{ctrl: ctrl} - mock.recorder = &MockStoreMockRecorder{mock} - return mock -} - - - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockStore) EXPECT() *MockStoreMockRecorder { - return m.recorder -} - -// BlockAllUserSessions mocks base method. -func (m *MockStore) BlockAllUserSessions(arg0 context.Context, arg1 uuid.UUID) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockAllUserSessions", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// BlockAllUserSessions indicates an expected call of BlockAllUserSessions. -func (mr *MockStoreMockRecorder) BlockAllUserSessions(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockAllUserSessions", reflect.TypeOf((*MockStore)(nil).BlockAllUserSessions), arg0, arg1) -} - -// BlockExpiredSessions mocks base method. -func (m *MockStore) BlockExpiredSessions(arg0 context.Context) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockExpiredSessions", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// BlockExpiredSessions indicates an expected call of BlockExpiredSessions. -func (mr *MockStoreMockRecorder) BlockExpiredSessions(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockExpiredSessions", reflect.TypeOf((*MockStore)(nil).BlockExpiredSessions), arg0) -} - -// BlockSession mocks base method. -func (m *MockStore) BlockSession(arg0 context.Context, arg1 uuid.UUID) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BlockSession", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// BlockSession indicates an expected call of BlockSession. -func (mr *MockStoreMockRecorder) BlockSession(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockSession", reflect.TypeOf((*MockStore)(nil).BlockSession), arg0, arg1) -} - -// CheckEmailExists mocks base method. -func (m *MockStore) CheckEmailExists(arg0 context.Context, arg1 string) (bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CheckEmailExists", arg0, arg1) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CheckEmailExists indicates an expected call of CheckEmailExists. -func (mr *MockStoreMockRecorder) CheckEmailExists(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckEmailExists", reflect.TypeOf((*MockStore)(nil).CheckEmailExists), arg0, arg1) -} - -// CountActiveDeviceTokensForUser mocks base method. -func (m *MockStore) CountActiveDeviceTokensForUser(arg0 context.Context, arg1 uuid.UUID) (int64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CountActiveDeviceTokensForUser", arg0, arg1) - ret0, _ := ret[0].(int64) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CountActiveDeviceTokensForUser indicates an expected call of CountActiveDeviceTokensForUser. -func (mr *MockStoreMockRecorder) CountActiveDeviceTokensForUser(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CountActiveDeviceTokensForUser", reflect.TypeOf((*MockStore)(nil).CountActiveDeviceTokensForUser), arg0, arg1) -} - -// CountActiveOTPsForUser mocks base method. -func (m *MockStore) CountActiveOTPsForUser(arg0 context.Context, arg1 sqlc.CountActiveOTPsForUserParams) (int64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CountActiveOTPsForUser", arg0, arg1) - ret0, _ := ret[0].(int64) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CountActiveOTPsForUser indicates an expected call of CountActiveOTPsForUser. -func (mr *MockStoreMockRecorder) CountActiveOTPsForUser(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CountActiveOTPsForUser", reflect.TypeOf((*MockStore)(nil).CountActiveOTPsForUser), arg0, arg1) -} - -// CountActiveSessions mocks base method. -func (m *MockStore) CountActiveSessions(arg0 context.Context) (int64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CountActiveSessions", arg0) - ret0, _ := ret[0].(int64) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CountActiveSessions indicates an expected call of CountActiveSessions. -func (mr *MockStoreMockRecorder) CountActiveSessions(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CountActiveSessions", reflect.TypeOf((*MockStore)(nil).CountActiveSessions), arg0) -} - -// CountActiveSessionsByUserID mocks base method. -func (m *MockStore) CountActiveSessionsByUserID(arg0 context.Context, arg1 uuid.UUID) (int64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CountActiveSessionsByUserID", arg0, arg1) - ret0, _ := ret[0].(int64) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CountActiveSessionsByUserID indicates an expected call of CountActiveSessionsByUserID. -func (mr *MockStoreMockRecorder) CountActiveSessionsByUserID(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CountActiveSessionsByUserID", reflect.TypeOf((*MockStore)(nil).CountActiveSessionsByUserID), arg0, arg1) -} - -// CountSearchUsers mocks base method. -func (m *MockStore) CountSearchUsers(arg0 context.Context, arg1 pgtype.Text) (int64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CountSearchUsers", arg0, arg1) - ret0, _ := ret[0].(int64) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CountSearchUsers indicates an expected call of CountSearchUsers. -func (mr *MockStoreMockRecorder) CountSearchUsers(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CountSearchUsers", reflect.TypeOf((*MockStore)(nil).CountSearchUsers), arg0, arg1) -} - -// CountUsers mocks base method. -func (m *MockStore) CountUsers(arg0 context.Context) (int64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CountUsers", arg0) - ret0, _ := ret[0].(int64) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CountUsers indicates an expected call of CountUsers. -func (mr *MockStoreMockRecorder) CountUsers(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CountUsers", reflect.TypeOf((*MockStore)(nil).CountUsers), arg0) -} - -// CountUsersByAccountType mocks base method. -func (m *MockStore) CountUsersByAccountType(arg0 context.Context, arg1 string) (int64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CountUsersByAccountType", arg0, arg1) - ret0, _ := ret[0].(int64) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CountUsersByAccountType indicates an expected call of CountUsersByAccountType. -func (mr *MockStoreMockRecorder) CountUsersByAccountType(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CountUsersByAccountType", reflect.TypeOf((*MockStore)(nil).CountUsersByAccountType), arg0, arg1) -} - -// CreateOTPVerification mocks base method. -func (m *MockStore) CreateOTPVerification(arg0 context.Context, arg1 sqlc.CreateOTPVerificationParams) (sqlc.OtpVerifications, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateOTPVerification", arg0, arg1) - ret0, _ := ret[0].(sqlc.OtpVerifications) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateOTPVerification indicates an expected call of CreateOTPVerification. -func (mr *MockStoreMockRecorder) CreateOTPVerification(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOTPVerification", reflect.TypeOf((*MockStore)(nil).CreateOTPVerification), arg0, arg1) -} - -// CreateSession mocks base method. -func (m *MockStore) CreateSession(arg0 context.Context, arg1 sqlc.CreateSessionParams) (sqlc.Sessions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateSession", arg0, arg1) - ret0, _ := ret[0].(sqlc.Sessions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateSession indicates an expected call of CreateSession. -func (mr *MockStoreMockRecorder) CreateSession(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSession", reflect.TypeOf((*MockStore)(nil).CreateSession), arg0, arg1) -} - -// CreateUser mocks base method. -func (m *MockStore) CreateUser(arg0 context.Context, arg1 sqlc.CreateUserParams) (sqlc.Users, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateUser", arg0, arg1) - ret0, _ := ret[0].(sqlc.Users) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateUser indicates an expected call of CreateUser. -func (mr *MockStoreMockRecorder) CreateUser(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUser", reflect.TypeOf((*MockStore)(nil).CreateUser), arg0, arg1) -} - -// CreateUserDeviceToken mocks base method. -func (m *MockStore) CreateUserDeviceToken(arg0 context.Context, arg1 sqlc.CreateUserDeviceTokenParams) (sqlc.UserDeviceTokens, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateUserDeviceToken", arg0, arg1) - ret0, _ := ret[0].(sqlc.UserDeviceTokens) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateUserDeviceToken indicates an expected call of CreateUserDeviceToken. -func (mr *MockStoreMockRecorder) CreateUserDeviceToken(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUserDeviceToken", reflect.TypeOf((*MockStore)(nil).CreateUserDeviceToken), arg0, arg1) -} - -// DeleteExpiredDeviceTokens mocks base method. -func (m *MockStore) DeleteExpiredDeviceTokens(arg0 context.Context) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteExpiredDeviceTokens", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// DeleteExpiredDeviceTokens indicates an expected call of DeleteExpiredDeviceTokens. -func (mr *MockStoreMockRecorder) DeleteExpiredDeviceTokens(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteExpiredDeviceTokens", reflect.TypeOf((*MockStore)(nil).DeleteExpiredDeviceTokens), arg0) -} - -// DeleteExpiredOTPs mocks base method. -func (m *MockStore) DeleteExpiredOTPs(arg0 context.Context) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteExpiredOTPs", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// DeleteExpiredOTPs indicates an expected call of DeleteExpiredOTPs. -func (mr *MockStoreMockRecorder) DeleteExpiredOTPs(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteExpiredOTPs", reflect.TypeOf((*MockStore)(nil).DeleteExpiredOTPs), arg0) -} - -// DeleteExpiredSessions mocks base method. -func (m *MockStore) DeleteExpiredSessions(arg0 context.Context, arg1 time.Time) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteExpiredSessions", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// DeleteExpiredSessions indicates an expected call of DeleteExpiredSessions. -func (mr *MockStoreMockRecorder) DeleteExpiredSessions(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteExpiredSessions", reflect.TypeOf((*MockStore)(nil).DeleteExpiredSessions), arg0, arg1) -} - -// DeleteSession mocks base method. -func (m *MockStore) DeleteSession(arg0 context.Context, arg1 uuid.UUID) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteSession", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// DeleteSession indicates an expected call of DeleteSession. -func (mr *MockStoreMockRecorder) DeleteSession(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSession", reflect.TypeOf((*MockStore)(nil).DeleteSession), arg0, arg1) -} - -// DeleteSessionsByUserID mocks base method. -func (m *MockStore) DeleteSessionsByUserID(arg0 context.Context, arg1 uuid.UUID) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteSessionsByUserID", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// DeleteSessionsByUserID indicates an expected call of DeleteSessionsByUserID. -func (mr *MockStoreMockRecorder) DeleteSessionsByUserID(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSessionsByUserID", reflect.TypeOf((*MockStore)(nil).DeleteSessionsByUserID), arg0, arg1) -} - -// DeleteTransaction mocks base method. -func (m *MockStore) DeleteTransaction(arg0 context.Context, arg1 uuid.UUID) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteTransaction", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// DeleteTransaction indicates an expected call of DeleteTransaction. -func (mr *MockStoreMockRecorder) DeleteTransaction(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteTransaction", reflect.TypeOf((*MockStore)(nil).DeleteTransaction), arg0, arg1) -} - -// DeleteTransactionsByUserID mocks base method. -func (m *MockStore) DeleteTransactionsByUserID(arg0 context.Context, arg1 uuid.UUID) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteTransactionsByUserID", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// DeleteTransactionsByUserID indicates an expected call of DeleteTransactionsByUserID. -func (mr *MockStoreMockRecorder) DeleteTransactionsByUserID(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteTransactionsByUserID", reflect.TypeOf((*MockStore)(nil).DeleteTransactionsByUserID), arg0, arg1) -} - -// DeleteUser mocks base method. -func (m *MockStore) DeleteUser(arg0 context.Context, arg1 uuid.UUID) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteUser", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// DeleteUser indicates an expected call of DeleteUser. -func (mr *MockStoreMockRecorder) DeleteUser(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUser", reflect.TypeOf((*MockStore)(nil).DeleteUser), arg0, arg1) -} - -// ExecTx mocks base method. -func (m *MockStore) ExecTx(arg0 context.Context, arg1 func(*sqlc.Queries) error) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ExecTx", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// ExecTx indicates an expected call of ExecTx. -func (mr *MockStoreMockRecorder) ExecTx(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecTx", reflect.TypeOf((*MockStore)(nil).ExecTx), arg0, arg1) -} - -// GetActiveDeviceTokensForUser mocks base method. -func (m *MockStore) GetActiveDeviceTokensForUser(arg0 context.Context, arg1 uuid.UUID) ([]sqlc.UserDeviceTokens, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetActiveDeviceTokensForUser", arg0, arg1) - ret0, _ := ret[0].([]sqlc.UserDeviceTokens) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetActiveDeviceTokensForUser indicates an expected call of GetActiveDeviceTokensForUser. -func (mr *MockStoreMockRecorder) GetActiveDeviceTokensForUser(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActiveDeviceTokensForUser", reflect.TypeOf((*MockStore)(nil).GetActiveDeviceTokensForUser), arg0, arg1) -} - -// GetActiveSessions mocks base method. -func (m *MockStore) GetActiveSessions(arg0 context.Context, arg1 sqlc.GetActiveSessionsParams) ([]sqlc.Sessions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetActiveSessions", arg0, arg1) - ret0, _ := ret[0].([]sqlc.Sessions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetActiveSessions indicates an expected call of GetActiveSessions. -func (mr *MockStoreMockRecorder) GetActiveSessions(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActiveSessions", reflect.TypeOf((*MockStore)(nil).GetActiveSessions), arg0, arg1) -} - -// GetActiveSessionsByUserID mocks base method. -func (m *MockStore) GetActiveSessionsByUserID(arg0 context.Context, arg1 uuid.UUID) ([]sqlc.Sessions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetActiveSessionsByUserID", arg0, arg1) - ret0, _ := ret[0].([]sqlc.Sessions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetActiveSessionsByUserID indicates an expected call of GetActiveSessionsByUserID. -func (mr *MockStoreMockRecorder) GetActiveSessionsByUserID(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActiveSessionsByUserID", reflect.TypeOf((*MockStore)(nil).GetActiveSessionsByUserID), arg0, arg1) -} - -// GetDeviceTokensByPlatform mocks base method. -func (m *MockStore) GetDeviceTokensByPlatform(arg0 context.Context, arg1 sqlc.GetDeviceTokensByPlatformParams) ([]sqlc.UserDeviceTokens, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDeviceTokensByPlatform", arg0, arg1) - ret0, _ := ret[0].([]sqlc.UserDeviceTokens) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetDeviceTokensByPlatform indicates an expected call of GetDeviceTokensByPlatform. -func (mr *MockStoreMockRecorder) GetDeviceTokensByPlatform(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeviceTokensByPlatform", reflect.TypeOf((*MockStore)(nil).GetDeviceTokensByPlatform), arg0, arg1) -} - -// GetOTPVerificationByID mocks base method. -func (m *MockStore) GetOTPVerificationByID(arg0 context.Context, arg1 uuid.UUID) (sqlc.OtpVerifications, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetOTPVerificationByID", arg0, arg1) - ret0, _ := ret[0].(sqlc.OtpVerifications) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetOTPVerificationByID indicates an expected call of GetOTPVerificationByID. -func (mr *MockStoreMockRecorder) GetOTPVerificationByID(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOTPVerificationByID", reflect.TypeOf((*MockStore)(nil).GetOTPVerificationByID), arg0, arg1) -} - -// GetOTPVerificationByUserAndPurpose mocks base method. -func (m *MockStore) GetOTPVerificationByUserAndPurpose(arg0 context.Context, arg1 sqlc.GetOTPVerificationByUserAndPurposeParams) (sqlc.OtpVerifications, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetOTPVerificationByUserAndPurpose", arg0, arg1) - ret0, _ := ret[0].(sqlc.OtpVerifications) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetOTPVerificationByUserAndPurpose indicates an expected call of GetOTPVerificationByUserAndPurpose. -func (mr *MockStoreMockRecorder) GetOTPVerificationByUserAndPurpose(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOTPVerificationByUserAndPurpose", reflect.TypeOf((*MockStore)(nil).GetOTPVerificationByUserAndPurpose), arg0, arg1) -} - -// GetSessionByID mocks base method. -func (m *MockStore) GetSessionByID(arg0 context.Context, arg1 uuid.UUID) (sqlc.Sessions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSessionByID", arg0, arg1) - ret0, _ := ret[0].(sqlc.Sessions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetSessionByID indicates an expected call of GetSessionByID. -func (mr *MockStoreMockRecorder) GetSessionByID(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSessionByID", reflect.TypeOf((*MockStore)(nil).GetSessionByID), arg0, arg1) -} - -// GetSessionByRefreshToken mocks base method. -func (m *MockStore) GetSessionByRefreshToken(arg0 context.Context, arg1 string) (sqlc.Sessions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSessionByRefreshToken", arg0, arg1) - ret0, _ := ret[0].(sqlc.Sessions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetSessionByRefreshToken indicates an expected call of GetSessionByRefreshToken. -func (mr *MockStoreMockRecorder) GetSessionByRefreshToken(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSessionByRefreshToken", reflect.TypeOf((*MockStore)(nil).GetSessionByRefreshToken), arg0, arg1) -} - -// GetSessionsByUserID mocks base method. -func (m *MockStore) GetSessionsByUserID(arg0 context.Context, arg1 uuid.UUID) ([]sqlc.Sessions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetSessionsByUserID", arg0, arg1) - ret0, _ := ret[0].([]sqlc.Sessions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetSessionsByUserID indicates an expected call of GetSessionsByUserID. -func (mr *MockStoreMockRecorder) GetSessionsByUserID(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSessionsByUserID", reflect.TypeOf((*MockStore)(nil).GetSessionsByUserID), arg0, arg1) -} - -// GetTransactionByID mocks base method. -func (m *MockStore) GetTransactionByID(arg0 context.Context, arg1 uuid.UUID) (sqlc.Transactions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTransactionByID", arg0, arg1) - ret0, _ := ret[0].(sqlc.Transactions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetTransactionByID indicates an expected call of GetTransactionByID. -func (mr *MockStoreMockRecorder) GetTransactionByID(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransactionByID", reflect.TypeOf((*MockStore)(nil).GetTransactionByID), arg0, arg1) -} - -// GetTransactionByTxHash mocks base method. -func (m *MockStore) GetTransactionByTxHash(arg0 context.Context, arg1 string) (sqlc.Transactions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTransactionByTxHash", arg0, arg1) - ret0, _ := ret[0].(sqlc.Transactions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetTransactionByTxHash indicates an expected call of GetTransactionByTxHash. -func (mr *MockStoreMockRecorder) GetTransactionByTxHash(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransactionByTxHash", reflect.TypeOf((*MockStore)(nil).GetTransactionByTxHash), arg0, arg1) -} - -// GetTransactionsByStatus mocks base method. -func (m *MockStore) GetTransactionsByStatus(arg0 context.Context, arg1 sqlc.GetTransactionsByStatusParams) ([]sqlc.Transactions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTransactionsByStatus", arg0, arg1) - ret0, _ := ret[0].([]sqlc.Transactions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetTransactionsByStatus indicates an expected call of GetTransactionsByStatus. -func (mr *MockStoreMockRecorder) GetTransactionsByStatus(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransactionsByStatus", reflect.TypeOf((*MockStore)(nil).GetTransactionsByStatus), arg0, arg1) -} - -// GetTransactionsByUserID mocks base method. -func (m *MockStore) GetTransactionsByUserID(arg0 context.Context, arg1 uuid.UUID) ([]sqlc.Transactions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTransactionsByUserID", arg0, arg1) - ret0, _ := ret[0].([]sqlc.Transactions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetTransactionsByUserID indicates an expected call of GetTransactionsByUserID. -func (mr *MockStoreMockRecorder) GetTransactionsByUserID(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransactionsByUserID", reflect.TypeOf((*MockStore)(nil).GetTransactionsByUserID), arg0, arg1) -} - -// GetTransactionsByUserIDAndStatus mocks base method. -func (m *MockStore) GetTransactionsByUserIDAndStatus(arg0 context.Context, arg1 sqlc.GetTransactionsByUserIDAndStatusParams) ([]sqlc.Transactions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTransactionsByUserIDAndStatus", arg0, arg1) - ret0, _ := ret[0].([]sqlc.Transactions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetTransactionsByUserIDAndStatus indicates an expected call of GetTransactionsByUserIDAndStatus. -func (mr *MockStoreMockRecorder) GetTransactionsByUserIDAndStatus(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransactionsByUserIDAndStatus", reflect.TypeOf((*MockStore)(nil).GetTransactionsByUserIDAndStatus), arg0, arg1) -} - -// GetUnverifiedOTPsForUser mocks base method. -func (m *MockStore) GetUnverifiedOTPsForUser(arg0 context.Context, arg1 pgtype.UUID) ([]sqlc.OtpVerifications, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUnverifiedOTPsForUser", arg0, arg1) - ret0, _ := ret[0].([]sqlc.OtpVerifications) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUnverifiedOTPsForUser indicates an expected call of GetUnverifiedOTPsForUser. -func (mr *MockStoreMockRecorder) GetUnverifiedOTPsForUser(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnverifiedOTPsForUser", reflect.TypeOf((*MockStore)(nil).GetUnverifiedOTPsForUser), arg0, arg1) -} - -// GetUser mocks base method. -func (m *MockStore) GetUser(arg0 context.Context, arg1 uuid.UUID) (sqlc.Users, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUser", arg0, arg1) - ret0, _ := ret[0].(sqlc.Users) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUser indicates an expected call of GetUser. -func (mr *MockStoreMockRecorder) GetUser(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUser", reflect.TypeOf((*MockStore)(nil).GetUser), arg0, arg1) -} - -// GetUserByEmail mocks base method. -func (m *MockStore) GetUserByEmail(arg0 context.Context, arg1 string) (sqlc.Users, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUserByEmail", arg0, arg1) - ret0, _ := ret[0].(sqlc.Users) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUserByEmail indicates an expected call of GetUserByEmail. -func (mr *MockStoreMockRecorder) GetUserByEmail(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByEmail", reflect.TypeOf((*MockStore)(nil).GetUserByEmail), arg0, arg1) -} - -// GetUserDeviceTokenByDeviceToken mocks base method. -func (m *MockStore) GetUserDeviceTokenByDeviceToken(arg0 context.Context, arg1 string) (sqlc.UserDeviceTokens, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUserDeviceTokenByDeviceToken", arg0, arg1) - ret0, _ := ret[0].(sqlc.UserDeviceTokens) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUserDeviceTokenByDeviceToken indicates an expected call of GetUserDeviceTokenByDeviceToken. -func (mr *MockStoreMockRecorder) GetUserDeviceTokenByDeviceToken(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserDeviceTokenByDeviceToken", reflect.TypeOf((*MockStore)(nil).GetUserDeviceTokenByDeviceToken), arg0, arg1) -} - -// GetUserDeviceTokenByID mocks base method. -func (m *MockStore) GetUserDeviceTokenByID(arg0 context.Context, arg1 uuid.UUID) (sqlc.UserDeviceTokens, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUserDeviceTokenByID", arg0, arg1) - ret0, _ := ret[0].(sqlc.UserDeviceTokens) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUserDeviceTokenByID indicates an expected call of GetUserDeviceTokenByID. -func (mr *MockStoreMockRecorder) GetUserDeviceTokenByID(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserDeviceTokenByID", reflect.TypeOf((*MockStore)(nil).GetUserDeviceTokenByID), arg0, arg1) -} - -// InValidateOTP mocks base method. -func (m *MockStore) InValidateOTP(arg0 context.Context, arg1 uuid.UUID) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InValidateOTP", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// InValidateOTP indicates an expected call of InValidateOTP. -func (mr *MockStoreMockRecorder) InValidateOTP(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InValidateOTP", reflect.TypeOf((*MockStore)(nil).InValidateOTP), arg0, arg1) -} - -// ListUsers mocks base method. -func (m *MockStore) ListUsers(arg0 context.Context, arg1 sqlc.ListUsersParams) ([]sqlc.Users, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListUsers", arg0, arg1) - ret0, _ := ret[0].([]sqlc.Users) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ListUsers indicates an expected call of ListUsers. -func (mr *MockStoreMockRecorder) ListUsers(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListUsers", reflect.TypeOf((*MockStore)(nil).ListUsers), arg0, arg1) -} - -// ListUsersByAccountType mocks base method. -func (m *MockStore) ListUsersByAccountType(arg0 context.Context, arg1 sqlc.ListUsersByAccountTypeParams) ([]sqlc.Users, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListUsersByAccountType", arg0, arg1) - ret0, _ := ret[0].([]sqlc.Users) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ListUsersByAccountType indicates an expected call of ListUsersByAccountType. -func (mr *MockStoreMockRecorder) ListUsersByAccountType(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListUsersByAccountType", reflect.TypeOf((*MockStore)(nil).ListUsersByAccountType), arg0, arg1) -} - -// RevokeDeviceToken mocks base method. -func (m *MockStore) RevokeDeviceToken(arg0 context.Context, arg1 uuid.UUID) (sqlc.UserDeviceTokens, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RevokeDeviceToken", arg0, arg1) - ret0, _ := ret[0].(sqlc.UserDeviceTokens) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// RevokeDeviceToken indicates an expected call of RevokeDeviceToken. -func (mr *MockStoreMockRecorder) RevokeDeviceToken(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RevokeDeviceToken", reflect.TypeOf((*MockStore)(nil).RevokeDeviceToken), arg0, arg1) -} - -// SearchDeviceTokens mocks base method. -func (m *MockStore) SearchDeviceTokens(arg0 context.Context, arg1 sqlc.SearchDeviceTokensParams) ([]sqlc.UserDeviceTokens, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SearchDeviceTokens", arg0, arg1) - ret0, _ := ret[0].([]sqlc.UserDeviceTokens) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SearchDeviceTokens indicates an expected call of SearchDeviceTokens. -func (mr *MockStoreMockRecorder) SearchDeviceTokens(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchDeviceTokens", reflect.TypeOf((*MockStore)(nil).SearchDeviceTokens), arg0, arg1) -} - -// SearchUsers mocks base method. -func (m *MockStore) SearchUsers(arg0 context.Context, arg1 sqlc.SearchUsersParams) ([]sqlc.Users, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SearchUsers", arg0, arg1) - ret0, _ := ret[0].([]sqlc.Users) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SearchUsers indicates an expected call of SearchUsers. -func (mr *MockStoreMockRecorder) SearchUsers(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchUsers", reflect.TypeOf((*MockStore)(nil).SearchUsers), arg0, arg1) -} - -// UpdateDeviceTokenDetails mocks base method. -func (m *MockStore) UpdateDeviceTokenDetails(arg0 context.Context, arg1 sqlc.UpdateDeviceTokenDetailsParams) (sqlc.UserDeviceTokens, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateDeviceTokenDetails", arg0, arg1) - ret0, _ := ret[0].(sqlc.UserDeviceTokens) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpdateDeviceTokenDetails indicates an expected call of UpdateDeviceTokenDetails. -func (mr *MockStoreMockRecorder) UpdateDeviceTokenDetails(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateDeviceTokenDetails", reflect.TypeOf((*MockStore)(nil).UpdateDeviceTokenDetails), arg0, arg1) -} - -// UpdateDeviceTokenLastUsed mocks base method. -func (m *MockStore) UpdateDeviceTokenLastUsed(arg0 context.Context, arg1 sqlc.UpdateDeviceTokenLastUsedParams) (sqlc.UserDeviceTokens, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateDeviceTokenLastUsed", arg0, arg1) - ret0, _ := ret[0].(sqlc.UserDeviceTokens) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpdateDeviceTokenLastUsed indicates an expected call of UpdateDeviceTokenLastUsed. -func (mr *MockStoreMockRecorder) UpdateDeviceTokenLastUsed(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateDeviceTokenLastUsed", reflect.TypeOf((*MockStore)(nil).UpdateDeviceTokenLastUsed), arg0, arg1) -} - -// UpdateDeviceTokenPushNotificationToken mocks base method. -func (m *MockStore) UpdateDeviceTokenPushNotificationToken(arg0 context.Context, arg1 sqlc.UpdateDeviceTokenPushNotificationTokenParams) (sqlc.UserDeviceTokens, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateDeviceTokenPushNotificationToken", arg0, arg1) - ret0, _ := ret[0].(sqlc.UserDeviceTokens) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpdateDeviceTokenPushNotificationToken indicates an expected call of UpdateDeviceTokenPushNotificationToken. -func (mr *MockStoreMockRecorder) UpdateDeviceTokenPushNotificationToken(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateDeviceTokenPushNotificationToken", reflect.TypeOf((*MockStore)(nil).UpdateDeviceTokenPushNotificationToken), arg0, arg1) -} - -// UpdateOTPAttempts mocks base method. -func (m *MockStore) UpdateOTPAttempts(arg0 context.Context, arg1 uuid.UUID) (sqlc.OtpVerifications, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateOTPAttempts", arg0, arg1) - ret0, _ := ret[0].(sqlc.OtpVerifications) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpdateOTPAttempts indicates an expected call of UpdateOTPAttempts. -func (mr *MockStoreMockRecorder) UpdateOTPAttempts(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateOTPAttempts", reflect.TypeOf((*MockStore)(nil).UpdateOTPAttempts), arg0, arg1) -} - -// UpdateRefreshToken mocks base method. -func (m *MockStore) UpdateRefreshToken(arg0 context.Context, arg1 sqlc.UpdateRefreshTokenParams) (sqlc.Sessions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateRefreshToken", arg0, arg1) - ret0, _ := ret[0].(sqlc.Sessions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpdateRefreshToken indicates an expected call of UpdateRefreshToken. -func (mr *MockStoreMockRecorder) UpdateRefreshToken(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateRefreshToken", reflect.TypeOf((*MockStore)(nil).UpdateRefreshToken), arg0, arg1) -} - -// UpdateSession mocks base method. -func (m *MockStore) UpdateSession(arg0 context.Context, arg1 sqlc.UpdateSessionParams) (sqlc.Sessions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateSession", arg0, arg1) - ret0, _ := ret[0].(sqlc.Sessions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpdateSession indicates an expected call of UpdateSession. -func (mr *MockStoreMockRecorder) UpdateSession(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateSession", reflect.TypeOf((*MockStore)(nil).UpdateSession), arg0, arg1) -} - -// UpdateTransaction mocks base method. -func (m *MockStore) UpdateTransaction(arg0 context.Context, arg1 sqlc.UpdateTransactionParams) (sqlc.Transactions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateTransaction", arg0, arg1) - ret0, _ := ret[0].(sqlc.Transactions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpdateTransaction indicates an expected call of UpdateTransaction. -func (mr *MockStoreMockRecorder) UpdateTransaction(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTransaction", reflect.TypeOf((*MockStore)(nil).UpdateTransaction), arg0, arg1) -} - -// UpdateTransactionStatus mocks base method. -func (m *MockStore) UpdateTransactionStatus(arg0 context.Context, arg1 sqlc.UpdateTransactionStatusParams) (sqlc.Transactions, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateTransactionStatus", arg0, arg1) - ret0, _ := ret[0].(sqlc.Transactions) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpdateTransactionStatus indicates an expected call of UpdateTransactionStatus. -func (mr *MockStoreMockRecorder) UpdateTransactionStatus(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTransactionStatus", reflect.TypeOf((*MockStore)(nil).UpdateTransactionStatus), arg0, arg1) -} - -// UpdateUser mocks base method. -func (m *MockStore) UpdateUser(arg0 context.Context, arg1 sqlc.UpdateUserParams) (sqlc.Users, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateUser", arg0, arg1) - ret0, _ := ret[0].(sqlc.Users) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpdateUser indicates an expected call of UpdateUser. -func (mr *MockStoreMockRecorder) UpdateUser(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUser", reflect.TypeOf((*MockStore)(nil).UpdateUser), arg0, arg1) -} - -// UpdateUserEmail mocks base method. -func (m *MockStore) UpdateUserEmail(arg0 context.Context, arg1 sqlc.UpdateUserEmailParams) (sqlc.Users, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateUserEmail", arg0, arg1) - ret0, _ := ret[0].(sqlc.Users) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpdateUserEmail indicates an expected call of UpdateUserEmail. -func (mr *MockStoreMockRecorder) UpdateUserEmail(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserEmail", reflect.TypeOf((*MockStore)(nil).UpdateUserEmail), arg0, arg1) -} - -// UpdateUserPassword mocks base method. -func (m *MockStore) UpdateUserPassword(arg0 context.Context, arg1 sqlc.UpdateUserPasswordParams) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateUserPassword", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpdateUserPassword indicates an expected call of UpdateUserPassword. -func (mr *MockStoreMockRecorder) UpdateUserPassword(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserPassword", reflect.TypeOf((*MockStore)(nil).UpdateUserPassword), arg0, arg1) -} - -// UpsertUserDeviceToken mocks base method. -func (m *MockStore) UpsertUserDeviceToken(arg0 context.Context, arg1 sqlc.UpsertUserDeviceTokenParams) (sqlc.UserDeviceTokens, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpsertUserDeviceToken", arg0, arg1) - ret0, _ := ret[0].(sqlc.UserDeviceTokens) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpsertUserDeviceToken indicates an expected call of UpsertUserDeviceToken. -func (mr *MockStoreMockRecorder) UpsertUserDeviceToken(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertUserDeviceToken", reflect.TypeOf((*MockStore)(nil).UpsertUserDeviceToken), arg0, arg1) -} - -// VerifyOTP mocks base method. -func (m *MockStore) VerifyOTP(arg0 context.Context, arg1 sqlc.VerifyOTPParams) (sqlc.OtpVerifications, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "VerifyOTP", arg0, arg1) - ret0, _ := ret[0].(sqlc.OtpVerifications) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// VerifyOTP indicates an expected call of VerifyOTP. -func (mr *MockStoreMockRecorder) VerifyOTP(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VerifyOTP", reflect.TypeOf((*MockStore)(nil).VerifyOTP), arg0, arg1) -} diff --git a/db/old_migration/00001_create_extension_uuid.sql b/db/old_migration/00001_create_extension_uuid.sql deleted file mode 100644 index 63e27cb..0000000 --- a/db/old_migration/00001_create_extension_uuid.sql +++ /dev/null @@ -1,6 +0,0 @@ - --- +goose Up -CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; - --- +goose Down -DROP EXTENSION IF EXISTS "uuid-ossp"; \ No newline at end of file diff --git a/db/old_migration/00002_create_users_table.sql b/db/old_migration/00002_create_users_table.sql deleted file mode 100644 index 1a0ccd1..0000000 --- a/db/old_migration/00002_create_users_table.sql +++ /dev/null @@ -1,43 +0,0 @@ --- +goose Up -CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; - -CREATE TABLE users ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - email VARCHAR(255) NOT NULL UNIQUE, - password_hash VARCHAR(255), - profile_picture VARCHAR(255) DEFAULT '', - account_type VARCHAR(50) NOT NULL, -- business, personal - gender VARCHAR(50) DEFAULT '', - personal_account_type VARCHAR(50) NOT NULL, -- contractor, freelancer, employee - phone_number VARCHAR(50) DEFAULT '', - phone_number_verified BOOLEAN DEFAULT false, - phone_number_verified_at TIMESTAMPTZ, - first_name VARCHAR(255) NOT NULL, - last_name VARCHAR(255) NOT NULL, - nationality VARCHAR(255) NOT NULL, - residential_country VARCHAR(255), - job_role VARCHAR(255), - company_name VARCHAR(255) DEFAULT '', - company_size VARCHAR(255) DEFAULT '', - company_industry VARCHAR(255) DEFAULT '', - company_description VARCHAR(255) DEFAULT '', - company_headquarters VARCHAR(255) DEFAULT '', - user_address VARCHAR(255) DEFAULT '', - user_city VARCHAR(255) DEFAULT '', - user_postal_code VARCHAR(255) DEFAULT '', - employee_type VARCHAR(255) DEFAULT '', - auth_provider VARCHAR(255), - provider_id VARCHAR(255) NOT NULL, - company_website VARCHAR(255), - employment_type VARCHAR(255), - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now() -); - -CREATE INDEX idx_users_email ON users(email); - -COMMENT ON COLUMN users.account_type IS 'business, personal'; -COMMENT ON COLUMN users.personal_account_type IS 'contractor, freelancer, employee'; - --- +goose Down -DROP TABLE IF EXISTS users; diff --git a/db/old_migration/00009_create_sessions_table.sql b/db/old_migration/00009_create_sessions_table.sql deleted file mode 100644 index ddf7222..0000000 --- a/db/old_migration/00009_create_sessions_table.sql +++ /dev/null @@ -1,32 +0,0 @@ --- +goose Up --- SQL in this section is executed when the migration is applied. -CREATE TABLE sessions ( - id UUID PRIMARY KEY, - user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, - refresh_token VARCHAR(1024) NOT NULL, - user_agent TEXT NOT NULL, - last_used_at TIMESTAMP NOT NULL, - web_oauth_client_id TEXT, - oauth_access_token TEXT, - oauth_id_token TEXT, - user_login_type VARCHAR(100) NOT NULL, - mfa_enabled BOOLEAN NOT NULL DEFAULT false, - client_ip TEXT NOT NULL, - is_blocked BOOLEAN NOT NULL DEFAULT false, - expires_at TIMESTAMP NOT NULL, - created_at TIMESTAMP NOT NULL DEFAULT now() -); - - --- Create index on user_id for faster lookups -CREATE INDEX idx_sessions_user_id ON sessions(user_id); - --- Create index on refresh_token for faster lookups -CREATE INDEX idx_sessions_refresh_token ON sessions(refresh_token); - --- Create index on expiration time for cleanup operations -CREATE INDEX idx_sessions_expires_at ON sessions(expires_at); - --- +goose Down --- SQL in this section is executed when the migration is rolled back. -DROP TABLE IF EXISTS sessions; \ No newline at end of file diff --git a/db/old_migration/00010_create_kyc_table.sql b/db/old_migration/00010_create_kyc_table.sql deleted file mode 100644 index 773d071..0000000 --- a/db/old_migration/00010_create_kyc_table.sql +++ /dev/null @@ -1,19 +0,0 @@ --- +goose Up --- SQL in this section is executed when the migration is applied. -CREATE TABLE kyc ( - id UUID PRIMARY KEY, - user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, - face_verification BOOLEAN NOT NULL, - identity_verification BOOLEAN NOT NULL, - verification_type VARCHAR(50) NOT NULL, - verification_number VARCHAR(50) NOT NULL, - verification_status VARCHAR(50) NOT NULL, - updated_at TIMESTAMPTZ NOT NULL DEFAULT '0001-01-01', - created_at TIMESTAMPTZ NOT NULL DEFAULT now() -); - -CREATE INDEX idx_kyc_user_id ON kyc(user_id); - --- +goose Down --- SQL in this section is executed when the migration is rolled back. -DROP TABLE IF EXISTS kyc; \ No newline at end of file diff --git a/db/old_migration/20250321122619_user_device.sql b/db/old_migration/20250321122619_user_device.sql deleted file mode 100644 index 08a26fa..0000000 --- a/db/old_migration/20250321122619_user_device.sql +++ /dev/null @@ -1,44 +0,0 @@ --- +goose Up --- SQL in this section is executed when the migration is applied -CREATE TABLE user_device_tokens ( - id UUID PRIMARY KEY, - user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, - - -- Device Identification - device_token VARCHAR NOT NULL UNIQUE, - platform VARCHAR(50) NOT NULL, -- e.g., 'ios', 'android', 'web' - device_type VARCHAR(100), -- e.g., 'smartphone', 'tablet', 'desktop' - device_model VARCHAR(100), -- e.g., 'iPhone 13', 'Samsung Galaxy S21' - - -- Operating System Details - os_name VARCHAR(50), - os_version VARCHAR(50), - - -- Push Notification Tokens (if applicable) - push_notification_token VARCHAR, - - -- Authentication and Security - is_active BOOLEAN NOT NULL DEFAULT true, - is_verified BOOLEAN NOT NULL DEFAULT false, - - -- Metadata - last_used_at TIMESTAMPTZ, - first_registered_at TIMESTAMPTZ NOT NULL DEFAULT now(), - - -- Additional Context - app_version VARCHAR(50), - client_ip VARCHAR(45), -- IPv4 or IPv6 - - -- Expiration and Management - expires_at TIMESTAMPTZ, - is_revoked BOOLEAN NOT NULL DEFAULT false -); - --- Indexes for performance and querying -CREATE INDEX idx_user_device_tokens_user_id ON user_device_tokens(user_id); -CREATE INDEX idx_user_device_tokens_platform ON user_device_tokens(platform); -CREATE INDEX idx_user_device_tokens_device_token ON user_device_tokens(device_token); - --- +goose Down --- SQL in this section is executed when the migration is rolled back -DROP TABLE IF EXISTS user_device_tokens; \ No newline at end of file diff --git a/db/old_migration/20250321123506_otp.sql b/db/old_migration/20250321123506_otp.sql deleted file mode 100644 index 4ef8bc9..0000000 --- a/db/old_migration/20250321123506_otp.sql +++ /dev/null @@ -1,63 +0,0 @@ --- +goose Up --- Create otp_verifications table for managing one-time password verifications - --- Create an enum for OTP purpose -DROP TYPE IF EXISTS otp_purpose; - -CREATE TYPE otp_purpose AS ENUM ( - 'email_verification', - 'password_reset', - 'phone_verification', - 'account_recovery', - 'two_factor_auth', - 'login_confirmation' -); - --- Create the otp_verifications table -CREATE TABLE otp_verifications ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - user_id UUID REFERENCES users(id) ON DELETE CASCADE, - - -- OTP Details - otp_code VARCHAR(10) NOT NULL, - hashed_otp VARCHAR(255) NOT NULL, - - -- Verification Context - purpose otp_purpose NOT NULL, - contact_method VARCHAR(255), - - -- Tracking and Limits - attempts_made INTEGER NOT NULL DEFAULT 0, - max_attempts INTEGER NOT NULL DEFAULT 5, - is_verified BOOLEAN NOT NULL DEFAULT false, - - -- Timestamps - created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), - expires_at TIMESTAMPTZ NOT NULL, - verified_at TIMESTAMPTZ, - - -- Additional Metadata - ip_address INET, - user_agent VARCHAR(500), - device_id UUID, - - -- Constraints - CONSTRAINT unique_unverified_otp UNIQUE (user_id, purpose, is_verified), - CONSTRAINT max_attempts_check CHECK (attempts_made <= max_attempts) -); - --- Indexes for performance -CREATE INDEX idx_otp_verifications_user_id ON otp_verifications(user_id); -CREATE INDEX idx_otp_verifications_purpose ON otp_verifications(purpose); -CREATE INDEX idx_otp_verifications_contact_method ON otp_verifications(contact_method); -CREATE INDEX idx_otp_verifications_created_at ON otp_verifications(created_at); - --- +goose Down --- Drop the table -DROP TABLE IF EXISTS otp_verifications; - --- Drop the custom type -DROP TYPE IF EXISTS otp_purpose; - --- Optionally remove the UUID extension if no longer needed --- DROP EXTENSION IF EXISTS "uuid-ossp"; \ No newline at end of file diff --git a/db/old_migration/20250321140031_transactions.sql b/db/old_migration/20250321140031_transactions.sql deleted file mode 100644 index b4f3c1b..0000000 --- a/db/old_migration/20250321140031_transactions.sql +++ /dev/null @@ -1,21 +0,0 @@ --- +goose Up --- SQL in this section is executed when the migration is applied. -CREATE TABLE transactions ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, - tx_hash VARCHAR(255) UNIQUE NOT NULL, - transaction_pin_hash VARCHAR(255) NOT NULL, - status VARCHAR(50) NOT NULL, - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now() -); - -CREATE INDEX idx_transactions_user_id ON transactions(user_id); -CREATE UNIQUE INDEX idx_transactions_tx_hash ON transactions(tx_hash); - -COMMENT ON COLUMN transactions.transaction_pin_hash IS 'hashed transaction pin'; -COMMENT ON COLUMN transactions.status IS 'created, pending, not_found, failed'; - --- +goose Down --- SQL in this section is executed when the migration is rolled back. -DROP TABLE IF EXISTS transactions; \ No newline at end of file diff --git a/db/old_migration/20250502134941_security.sql b/db/old_migration/20250502134941_security.sql deleted file mode 100644 index f8d2354..0000000 --- a/db/old_migration/20250502134941_security.sql +++ /dev/null @@ -1,16 +0,0 @@ --- +goose Up -CREATE TABLE security_events ( - id UUID PRIMARY KEY, - user_id UUID NOT NULL, - event_type TEXT NOT NULL, - ip_address TEXT NOT NULL, - user_agent TEXT, - metadata JSONB, - timestamp TIMESTAMP NOT NULL -); - -CREATE INDEX idx_security_events_user_id ON security_events(user_id); -CREATE INDEX idx_security_events_type_time ON security_events(event_type, timestamp); - --- +goose Down -DROP TABLE security_events; diff --git a/db/old_migration/20250502134956_wallet.sql b/db/old_migration/20250502134956_wallet.sql deleted file mode 100644 index def62ac..0000000 --- a/db/old_migration/20250502134956_wallet.sql +++ /dev/null @@ -1,14 +0,0 @@ --- +goose Up -CREATE TABLE user_wallets ( - id UUID PRIMARY KEY, - user_id UUID NOT NULL, - address TEXT NOT NULL UNIQUE, - type TEXT NOT NULL, - chain TEXT NOT NULL, - is_default BOOLEAN NOT NULL DEFAULT false, - created_at TIMESTAMP NOT NULL, - updated_at TIMESTAMP NOT NULL -); - --- +goose Down -DROP TABLE user_wallets; \ No newline at end of file diff --git a/db/query/audit.sql b/db/query/audit.sql new file mode 100644 index 0000000..8512c78 --- /dev/null +++ b/db/query/audit.sql @@ -0,0 +1,158 @@ +-- name: CreateAuditLog :one +INSERT INTO audit_logs ( + id, + user_id, + company_id, + action, + entity_type, + entity_id, + previous_state, + new_state, + ip_address, + user_agent, + created_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @user_id, + @company_id, + @action, + @entity_type, + @entity_id, + @previous_state, + @new_state, + @ip_address, + @user_agent, + COALESCE(@created_at, NOW()) +) RETURNING *; + +-- name: GetAuditLogsByUser :many +SELECT al.*, u.email +FROM audit_logs al +LEFT JOIN users u ON al.user_id = u.id +WHERE al.user_id = @user_id +ORDER BY al.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetAuditLogsByCompany :many +SELECT al.*, u.email +FROM audit_logs al +LEFT JOIN users u ON al.user_id = u.id +WHERE al.company_id = @company_id +ORDER BY al.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetAuditLogsByEntity :many +SELECT al.*, u.email +FROM audit_logs al +LEFT JOIN users u ON al.user_id = u.id +WHERE al.entity_type = @entity_type AND al.entity_id = @entity_id +ORDER BY al.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetAuditLogsByAction :many +SELECT al.*, u.email +FROM audit_logs al +LEFT JOIN users u ON al.user_id = u.id +WHERE al.action = @action + AND (@user_id::uuid IS NULL OR al.user_id = @user_id) + AND (@company_id::uuid IS NULL OR al.company_id = @company_id) + AND (@start_date::timestamptz IS NULL OR al.created_at >= @start_date) + AND (@end_date::timestamptz IS NULL OR al.created_at <= @end_date) +ORDER BY al.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: SearchAuditLogs :many +SELECT al.*, u.email +FROM audit_logs al +LEFT JOIN users u ON al.user_id = u.id +WHERE (@user_id::uuid IS NULL OR al.user_id = @user_id) + AND (@company_id::uuid IS NULL OR al.company_id = @company_id) + AND (@entity_type::text IS NULL OR al.entity_type = @entity_type) + AND (@action::text IS NULL OR al.action = @action) + AND (@start_date::timestamptz IS NULL OR al.created_at >= @start_date) + AND (@end_date::timestamptz IS NULL OR al.created_at <= @end_date) +ORDER BY al.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: CreateActivityLog :one +INSERT INTO activity_logs ( + id, + user_id, + activity_type, + description, + metadata, + ip_address, + user_agent, + created_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @user_id, + @activity_type, + @description, + @metadata, + @ip_address, + @user_agent, + COALESCE(@created_at, NOW()) +) RETURNING *; + +-- name: GetActivityLogsByUser :many +SELECT * FROM activity_logs +WHERE user_id = @user_id +ORDER BY created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetActivityLogsByType :many +SELECT al.*, u.email +FROM activity_logs al +JOIN users u ON al.user_id = u.id +WHERE al.activity_type = @activity_type + AND (@user_id::uuid IS NULL OR al.user_id = @user_id) + AND (@start_date::timestamptz IS NULL OR al.created_at >= @start_date) + AND (@end_date::timestamptz IS NULL OR al.created_at <= @end_date) +ORDER BY al.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetRecentActivity :many +SELECT al.*, u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM activity_logs al +JOIN users u ON al.user_id = u.id +LEFT JOIN company_staff_profiles csp ON u.id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE (@user_id::uuid IS NULL OR al.user_id = @user_id) + AND al.created_at >= NOW() - INTERVAL '@hours hours' +ORDER BY al.created_at DESC +LIMIT @limit_val; + +-- name: CleanupOldAuditLogs :exec +DELETE FROM audit_logs +WHERE created_at < NOW() - INTERVAL '@days days'; + +-- name: CleanupOldActivityLogs :exec +DELETE FROM activity_logs +WHERE created_at < NOW() - INTERVAL '@days days'; + +-- name: GetUserActivitySummary :one +SELECT + COUNT(*) as total_activities, + COUNT(DISTINCT activity_type) as unique_activity_types, + MAX(created_at) as last_activity, + MIN(created_at) as first_activity +FROM activity_logs +WHERE user_id = @user_id + AND (@start_date::timestamptz IS NULL OR created_at >= @start_date) + AND (@end_date::timestamptz IS NULL OR created_at <= @end_date); + +-- name: GetCompanyAuditSummary :one +SELECT + COUNT(*) as total_audit_logs, + COUNT(DISTINCT user_id) as unique_users, + COUNT(DISTINCT action) as unique_actions, + COUNT(DISTINCT entity_type) as unique_entity_types, + MAX(created_at) as last_audit, + MIN(created_at) as first_audit +FROM audit_logs +WHERE company_id = @company_id + AND (@start_date::timestamptz IS NULL OR created_at >= @start_date) + AND (@end_date::timestamptz IS NULL OR created_at <= @end_date); \ No newline at end of file diff --git a/db/query/auth.sql b/db/query/auth.sql new file mode 100644 index 0000000..c75fe21 --- /dev/null +++ b/db/query/auth.sql @@ -0,0 +1,181 @@ +-- name: CreateSession :one +INSERT INTO sessions ( + id, + user_id, + refresh_token, + user_agent, + client_ip, + last_used_at, + web_oauth_client_id, + oauth_access_token, + oauth_id_token, + user_login_type, + mfa_verified, + is_blocked, + expires_at, + created_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @user_id, + @refresh_token, + @user_agent, + @client_ip, + COALESCE(@last_used_at, NOW()), + @web_oauth_client_id, + @oauth_access_token, + @oauth_id_token, + @user_login_type, + COALESCE(@mfa_verified, FALSE), + COALESCE(@is_blocked, FALSE), + @expires_at, + COALESCE(@created_at, NOW()) +) RETURNING *; + +-- name: GetSessionByID :one +SELECT * FROM sessions +WHERE id = @id AND is_blocked = FALSE; + +-- name: GetSessionsByUser :many +SELECT * FROM sessions +WHERE user_id = @user_id AND is_blocked = FALSE +ORDER BY last_used_at DESC; + +-- name: UpdateSessionLastUsed :exec +UPDATE sessions SET + last_used_at = NOW() +WHERE id = @id; + +-- name: RevokeSession :exec +UPDATE sessions SET + is_blocked = TRUE +WHERE id = @id; + +-- name: RevokeAllUserSessions :exec +UPDATE sessions SET + is_blocked = TRUE +WHERE user_id = @user_id; + +-- name: CleanupExpiredSessions :exec +DELETE FROM sessions +WHERE expires_at < NOW() OR is_blocked = TRUE; + +-- name: CreateUserDevice :one +INSERT INTO user_devices ( + id, + user_id, + device_token, + platform, + device_type, + device_model, + os_name, + os_version, + push_notification_token, + is_active, + is_verified, + last_used_at, + app_version, + client_ip, + expires_at, + is_revoked, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @user_id, + @device_token, + @platform, + @device_type, + @device_model, + @os_name, + @os_version, + @push_notification_token, + COALESCE(@is_active, TRUE), + COALESCE(@is_verified, FALSE), + COALESCE(@last_used_at, NOW()), + @app_version, + @client_ip, + @expires_at, + COALESCE(@is_revoked, FALSE), + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetUserDeviceByID :one +SELECT * FROM user_devices +WHERE id = @id AND is_revoked = FALSE; + +-- name: GetUserDevicesByUser :many +SELECT * FROM user_devices +WHERE user_id = @user_id AND is_revoked = FALSE +ORDER BY last_used_at DESC; + +-- name: GetUserDeviceByToken :one +SELECT * FROM user_devices +WHERE device_token = @device_token AND is_revoked = FALSE; + +-- name: UpdateUserDevice :one +UPDATE user_devices SET + platform = COALESCE(@platform, platform), + device_type = COALESCE(@device_type, device_type), + device_model = COALESCE(@device_model, device_model), + os_name = COALESCE(@os_name, os_name), + os_version = COALESCE(@os_version, os_version), + push_notification_token = COALESCE(@push_notification_token, push_notification_token), + is_active = COALESCE(@is_active, is_active), + is_verified = COALESCE(@is_verified, is_verified), + last_used_at = NOW(), + app_version = COALESCE(@app_version, app_version), + client_ip = COALESCE(@client_ip, client_ip), + expires_at = COALESCE(@expires_at, expires_at), + updated_at = NOW() +WHERE id = @id +RETURNING *; + +-- name: RevokeUserDevice :exec +UPDATE user_devices SET + is_revoked = TRUE, + updated_at = NOW() +WHERE id = @id; + +-- name: CreateSecurityEvent :one +INSERT INTO security_events ( + id, + user_id, + company_id, + event_type, + severity, + ip_address, + user_agent, + metadata, + created_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @user_id, + @company_id, + @event_type, + @severity, + @ip_address, + @user_agent, + @metadata, + COALESCE(@created_at, NOW()) +) RETURNING *; + +-- name: GetSecurityEventsByUser :many +SELECT * FROM security_events +WHERE user_id = @user_id +ORDER BY created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetSecurityEventsByCompany :many +SELECT * FROM security_events +WHERE company_id = @company_id +ORDER BY created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetSecurityEventsByType :many +SELECT * FROM security_events +WHERE event_type = @event_type + AND (@user_id::uuid IS NULL OR user_id = @user_id) + AND (@company_id::uuid IS NULL OR company_id = @company_id) +ORDER BY created_at DESC +LIMIT @limit_val OFFSET @offset_val; \ No newline at end of file diff --git a/db/query/companies.sql b/db/query/companies.sql new file mode 100644 index 0000000..53cf683 --- /dev/null +++ b/db/query/companies.sql @@ -0,0 +1,283 @@ +-- name: CreateCompany :one +INSERT INTO companies ( + id, + owner_id, + company_name, + company_email, + company_phone, + company_size, + company_industry, + company_description, + company_headquarters, + company_logo, + company_website, + primary_contact_name, + primary_contact_email, + primary_contact_phone, + company_address, + company_city, + company_postal_code, + company_country, + company_registration_number, + registration_country, + tax_id, + incorporation_date, + account_status, + kyb_status, + kyb_verified_at, + kyb_verification_method, + kyb_verification_provider, + kyb_rejection_reason, + legal_entity_type, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @owner_id, + @company_name, + @company_email, + @company_phone, + @company_size, + @company_industry, + @company_description, + @company_headquarters, + @company_logo, + @company_website, + @primary_contact_name, + @primary_contact_email, + @primary_contact_phone, + @company_address, + @company_city, + @company_postal_code, + @company_country, + @company_registration_number, + @registration_country, + @tax_id, + @incorporation_date, + COALESCE(@account_status, 'pending'), + COALESCE(@kyb_status, 'pending'), + @kyb_verified_at, + @kyb_verification_method, + @kyb_verification_provider, + @kyb_rejection_reason, + @legal_entity_type, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetCompanyByID :one +SELECT * FROM companies WHERE id = @id; + +-- name: GetCompaniesByOwner :many +SELECT * FROM companies +WHERE owner_id = @owner_id +ORDER BY created_at DESC; + +-- name: GetCompaniesAccessibleToUser :many +SELECT DISTINCT c.* +FROM companies c +LEFT JOIN company_users cu ON c.id = cu.company_id +WHERE c.owner_id = @user_id OR cu.user_id = @user_id +ORDER BY c.created_at DESC; + +-- name: UpdateCompany :one +UPDATE companies SET + company_name = COALESCE(@company_name, company_name), + company_email = COALESCE(@company_email, company_email), + company_phone = COALESCE(@company_phone, company_phone), + company_size = COALESCE(@company_size, company_size), + company_industry = COALESCE(@company_industry, company_industry), + company_description = COALESCE(@company_description, company_description), + company_headquarters = COALESCE(@company_headquarters, company_headquarters), + company_logo = COALESCE(@company_logo, company_logo), + company_website = COALESCE(@company_website, company_website), + primary_contact_name = COALESCE(@primary_contact_name, primary_contact_name), + primary_contact_email = COALESCE(@primary_contact_email, primary_contact_email), + primary_contact_phone = COALESCE(@primary_contact_phone, primary_contact_phone), + company_address = COALESCE(@company_address, company_address), + company_city = COALESCE(@company_city, company_city), + company_postal_code = COALESCE(@company_postal_code, company_postal_code), + company_country = COALESCE(@company_country, company_country), + company_registration_number = COALESCE(@company_registration_number, company_registration_number), + registration_country = COALESCE(@registration_country, registration_country), + tax_id = COALESCE(@tax_id, tax_id), + incorporation_date = COALESCE(@incorporation_date, incorporation_date), + account_status = COALESCE(@account_status, account_status), + kyb_status = COALESCE(@kyb_status, kyb_status), + kyb_verified_at = COALESCE(@kyb_verified_at, kyb_verified_at), + kyb_verification_method = COALESCE(@kyb_verification_method, kyb_verification_method), + kyb_verification_provider = COALESCE(@kyb_verification_provider, kyb_verification_provider), + kyb_rejection_reason = COALESCE(@kyb_rejection_reason, kyb_rejection_reason), + legal_entity_type = COALESCE(@legal_entity_type, legal_entity_type), + updated_at = NOW() +WHERE id = @id +RETURNING *; + +-- name: CreateCompanyUser :one +INSERT INTO company_users ( + id, + company_id, + user_id, + role, + department, + job_title, + is_administrator, + can_manage_payroll, + can_manage_invoices, + can_manage_employees, + can_manage_company_settings, + can_manage_bank_accounts, + can_manage_wallets, + permissions, + is_active, + added_by, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @company_id, + @user_id, + @role, + @department, + @job_title, + COALESCE(@is_administrator, FALSE), + COALESCE(@can_manage_payroll, FALSE), + COALESCE(@can_manage_invoices, FALSE), + COALESCE(@can_manage_employees, FALSE), + COALESCE(@can_manage_company_settings, FALSE), + COALESCE(@can_manage_bank_accounts, FALSE), + COALESCE(@can_manage_wallets, FALSE), + @permissions, + COALESCE(@is_active, TRUE), + @added_by, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetCompanyUser :one +SELECT cu.*, u.email, u.account_status, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM company_users cu +JOIN users u ON cu.user_id = u.id +LEFT JOIN company_staff_profiles csp ON cu.id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE cu.company_id = @company_id AND cu.user_id = @user_id; + +-- name: GetCompanyUsersByCompany :many +SELECT cu.*, u.email, u.account_status, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM company_users cu +JOIN users u ON cu.user_id = u.id +LEFT JOIN company_staff_profiles csp ON cu.id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE cu.company_id = @company_id AND cu.is_active = TRUE +ORDER BY cu.created_at DESC; + +-- name: UpdateCompanyUser :one +UPDATE company_users SET + role = COALESCE(@role, role), + department = COALESCE(@department, department), + job_title = COALESCE(@job_title, job_title), + is_administrator = COALESCE(@is_administrator, is_administrator), + can_manage_payroll = COALESCE(@can_manage_payroll, can_manage_payroll), + can_manage_invoices = COALESCE(@can_manage_invoices, can_manage_invoices), + can_manage_employees = COALESCE(@can_manage_employees, can_manage_employees), + can_manage_company_settings = COALESCE(@can_manage_company_settings, can_manage_company_settings), + can_manage_bank_accounts = COALESCE(@can_manage_bank_accounts, can_manage_bank_accounts), + can_manage_wallets = COALESCE(@can_manage_wallets, can_manage_wallets), + permissions = COALESCE(@permissions, permissions), + is_active = COALESCE(@is_active, is_active), + updated_at = NOW() +WHERE company_id = @company_id AND user_id = @user_id +RETURNING *; + +-- name: CreateCompanyEmployee :one +INSERT INTO company_employees ( + id, + company_id, + user_id, + employee_id, + department, + position, + employment_status, + employment_type, + start_date, + end_date, + manager_id, + salary_amount, + salary_currency, + salary_frequency, + hourly_rate, + payment_method, + payment_split, + tax_information, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @company_id, + @user_id, + @employee_id, + @department, + @position, + COALESCE(@employment_status, 'active'), + @employment_type, + @start_date, + @end_date, + @manager_id, + @salary_amount, + @salary_currency, + @salary_frequency, + @hourly_rate, + @payment_method, + @payment_split, + @tax_information, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetCompanyEmployeeByID :one +SELECT ce.*, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM company_employees ce +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE ce.id = @id; + +-- name: GetCompanyEmployeesByCompany :many +SELECT ce.*, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM company_employees ce +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE ce.company_id = @company_id +ORDER BY ce.created_at DESC; + +-- name: UpdateCompanyEmployee :one +UPDATE company_employees SET + employee_id = COALESCE(@employee_id, employee_id), + department = COALESCE(@department, department), + position = COALESCE(@position, position), + employment_status = COALESCE(@employment_status, employment_status), + employment_type = COALESCE(@employment_type, employment_type), + start_date = COALESCE(@start_date, start_date), + end_date = COALESCE(@end_date, end_date), + manager_id = COALESCE(@manager_id, manager_id), + salary_amount = COALESCE(@salary_amount, salary_amount), + salary_currency = COALESCE(@salary_currency, salary_currency), + salary_frequency = COALESCE(@salary_frequency, salary_frequency), + hourly_rate = COALESCE(@hourly_rate, hourly_rate), + payment_method = COALESCE(@payment_method, payment_method), + payment_split = COALESCE(@payment_split, payment_split), + tax_information = COALESCE(@tax_information, tax_information), + updated_at = NOW() +WHERE id = @id +RETURNING *; \ No newline at end of file diff --git a/db/query/compliance.sql b/db/query/compliance.sql new file mode 100644 index 0000000..7f03d0f --- /dev/null +++ b/db/query/compliance.sql @@ -0,0 +1,295 @@ +-- name: CreateSupportedCountry :one +INSERT INTO supported_countries ( + id, + country_code, + country_name, + region, + currency_code, + currency_symbol, + is_active, + is_high_risk, + requires_enhanced_kyc, + requires_enhanced_kyb, + timezone, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @country_code, + @country_name, + @region, + @currency_code, + @currency_symbol, + COALESCE(@is_active, TRUE), + COALESCE(@is_high_risk, FALSE), + COALESCE(@requires_enhanced_kyc, FALSE), + COALESCE(@requires_enhanced_kyb, FALSE), + @timezone, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetSupportedCountries :many +SELECT * FROM supported_countries +WHERE is_active = TRUE +ORDER BY country_name; + +-- name: GetSupportedCountryByCode :one +SELECT * FROM supported_countries +WHERE country_code = @country_code AND is_active = TRUE; + +-- name: CreateKYCDocument :one +INSERT INTO kyc_documents ( + id, + user_id, + country_id, + document_type, + document_number, + document_country, + issue_date, + expiry_date, + document_url, + ipfs_hash, + verification_status, + verification_level, + verification_notes, + verified_by, + verified_at, + rejection_reason, + metadata, + meets_requirements, + requirement_id, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @user_id, + @country_id, + @document_type, + @document_number, + @document_country, + @issue_date, + @expiry_date, + @document_url, + @ipfs_hash, + COALESCE(@verification_status, 'pending'), + @verification_level, + @verification_notes, + @verified_by, + @verified_at, + @rejection_reason, + @metadata, + COALESCE(@meets_requirements, FALSE), + @requirement_id, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetKYCDocumentsByUser :many +SELECT kd.*, sc.country_name, kcr.document_type as required_document_type +FROM kyc_documents kd +JOIN supported_countries sc ON kd.country_id = sc.id +LEFT JOIN kyc_country_requirements kcr ON kd.requirement_id = kcr.id +WHERE kd.user_id = @user_id +ORDER BY kd.created_at DESC; + +-- name: GetKYCDocumentsByCountry :many +SELECT kd.*, sc.country_name, kcr.document_type as required_document_type +FROM kyc_documents kd +JOIN supported_countries sc ON kd.country_id = sc.id +LEFT JOIN kyc_country_requirements kcr ON kd.requirement_id = kcr.id +WHERE kd.user_id = @user_id AND kd.country_id = @country_id +ORDER BY kd.created_at DESC; + +-- name: UpdateKYCDocument :one +UPDATE kyc_documents SET + document_number = COALESCE(@document_number, document_number), + document_country = COALESCE(@document_country, document_country), + issue_date = COALESCE(@issue_date, issue_date), + expiry_date = COALESCE(@expiry_date, expiry_date), + document_url = COALESCE(@document_url, document_url), + ipfs_hash = COALESCE(@ipfs_hash, ipfs_hash), + verification_status = COALESCE(@verification_status, verification_status), + verification_level = COALESCE(@verification_level, verification_level), + verification_notes = COALESCE(@verification_notes, verification_notes), + verified_by = COALESCE(@verified_by, verified_by), + verified_at = COALESCE(@verified_at, verified_at), + rejection_reason = COALESCE(@rejection_reason, rejection_reason), + metadata = COALESCE(@metadata, metadata), + meets_requirements = COALESCE(@meets_requirements, meets_requirements), + updated_at = NOW() +WHERE id = @id +RETURNING *; + +-- name: CreateKYBDocument :one +INSERT INTO kyb_documents ( + id, + company_id, + country_id, + document_type, + document_number, + document_country, + issue_date, + expiry_date, + document_url, + ipfs_hash, + verification_status, + verification_level, + verification_notes, + verified_by, + verified_at, + rejection_reason, + metadata, + meets_requirements, + requirement_id, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @company_id, + @country_id, + @document_type, + @document_number, + @document_country, + @issue_date, + @expiry_date, + @document_url, + @ipfs_hash, + COALESCE(@verification_status, 'pending'), + @verification_level, + @verification_notes, + @verified_by, + @verified_at, + @rejection_reason, + @metadata, + COALESCE(@meets_requirements, FALSE), + @requirement_id, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetKYBDocumentsByCompany :many +SELECT kbd.*, sc.country_name, kbcr.document_type as required_document_type +FROM kyb_documents kbd +JOIN supported_countries sc ON kbd.country_id = sc.id +LEFT JOIN kyb_country_requirements kbcr ON kbd.requirement_id = kbcr.id +WHERE kbd.company_id = @company_id +ORDER BY kbd.created_at DESC; + +-- name: GetKYCCountryRequirements :many +SELECT * FROM kyc_country_requirements +WHERE country_id = @country_id AND is_active = TRUE +ORDER BY document_type; + +-- name: GetKYBCountryRequirements :many +SELECT * FROM kyb_country_requirements +WHERE country_id = @country_id AND is_active = TRUE +ORDER BY document_type; + +-- name: CreateUserCountryKYCStatus :one +INSERT INTO user_country_kyc_status ( + id, + user_id, + country_id, + verification_status, + verification_level, + verification_date, + expiry_date, + rejection_reason, + notes, + risk_rating, + restricted_features, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @user_id, + @country_id, + COALESCE(@verification_status, 'pending'), + @verification_level, + @verification_date, + @expiry_date, + @rejection_reason, + @notes, + @risk_rating, + @restricted_features, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetUserKYCStatus :one +SELECT ukcs.*, sc.country_name +FROM user_country_kyc_status ukcs +JOIN supported_countries sc ON ukcs.country_id = sc.id +WHERE ukcs.user_id = @user_id AND ukcs.country_id = @country_id; + +-- name: GetUserKYCStatusByCountryCode :one +SELECT ukcs.*, sc.country_name +FROM user_country_kyc_status ukcs +JOIN supported_countries sc ON ukcs.country_id = sc.id +WHERE ukcs.user_id = @user_id AND sc.country_code = @country_code; + +-- name: UpdateUserKYCStatus :one +UPDATE user_country_kyc_status SET + verification_status = COALESCE(@verification_status, verification_status), + verification_level = COALESCE(@verification_level, verification_level), + verification_date = COALESCE(@verification_date, verification_date), + expiry_date = COALESCE(@expiry_date, expiry_date), + rejection_reason = COALESCE(@rejection_reason, rejection_reason), + notes = COALESCE(@notes, notes), + risk_rating = COALESCE(@risk_rating, risk_rating), + restricted_features = COALESCE(@restricted_features, restricted_features), + updated_at = NOW() +WHERE user_id = @user_id AND country_id = @country_id +RETURNING *; + +-- name: CreateCompanyCountryKYBStatus :one +INSERT INTO company_country_kyb_status ( + id, + company_id, + country_id, + verification_status, + verification_level, + verification_date, + expiry_date, + rejection_reason, + notes, + risk_rating, + restricted_features, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @company_id, + @country_id, + COALESCE(@verification_status, 'pending'), + @verification_level, + @verification_date, + @expiry_date, + @rejection_reason, + @notes, + @risk_rating, + @restricted_features, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetCompanyKYBStatus :one +SELECT ckbs.*, sc.country_name +FROM company_country_kyb_status ckbs +JOIN supported_countries sc ON ckbs.country_id = sc.id +WHERE ckbs.company_id = @company_id AND ckbs.country_id = @country_id; + +-- name: UpdateCompanyKYBStatus :one +UPDATE company_country_kyb_status SET + verification_status = COALESCE(@verification_status, verification_status), + verification_level = COALESCE(@verification_level, verification_level), + verification_date = COALESCE(@verification_date, verification_date), + expiry_date = COALESCE(@expiry_date, expiry_date), + rejection_reason = COALESCE(@rejection_reason, rejection_reason), + notes = COALESCE(@notes, notes), + risk_rating = COALESCE(@risk_rating, risk_rating), + restricted_features = COALESCE(@restricted_features, restricted_features), + updated_at = NOW() +WHERE company_id = @company_id AND country_id = @country_id +RETURNING *; \ No newline at end of file diff --git a/db/query/invoices.sql b/db/query/invoices.sql new file mode 100644 index 0000000..2433736 --- /dev/null +++ b/db/query/invoices.sql @@ -0,0 +1,253 @@ +-- name: CreateInvoice :one +INSERT INTO invoices ( + id, + invoice_number, + issuer_id, + recipient_id, + title, + description, + issue_date, + due_date, + total_amount, + currency, + status, + payment_method, + recipient_wallet_address, + recipient_bank_account_id, + transaction_hash, + payment_date, + rejection_reason, + ipfs_hash, + smart_contract_address, + chain_id, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @invoice_number, + @issuer_id, + @recipient_id, + @title, + @description, + @issue_date, + @due_date, + @total_amount, + @currency, + COALESCE(@status, 'draft'), + @payment_method, + @recipient_wallet_address, + @recipient_bank_account_id, + @transaction_hash, + @payment_date, + @rejection_reason, + @ipfs_hash, + @smart_contract_address, + @chain_id, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetInvoiceByID :one +SELECT i.*, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +JOIN companies recipient ON i.recipient_id = recipient.id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE i.id = @id; + +-- name: GetInvoiceByNumber :one +SELECT i.*, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +JOIN companies recipient ON i.recipient_id = recipient.id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE i.invoice_number = @invoice_number; + +-- name: GetUserInvoices :many +SELECT i.*, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN companies recipient ON i.recipient_id = recipient.id +WHERE i.issuer_id = @user_id +ORDER BY i.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetCompanyReceivedInvoices :many +SELECT i.*, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE i.recipient_id = @company_id +ORDER BY i.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetCompanySentInvoices :many +SELECT i.*, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN companies recipient ON i.recipient_id = recipient.id +JOIN company_users cu ON cu.company_id = recipient.id +WHERE cu.user_id = @user_id AND i.issuer_id = @user_id +ORDER BY i.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetInvoicesForApproval :many +SELECT i.*, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +JOIN company_users cu ON cu.company_id = i.recipient_id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE cu.user_id = @user_id + AND i.status = 'pending' + AND (cu.can_manage_invoices = TRUE OR cu.is_administrator = TRUE) +ORDER BY i.created_at; + +-- name: UpdateInvoice :one +UPDATE invoices SET + title = COALESCE(@title, title), + description = COALESCE(@description, description), + issue_date = COALESCE(@issue_date, issue_date), + due_date = COALESCE(@due_date, due_date), + total_amount = COALESCE(@total_amount, total_amount), + currency = COALESCE(@currency, currency), + status = COALESCE(@status, status), + payment_method = COALESCE(@payment_method, payment_method), + recipient_wallet_address = COALESCE(@recipient_wallet_address, recipient_wallet_address), + recipient_bank_account_id = COALESCE(@recipient_bank_account_id, recipient_bank_account_id), + transaction_hash = COALESCE(@transaction_hash, transaction_hash), + payment_date = COALESCE(@payment_date, payment_date), + rejection_reason = COALESCE(@rejection_reason, rejection_reason), + ipfs_hash = COALESCE(@ipfs_hash, ipfs_hash), + smart_contract_address = COALESCE(@smart_contract_address, smart_contract_address), + chain_id = COALESCE(@chain_id, chain_id), + updated_at = NOW() +WHERE id = @id +RETURNING *; + +-- name: CreateInvoiceItem :one +INSERT INTO invoice_items ( + id, + invoice_id, + description, + quantity, + unit_price, + amount, + tax_rate, + tax_amount, + discount_percentage, + discount_amount, + total_amount, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @invoice_id, + @description, + COALESCE(@quantity, 1), + @unit_price, + @amount, + COALESCE(@tax_rate, 0), + COALESCE(@tax_amount, 0), + COALESCE(@discount_percentage, 0), + COALESCE(@discount_amount, 0), + @total_amount, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetInvoiceItems :many +SELECT * FROM invoice_items +WHERE invoice_id = @invoice_id +ORDER BY created_at; + +-- name: UpdateInvoiceItem :one +UPDATE invoice_items SET + description = COALESCE(@description, description), + quantity = COALESCE(@quantity, quantity), + unit_price = COALESCE(@unit_price, unit_price), + amount = COALESCE(@amount, amount), + tax_rate = COALESCE(@tax_rate, tax_rate), + tax_amount = COALESCE(@tax_amount, tax_amount), + discount_percentage = COALESCE(@discount_percentage, discount_percentage), + discount_amount = COALESCE(@discount_amount, discount_amount), + total_amount = COALESCE(@total_amount, total_amount), + updated_at = NOW() +WHERE id = @id +RETURNING *; + +-- name: DeleteInvoiceItem :exec +DELETE FROM invoice_items WHERE id = @id; + +-- name: SearchInvoices :many +SELECT i.*, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +JOIN companies recipient ON i.recipient_id = recipient.id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE (i.issuer_id = @user_id OR i.recipient_id IN ( + SELECT company_id FROM company_users WHERE user_id = @user_id +)) +AND ( + i.invoice_number ILIKE '%' || @search_term || '%' OR + i.title ILIKE '%' || @search_term || '%' OR + recipient.company_name ILIKE '%' || @search_term || '%' +) +ORDER BY i.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetOverdueInvoices :many +SELECT i.*, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +JOIN companies recipient ON i.recipient_id = recipient.id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE i.due_date < CURRENT_DATE + AND i.status NOT IN ('paid', 'cancelled') + AND (@company_id::uuid IS NULL OR i.recipient_id = @company_id) + AND (@user_id::uuid IS NULL OR i.issuer_id = @user_id) +ORDER BY i.due_date; + +-- name: GetInvoicesByStatus :many +SELECT i.*, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +JOIN companies recipient ON i.recipient_id = recipient.id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE i.status = @status + AND (@company_id::uuid IS NULL OR i.recipient_id = @company_id) + AND (@user_id::uuid IS NULL OR i.issuer_id = @user_id) +ORDER BY i.created_at DESC +LIMIT @limit_val OFFSET @offset_val; \ No newline at end of file diff --git a/db/query/notifications.sql b/db/query/notifications.sql new file mode 100644 index 0000000..f519674 --- /dev/null +++ b/db/query/notifications.sql @@ -0,0 +1,256 @@ +-- name: CreateNotificationTemplate :one +INSERT INTO notification_templates ( + id, + template_name, + template_type, + subject, + content, + variables, + is_active, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @template_name, + @template_type, + @subject, + @content, + @variables, + COALESCE(@is_active, TRUE), + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetNotificationTemplateByName :one +SELECT * FROM notification_templates +WHERE template_name = @template_name AND is_active = TRUE; + +-- name: GetNotificationTemplatesByType :many +SELECT * FROM notification_templates +WHERE template_type = @template_type AND is_active = TRUE +ORDER BY template_name; + +-- name: CreateNotification :one +INSERT INTO notifications ( + id, + user_id, + template_id, + notification_type, + title, + content, + reference_type, + reference_id, + is_read, + read_at, + delivery_status, + priority, + created_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @user_id, + @template_id, + @notification_type, + @title, + @content, + @reference_type, + @reference_id, + COALESCE(@is_read, FALSE), + @read_at, + COALESCE(@delivery_status, 'pending'), + COALESCE(@priority, 'normal'), + COALESCE(@created_at, NOW()) +) RETURNING *; + +-- name: GetUserNotifications :many +SELECT n.*, nt.template_name +FROM notifications n +LEFT JOIN notification_templates nt ON n.template_id = nt.id +WHERE n.user_id = @user_id +ORDER BY n.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetUnreadNotifications :many +SELECT n.*, nt.template_name +FROM notifications n +LEFT JOIN notification_templates nt ON n.template_id = nt.id +WHERE n.user_id = @user_id AND n.is_read = FALSE +ORDER BY n.created_at DESC; + +-- name: GetNotificationsByType :many +SELECT n.*, nt.template_name +FROM notifications n +LEFT JOIN notification_templates nt ON n.template_id = nt.id +WHERE n.user_id = @user_id AND n.notification_type = @notification_type +ORDER BY n.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: MarkNotificationAsRead :one +UPDATE notifications SET + is_read = TRUE, + read_at = NOW() +WHERE id = @id AND user_id = @user_id +RETURNING *; + +-- name: MarkAllNotificationsAsRead :exec +UPDATE notifications SET + is_read = TRUE, + read_at = NOW() +WHERE user_id = @user_id AND is_read = FALSE; + +-- name: DeleteNotification :exec +DELETE FROM notifications +WHERE id = @id AND user_id = @user_id; + +-- name: GetNotificationCount :one +SELECT + COUNT(*) as total_count, + COUNT(*) FILTER (WHERE is_read = FALSE) as unread_count +FROM notifications +WHERE user_id = @user_id; + +-- name: CreateRole :one +INSERT INTO roles ( + id, + company_id, + role_name, + description, + is_system_role, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @company_id, + @role_name, + @description, + COALESCE(@is_system_role, FALSE), + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetRolesByCompany :many +SELECT * FROM roles +WHERE company_id = @company_id OR is_system_role = TRUE +ORDER BY is_system_role DESC, role_name; + +-- name: GetRoleByID :one +SELECT * FROM roles WHERE id = @id; + +-- name: UpdateRole :one +UPDATE roles SET + role_name = COALESCE(@role_name, role_name), + description = COALESCE(@description, description), + updated_at = NOW() +WHERE id = @id AND is_system_role = FALSE +RETURNING *; + +-- name: DeleteRole :exec +DELETE FROM roles +WHERE id = @id AND is_system_role = FALSE; + +-- name: CreatePermission :one +INSERT INTO permissions ( + id, + permission_key, + description, + category, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @permission_key, + @description, + @category, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetAllPermissions :many +SELECT * FROM permissions +ORDER BY category, permission_key; + +-- name: GetPermissionsByCategory :many +SELECT * FROM permissions +WHERE category = @category +ORDER BY permission_key; + +-- name: CreateRolePermission :one +INSERT INTO role_permissions ( + id, + role_id, + permission_id, + created_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @role_id, + @permission_id, + COALESCE(@created_at, NOW()) +) RETURNING *; + +-- name: GetRolePermissions :many +SELECT rp.*, p.permission_key, p.description, p.category +FROM role_permissions rp +JOIN permissions p ON rp.permission_id = p.id +WHERE rp.role_id = @role_id +ORDER BY p.category, p.permission_key; + +-- name: DeleteRolePermission :exec +DELETE FROM role_permissions +WHERE role_id = @role_id AND permission_id = @permission_id; + +-- name: CreateUserRole :one +INSERT INTO user_roles ( + id, + user_id, + role_id, + company_id, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @user_id, + @role_id, + @company_id, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetUserRoles :many +SELECT ur.*, r.role_name, r.description, c.company_name +FROM user_roles ur +JOIN roles r ON ur.role_id = r.id +LEFT JOIN companies c ON ur.company_id = c.id +WHERE ur.user_id = @user_id +ORDER BY c.company_name, r.role_name; + +-- name: GetUserRolesByCompany :many +SELECT ur.*, r.role_name, r.description +FROM user_roles ur +JOIN roles r ON ur.role_id = r.id +WHERE ur.user_id = @user_id AND ur.company_id = @company_id +ORDER BY r.role_name; + +-- name: GetUsersWithRole :many +SELECT ur.*, u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM user_roles ur +JOIN users u ON ur.user_id = u.id +LEFT JOIN company_staff_profiles csp ON u.id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE ur.role_id = @role_id + AND (@company_id::uuid IS NULL OR ur.company_id = @company_id) +ORDER BY u.email; + +-- name: DeleteUserRole :exec +DELETE FROM user_roles +WHERE user_id = @user_id AND role_id = @role_id + AND (@company_id::uuid IS NULL OR company_id = @company_id); + +-- name: GetUserPermissions :many +SELECT DISTINCT p.permission_key, p.description, p.category +FROM user_roles ur +JOIN role_permissions rp ON ur.role_id = rp.role_id +JOIN permissions p ON rp.permission_id = p.id +WHERE ur.user_id = @user_id + AND (@company_id::uuid IS NULL OR ur.company_id = @company_id) +ORDER BY p.category, p.permission_key; \ No newline at end of file diff --git a/db/query/otp_verifications.sql b/db/query/otp_verifications.sql deleted file mode 100644 index f624fb8..0000000 --- a/db/query/otp_verifications.sql +++ /dev/null @@ -1,70 +0,0 @@ --- name: CreateOTPVerification :one -INSERT INTO otp_verifications ( - user_id, - otp_code, - hashed_otp, - purpose, - contact_method, - attempts_made, - max_attempts, - expires_at, - ip_address, - user_agent, - device_id -) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11 -) RETURNING *; - --- name: GetOTPVerificationByID :one -SELECT * FROM otp_verifications -WHERE id = $1; - --- name: GetOTPVerificationByUserAndPurpose :one -SELECT * FROM otp_verifications -WHERE user_id = $1 - AND purpose = $2 - AND is_verified = false - AND expires_at > NOW() -ORDER BY created_at DESC -LIMIT 1; - --- name: UpdateOTPAttempts :one -UPDATE otp_verifications -SET attempts_made = attempts_made + 1 -WHERE id = $1 -RETURNING *; - --- name: VerifyOTP :one -UPDATE otp_verifications -SET - is_verified = true, - verified_at = NOW() -WHERE id = $1 - AND otp_code = $2 - AND expires_at > NOW() - AND attempts_made <= max_attempts -RETURNING *; - --- name: InValidateOTP :exec -UPDATE otp_verifications -SET is_verified = false -WHERE id = $1; - --- name: DeleteExpiredOTPs :exec -DELETE FROM otp_verifications -WHERE expires_at < NOW(); - --- name: CountActiveOTPsForUser :one -SELECT COUNT(*) -FROM otp_verifications -WHERE user_id = $1 - AND purpose = $2 - AND is_verified = false - AND expires_at > NOW(); - --- name: GetUnverifiedOTPsForUser :many -SELECT * FROM otp_verifications -WHERE user_id = $1 - AND is_verified = false - AND expires_at > NOW() -ORDER BY created_at DESC; \ No newline at end of file diff --git a/db/query/payroll.sql b/db/query/payroll.sql new file mode 100644 index 0000000..6cdf321 --- /dev/null +++ b/db/query/payroll.sql @@ -0,0 +1,276 @@ +-- name: CreatePayrollPeriod :one +INSERT INTO payroll_periods ( + id, + company_id, + period_name, + frequency, + start_date, + end_date, + payment_date, + status, + is_recurring, + next_period_id, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @company_id, + @period_name, + @frequency, + @start_date, + @end_date, + @payment_date, + COALESCE(@status, 'draft'), + COALESCE(@is_recurring, FALSE), + @next_period_id, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetPayrollPeriodByID :one +SELECT * FROM payroll_periods WHERE id = @id; + +-- name: GetPayrollPeriodsByCompany :many +SELECT * FROM payroll_periods +WHERE company_id = @company_id +ORDER BY start_date DESC; + +-- name: GetActivePayrollPeriods :many +SELECT * FROM payroll_periods +WHERE company_id = @company_id AND status = 'active' +ORDER BY start_date DESC; + +-- name: UpdatePayrollPeriod :one +UPDATE payroll_periods SET + period_name = COALESCE(@period_name, period_name), + frequency = COALESCE(@frequency, frequency), + start_date = COALESCE(@start_date, start_date), + end_date = COALESCE(@end_date, end_date), + payment_date = COALESCE(@payment_date, payment_date), + status = COALESCE(@status, status), + is_recurring = COALESCE(@is_recurring, is_recurring), + next_period_id = COALESCE(@next_period_id, next_period_id), + updated_at = NOW() +WHERE id = @id +RETURNING *; + +-- name: CreatePayroll :one +INSERT INTO payrolls ( + id, + company_id, + period_id, + name, + description, + total_amount, + base_currency, + status, + execution_type, + scheduled_execution_time, + executed_at, + smart_contract_address, + chain_id, + transaction_hash, + created_by, + approved_by, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @company_id, + @period_id, + @name, + @description, + COALESCE(@total_amount, 0), + @base_currency, + COALESCE(@status, 'draft'), + COALESCE(@execution_type, 'manual'), + @scheduled_execution_time, + @executed_at, + @smart_contract_address, + @chain_id, + @transaction_hash, + @created_by, + @approved_by, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetPayrollByID :one +SELECT p.*, pp.period_name, pp.start_date, pp.end_date +FROM payrolls p +JOIN payroll_periods pp ON p.period_id = pp.id +WHERE p.id = @id; + +-- name: GetPayrollsByCompany :many +SELECT p.*, pp.period_name, pp.start_date, pp.end_date +FROM payrolls p +JOIN payroll_periods pp ON p.period_id = pp.id +WHERE p.company_id = @company_id +ORDER BY p.created_at DESC; + +-- name: GetPayrollsByStatus :many +SELECT p.*, pp.period_name, pp.start_date, pp.end_date +FROM payrolls p +JOIN payroll_periods pp ON p.period_id = pp.id +WHERE p.company_id = @company_id AND p.status = @status +ORDER BY p.created_at DESC; + +-- name: UpdatePayroll :one +UPDATE payrolls SET + name = COALESCE(@name, name), + description = COALESCE(@description, description), + total_amount = COALESCE(@total_amount, total_amount), + base_currency = COALESCE(@base_currency, base_currency), + status = COALESCE(@status, status), + execution_type = COALESCE(@execution_type, execution_type), + scheduled_execution_time = COALESCE(@scheduled_execution_time, scheduled_execution_time), + executed_at = COALESCE(@executed_at, executed_at), + smart_contract_address = COALESCE(@smart_contract_address, smart_contract_address), + chain_id = COALESCE(@chain_id, chain_id), + transaction_hash = COALESCE(@transaction_hash, transaction_hash), + approved_by = COALESCE(@approved_by, approved_by), + updated_at = NOW() +WHERE id = @id +RETURNING *; + +-- name: CreatePayrollItem :one +INSERT INTO payroll_items ( + id, + payroll_id, + employee_id, + base_amount, + base_currency, + payment_amount, + payment_currency, + exchange_rate, + payment_method, + payment_split, + status, + transaction_hash, + recipient_wallet_address, + recipient_bank_account_id, + notes, + timesheet_id, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @payroll_id, + @employee_id, + @base_amount, + @base_currency, + @payment_amount, + @payment_currency, + COALESCE(@exchange_rate, 1), + @payment_method, + @payment_split, + COALESCE(@status, 'pending'), + @transaction_hash, + @recipient_wallet_address, + @recipient_bank_account_id, + @notes, + @timesheet_id, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetPayrollItemByID :one +SELECT pi.*, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM payroll_items pi +JOIN company_employees ce ON pi.employee_id = ce.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE pi.id = @id; + +-- name: GetPayrollItemsByPayroll :many +SELECT pi.*, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM payroll_items pi +JOIN company_employees ce ON pi.employee_id = ce.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE pi.payroll_id = @payroll_id +ORDER BY pi.created_at; + +-- name: GetPayrollItemsByEmployee :many +SELECT pi.*, p.name as payroll_name, pp.period_name +FROM payroll_items pi +JOIN payrolls p ON pi.payroll_id = p.id +JOIN payroll_periods pp ON p.period_id = pp.id +WHERE pi.employee_id = @employee_id +ORDER BY pi.created_at DESC; + +-- name: GetUserPayrollHistory :many +SELECT pi.*, p.name as payroll_name, pp.period_name, c.company_name +FROM payroll_items pi +JOIN payrolls p ON pi.payroll_id = p.id +JOIN payroll_periods pp ON p.period_id = pp.id +JOIN companies c ON p.company_id = c.id +JOIN company_employees ce ON pi.employee_id = ce.id +WHERE ce.user_id = @user_id +ORDER BY pi.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: UpdatePayrollItem :one +UPDATE payroll_items SET + base_amount = COALESCE(@base_amount, base_amount), + base_currency = COALESCE(@base_currency, base_currency), + payment_amount = COALESCE(@payment_amount, payment_amount), + payment_currency = COALESCE(@payment_currency, payment_currency), + exchange_rate = COALESCE(@exchange_rate, exchange_rate), + payment_method = COALESCE(@payment_method, payment_method), + payment_split = COALESCE(@payment_split, payment_split), + status = COALESCE(@status, status), + transaction_hash = COALESCE(@transaction_hash, transaction_hash), + recipient_wallet_address = COALESCE(@recipient_wallet_address, recipient_wallet_address), + recipient_bank_account_id = COALESCE(@recipient_bank_account_id, recipient_bank_account_id), + notes = COALESCE(@notes, notes), + timesheet_id = COALESCE(@timesheet_id, timesheet_id), + updated_at = NOW() +WHERE id = @id +RETURNING *; + +-- name: GetPayrollApprovalQueue :many +SELECT pi.*, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name, + p.name as payroll_name +FROM payroll_items pi +JOIN company_employees ce ON pi.employee_id = ce.id +JOIN payrolls p ON pi.payroll_id = p.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE p.company_id = @company_id AND pi.status = 'pending' +ORDER BY pi.created_at; + +-- name: GetUpcomingPayments :many +SELECT pi.*, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name, + p.name as payroll_name, + pp.payment_date +FROM payroll_items pi +JOIN company_employees ce ON pi.employee_id = ce.id +JOIN payrolls p ON pi.payroll_id = p.id +JOIN payroll_periods pp ON p.period_id = pp.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE ce.user_id = @user_id + AND pi.status IN ('approved', 'processing') + AND pp.payment_date >= CURRENT_DATE +ORDER BY pp.payment_date; \ No newline at end of file diff --git a/db/query/security_events.sql b/db/query/security_events.sql deleted file mode 100644 index 2f0050f..0000000 --- a/db/query/security_events.sql +++ /dev/null @@ -1,20 +0,0 @@ --- name: CreateSecurityEvent :one -INSERT INTO security_events ( - id, user_id, event_type, ip_address, user_agent, metadata, timestamp -) VALUES ( - $1, $2, $3, $4, $5, $6, $7 -) -RETURNING *; - --- name: GetRecentLoginEventsByUserID :many -SELECT * FROM security_events -WHERE user_id = $1 AND event_type = 'login' -ORDER BY timestamp DESC -LIMIT $2; - --- name: GetSecurityEventsByUserIDAndType :many -SELECT * FROM security_events -WHERE user_id = $1 - AND event_type = $2 - AND timestamp BETWEEN $3 AND $4 -ORDER BY timestamp DESC; diff --git a/db/query/sessions.sql b/db/query/sessions.sql deleted file mode 100644 index a0523fa..0000000 --- a/db/query/sessions.sql +++ /dev/null @@ -1,126 +0,0 @@ --- name: CreateSession :one --- Creates a new session and returns the created session record -INSERT INTO sessions ( - id, - user_id, - refresh_token, - user_agent, - web_oauth_client_id, - oauth_access_token, - oauth_id_token, - user_login_type, - last_used_at, - mfa_enabled, - client_ip, - is_blocked, - expires_at, - created_at -) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, COALESCE($14, now()) -) RETURNING *; - --- name: GetSessionByID :one --- Retrieves a session by its ID -SELECT * FROM sessions -WHERE id = $1 -LIMIT 1; - --- name: GetSessionByRefreshToken :one --- Retrieves a session by refresh token -SELECT * FROM sessions -WHERE refresh_token = $1 -LIMIT 1; - --- name: GetSessionsByUserID :many --- Retrieves all sessions for a specific user -SELECT * FROM sessions -WHERE user_id = $1 -ORDER BY created_at DESC; - --- name: GetActiveSessions :many --- Retrieves active (non-expired, non-blocked) sessions with pagination -SELECT * FROM sessions -WHERE is_blocked = false AND expires_at > now() -ORDER BY created_at DESC -LIMIT $1 -OFFSET $2; - --- name: GetActiveSessionsByUserID :many --- Retrieves active sessions for a specific user -SELECT * FROM sessions -WHERE user_id = $1 AND is_blocked = false AND expires_at > now() -ORDER BY created_at DESC; - --- name: UpdateSession :one --- Updates session details -UPDATE sessions -SET - user_agent = COALESCE($2, user_agent), - web_oauth_client_id = $3, - oauth_access_token = $4, - oauth_id_token = $5, - mfa_enabled = COALESCE($6, mfa_enabled), - client_ip = COALESCE($7, client_ip), - is_blocked = COALESCE($8, is_blocked), - expires_at = COALESCE($9, expires_at), - last_used_at = COALESCE($10, last_used_at) -WHERE id = $1 -RETURNING *; - --- name: UpdateRefreshToken :one --- Updates just the refresh token of a session -UPDATE sessions -SET refresh_token = $2 -WHERE id = $1 -RETURNING *; - --- name: BlockSession :exec --- Blocks a session (marks it as invalid) -UPDATE sessions -SET is_blocked = true -WHERE id = $1; - --- name: BlockAllUserSessions :exec --- Blocks all sessions for a specific user -UPDATE sessions -SET is_blocked = true -WHERE user_id = $1; - --- name: BlockExpiredSessions :exec --- Blocks all expired sessions -UPDATE sessions -SET is_blocked = true -WHERE expires_at <= now() AND is_blocked = false; - --- name: DeleteSession :exec --- Deletes a session by its ID -DELETE FROM sessions -WHERE id = $1; - --- name: DeleteSessionsByUserID :exec --- Deletes all sessions for a specific user -DELETE FROM sessions -WHERE user_id = $1; - --- name: DeleteExpiredSessions :exec --- Cleans up expired sessions that are older than the specified date -DELETE FROM sessions -WHERE expires_at < $1; - --- name: CountActiveSessions :one --- Counts the number of active sessions -SELECT COUNT(*) FROM sessions -WHERE is_blocked = false AND expires_at > now(); - --- name: CountActiveSessionsByUserID :one --- Counts the number of active sessions for a specific user -SELECT COUNT(*) FROM sessions -WHERE user_id = $1 AND is_blocked = false AND expires_at > now(); - --- name: UpdateSessionRefreshToken :one -UPDATE sessions -SET - refresh_token = $2, - last_used_at = $3 -WHERE id = $1 -RETURNING *; \ No newline at end of file diff --git a/db/query/settings.sql b/db/query/settings.sql new file mode 100644 index 0000000..872cd68 --- /dev/null +++ b/db/query/settings.sql @@ -0,0 +1,237 @@ +-- name: CreateSystemSetting :one +INSERT INTO system_settings ( + id, + setting_key, + setting_value, + data_type, + description, + is_sensitive, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @setting_key, + @setting_value, + COALESCE(@data_type, 'string'), + @description, + COALESCE(@is_sensitive, FALSE), + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetSystemSetting :one +SELECT * FROM system_settings +WHERE setting_key = @setting_key; + +-- name: GetAllSystemSettings :many +SELECT * FROM system_settings +ORDER BY setting_key; + +-- name: GetPublicSystemSettings :many +SELECT setting_key, setting_value, data_type, description +FROM system_settings +WHERE is_sensitive = FALSE +ORDER BY setting_key; + +-- name: UpdateSystemSetting :one +UPDATE system_settings SET + setting_value = @setting_value, + data_type = COALESCE(@data_type, data_type), + description = COALESCE(@description, description), + is_sensitive = COALESCE(@is_sensitive, is_sensitive), + updated_at = NOW() +WHERE setting_key = @setting_key +RETURNING *; + +-- name: DeleteSystemSetting :exec +DELETE FROM system_settings WHERE setting_key = @setting_key; + +-- name: CreateCompanySetting :one +INSERT INTO company_settings ( + id, + company_id, + setting_key, + setting_value, + data_type, + description, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @company_id, + @setting_key, + @setting_value, + COALESCE(@data_type, 'string'), + @description, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetCompanySetting :one +SELECT * FROM company_settings +WHERE company_id = @company_id AND setting_key = @setting_key; + +-- name: GetCompanySettings :many +SELECT * FROM company_settings +WHERE company_id = @company_id +ORDER BY setting_key; + +-- name: UpdateCompanySetting :one +UPDATE company_settings SET + setting_value = @setting_value, + data_type = COALESCE(@data_type, data_type), + description = COALESCE(@description, description), + updated_at = NOW() +WHERE company_id = @company_id AND setting_key = @setting_key +RETURNING *; + +-- name: DeleteCompanySetting :exec +DELETE FROM company_settings +WHERE company_id = @company_id AND setting_key = @setting_key; + +-- name: CreateUserSetting :one +INSERT INTO user_settings ( + id, + user_id, + setting_key, + setting_value, + data_type, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @user_id, + @setting_key, + @setting_value, + COALESCE(@data_type, 'string'), + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetUserSetting :one +SELECT * FROM user_settings +WHERE user_id = @user_id AND setting_key = @setting_key; + +-- name: GetUserSettings :many +SELECT * FROM user_settings +WHERE user_id = @user_id +ORDER BY setting_key; + +-- name: UpdateUserSetting :one +UPDATE user_settings SET + setting_value = @setting_value, + data_type = COALESCE(@data_type, data_type), + updated_at = NOW() +WHERE user_id = @user_id AND setting_key = @setting_key +RETURNING *; + +-- name: DeleteUserSetting :exec +DELETE FROM user_settings +WHERE user_id = @user_id AND setting_key = @setting_key; + +-- name: CreateFeatureFlag :one +INSERT INTO feature_flags ( + id, + flag_key, + description, + is_enabled, + rollout_percentage, + conditions, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @flag_key, + @description, + COALESCE(@is_enabled, FALSE), + COALESCE(@rollout_percentage, 0), + @conditions, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetFeatureFlag :one +SELECT * FROM feature_flags WHERE flag_key = @flag_key; + +-- name: GetAllFeatureFlags :many +SELECT * FROM feature_flags ORDER BY flag_key; + +-- name: UpdateFeatureFlag :one +UPDATE feature_flags SET + description = COALESCE(@description, description), + is_enabled = COALESCE(@is_enabled, is_enabled), + rollout_percentage = COALESCE(@rollout_percentage, rollout_percentage), + conditions = COALESCE(@conditions, conditions), + updated_at = NOW() +WHERE flag_key = @flag_key +RETURNING *; + +-- name: CreateUserFeatureFlag :one +INSERT INTO user_feature_flags ( + id, + user_id, + flag_key, + is_enabled, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @user_id, + @flag_key, + @is_enabled, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetUserFeatureFlag :one +SELECT * FROM user_feature_flags +WHERE user_id = @user_id AND flag_key = @flag_key; + +-- name: GetUserFeatureFlags :many +SELECT uff.*, ff.description +FROM user_feature_flags uff +JOIN feature_flags ff ON uff.flag_key = ff.flag_key +WHERE uff.user_id = @user_id +ORDER BY uff.flag_key; + +-- name: UpdateUserFeatureFlag :one +UPDATE user_feature_flags SET + is_enabled = @is_enabled, + updated_at = NOW() +WHERE user_id = @user_id AND flag_key = @flag_key +RETURNING *; + +-- name: CreateCompanyFeatureFlag :one +INSERT INTO company_feature_flags ( + id, + company_id, + flag_key, + is_enabled, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @company_id, + @flag_key, + @is_enabled, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetCompanyFeatureFlag :one +SELECT * FROM company_feature_flags +WHERE company_id = @company_id AND flag_key = @flag_key; + +-- name: GetCompanyFeatureFlags :many +SELECT cff.*, ff.description +FROM company_feature_flags cff +JOIN feature_flags ff ON cff.flag_key = ff.flag_key +WHERE cff.company_id = @company_id +ORDER BY cff.flag_key; + +-- name: UpdateCompanyFeatureFlag :one +UPDATE company_feature_flags SET + is_enabled = @is_enabled, + updated_at = NOW() +WHERE company_id = @company_id AND flag_key = @flag_key +RETURNING *; \ No newline at end of file diff --git a/db/query/timesheets.sql b/db/query/timesheets.sql new file mode 100644 index 0000000..f6da4b8 --- /dev/null +++ b/db/query/timesheets.sql @@ -0,0 +1,219 @@ +-- name: CreateTimesheet :one +INSERT INTO timesheets ( + id, + company_id, + employee_id, + period_id, + status, + total_hours, + billable_hours, + overtime_hours, + hourly_rate, + rate_currency, + total_amount, + submitted_at, + approved_at, + approved_by, + rejection_reason, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @company_id, + @employee_id, + @period_id, + COALESCE(@status, 'draft'), + COALESCE(@total_hours, 0), + COALESCE(@billable_hours, 0), + COALESCE(@overtime_hours, 0), + @hourly_rate, + @rate_currency, + COALESCE(@total_amount, 0), + @submitted_at, + @approved_at, + @approved_by, + @rejection_reason, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetTimesheetByID :one +SELECT t.*, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name, + pp.period_name, pp.start_date, pp.end_date +FROM timesheets t +JOIN company_employees ce ON t.employee_id = ce.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +LEFT JOIN payroll_periods pp ON t.period_id = pp.id +WHERE t.id = @id; + +-- name: GetTimesheetsByEmployee :many +SELECT t.*, + pp.period_name, pp.start_date, pp.end_date +FROM timesheets t +LEFT JOIN payroll_periods pp ON t.period_id = pp.id +WHERE t.employee_id = @employee_id +ORDER BY t.created_at DESC; + +-- name: GetUserTimesheets :many +SELECT t.*, + ce.employee_id, + c.company_name, + pp.period_name, pp.start_date, pp.end_date +FROM timesheets t +JOIN company_employees ce ON t.employee_id = ce.id +JOIN companies c ON t.company_id = c.id +LEFT JOIN payroll_periods pp ON t.period_id = pp.id +WHERE ce.user_id = @user_id +ORDER BY t.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetCompanyTimesheets :many +SELECT t.*, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name, + pp.period_name, pp.start_date, pp.end_date +FROM timesheets t +JOIN company_employees ce ON t.employee_id = ce.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +LEFT JOIN payroll_periods pp ON t.period_id = pp.id +WHERE t.company_id = @company_id +ORDER BY t.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetTimesheetsByStatus :many +SELECT t.*, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name, + pp.period_name, pp.start_date, pp.end_date +FROM timesheets t +JOIN company_employees ce ON t.employee_id = ce.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +LEFT JOIN payroll_periods pp ON t.period_id = pp.id +WHERE t.company_id = @company_id AND t.status = @status +ORDER BY t.created_at DESC; + +-- name: UpdateTimesheet :one +UPDATE timesheets SET + period_id = COALESCE(@period_id, period_id), + status = COALESCE(@status, status), + total_hours = COALESCE(@total_hours, total_hours), + billable_hours = COALESCE(@billable_hours, billable_hours), + overtime_hours = COALESCE(@overtime_hours, overtime_hours), + hourly_rate = COALESCE(@hourly_rate, hourly_rate), + rate_currency = COALESCE(@rate_currency, rate_currency), + total_amount = COALESCE(@total_amount, total_amount), + submitted_at = COALESCE(@submitted_at, submitted_at), + approved_at = COALESCE(@approved_at, approved_at), + approved_by = COALESCE(@approved_by, approved_by), + rejection_reason = COALESCE(@rejection_reason, rejection_reason), + updated_at = NOW() +WHERE id = @id +RETURNING *; + +-- name: CreateTimesheetEntry :one +INSERT INTO timesheet_entries ( + id, + timesheet_id, + date, + start_time, + end_time, + hours, + is_billable, + is_overtime, + project, + task, + description, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @timesheet_id, + @date, + @start_time, + @end_time, + @hours, + COALESCE(@is_billable, TRUE), + COALESCE(@is_overtime, FALSE), + @project, + @task, + @description, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetTimesheetEntries :many +SELECT * FROM timesheet_entries +WHERE timesheet_id = @timesheet_id +ORDER BY date, start_time; + +-- name: GetTimesheetEntriesByDate :many +SELECT * FROM timesheet_entries +WHERE timesheet_id = @timesheet_id + AND date >= @start_date + AND date <= @end_date +ORDER BY date, start_time; + +-- name: UpdateTimesheetEntry :one +UPDATE timesheet_entries SET + date = COALESCE(@date, date), + start_time = COALESCE(@start_time, start_time), + end_time = COALESCE(@end_time, end_time), + hours = COALESCE(@hours, hours), + is_billable = COALESCE(@is_billable, is_billable), + is_overtime = COALESCE(@is_overtime, is_overtime), + project = COALESCE(@project, project), + task = COALESCE(@task, task), + description = COALESCE(@description, description), + updated_at = NOW() +WHERE id = @id +RETURNING *; + +-- name: DeleteTimesheetEntry :exec +DELETE FROM timesheet_entries WHERE id = @id; + +-- name: GetTimesheetProjects :many +SELECT DISTINCT project +FROM timesheet_entries +WHERE timesheet_id IN ( + SELECT id FROM timesheets WHERE company_id = @company_id +) +AND project IS NOT NULL +ORDER BY project; + +-- name: GetEmployeeTimesheetSummary :one +SELECT + COUNT(*) as total_timesheets, + SUM(total_hours) as total_hours, + SUM(billable_hours) as total_billable_hours, + SUM(overtime_hours) as total_overtime_hours, + SUM(total_amount) as total_amount +FROM timesheets +WHERE employee_id = @employee_id + AND (@start_date::date IS NULL OR created_at >= @start_date) + AND (@end_date::date IS NULL OR created_at <= @end_date); + +-- name: GetCompanyTimesheetSummary :one +SELECT + COUNT(*) as total_timesheets, + SUM(total_hours) as total_hours, + SUM(billable_hours) as total_billable_hours, + SUM(overtime_hours) as total_overtime_hours, + SUM(total_amount) as total_amount +FROM timesheets +WHERE company_id = @company_id + AND (@start_date::date IS NULL OR created_at >= @start_date) + AND (@end_date::date IS NULL OR created_at <= @end_date); \ No newline at end of file diff --git a/db/query/transactions.sql b/db/query/transactions.sql index 2258fc8..27a57b8 100644 --- a/db/query/transactions.sql +++ b/db/query/transactions.sql @@ -1,60 +1,232 @@ --- name: GetTransactionByID :one --- Retrieves a single transaction by its ID -SELECT * FROM transactions -WHERE id = $1 -LIMIT 1; +-- name: CreateWalletTransaction :one +INSERT INTO wallet_transactions ( + id, + wallet_address, + transaction_hash, + chain_id, + block_number, + from_address, + to_address, + token_address, + token_symbol, + amount, + transaction_type, + transaction_status, + gas_price, + gas_used, + transaction_fee, + reference_type, + reference_id, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @wallet_address, + @transaction_hash, + @chain_id, + @block_number, + @from_address, + @to_address, + @token_address, + @token_symbol, + @amount, + @transaction_type, + COALESCE(@transaction_status, 'pending'), + @gas_price, + @gas_used, + @transaction_fee, + @reference_type, + @reference_id, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; --- name: GetTransactionByTxHash :one --- Retrieves a single transaction by its transaction hash -SELECT * FROM transactions -WHERE tx_hash = $1 -LIMIT 1; +-- name: GetWalletTransactionByHash :one +SELECT wt.*, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +WHERE wt.transaction_hash = @transaction_hash; + +-- name: GetWalletTransactionsByAddress :many +SELECT wt.*, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +WHERE wt.wallet_address = @wallet_address +ORDER BY wt.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetWalletTransactionsByNetwork :many +SELECT wt.*, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +WHERE wt.chain_id = @chain_id + AND (@wallet_address::text IS NULL OR wt.wallet_address = @wallet_address) +ORDER BY wt.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetUserTransactions :many +SELECT wt.*, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +JOIN user_wallets uw ON wt.wallet_address = uw.wallet_address AND wt.chain_id = uw.chain_id +WHERE uw.user_id = @user_id +ORDER BY wt.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetCompanyTransactions :many +SELECT wt.*, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +JOIN company_wallets cw ON wt.wallet_address = cw.wallet_address AND wt.chain_id = cw.chain_id +WHERE cw.company_id = @company_id +ORDER BY wt.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetTransactionsByToken :many +SELECT wt.*, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +WHERE wt.token_symbol = @token_symbol + AND (@user_id::uuid IS NULL OR wt.wallet_address IN ( + SELECT wallet_address FROM user_wallets WHERE user_id = @user_id + )) +ORDER BY wt.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetPendingTransactions :many +SELECT wt.*, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +WHERE wt.transaction_status = 'pending' + AND (@user_id::uuid IS NULL OR wt.wallet_address IN ( + SELECT wallet_address FROM user_wallets WHERE user_id = @user_id + )) +ORDER BY wt.created_at DESC; --- name: GetTransactionsByUserID :many --- Retrieves all transactions for a specific user -SELECT * FROM transactions -WHERE user_id = $1 -ORDER BY created_at DESC; - --- name: GetTransactionsByStatus :many --- Retrieves transactions by status -SELECT * FROM transactions -WHERE status = $1 -ORDER BY created_at DESC -LIMIT $2 -OFFSET $3; - --- name: GetTransactionsByUserIDAndStatus :many --- Retrieves transactions for a specific user with a specific status -SELECT * FROM transactions -WHERE user_id = $1 AND status = $2 -ORDER BY created_at DESC; - --- name: UpdateTransactionStatus :one --- Updates the status of a transaction and returns the updated transaction -UPDATE transactions -SET - status = $2, - updated_at = now() -WHERE id = $1 +-- name: UpdateWalletTransaction :one +UPDATE wallet_transactions SET + block_number = COALESCE(@block_number, block_number), + transaction_status = COALESCE(@transaction_status, transaction_status), + gas_price = COALESCE(@gas_price, gas_price), + gas_used = COALESCE(@gas_used, gas_used), + transaction_fee = COALESCE(@transaction_fee, transaction_fee), + updated_at = NOW() +WHERE transaction_hash = @transaction_hash RETURNING *; --- name: UpdateTransaction :one --- Updates transaction details and returns the updated transaction -UPDATE transactions -SET - status = COALESCE($2, status), - transaction_pin_hash = COALESCE($3, transaction_pin_hash), - updated_at = now() -WHERE id = $1 +-- name: CreateFiatTransaction :one +INSERT INTO fiat_transactions ( + id, + bank_account_id, + transaction_reference, + transaction_type, + amount, + currency, + status, + payment_provider, + payment_method, + provider_reference, + provider_fee, + reference_type, + reference_id, + metadata, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @bank_account_id, + @transaction_reference, + @transaction_type, + @amount, + @currency, + COALESCE(@status, 'pending'), + @payment_provider, + @payment_method, + @provider_reference, + COALESCE(@provider_fee, 0), + @reference_type, + @reference_id, + @metadata, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetFiatTransactionByReference :one +SELECT ft.*, ba.account_holder_name, ba.bank_name +FROM fiat_transactions ft +JOIN bank_accounts ba ON ft.bank_account_id = ba.id +WHERE ft.transaction_reference = @transaction_reference; + +-- name: GetFiatTransactionsByBankAccount :many +SELECT ft.*, ba.account_holder_name, ba.bank_name +FROM fiat_transactions ft +JOIN bank_accounts ba ON ft.bank_account_id = ba.id +WHERE ft.bank_account_id = @bank_account_id +ORDER BY ft.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetUserFiatTransactions :many +SELECT ft.*, ba.account_holder_name, ba.bank_name +FROM fiat_transactions ft +JOIN bank_accounts ba ON ft.bank_account_id = ba.id +WHERE ba.user_id = @user_id +ORDER BY ft.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetCompanyFiatTransactions :many +SELECT ft.*, ba.account_holder_name, ba.bank_name +FROM fiat_transactions ft +JOIN bank_accounts ba ON ft.bank_account_id = ba.id +WHERE ba.company_id = @company_id +ORDER BY ft.created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: UpdateFiatTransaction :one +UPDATE fiat_transactions SET + status = COALESCE(@status, status), + payment_provider = COALESCE(@payment_provider, payment_provider), + payment_method = COALESCE(@payment_method, payment_method), + provider_reference = COALESCE(@provider_reference, provider_reference), + provider_fee = COALESCE(@provider_fee, provider_fee), + metadata = COALESCE(@metadata, metadata), + updated_at = NOW() +WHERE transaction_reference = @transaction_reference RETURNING *; --- name: DeleteTransaction :exec --- Permanently deletes a transaction record -DELETE FROM transactions -WHERE id = $1; +-- name: CreateExchangeRate :one +INSERT INTO exchange_rates ( + id, + base_currency, + quote_currency, + rate, + source, + timestamp, + created_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @base_currency, + @quote_currency, + @rate, + @source, + @timestamp, + COALESCE(@created_at, NOW()) +) RETURNING *; + +-- name: GetLatestExchangeRate :one +SELECT * FROM exchange_rates +WHERE base_currency = @base_currency AND quote_currency = @quote_currency +ORDER BY timestamp DESC +LIMIT 1; + +-- name: GetExchangeRateHistory :many +SELECT * FROM exchange_rates +WHERE base_currency = @base_currency + AND quote_currency = @quote_currency + AND timestamp >= @start_time + AND timestamp <= @end_time +ORDER BY timestamp DESC; --- name: DeleteTransactionsByUserID :exec --- Deletes all transactions for a specific user -DELETE FROM transactions -WHERE user_id = $1; \ No newline at end of file +-- name: GetAllLatestExchangeRates :many +SELECT DISTINCT ON (base_currency, quote_currency) * +FROM exchange_rates +ORDER BY base_currency, quote_currency, timestamp DESC; \ No newline at end of file diff --git a/db/query/user_device.sql b/db/query/user_device.sql deleted file mode 100644 index 64450ac..0000000 --- a/db/query/user_device.sql +++ /dev/null @@ -1,167 +0,0 @@ --- name: CreateUserDeviceToken :one -INSERT INTO user_device_tokens ( - id, - user_id, - device_token, - platform, - device_type, - device_model, - os_name, - os_version, - push_notification_token, - is_active, - is_verified, - app_version, - client_ip, - expires_at -) VALUES ( - $1, - $2, - $3, - COALESCE($4, 'unknown'), - COALESCE($5, 'unknown'), - COALESCE($6, 'unknown'), - COALESCE($7, 'unknown'), - COALESCE($8, 'unknown'), - $9, - COALESCE($10, true), - COALESCE($11, false), - $12, - $13, - $14 -) RETURNING *; - --- name: UpsertUserDeviceToken :one -INSERT INTO user_device_tokens ( - id, - user_id, - device_token, - platform, - device_type, - device_model, - os_name, - os_version, - push_notification_token, - is_active, - is_verified, - app_version, - client_ip, - expires_at -) VALUES ( - $1, - $2, - $3, - COALESCE($4, 'unknown'), - COALESCE($5, 'unknown'), - COALESCE($6, 'unknown'), - COALESCE($7, 'unknown'), - COALESCE($8, 'unknown'), - $9, - COALESCE($10, true), - COALESCE($11, false), - $12, - $13, - $14 -) ON CONFLICT (device_token) DO UPDATE SET - platform = COALESCE(EXCLUDED.platform, user_device_tokens.platform), - device_type = COALESCE(EXCLUDED.device_type, user_device_tokens.device_type), - device_model = COALESCE(EXCLUDED.device_model, user_device_tokens.device_model), - os_name = COALESCE(EXCLUDED.os_name, user_device_tokens.os_name), - os_version = COALESCE(EXCLUDED.os_version, user_device_tokens.os_version), - push_notification_token = COALESCE(EXCLUDED.push_notification_token, user_device_tokens.push_notification_token), - is_active = COALESCE(EXCLUDED.is_active, user_device_tokens.is_active), - is_verified = COALESCE(EXCLUDED.is_verified, user_device_tokens.is_verified), - app_version = COALESCE(EXCLUDED.app_version, user_device_tokens.app_version), - client_ip = COALESCE(EXCLUDED.client_ip, user_device_tokens.client_ip), - expires_at = COALESCE(EXCLUDED.expires_at, user_device_tokens.expires_at), - last_used_at = NOW() -RETURNING *; - --- name: GetUserDeviceTokenByID :one -SELECT * FROM user_device_tokens -WHERE id = $1; - --- name: GetUserDeviceTokenByDeviceToken :one -SELECT * FROM user_device_tokens -WHERE device_token = $1; - --- name: GetActiveDeviceTokensForUser :many -SELECT * FROM user_device_tokens -WHERE user_id = $1 - AND is_active = true - AND (expires_at IS NULL OR expires_at > NOW()) -ORDER BY first_registered_at DESC; - --- name: UpdateDeviceTokenDetails :one -UPDATE user_device_tokens -SET - platform = COALESCE($2, platform), - device_type = COALESCE($3, device_type), - device_model = COALESCE($4, device_model), - os_name = COALESCE($5, os_name), - os_version = COALESCE($6, os_version), - app_version = COALESCE($7, app_version), - client_ip = COALESCE($8, client_ip), - last_used_at = NOW(), - is_verified = COALESCE($9, is_verified) -WHERE id = $1 -RETURNING *; - --- name: UpdateDeviceTokenLastUsed :one -UPDATE user_device_tokens -SET - last_used_at = NOW(), - client_ip = COALESCE($2, client_ip) -WHERE id = $1 -RETURNING *; - --- name: RevokeDeviceToken :one -UPDATE user_device_tokens -SET - is_active = false, - is_revoked = true -WHERE id = $1 -RETURNING *; - --- name: DeleteExpiredDeviceTokens :exec -DELETE FROM user_device_tokens -WHERE - expires_at < NOW() - AND is_active = false; - --- name: CountActiveDeviceTokensForUser :one -SELECT COUNT(*) -FROM user_device_tokens -WHERE - user_id = $1 - AND is_active = true - AND (expires_at IS NULL OR expires_at > NOW()); - --- name: UpdateDeviceTokenPushNotificationToken :one -UPDATE user_device_tokens -SET - push_notification_token = $2, - is_verified = true -WHERE id = $1 -RETURNING *; - --- name: GetDeviceTokensByPlatform :many -SELECT * FROM user_device_tokens -WHERE - user_id = $1 - AND platform = $2 - AND is_active = true - AND (expires_at IS NULL OR expires_at > NOW()) -ORDER BY first_registered_at DESC; - --- name: SearchDeviceTokens :many -SELECT * FROM user_device_tokens -WHERE - user_id = $1 - AND ( - COALESCE(device_type, '') ILIKE '%' || $2 || '%' - OR COALESCE(device_model, '') ILIKE '%' || $2 || '%' - OR platform ILIKE '%' || $2 || '%' - ) -ORDER BY first_registered_at DESC -LIMIT $3 OFFSET $4; \ No newline at end of file diff --git a/db/query/user_wallets.sql b/db/query/user_wallets.sql deleted file mode 100644 index ae1c837..0000000 --- a/db/query/user_wallets.sql +++ /dev/null @@ -1,22 +0,0 @@ --- name: CreateUserWallet :one -INSERT INTO user_wallets ( - id, user_id, address, type, chain, is_default, created_at, updated_at -) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8 -) -RETURNING *; - --- name: GetWalletByAddress :one -SELECT * FROM user_wallets WHERE address = $1; - --- name: GetWalletsByUserID :many -SELECT * FROM user_wallets WHERE user_id = $1; - --- name: UpdateUserWallet :one -UPDATE user_wallets -SET is_default = $2, updated_at = $3 -WHERE id = $1 -RETURNING *; - --- name: DeleteUserWallet :exec -DELETE FROM user_wallets WHERE id = $1; diff --git a/db/query/users.sql b/db/query/users.sql index 13dbf5c..0e29e72 100644 --- a/db/query/users.sql +++ b/db/query/users.sql @@ -1,252 +1,181 @@ -- name: CreateUser :one --- Creates a new user record and returns the created user INSERT INTO users ( id, email, password_hash, - profile_picture, - account_type, - gender, - personal_account_type, - first_name, - last_name, - nationality, - residential_country, - job_role, - company_name, - company_size, - company_industry, - company_description, - company_headquarters, auth_provider, provider_id, - employee_type, - company_website, - employment_type, - user_address, - user_city, - user_postal_code, + email_verified, + email_verified_at, + account_type, + account_status, + two_factor_enabled, + two_factor_method, + user_login_type, created_at, - updated_at + updated_at, + last_login_at, + deleted_at ) VALUES ( COALESCE(@id, uuid_generate_v4()), @email, @password_hash, - COALESCE(@profile_picture, ''), - @account_type, - @gender, - @personal_account_type, - @first_name, - @last_name, - @nationality, - @residential_country, - @job_role, - COALESCE(@company_name, ''), - COALESCE(@company_size, ''), - COALESCE(@company_industry, ''), - COALESCE(@company_description, ''), - COALESCE(@company_headquarters, ''), @auth_provider, @provider_id, - @employee_type, - COALESCE(@company_website, ''), - COALESCE(@employment_type, ''), - COALESCE(@user_address, ''), - COALESCE(@user_city, ''), - COALESCE(@user_postal_code, ''), - COALESCE(@created_at, now()), - COALESCE(@updated_at, now()) + COALESCE(@email_verified, FALSE), + @email_verified_at, + @account_type, + COALESCE(@account_status, 'pending'), + COALESCE(@two_factor_enabled, FALSE), + @two_factor_method, + @user_login_type, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()), + @last_login_at, + @deleted_at ) RETURNING *; --- name: GetUser :one -SELECT * FROM users WHERE id = $1::uuid LIMIT 1; +-- name: GetUserByID :one +SELECT * FROM users +WHERE id = @id AND deleted_at IS NULL; -- name: GetUserByEmail :one --- Retrieves a single user by their email address -SELECT * FROM users -WHERE email = $1 -LIMIT 1; - --- name: CheckEmailExists :one -SELECT EXISTS ( - SELECT 1 - FROM users - WHERE - email = $1 - LIMIT 1 - ) AS exists; - --- name: ListUsers :many --- Lists users with pagination support -SELECT * -FROM users -ORDER BY - CASE WHEN $3::text = 'ASC' THEN created_at END ASC, - CASE WHEN $3::text = 'DESC' OR $3::text IS NULL THEN created_at END DESC -LIMIT $1 -OFFSET $2; - --- name: ListUsersByAccountType :many --- Lists users filtered by account type with pagination -SELECT * -FROM users -WHERE account_type = $3 -ORDER BY - CASE WHEN $4::text = 'ASC' THEN created_at END ASC, - CASE WHEN $4::text = 'DESC' OR $4::text IS NULL THEN created_at END DESC -LIMIT $1 -OFFSET $2; - --- name: CountUsers :one --- Counts the total number of users (useful for pagination) -SELECT COUNT(*) FROM users; - --- name: CountUsersByAccountType :one --- Counts users filtered by account type -SELECT COUNT(*) FROM users -WHERE account_type = $1; - - +SELECT * FROM users +WHERE email = @email AND deleted_at IS NULL; -- name: UpdateUser :one --- Updates user details and returns the updated user -UPDATE users -SET - email = COALESCE($2, email), - profile_picture = $3, - account_type = COALESCE($4, account_type), - gender = $5, - personal_account_type = COALESCE($6, personal_account_type), - first_name = COALESCE($7, first_name), - last_name = COALESCE($8, last_name), - nationality = COALESCE($9, nationality), - residential_country = $10, - job_role = $11, - company_website = $12, - employment_type = $13, - company_name = $14, - company_headquarters = $15, - company_size = $16, - company_description = $17, - company_industry = $18, - auth_provider = COALESCE($19, auth_provider), - provider_id = COALESCE($20, provider_id), - user_address = COALESCE($21, user_address), - user_city = COALESCE($22, user_city), - user_postal_code = COALESCE($23, user_postal_code), - updated_at = now() -WHERE id = $1 -RETURNING *; - - --- name: UpdateUserProfile :one --- Updates a user's profile information -UPDATE users -SET - profile_picture = COALESCE($2, profile_picture), - first_name = COALESCE($3, first_name), - last_name = COALESCE($4, last_name) -WHERE id = $1 -RETURNING *; - --- name: UpdateUserPersonalDetails :one --- Updates a user's personal details -UPDATE users -SET - nationality = COALESCE($2, nationality), - phone_number = COALESCE($3, phone_number), - residential_country = COALESCE($4, residential_country), - account_type = COALESCE($5, account_type), - personal_account_type = COALESCE($6, personal_account_type), - updated_at = now() - WHERE id = $1 - RETURNING *; - - --- name: UpdateUserAddress :one --- Updates a user's address -UPDATE users -SET - user_address = COALESCE($2, user_address), - user_city = COALESCE($3, user_city), - user_postal_code = COALESCE($4, user_postal_code), - updated_at = now() -WHERE id = $1 -RETURNING *; - --- name: UpdateUserCompanyDetails :one --- Updates a user's company details -UPDATE users -SET - company_name = COALESCE($2, company_name), - company_headquarters = COALESCE($3, company_headquarters), - company_size = COALESCE($4, company_size), - company_industry = COALESCE($5, company_industry), - company_description = COALESCE($6, company_description), - company_headquarters = COALESCE($7, company_headquarters), - account_type = COALESCE($8, account_type), - updated_at = now() -WHERE id = $1 +UPDATE users SET + password_hash = COALESCE(@password_hash, password_hash), + auth_provider = COALESCE(@auth_provider, auth_provider), + provider_id = COALESCE(@provider_id, provider_id), + email_verified = COALESCE(@email_verified, email_verified), + email_verified_at = COALESCE(@email_verified_at, email_verified_at), + account_status = COALESCE(@account_status, account_status), + two_factor_enabled = COALESCE(@two_factor_enabled, two_factor_enabled), + two_factor_method = COALESCE(@two_factor_method, two_factor_method), + last_login_at = COALESCE(@last_login_at, last_login_at), + updated_at = NOW() +WHERE id = @id AND deleted_at IS NULL RETURNING *; +-- name: UpdateUserLoginTime :exec +UPDATE users SET + last_login_at = NOW(), + updated_at = NOW() +WHERE id = @id; --- name: UpdateUserJobRole :one --- Updates a user's job role -UPDATE users -SET - job_role = COALESCE($2, job_role), - updated_at = now() -WHERE id = $1 -RETURNING *; - - --- name: UpdateUserPassword :exec --- Updates a user's password -UPDATE users -SET - password_hash = $2, - updated_at = now() -WHERE id = $1; - --- name: UpdateUserEmail :one --- Updates a user's email address with validation that the new email is unique -UPDATE users -SET - email = $2, - updated_at = now() -WHERE id = $1 -RETURNING *; - --- name: DeleteUser :exec --- Permanently deletes a user record -DELETE FROM users -WHERE id = $1; +-- name: SoftDeleteUser :exec +UPDATE users SET + deleted_at = NOW(), + updated_at = NOW() +WHERE id = @id; --- name: SearchUsers :many --- Searches for users by name, email, or nationality with pagination -SELECT * -FROM users -WHERE - ( - first_name ILIKE '%' || $3 || '%' OR - last_name ILIKE '%' || $3 || '%' OR - email ILIKE '%' || $3 || '%' OR - nationality ILIKE '%' || $3 || '%' - ) -ORDER BY - CASE WHEN $4::text = 'ASC' THEN created_at END ASC, - CASE WHEN $4::text = 'DESC' OR $4::text IS NULL THEN created_at END DESC -LIMIT $1 -OFFSET $2; +-- name: ListUsers :many +SELECT * FROM users +WHERE deleted_at IS NULL +ORDER BY created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: SearchUsersByEmail :many +SELECT * FROM users +WHERE email ILIKE '%' || @search_term || '%' + AND deleted_at IS NULL +ORDER BY email +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetUsersByAccountType :many +SELECT * FROM users +WHERE account_type = @account_type AND deleted_at IS NULL +ORDER BY created_at DESC +LIMIT @limit_val OFFSET @offset_val; + +-- name: CreatePersonalUser :one +INSERT INTO personal_users ( + id, + first_name, + last_name, + profile_picture, + phone_number, + phone_number_verified, + phone_number_verified_at, + nationality, + residential_country, + user_address, + user_city, + user_postal_code, + gender, + date_of_birth, + job_role, + personal_account_type, + employment_type, + tax_id, + default_payment_currency, + default_payment_method, + hourly_rate, + specialization, + kyc_status, + kyc_verified_at, + created_at, + updated_at +) VALUES ( + @id, + @first_name, + @last_name, + @profile_picture, + @phone_number, + COALESCE(@phone_number_verified, FALSE), + @phone_number_verified_at, + @nationality, + @residential_country, + @user_address, + @user_city, + @user_postal_code, + @gender, + @date_of_birth, + @job_role, + @personal_account_type, + @employment_type, + @tax_id, + @default_payment_currency, + @default_payment_method, + @hourly_rate, + @specialization, + COALESCE(@kyc_status, 'pending'), + @kyc_verified_at, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; --- name: CountSearchUsers :one --- Counts the number of users matching a search query -SELECT COUNT(*) -FROM users -WHERE - ( - first_name ILIKE '%' || $1 || '%' OR - last_name ILIKE '%' || $1 || '%' OR - email ILIKE '%' || $1 || '%' OR - nationality ILIKE '%' || $1 || '%' - ); \ No newline at end of file +-- name: GetPersonalUserByID :one +SELECT pu.*, u.email, u.account_status +FROM personal_users pu +JOIN users u ON pu.id = u.id +WHERE pu.id = @id AND u.deleted_at IS NULL; + +-- name: UpdatePersonalUser :one +UPDATE personal_users SET + first_name = COALESCE(@first_name, first_name), + last_name = COALESCE(@last_name, last_name), + profile_picture = COALESCE(@profile_picture, profile_picture), + phone_number = COALESCE(@phone_number, phone_number), + phone_number_verified = COALESCE(@phone_number_verified, phone_number_verified), + phone_number_verified_at = COALESCE(@phone_number_verified_at, phone_number_verified_at), + nationality = COALESCE(@nationality, nationality), + residential_country = COALESCE(@residential_country, residential_country), + user_address = COALESCE(@user_address, user_address), + user_city = COALESCE(@user_city, user_city), + user_postal_code = COALESCE(@user_postal_code, user_postal_code), + gender = COALESCE(@gender, gender), + date_of_birth = COALESCE(@date_of_birth, date_of_birth), + job_role = COALESCE(@job_role, job_role), + employment_type = COALESCE(@employment_type, employment_type), + tax_id = COALESCE(@tax_id, tax_id), + default_payment_currency = COALESCE(@default_payment_currency, default_payment_currency), + default_payment_method = COALESCE(@default_payment_method, default_payment_method), + hourly_rate = COALESCE(@hourly_rate, hourly_rate), + specialization = COALESCE(@specialization, specialization), + kyc_status = COALESCE(@kyc_status, kyc_status), + kyc_verified_at = COALESCE(@kyc_verified_at, kyc_verified_at), + updated_at = NOW() +WHERE id = @id +RETURNING *; \ No newline at end of file diff --git a/db/query/wallet.sql b/db/query/wallet.sql new file mode 100644 index 0000000..032bc9e --- /dev/null +++ b/db/query/wallet.sql @@ -0,0 +1,178 @@ +-- name: CreateSupportedNetwork :one +INSERT INTO supported_networks ( + id, + name, + chain_id, + network_type, + currency_symbol, + block_explorer_url, + rpc_url, + is_evm_compatible, + is_active, + transaction_speed, + average_block_time, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @name, + @chain_id, + @network_type, + @currency_symbol, + @block_explorer_url, + @rpc_url, + COALESCE(@is_evm_compatible, FALSE), + COALESCE(@is_active, TRUE), + @transaction_speed, + @average_block_time, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetSupportedNetworks :many +SELECT * FROM supported_networks +WHERE is_active = TRUE +ORDER BY chain_id; + +-- name: GetSupportedNetworkByChainID :one +SELECT * FROM supported_networks +WHERE chain_id = @chain_id AND is_active = TRUE; + +-- name: GetMainnetNetworks :many +SELECT * FROM supported_networks +WHERE network_type = 'mainnet' AND is_active = TRUE +ORDER BY chain_id; + +-- name: GetTestnetNetworks :many +SELECT * FROM supported_networks +WHERE network_type = 'testnet' AND is_active = TRUE +ORDER BY chain_id; + +-- name: UpdateNetworkStatus :one +UPDATE supported_networks SET + is_active = @is_active, + updated_at = NOW() +WHERE chain_id = @chain_id +RETURNING *; + +-- name: CreateSupportedToken :one +INSERT INTO supported_tokens ( + id, + network_id, + name, + symbol, + decimals, + contract_address, + token_type, + logo_url, + is_stablecoin, + is_active, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @network_id, + @name, + @symbol, + COALESCE(@decimals, 18), + @contract_address, + @token_type, + @logo_url, + COALESCE(@is_stablecoin, FALSE), + COALESCE(@is_active, TRUE), + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetTokensByNetwork :many +SELECT st.*, sn.name as network_name, sn.chain_id +FROM supported_tokens st +JOIN supported_networks sn ON st.network_id = sn.id +WHERE sn.chain_id = @chain_id AND st.is_active = TRUE +ORDER BY st.symbol; + +-- name: GetStablecoinsByNetwork :many +SELECT st.*, sn.name as network_name, sn.chain_id +FROM supported_tokens st +JOIN supported_networks sn ON st.network_id = sn.id +WHERE sn.chain_id = @chain_id AND st.is_stablecoin = TRUE AND st.is_active = TRUE +ORDER BY st.symbol; + +-- name: SearchTokens :many +SELECT st.*, sn.name as network_name, sn.chain_id +FROM supported_tokens st +JOIN supported_networks sn ON st.network_id = sn.id +WHERE (st.name ILIKE '%' || @search_term || '%' OR st.symbol ILIKE '%' || @search_term || '%') + AND st.is_active = TRUE +ORDER BY st.symbol +LIMIT @limit_val OFFSET @offset_val; + +-- name: GetTokenByContract :one +SELECT st.*, sn.name as network_name, sn.chain_id +FROM supported_tokens st +JOIN supported_networks sn ON st.network_id = sn.id +WHERE st.contract_address = @contract_address AND sn.chain_id = @chain_id; + +-- name: CreateUserWallet :one +INSERT INTO user_wallets ( + id, + user_id, + wallet_address, + wallet_type, + chain_id, + is_default, + is_verified, + verification_method, + verified_at, + nickname, + created_at, + updated_at +) VALUES ( + COALESCE(@id, uuid_generate_v4()), + @user_id, + @wallet_address, + @wallet_type, + @chain_id, + COALESCE(@is_default, FALSE), + COALESCE(@is_verified, FALSE), + @verification_method, + @verified_at, + @nickname, + COALESCE(@created_at, NOW()), + COALESCE(@updated_at, NOW()) +) RETURNING *; + +-- name: GetUserWalletsByUser :many +SELECT uw.*, sn.name as network_name +FROM user_wallets uw +JOIN supported_networks sn ON uw.chain_id = sn.chain_id +WHERE uw.user_id = @user_id +ORDER BY uw.is_default DESC, uw.created_at DESC; + +-- name: GetUserWalletsByNetwork :many +SELECT uw.*, sn.name as network_name +FROM user_wallets uw +JOIN supported_networks sn ON uw.chain_id = sn.chain_id +WHERE uw.user_id = @user_id AND uw.chain_id = @chain_id +ORDER BY uw.is_default DESC, uw.created_at DESC; + +-- name: UpdateUserWallet :one +UPDATE user_wallets SET + wallet_type = COALESCE(@wallet_type, wallet_type), + is_default = COALESCE(@is_default, is_default), + is_verified = COALESCE(@is_verified, is_verified), + verification_method = COALESCE(@verification_method, verification_method), + verified_at = COALESCE(@verified_at, verified_at), + nickname = COALESCE(@nickname, nickname), + updated_at = NOW() +WHERE id = @id +RETURNING *; + +-- name: SetUserWalletAsDefault :exec +UPDATE user_wallets SET + is_default = CASE WHEN id = @wallet_id THEN TRUE ELSE FALSE END, + updated_at = NOW() +WHERE user_id = @user_id AND chain_id = @chain_id; + +-- name: DeleteUserWallet :exec +DELETE FROM user_wallets WHERE id = @id; \ No newline at end of file diff --git a/db/sqlc/audit.sql.go b/db/sqlc/audit.sql.go new file mode 100644 index 0000000..00d59b6 --- /dev/null +++ b/db/sqlc/audit.sql.go @@ -0,0 +1,778 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.29.0 +// source: audit.sql + +package sqlc + +import ( + "context" + "time" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" +) + +const cleanupOldActivityLogs = `-- name: CleanupOldActivityLogs :exec +DELETE FROM activity_logs +WHERE created_at < NOW() - INTERVAL '@days days' +` + +func (q *Queries) CleanupOldActivityLogs(ctx context.Context) error { + _, err := q.db.Exec(ctx, cleanupOldActivityLogs) + return err +} + +const cleanupOldAuditLogs = `-- name: CleanupOldAuditLogs :exec +DELETE FROM audit_logs +WHERE created_at < NOW() - INTERVAL '@days days' +` + +func (q *Queries) CleanupOldAuditLogs(ctx context.Context) error { + _, err := q.db.Exec(ctx, cleanupOldAuditLogs) + return err +} + +const createActivityLog = `-- name: CreateActivityLog :one +INSERT INTO activity_logs ( + id, + user_id, + activity_type, + description, + metadata, + ip_address, + user_agent, + created_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + $7, + COALESCE($8, NOW()) +) RETURNING id, user_id, activity_type, description, metadata, ip_address, user_agent, created_at +` + +type CreateActivityLogParams struct { + ID interface{} `json:"id"` + UserID uuid.UUID `json:"user_id"` + ActivityType string `json:"activity_type"` + Description pgtype.Text `json:"description"` + Metadata []byte `json:"metadata"` + IpAddress pgtype.Text `json:"ip_address"` + UserAgent pgtype.Text `json:"user_agent"` + CreatedAt interface{} `json:"created_at"` +} + +func (q *Queries) CreateActivityLog(ctx context.Context, arg CreateActivityLogParams) (ActivityLogs, error) { + row := q.db.QueryRow(ctx, createActivityLog, + arg.ID, + arg.UserID, + arg.ActivityType, + arg.Description, + arg.Metadata, + arg.IpAddress, + arg.UserAgent, + arg.CreatedAt, + ) + var i ActivityLogs + err := row.Scan( + &i.ID, + &i.UserID, + &i.ActivityType, + &i.Description, + &i.Metadata, + &i.IpAddress, + &i.UserAgent, + &i.CreatedAt, + ) + return i, err +} + +const createAuditLog = `-- name: CreateAuditLog :one +INSERT INTO audit_logs ( + id, + user_id, + company_id, + action, + entity_type, + entity_id, + previous_state, + new_state, + ip_address, + user_agent, + created_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + $7, + $8, + $9, + $10, + COALESCE($11, NOW()) +) RETURNING id, user_id, company_id, action, entity_type, entity_id, previous_state, new_state, ip_address, user_agent, created_at +` + +type CreateAuditLogParams struct { + ID interface{} `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + Action string `json:"action"` + EntityType string `json:"entity_type"` + EntityID uuid.UUID `json:"entity_id"` + PreviousState []byte `json:"previous_state"` + NewState []byte `json:"new_state"` + IpAddress pgtype.Text `json:"ip_address"` + UserAgent pgtype.Text `json:"user_agent"` + CreatedAt interface{} `json:"created_at"` +} + +func (q *Queries) CreateAuditLog(ctx context.Context, arg CreateAuditLogParams) (AuditLogs, error) { + row := q.db.QueryRow(ctx, createAuditLog, + arg.ID, + arg.UserID, + arg.CompanyID, + arg.Action, + arg.EntityType, + arg.EntityID, + arg.PreviousState, + arg.NewState, + arg.IpAddress, + arg.UserAgent, + arg.CreatedAt, + ) + var i AuditLogs + err := row.Scan( + &i.ID, + &i.UserID, + &i.CompanyID, + &i.Action, + &i.EntityType, + &i.EntityID, + &i.PreviousState, + &i.NewState, + &i.IpAddress, + &i.UserAgent, + &i.CreatedAt, + ) + return i, err +} + +const getActivityLogsByType = `-- name: GetActivityLogsByType :many +SELECT al.id, al.user_id, al.activity_type, al.description, al.metadata, al.ip_address, al.user_agent, al.created_at, u.email +FROM activity_logs al +JOIN users u ON al.user_id = u.id +WHERE al.activity_type = $1 + AND ($2::uuid IS NULL OR al.user_id = $2) + AND ($3::timestamptz IS NULL OR al.created_at >= $3) + AND ($4::timestamptz IS NULL OR al.created_at <= $4) +ORDER BY al.created_at DESC +LIMIT $6 OFFSET $5 +` + +type GetActivityLogsByTypeParams struct { + ActivityType string `json:"activity_type"` + UserID uuid.UUID `json:"user_id"` + StartDate time.Time `json:"start_date"` + EndDate time.Time `json:"end_date"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetActivityLogsByTypeRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + ActivityType string `json:"activity_type"` + Description pgtype.Text `json:"description"` + Metadata []byte `json:"metadata"` + IpAddress pgtype.Text `json:"ip_address"` + UserAgent pgtype.Text `json:"user_agent"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + Email string `json:"email"` +} + +func (q *Queries) GetActivityLogsByType(ctx context.Context, arg GetActivityLogsByTypeParams) ([]GetActivityLogsByTypeRow, error) { + rows, err := q.db.Query(ctx, getActivityLogsByType, + arg.ActivityType, + arg.UserID, + arg.StartDate, + arg.EndDate, + arg.OffsetVal, + arg.LimitVal, + ) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetActivityLogsByTypeRow{} + for rows.Next() { + var i GetActivityLogsByTypeRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.ActivityType, + &i.Description, + &i.Metadata, + &i.IpAddress, + &i.UserAgent, + &i.CreatedAt, + &i.Email, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getActivityLogsByUser = `-- name: GetActivityLogsByUser :many +SELECT id, user_id, activity_type, description, metadata, ip_address, user_agent, created_at FROM activity_logs +WHERE user_id = $1 +ORDER BY created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetActivityLogsByUserParams struct { + UserID uuid.UUID `json:"user_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +func (q *Queries) GetActivityLogsByUser(ctx context.Context, arg GetActivityLogsByUserParams) ([]ActivityLogs, error) { + rows, err := q.db.Query(ctx, getActivityLogsByUser, arg.UserID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []ActivityLogs{} + for rows.Next() { + var i ActivityLogs + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.ActivityType, + &i.Description, + &i.Metadata, + &i.IpAddress, + &i.UserAgent, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAuditLogsByAction = `-- name: GetAuditLogsByAction :many +SELECT al.id, al.user_id, al.company_id, al.action, al.entity_type, al.entity_id, al.previous_state, al.new_state, al.ip_address, al.user_agent, al.created_at, u.email +FROM audit_logs al +LEFT JOIN users u ON al.user_id = u.id +WHERE al.action = $1 + AND ($2::uuid IS NULL OR al.user_id = $2) + AND ($3::uuid IS NULL OR al.company_id = $3) + AND ($4::timestamptz IS NULL OR al.created_at >= $4) + AND ($5::timestamptz IS NULL OR al.created_at <= $5) +ORDER BY al.created_at DESC +LIMIT $7 OFFSET $6 +` + +type GetAuditLogsByActionParams struct { + Action string `json:"action"` + UserID uuid.UUID `json:"user_id"` + CompanyID uuid.UUID `json:"company_id"` + StartDate time.Time `json:"start_date"` + EndDate time.Time `json:"end_date"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetAuditLogsByActionRow struct { + ID uuid.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + Action string `json:"action"` + EntityType string `json:"entity_type"` + EntityID uuid.UUID `json:"entity_id"` + PreviousState []byte `json:"previous_state"` + NewState []byte `json:"new_state"` + IpAddress pgtype.Text `json:"ip_address"` + UserAgent pgtype.Text `json:"user_agent"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + Email pgtype.Text `json:"email"` +} + +func (q *Queries) GetAuditLogsByAction(ctx context.Context, arg GetAuditLogsByActionParams) ([]GetAuditLogsByActionRow, error) { + rows, err := q.db.Query(ctx, getAuditLogsByAction, + arg.Action, + arg.UserID, + arg.CompanyID, + arg.StartDate, + arg.EndDate, + arg.OffsetVal, + arg.LimitVal, + ) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetAuditLogsByActionRow{} + for rows.Next() { + var i GetAuditLogsByActionRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.CompanyID, + &i.Action, + &i.EntityType, + &i.EntityID, + &i.PreviousState, + &i.NewState, + &i.IpAddress, + &i.UserAgent, + &i.CreatedAt, + &i.Email, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAuditLogsByCompany = `-- name: GetAuditLogsByCompany :many +SELECT al.id, al.user_id, al.company_id, al.action, al.entity_type, al.entity_id, al.previous_state, al.new_state, al.ip_address, al.user_agent, al.created_at, u.email +FROM audit_logs al +LEFT JOIN users u ON al.user_id = u.id +WHERE al.company_id = $1 +ORDER BY al.created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetAuditLogsByCompanyParams struct { + CompanyID pgtype.UUID `json:"company_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetAuditLogsByCompanyRow struct { + ID uuid.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + Action string `json:"action"` + EntityType string `json:"entity_type"` + EntityID uuid.UUID `json:"entity_id"` + PreviousState []byte `json:"previous_state"` + NewState []byte `json:"new_state"` + IpAddress pgtype.Text `json:"ip_address"` + UserAgent pgtype.Text `json:"user_agent"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + Email pgtype.Text `json:"email"` +} + +func (q *Queries) GetAuditLogsByCompany(ctx context.Context, arg GetAuditLogsByCompanyParams) ([]GetAuditLogsByCompanyRow, error) { + rows, err := q.db.Query(ctx, getAuditLogsByCompany, arg.CompanyID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetAuditLogsByCompanyRow{} + for rows.Next() { + var i GetAuditLogsByCompanyRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.CompanyID, + &i.Action, + &i.EntityType, + &i.EntityID, + &i.PreviousState, + &i.NewState, + &i.IpAddress, + &i.UserAgent, + &i.CreatedAt, + &i.Email, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAuditLogsByEntity = `-- name: GetAuditLogsByEntity :many +SELECT al.id, al.user_id, al.company_id, al.action, al.entity_type, al.entity_id, al.previous_state, al.new_state, al.ip_address, al.user_agent, al.created_at, u.email +FROM audit_logs al +LEFT JOIN users u ON al.user_id = u.id +WHERE al.entity_type = $1 AND al.entity_id = $2 +ORDER BY al.created_at DESC +LIMIT $4 OFFSET $3 +` + +type GetAuditLogsByEntityParams struct { + EntityType string `json:"entity_type"` + EntityID uuid.UUID `json:"entity_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetAuditLogsByEntityRow struct { + ID uuid.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + Action string `json:"action"` + EntityType string `json:"entity_type"` + EntityID uuid.UUID `json:"entity_id"` + PreviousState []byte `json:"previous_state"` + NewState []byte `json:"new_state"` + IpAddress pgtype.Text `json:"ip_address"` + UserAgent pgtype.Text `json:"user_agent"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + Email pgtype.Text `json:"email"` +} + +func (q *Queries) GetAuditLogsByEntity(ctx context.Context, arg GetAuditLogsByEntityParams) ([]GetAuditLogsByEntityRow, error) { + rows, err := q.db.Query(ctx, getAuditLogsByEntity, + arg.EntityType, + arg.EntityID, + arg.OffsetVal, + arg.LimitVal, + ) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetAuditLogsByEntityRow{} + for rows.Next() { + var i GetAuditLogsByEntityRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.CompanyID, + &i.Action, + &i.EntityType, + &i.EntityID, + &i.PreviousState, + &i.NewState, + &i.IpAddress, + &i.UserAgent, + &i.CreatedAt, + &i.Email, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAuditLogsByUser = `-- name: GetAuditLogsByUser :many +SELECT al.id, al.user_id, al.company_id, al.action, al.entity_type, al.entity_id, al.previous_state, al.new_state, al.ip_address, al.user_agent, al.created_at, u.email +FROM audit_logs al +LEFT JOIN users u ON al.user_id = u.id +WHERE al.user_id = $1 +ORDER BY al.created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetAuditLogsByUserParams struct { + UserID pgtype.UUID `json:"user_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetAuditLogsByUserRow struct { + ID uuid.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + Action string `json:"action"` + EntityType string `json:"entity_type"` + EntityID uuid.UUID `json:"entity_id"` + PreviousState []byte `json:"previous_state"` + NewState []byte `json:"new_state"` + IpAddress pgtype.Text `json:"ip_address"` + UserAgent pgtype.Text `json:"user_agent"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + Email pgtype.Text `json:"email"` +} + +func (q *Queries) GetAuditLogsByUser(ctx context.Context, arg GetAuditLogsByUserParams) ([]GetAuditLogsByUserRow, error) { + rows, err := q.db.Query(ctx, getAuditLogsByUser, arg.UserID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetAuditLogsByUserRow{} + for rows.Next() { + var i GetAuditLogsByUserRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.CompanyID, + &i.Action, + &i.EntityType, + &i.EntityID, + &i.PreviousState, + &i.NewState, + &i.IpAddress, + &i.UserAgent, + &i.CreatedAt, + &i.Email, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getCompanyAuditSummary = `-- name: GetCompanyAuditSummary :one +SELECT + COUNT(*) as total_audit_logs, + COUNT(DISTINCT user_id) as unique_users, + COUNT(DISTINCT action) as unique_actions, + COUNT(DISTINCT entity_type) as unique_entity_types, + MAX(created_at) as last_audit, + MIN(created_at) as first_audit +FROM audit_logs +WHERE company_id = $1 + AND ($2::timestamptz IS NULL OR created_at >= $2) + AND ($3::timestamptz IS NULL OR created_at <= $3) +` + +type GetCompanyAuditSummaryParams struct { + CompanyID pgtype.UUID `json:"company_id"` + StartDate time.Time `json:"start_date"` + EndDate time.Time `json:"end_date"` +} + +type GetCompanyAuditSummaryRow struct { + TotalAuditLogs int64 `json:"total_audit_logs"` + UniqueUsers int64 `json:"unique_users"` + UniqueActions int64 `json:"unique_actions"` + UniqueEntityTypes int64 `json:"unique_entity_types"` + LastAudit interface{} `json:"last_audit"` + FirstAudit interface{} `json:"first_audit"` +} + +func (q *Queries) GetCompanyAuditSummary(ctx context.Context, arg GetCompanyAuditSummaryParams) (GetCompanyAuditSummaryRow, error) { + row := q.db.QueryRow(ctx, getCompanyAuditSummary, arg.CompanyID, arg.StartDate, arg.EndDate) + var i GetCompanyAuditSummaryRow + err := row.Scan( + &i.TotalAuditLogs, + &i.UniqueUsers, + &i.UniqueActions, + &i.UniqueEntityTypes, + &i.LastAudit, + &i.FirstAudit, + ) + return i, err +} + +const getRecentActivity = `-- name: GetRecentActivity :many +SELECT al.id, al.user_id, al.activity_type, al.description, al.metadata, al.ip_address, al.user_agent, al.created_at, u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM activity_logs al +JOIN users u ON al.user_id = u.id +LEFT JOIN company_staff_profiles csp ON u.id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE ($1::uuid IS NULL OR al.user_id = $1) + AND al.created_at >= NOW() - INTERVAL '@hours hours' +ORDER BY al.created_at DESC +LIMIT $2 +` + +type GetRecentActivityParams struct { + UserID uuid.UUID `json:"user_id"` + LimitVal int32 `json:"limit_val"` +} + +type GetRecentActivityRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + ActivityType string `json:"activity_type"` + Description pgtype.Text `json:"description"` + Metadata []byte `json:"metadata"` + IpAddress pgtype.Text `json:"ip_address"` + UserAgent pgtype.Text `json:"user_agent"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + Email string `json:"email"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` +} + +func (q *Queries) GetRecentActivity(ctx context.Context, arg GetRecentActivityParams) ([]GetRecentActivityRow, error) { + rows, err := q.db.Query(ctx, getRecentActivity, arg.UserID, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetRecentActivityRow{} + for rows.Next() { + var i GetRecentActivityRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.ActivityType, + &i.Description, + &i.Metadata, + &i.IpAddress, + &i.UserAgent, + &i.CreatedAt, + &i.Email, + &i.FirstName, + &i.LastName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserActivitySummary = `-- name: GetUserActivitySummary :one +SELECT + COUNT(*) as total_activities, + COUNT(DISTINCT activity_type) as unique_activity_types, + MAX(created_at) as last_activity, + MIN(created_at) as first_activity +FROM activity_logs +WHERE user_id = $1 + AND ($2::timestamptz IS NULL OR created_at >= $2) + AND ($3::timestamptz IS NULL OR created_at <= $3) +` + +type GetUserActivitySummaryParams struct { + UserID uuid.UUID `json:"user_id"` + StartDate time.Time `json:"start_date"` + EndDate time.Time `json:"end_date"` +} + +type GetUserActivitySummaryRow struct { + TotalActivities int64 `json:"total_activities"` + UniqueActivityTypes int64 `json:"unique_activity_types"` + LastActivity interface{} `json:"last_activity"` + FirstActivity interface{} `json:"first_activity"` +} + +func (q *Queries) GetUserActivitySummary(ctx context.Context, arg GetUserActivitySummaryParams) (GetUserActivitySummaryRow, error) { + row := q.db.QueryRow(ctx, getUserActivitySummary, arg.UserID, arg.StartDate, arg.EndDate) + var i GetUserActivitySummaryRow + err := row.Scan( + &i.TotalActivities, + &i.UniqueActivityTypes, + &i.LastActivity, + &i.FirstActivity, + ) + return i, err +} + +const searchAuditLogs = `-- name: SearchAuditLogs :many +SELECT al.id, al.user_id, al.company_id, al.action, al.entity_type, al.entity_id, al.previous_state, al.new_state, al.ip_address, al.user_agent, al.created_at, u.email +FROM audit_logs al +LEFT JOIN users u ON al.user_id = u.id +WHERE ($1::uuid IS NULL OR al.user_id = $1) + AND ($2::uuid IS NULL OR al.company_id = $2) + AND ($3::text IS NULL OR al.entity_type = $3) + AND ($4::text IS NULL OR al.action = $4) + AND ($5::timestamptz IS NULL OR al.created_at >= $5) + AND ($6::timestamptz IS NULL OR al.created_at <= $6) +ORDER BY al.created_at DESC +LIMIT $8 OFFSET $7 +` + +type SearchAuditLogsParams struct { + UserID uuid.UUID `json:"user_id"` + CompanyID uuid.UUID `json:"company_id"` + EntityType string `json:"entity_type"` + Action string `json:"action"` + StartDate time.Time `json:"start_date"` + EndDate time.Time `json:"end_date"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type SearchAuditLogsRow struct { + ID uuid.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + Action string `json:"action"` + EntityType string `json:"entity_type"` + EntityID uuid.UUID `json:"entity_id"` + PreviousState []byte `json:"previous_state"` + NewState []byte `json:"new_state"` + IpAddress pgtype.Text `json:"ip_address"` + UserAgent pgtype.Text `json:"user_agent"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + Email pgtype.Text `json:"email"` +} + +func (q *Queries) SearchAuditLogs(ctx context.Context, arg SearchAuditLogsParams) ([]SearchAuditLogsRow, error) { + rows, err := q.db.Query(ctx, searchAuditLogs, + arg.UserID, + arg.CompanyID, + arg.EntityType, + arg.Action, + arg.StartDate, + arg.EndDate, + arg.OffsetVal, + arg.LimitVal, + ) + if err != nil { + return nil, err + } + defer rows.Close() + items := []SearchAuditLogsRow{} + for rows.Next() { + var i SearchAuditLogsRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.CompanyID, + &i.Action, + &i.EntityType, + &i.EntityID, + &i.PreviousState, + &i.NewState, + &i.IpAddress, + &i.UserAgent, + &i.CreatedAt, + &i.Email, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/db/sqlc/auth.sql.go b/db/sqlc/auth.sql.go new file mode 100644 index 0000000..2e4cc12 --- /dev/null +++ b/db/sqlc/auth.sql.go @@ -0,0 +1,714 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.29.0 +// source: auth.sql + +package sqlc + +import ( + "context" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" +) + +const cleanupExpiredSessions = `-- name: CleanupExpiredSessions :exec +DELETE FROM sessions +WHERE expires_at < NOW() OR is_blocked = TRUE +` + +func (q *Queries) CleanupExpiredSessions(ctx context.Context) error { + _, err := q.db.Exec(ctx, cleanupExpiredSessions) + return err +} + +const createSecurityEvent = `-- name: CreateSecurityEvent :one +INSERT INTO security_events ( + id, + user_id, + company_id, + event_type, + severity, + ip_address, + user_agent, + metadata, + created_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + $7, + $8, + COALESCE($9, NOW()) +) RETURNING id, user_id, company_id, event_type, severity, ip_address, user_agent, metadata, created_at +` + +type CreateSecurityEventParams struct { + ID interface{} `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + EventType string `json:"event_type"` + Severity string `json:"severity"` + IpAddress pgtype.Text `json:"ip_address"` + UserAgent pgtype.Text `json:"user_agent"` + Metadata []byte `json:"metadata"` + CreatedAt interface{} `json:"created_at"` +} + +func (q *Queries) CreateSecurityEvent(ctx context.Context, arg CreateSecurityEventParams) (SecurityEvents, error) { + row := q.db.QueryRow(ctx, createSecurityEvent, + arg.ID, + arg.UserID, + arg.CompanyID, + arg.EventType, + arg.Severity, + arg.IpAddress, + arg.UserAgent, + arg.Metadata, + arg.CreatedAt, + ) + var i SecurityEvents + err := row.Scan( + &i.ID, + &i.UserID, + &i.CompanyID, + &i.EventType, + &i.Severity, + &i.IpAddress, + &i.UserAgent, + &i.Metadata, + &i.CreatedAt, + ) + return i, err +} + +const createSession = `-- name: CreateSession :one +INSERT INTO sessions ( + id, + user_id, + refresh_token, + user_agent, + client_ip, + last_used_at, + web_oauth_client_id, + oauth_access_token, + oauth_id_token, + user_login_type, + mfa_verified, + is_blocked, + expires_at, + created_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + COALESCE($6, NOW()), + $7, + $8, + $9, + $10, + COALESCE($11, FALSE), + COALESCE($12, FALSE), + $13, + COALESCE($14, NOW()) +) RETURNING id, user_id, refresh_token, user_agent, client_ip, last_used_at, web_oauth_client_id, oauth_access_token, oauth_id_token, user_login_type, mfa_verified, is_blocked, expires_at, created_at +` + +type CreateSessionParams struct { + ID interface{} `json:"id"` + UserID uuid.UUID `json:"user_id"` + RefreshToken pgtype.Text `json:"refresh_token"` + UserAgent pgtype.Text `json:"user_agent"` + ClientIp pgtype.Text `json:"client_ip"` + LastUsedAt interface{} `json:"last_used_at"` + WebOauthClientID pgtype.Text `json:"web_oauth_client_id"` + OauthAccessToken pgtype.Text `json:"oauth_access_token"` + OauthIDToken pgtype.Text `json:"oauth_id_token"` + UserLoginType pgtype.Text `json:"user_login_type"` + MfaVerified interface{} `json:"mfa_verified"` + IsBlocked interface{} `json:"is_blocked"` + ExpiresAt pgtype.Timestamptz `json:"expires_at"` + CreatedAt interface{} `json:"created_at"` +} + +func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) (Sessions, error) { + row := q.db.QueryRow(ctx, createSession, + arg.ID, + arg.UserID, + arg.RefreshToken, + arg.UserAgent, + arg.ClientIp, + arg.LastUsedAt, + arg.WebOauthClientID, + arg.OauthAccessToken, + arg.OauthIDToken, + arg.UserLoginType, + arg.MfaVerified, + arg.IsBlocked, + arg.ExpiresAt, + arg.CreatedAt, + ) + var i Sessions + err := row.Scan( + &i.ID, + &i.UserID, + &i.RefreshToken, + &i.UserAgent, + &i.ClientIp, + &i.LastUsedAt, + &i.WebOauthClientID, + &i.OauthAccessToken, + &i.OauthIDToken, + &i.UserLoginType, + &i.MfaVerified, + &i.IsBlocked, + &i.ExpiresAt, + &i.CreatedAt, + ) + return i, err +} + +const createUserDevice = `-- name: CreateUserDevice :one +INSERT INTO user_devices ( + id, + user_id, + device_token, + platform, + device_type, + device_model, + os_name, + os_version, + push_notification_token, + is_active, + is_verified, + last_used_at, + app_version, + client_ip, + expires_at, + is_revoked, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + $7, + $8, + $9, + COALESCE($10, TRUE), + COALESCE($11, FALSE), + COALESCE($12, NOW()), + $13, + $14, + $15, + COALESCE($16, FALSE), + COALESCE($17, NOW()), + COALESCE($18, NOW()) +) RETURNING id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, app_version, client_ip, expires_at, is_revoked, created_at, updated_at +` + +type CreateUserDeviceParams struct { + ID interface{} `json:"id"` + UserID uuid.UUID `json:"user_id"` + DeviceToken pgtype.Text `json:"device_token"` + Platform pgtype.Text `json:"platform"` + DeviceType pgtype.Text `json:"device_type"` + DeviceModel pgtype.Text `json:"device_model"` + OsName pgtype.Text `json:"os_name"` + OsVersion pgtype.Text `json:"os_version"` + PushNotificationToken pgtype.Text `json:"push_notification_token"` + IsActive interface{} `json:"is_active"` + IsVerified interface{} `json:"is_verified"` + LastUsedAt interface{} `json:"last_used_at"` + AppVersion pgtype.Text `json:"app_version"` + ClientIp pgtype.Text `json:"client_ip"` + ExpiresAt pgtype.Timestamptz `json:"expires_at"` + IsRevoked interface{} `json:"is_revoked"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateUserDevice(ctx context.Context, arg CreateUserDeviceParams) (UserDevices, error) { + row := q.db.QueryRow(ctx, createUserDevice, + arg.ID, + arg.UserID, + arg.DeviceToken, + arg.Platform, + arg.DeviceType, + arg.DeviceModel, + arg.OsName, + arg.OsVersion, + arg.PushNotificationToken, + arg.IsActive, + arg.IsVerified, + arg.LastUsedAt, + arg.AppVersion, + arg.ClientIp, + arg.ExpiresAt, + arg.IsRevoked, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i UserDevices + err := row.Scan( + &i.ID, + &i.UserID, + &i.DeviceToken, + &i.Platform, + &i.DeviceType, + &i.DeviceModel, + &i.OsName, + &i.OsVersion, + &i.PushNotificationToken, + &i.IsActive, + &i.IsVerified, + &i.LastUsedAt, + &i.AppVersion, + &i.ClientIp, + &i.ExpiresAt, + &i.IsRevoked, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getSecurityEventsByCompany = `-- name: GetSecurityEventsByCompany :many +SELECT id, user_id, company_id, event_type, severity, ip_address, user_agent, metadata, created_at FROM security_events +WHERE company_id = $1 +ORDER BY created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetSecurityEventsByCompanyParams struct { + CompanyID pgtype.UUID `json:"company_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +func (q *Queries) GetSecurityEventsByCompany(ctx context.Context, arg GetSecurityEventsByCompanyParams) ([]SecurityEvents, error) { + rows, err := q.db.Query(ctx, getSecurityEventsByCompany, arg.CompanyID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []SecurityEvents{} + for rows.Next() { + var i SecurityEvents + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.CompanyID, + &i.EventType, + &i.Severity, + &i.IpAddress, + &i.UserAgent, + &i.Metadata, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getSecurityEventsByType = `-- name: GetSecurityEventsByType :many +SELECT id, user_id, company_id, event_type, severity, ip_address, user_agent, metadata, created_at FROM security_events +WHERE event_type = $1 + AND ($2::uuid IS NULL OR user_id = $2) + AND ($3::uuid IS NULL OR company_id = $3) +ORDER BY created_at DESC +LIMIT $5 OFFSET $4 +` + +type GetSecurityEventsByTypeParams struct { + EventType string `json:"event_type"` + UserID uuid.UUID `json:"user_id"` + CompanyID uuid.UUID `json:"company_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +func (q *Queries) GetSecurityEventsByType(ctx context.Context, arg GetSecurityEventsByTypeParams) ([]SecurityEvents, error) { + rows, err := q.db.Query(ctx, getSecurityEventsByType, + arg.EventType, + arg.UserID, + arg.CompanyID, + arg.OffsetVal, + arg.LimitVal, + ) + if err != nil { + return nil, err + } + defer rows.Close() + items := []SecurityEvents{} + for rows.Next() { + var i SecurityEvents + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.CompanyID, + &i.EventType, + &i.Severity, + &i.IpAddress, + &i.UserAgent, + &i.Metadata, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getSecurityEventsByUser = `-- name: GetSecurityEventsByUser :many +SELECT id, user_id, company_id, event_type, severity, ip_address, user_agent, metadata, created_at FROM security_events +WHERE user_id = $1 +ORDER BY created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetSecurityEventsByUserParams struct { + UserID pgtype.UUID `json:"user_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +func (q *Queries) GetSecurityEventsByUser(ctx context.Context, arg GetSecurityEventsByUserParams) ([]SecurityEvents, error) { + rows, err := q.db.Query(ctx, getSecurityEventsByUser, arg.UserID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []SecurityEvents{} + for rows.Next() { + var i SecurityEvents + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.CompanyID, + &i.EventType, + &i.Severity, + &i.IpAddress, + &i.UserAgent, + &i.Metadata, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getSessionByID = `-- name: GetSessionByID :one +SELECT id, user_id, refresh_token, user_agent, client_ip, last_used_at, web_oauth_client_id, oauth_access_token, oauth_id_token, user_login_type, mfa_verified, is_blocked, expires_at, created_at FROM sessions +WHERE id = $1 AND is_blocked = FALSE +` + +func (q *Queries) GetSessionByID(ctx context.Context, id uuid.UUID) (Sessions, error) { + row := q.db.QueryRow(ctx, getSessionByID, id) + var i Sessions + err := row.Scan( + &i.ID, + &i.UserID, + &i.RefreshToken, + &i.UserAgent, + &i.ClientIp, + &i.LastUsedAt, + &i.WebOauthClientID, + &i.OauthAccessToken, + &i.OauthIDToken, + &i.UserLoginType, + &i.MfaVerified, + &i.IsBlocked, + &i.ExpiresAt, + &i.CreatedAt, + ) + return i, err +} + +const getSessionsByUser = `-- name: GetSessionsByUser :many +SELECT id, user_id, refresh_token, user_agent, client_ip, last_used_at, web_oauth_client_id, oauth_access_token, oauth_id_token, user_login_type, mfa_verified, is_blocked, expires_at, created_at FROM sessions +WHERE user_id = $1 AND is_blocked = FALSE +ORDER BY last_used_at DESC +` + +func (q *Queries) GetSessionsByUser(ctx context.Context, userID uuid.UUID) ([]Sessions, error) { + rows, err := q.db.Query(ctx, getSessionsByUser, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []Sessions{} + for rows.Next() { + var i Sessions + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.RefreshToken, + &i.UserAgent, + &i.ClientIp, + &i.LastUsedAt, + &i.WebOauthClientID, + &i.OauthAccessToken, + &i.OauthIDToken, + &i.UserLoginType, + &i.MfaVerified, + &i.IsBlocked, + &i.ExpiresAt, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserDeviceByID = `-- name: GetUserDeviceByID :one +SELECT id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, app_version, client_ip, expires_at, is_revoked, created_at, updated_at FROM user_devices +WHERE id = $1 AND is_revoked = FALSE +` + +func (q *Queries) GetUserDeviceByID(ctx context.Context, id uuid.UUID) (UserDevices, error) { + row := q.db.QueryRow(ctx, getUserDeviceByID, id) + var i UserDevices + err := row.Scan( + &i.ID, + &i.UserID, + &i.DeviceToken, + &i.Platform, + &i.DeviceType, + &i.DeviceModel, + &i.OsName, + &i.OsVersion, + &i.PushNotificationToken, + &i.IsActive, + &i.IsVerified, + &i.LastUsedAt, + &i.AppVersion, + &i.ClientIp, + &i.ExpiresAt, + &i.IsRevoked, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getUserDeviceByToken = `-- name: GetUserDeviceByToken :one +SELECT id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, app_version, client_ip, expires_at, is_revoked, created_at, updated_at FROM user_devices +WHERE device_token = $1 AND is_revoked = FALSE +` + +func (q *Queries) GetUserDeviceByToken(ctx context.Context, deviceToken pgtype.Text) (UserDevices, error) { + row := q.db.QueryRow(ctx, getUserDeviceByToken, deviceToken) + var i UserDevices + err := row.Scan( + &i.ID, + &i.UserID, + &i.DeviceToken, + &i.Platform, + &i.DeviceType, + &i.DeviceModel, + &i.OsName, + &i.OsVersion, + &i.PushNotificationToken, + &i.IsActive, + &i.IsVerified, + &i.LastUsedAt, + &i.AppVersion, + &i.ClientIp, + &i.ExpiresAt, + &i.IsRevoked, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getUserDevicesByUser = `-- name: GetUserDevicesByUser :many +SELECT id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, app_version, client_ip, expires_at, is_revoked, created_at, updated_at FROM user_devices +WHERE user_id = $1 AND is_revoked = FALSE +ORDER BY last_used_at DESC +` + +func (q *Queries) GetUserDevicesByUser(ctx context.Context, userID uuid.UUID) ([]UserDevices, error) { + rows, err := q.db.Query(ctx, getUserDevicesByUser, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []UserDevices{} + for rows.Next() { + var i UserDevices + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.DeviceToken, + &i.Platform, + &i.DeviceType, + &i.DeviceModel, + &i.OsName, + &i.OsVersion, + &i.PushNotificationToken, + &i.IsActive, + &i.IsVerified, + &i.LastUsedAt, + &i.AppVersion, + &i.ClientIp, + &i.ExpiresAt, + &i.IsRevoked, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const revokeAllUserSessions = `-- name: RevokeAllUserSessions :exec +UPDATE sessions SET + is_blocked = TRUE +WHERE user_id = $1 +` + +func (q *Queries) RevokeAllUserSessions(ctx context.Context, userID uuid.UUID) error { + _, err := q.db.Exec(ctx, revokeAllUserSessions, userID) + return err +} + +const revokeSession = `-- name: RevokeSession :exec +UPDATE sessions SET + is_blocked = TRUE +WHERE id = $1 +` + +func (q *Queries) RevokeSession(ctx context.Context, id uuid.UUID) error { + _, err := q.db.Exec(ctx, revokeSession, id) + return err +} + +const revokeUserDevice = `-- name: RevokeUserDevice :exec +UPDATE user_devices SET + is_revoked = TRUE, + updated_at = NOW() +WHERE id = $1 +` + +func (q *Queries) RevokeUserDevice(ctx context.Context, id uuid.UUID) error { + _, err := q.db.Exec(ctx, revokeUserDevice, id) + return err +} + +const updateSessionLastUsed = `-- name: UpdateSessionLastUsed :exec +UPDATE sessions SET + last_used_at = NOW() +WHERE id = $1 +` + +func (q *Queries) UpdateSessionLastUsed(ctx context.Context, id uuid.UUID) error { + _, err := q.db.Exec(ctx, updateSessionLastUsed, id) + return err +} + +const updateUserDevice = `-- name: UpdateUserDevice :one +UPDATE user_devices SET + platform = COALESCE($1, platform), + device_type = COALESCE($2, device_type), + device_model = COALESCE($3, device_model), + os_name = COALESCE($4, os_name), + os_version = COALESCE($5, os_version), + push_notification_token = COALESCE($6, push_notification_token), + is_active = COALESCE($7, is_active), + is_verified = COALESCE($8, is_verified), + last_used_at = NOW(), + app_version = COALESCE($9, app_version), + client_ip = COALESCE($10, client_ip), + expires_at = COALESCE($11, expires_at), + updated_at = NOW() +WHERE id = $12 +RETURNING id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, app_version, client_ip, expires_at, is_revoked, created_at, updated_at +` + +type UpdateUserDeviceParams struct { + Platform pgtype.Text `json:"platform"` + DeviceType pgtype.Text `json:"device_type"` + DeviceModel pgtype.Text `json:"device_model"` + OsName pgtype.Text `json:"os_name"` + OsVersion pgtype.Text `json:"os_version"` + PushNotificationToken pgtype.Text `json:"push_notification_token"` + IsActive pgtype.Bool `json:"is_active"` + IsVerified pgtype.Bool `json:"is_verified"` + AppVersion pgtype.Text `json:"app_version"` + ClientIp pgtype.Text `json:"client_ip"` + ExpiresAt pgtype.Timestamptz `json:"expires_at"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdateUserDevice(ctx context.Context, arg UpdateUserDeviceParams) (UserDevices, error) { + row := q.db.QueryRow(ctx, updateUserDevice, + arg.Platform, + arg.DeviceType, + arg.DeviceModel, + arg.OsName, + arg.OsVersion, + arg.PushNotificationToken, + arg.IsActive, + arg.IsVerified, + arg.AppVersion, + arg.ClientIp, + arg.ExpiresAt, + arg.ID, + ) + var i UserDevices + err := row.Scan( + &i.ID, + &i.UserID, + &i.DeviceToken, + &i.Platform, + &i.DeviceType, + &i.DeviceModel, + &i.OsName, + &i.OsVersion, + &i.PushNotificationToken, + &i.IsActive, + &i.IsVerified, + &i.LastUsedAt, + &i.AppVersion, + &i.ClientIp, + &i.ExpiresAt, + &i.IsRevoked, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/db/sqlc/companies.sql.go b/db/sqlc/companies.sql.go new file mode 100644 index 0000000..53af8ae --- /dev/null +++ b/db/sqlc/companies.sql.go @@ -0,0 +1,1172 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.29.0 +// source: companies.sql + +package sqlc + +import ( + "context" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" +) + +const createCompany = `-- name: CreateCompany :one +INSERT INTO companies ( + id, + owner_id, + company_name, + company_email, + company_phone, + company_size, + company_industry, + company_description, + company_headquarters, + company_logo, + company_website, + primary_contact_name, + primary_contact_email, + primary_contact_phone, + company_address, + company_city, + company_postal_code, + company_country, + company_registration_number, + registration_country, + tax_id, + incorporation_date, + account_status, + kyb_status, + kyb_verified_at, + kyb_verification_method, + kyb_verification_provider, + kyb_rejection_reason, + legal_entity_type, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + $7, + $8, + $9, + $10, + $11, + $12, + $13, + $14, + $15, + $16, + $17, + $18, + $19, + $20, + $21, + $22, + COALESCE($23, 'pending'), + COALESCE($24, 'pending'), + $25, + $26, + $27, + $28, + $29, + COALESCE($30, NOW()), + COALESCE($31, NOW()) +) RETURNING id, owner_id, company_name, company_email, company_phone, company_size, company_industry, company_description, company_headquarters, company_logo, company_website, primary_contact_name, primary_contact_email, primary_contact_phone, company_address, company_city, company_postal_code, company_country, company_registration_number, registration_country, tax_id, incorporation_date, account_status, kyb_status, kyb_verified_at, kyb_verification_method, kyb_verification_provider, kyb_rejection_reason, legal_entity_type, created_at, updated_at +` + +type CreateCompanyParams struct { + ID interface{} `json:"id"` + OwnerID uuid.UUID `json:"owner_id"` + CompanyName string `json:"company_name"` + CompanyEmail pgtype.Text `json:"company_email"` + CompanyPhone pgtype.Text `json:"company_phone"` + CompanySize pgtype.Text `json:"company_size"` + CompanyIndustry pgtype.Text `json:"company_industry"` + CompanyDescription pgtype.Text `json:"company_description"` + CompanyHeadquarters pgtype.Text `json:"company_headquarters"` + CompanyLogo pgtype.Text `json:"company_logo"` + CompanyWebsite pgtype.Text `json:"company_website"` + PrimaryContactName pgtype.Text `json:"primary_contact_name"` + PrimaryContactEmail pgtype.Text `json:"primary_contact_email"` + PrimaryContactPhone pgtype.Text `json:"primary_contact_phone"` + CompanyAddress pgtype.Text `json:"company_address"` + CompanyCity pgtype.Text `json:"company_city"` + CompanyPostalCode pgtype.Text `json:"company_postal_code"` + CompanyCountry pgtype.Text `json:"company_country"` + CompanyRegistrationNumber pgtype.Text `json:"company_registration_number"` + RegistrationCountry pgtype.Text `json:"registration_country"` + TaxID pgtype.Text `json:"tax_id"` + IncorporationDate pgtype.Date `json:"incorporation_date"` + AccountStatus interface{} `json:"account_status"` + KybStatus interface{} `json:"kyb_status"` + KybVerifiedAt pgtype.Timestamptz `json:"kyb_verified_at"` + KybVerificationMethod pgtype.Text `json:"kyb_verification_method"` + KybVerificationProvider pgtype.Text `json:"kyb_verification_provider"` + KybRejectionReason pgtype.Text `json:"kyb_rejection_reason"` + LegalEntityType pgtype.Text `json:"legal_entity_type"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateCompany(ctx context.Context, arg CreateCompanyParams) (Companies, error) { + row := q.db.QueryRow(ctx, createCompany, + arg.ID, + arg.OwnerID, + arg.CompanyName, + arg.CompanyEmail, + arg.CompanyPhone, + arg.CompanySize, + arg.CompanyIndustry, + arg.CompanyDescription, + arg.CompanyHeadquarters, + arg.CompanyLogo, + arg.CompanyWebsite, + arg.PrimaryContactName, + arg.PrimaryContactEmail, + arg.PrimaryContactPhone, + arg.CompanyAddress, + arg.CompanyCity, + arg.CompanyPostalCode, + arg.CompanyCountry, + arg.CompanyRegistrationNumber, + arg.RegistrationCountry, + arg.TaxID, + arg.IncorporationDate, + arg.AccountStatus, + arg.KybStatus, + arg.KybVerifiedAt, + arg.KybVerificationMethod, + arg.KybVerificationProvider, + arg.KybRejectionReason, + arg.LegalEntityType, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i Companies + err := row.Scan( + &i.ID, + &i.OwnerID, + &i.CompanyName, + &i.CompanyEmail, + &i.CompanyPhone, + &i.CompanySize, + &i.CompanyIndustry, + &i.CompanyDescription, + &i.CompanyHeadquarters, + &i.CompanyLogo, + &i.CompanyWebsite, + &i.PrimaryContactName, + &i.PrimaryContactEmail, + &i.PrimaryContactPhone, + &i.CompanyAddress, + &i.CompanyCity, + &i.CompanyPostalCode, + &i.CompanyCountry, + &i.CompanyRegistrationNumber, + &i.RegistrationCountry, + &i.TaxID, + &i.IncorporationDate, + &i.AccountStatus, + &i.KybStatus, + &i.KybVerifiedAt, + &i.KybVerificationMethod, + &i.KybVerificationProvider, + &i.KybRejectionReason, + &i.LegalEntityType, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createCompanyEmployee = `-- name: CreateCompanyEmployee :one +INSERT INTO company_employees ( + id, + company_id, + user_id, + employee_id, + department, + position, + employment_status, + employment_type, + start_date, + end_date, + manager_id, + salary_amount, + salary_currency, + salary_frequency, + hourly_rate, + payment_method, + payment_split, + tax_information, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + COALESCE($7, 'active'), + $8, + $9, + $10, + $11, + $12, + $13, + $14, + $15, + $16, + $17, + $18, + COALESCE($19, NOW()), + COALESCE($20, NOW()) +) RETURNING id, company_id, user_id, employee_id, department, position, employment_status, employment_type, start_date, end_date, manager_id, salary_amount, salary_currency, salary_frequency, hourly_rate, payment_method, payment_split, tax_information, created_at, updated_at +` + +type CreateCompanyEmployeeParams struct { + ID interface{} `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + UserID pgtype.UUID `json:"user_id"` + EmployeeID pgtype.Text `json:"employee_id"` + Department pgtype.Text `json:"department"` + Position pgtype.Text `json:"position"` + EmploymentStatus interface{} `json:"employment_status"` + EmploymentType pgtype.Text `json:"employment_type"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` + ManagerID pgtype.UUID `json:"manager_id"` + SalaryAmount pgtype.Numeric `json:"salary_amount"` + SalaryCurrency pgtype.Text `json:"salary_currency"` + SalaryFrequency pgtype.Text `json:"salary_frequency"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + PaymentMethod pgtype.Text `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + TaxInformation []byte `json:"tax_information"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateCompanyEmployee(ctx context.Context, arg CreateCompanyEmployeeParams) (CompanyEmployees, error) { + row := q.db.QueryRow(ctx, createCompanyEmployee, + arg.ID, + arg.CompanyID, + arg.UserID, + arg.EmployeeID, + arg.Department, + arg.Position, + arg.EmploymentStatus, + arg.EmploymentType, + arg.StartDate, + arg.EndDate, + arg.ManagerID, + arg.SalaryAmount, + arg.SalaryCurrency, + arg.SalaryFrequency, + arg.HourlyRate, + arg.PaymentMethod, + arg.PaymentSplit, + arg.TaxInformation, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i CompanyEmployees + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.UserID, + &i.EmployeeID, + &i.Department, + &i.Position, + &i.EmploymentStatus, + &i.EmploymentType, + &i.StartDate, + &i.EndDate, + &i.ManagerID, + &i.SalaryAmount, + &i.SalaryCurrency, + &i.SalaryFrequency, + &i.HourlyRate, + &i.PaymentMethod, + &i.PaymentSplit, + &i.TaxInformation, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createCompanyUser = `-- name: CreateCompanyUser :one +INSERT INTO company_users ( + id, + company_id, + user_id, + role, + department, + job_title, + is_administrator, + can_manage_payroll, + can_manage_invoices, + can_manage_employees, + can_manage_company_settings, + can_manage_bank_accounts, + can_manage_wallets, + permissions, + is_active, + added_by, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + COALESCE($7, FALSE), + COALESCE($8, FALSE), + COALESCE($9, FALSE), + COALESCE($10, FALSE), + COALESCE($11, FALSE), + COALESCE($12, FALSE), + COALESCE($13, FALSE), + $14, + COALESCE($15, TRUE), + $16, + COALESCE($17, NOW()), + COALESCE($18, NOW()) +) RETURNING id, company_id, user_id, role, department, job_title, is_administrator, can_manage_payroll, can_manage_invoices, can_manage_employees, can_manage_company_settings, can_manage_bank_accounts, can_manage_wallets, permissions, is_active, added_by, created_at, updated_at +` + +type CreateCompanyUserParams struct { + ID interface{} `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + UserID uuid.UUID `json:"user_id"` + Role string `json:"role"` + Department pgtype.Text `json:"department"` + JobTitle pgtype.Text `json:"job_title"` + IsAdministrator interface{} `json:"is_administrator"` + CanManagePayroll interface{} `json:"can_manage_payroll"` + CanManageInvoices interface{} `json:"can_manage_invoices"` + CanManageEmployees interface{} `json:"can_manage_employees"` + CanManageCompanySettings interface{} `json:"can_manage_company_settings"` + CanManageBankAccounts interface{} `json:"can_manage_bank_accounts"` + CanManageWallets interface{} `json:"can_manage_wallets"` + Permissions []byte `json:"permissions"` + IsActive interface{} `json:"is_active"` + AddedBy pgtype.UUID `json:"added_by"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateCompanyUser(ctx context.Context, arg CreateCompanyUserParams) (CompanyUsers, error) { + row := q.db.QueryRow(ctx, createCompanyUser, + arg.ID, + arg.CompanyID, + arg.UserID, + arg.Role, + arg.Department, + arg.JobTitle, + arg.IsAdministrator, + arg.CanManagePayroll, + arg.CanManageInvoices, + arg.CanManageEmployees, + arg.CanManageCompanySettings, + arg.CanManageBankAccounts, + arg.CanManageWallets, + arg.Permissions, + arg.IsActive, + arg.AddedBy, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i CompanyUsers + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.UserID, + &i.Role, + &i.Department, + &i.JobTitle, + &i.IsAdministrator, + &i.CanManagePayroll, + &i.CanManageInvoices, + &i.CanManageEmployees, + &i.CanManageCompanySettings, + &i.CanManageBankAccounts, + &i.CanManageWallets, + &i.Permissions, + &i.IsActive, + &i.AddedBy, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getCompaniesAccessibleToUser = `-- name: GetCompaniesAccessibleToUser :many +SELECT DISTINCT c.id, c.owner_id, c.company_name, c.company_email, c.company_phone, c.company_size, c.company_industry, c.company_description, c.company_headquarters, c.company_logo, c.company_website, c.primary_contact_name, c.primary_contact_email, c.primary_contact_phone, c.company_address, c.company_city, c.company_postal_code, c.company_country, c.company_registration_number, c.registration_country, c.tax_id, c.incorporation_date, c.account_status, c.kyb_status, c.kyb_verified_at, c.kyb_verification_method, c.kyb_verification_provider, c.kyb_rejection_reason, c.legal_entity_type, c.created_at, c.updated_at +FROM companies c +LEFT JOIN company_users cu ON c.id = cu.company_id +WHERE c.owner_id = $1 OR cu.user_id = $1 +ORDER BY c.created_at DESC +` + +func (q *Queries) GetCompaniesAccessibleToUser(ctx context.Context, userID uuid.UUID) ([]Companies, error) { + rows, err := q.db.Query(ctx, getCompaniesAccessibleToUser, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []Companies{} + for rows.Next() { + var i Companies + if err := rows.Scan( + &i.ID, + &i.OwnerID, + &i.CompanyName, + &i.CompanyEmail, + &i.CompanyPhone, + &i.CompanySize, + &i.CompanyIndustry, + &i.CompanyDescription, + &i.CompanyHeadquarters, + &i.CompanyLogo, + &i.CompanyWebsite, + &i.PrimaryContactName, + &i.PrimaryContactEmail, + &i.PrimaryContactPhone, + &i.CompanyAddress, + &i.CompanyCity, + &i.CompanyPostalCode, + &i.CompanyCountry, + &i.CompanyRegistrationNumber, + &i.RegistrationCountry, + &i.TaxID, + &i.IncorporationDate, + &i.AccountStatus, + &i.KybStatus, + &i.KybVerifiedAt, + &i.KybVerificationMethod, + &i.KybVerificationProvider, + &i.KybRejectionReason, + &i.LegalEntityType, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getCompaniesByOwner = `-- name: GetCompaniesByOwner :many +SELECT id, owner_id, company_name, company_email, company_phone, company_size, company_industry, company_description, company_headquarters, company_logo, company_website, primary_contact_name, primary_contact_email, primary_contact_phone, company_address, company_city, company_postal_code, company_country, company_registration_number, registration_country, tax_id, incorporation_date, account_status, kyb_status, kyb_verified_at, kyb_verification_method, kyb_verification_provider, kyb_rejection_reason, legal_entity_type, created_at, updated_at FROM companies +WHERE owner_id = $1 +ORDER BY created_at DESC +` + +func (q *Queries) GetCompaniesByOwner(ctx context.Context, ownerID uuid.UUID) ([]Companies, error) { + rows, err := q.db.Query(ctx, getCompaniesByOwner, ownerID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []Companies{} + for rows.Next() { + var i Companies + if err := rows.Scan( + &i.ID, + &i.OwnerID, + &i.CompanyName, + &i.CompanyEmail, + &i.CompanyPhone, + &i.CompanySize, + &i.CompanyIndustry, + &i.CompanyDescription, + &i.CompanyHeadquarters, + &i.CompanyLogo, + &i.CompanyWebsite, + &i.PrimaryContactName, + &i.PrimaryContactEmail, + &i.PrimaryContactPhone, + &i.CompanyAddress, + &i.CompanyCity, + &i.CompanyPostalCode, + &i.CompanyCountry, + &i.CompanyRegistrationNumber, + &i.RegistrationCountry, + &i.TaxID, + &i.IncorporationDate, + &i.AccountStatus, + &i.KybStatus, + &i.KybVerifiedAt, + &i.KybVerificationMethod, + &i.KybVerificationProvider, + &i.KybRejectionReason, + &i.LegalEntityType, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getCompanyByID = `-- name: GetCompanyByID :one +SELECT id, owner_id, company_name, company_email, company_phone, company_size, company_industry, company_description, company_headquarters, company_logo, company_website, primary_contact_name, primary_contact_email, primary_contact_phone, company_address, company_city, company_postal_code, company_country, company_registration_number, registration_country, tax_id, incorporation_date, account_status, kyb_status, kyb_verified_at, kyb_verification_method, kyb_verification_provider, kyb_rejection_reason, legal_entity_type, created_at, updated_at FROM companies WHERE id = $1 +` + +func (q *Queries) GetCompanyByID(ctx context.Context, id uuid.UUID) (Companies, error) { + row := q.db.QueryRow(ctx, getCompanyByID, id) + var i Companies + err := row.Scan( + &i.ID, + &i.OwnerID, + &i.CompanyName, + &i.CompanyEmail, + &i.CompanyPhone, + &i.CompanySize, + &i.CompanyIndustry, + &i.CompanyDescription, + &i.CompanyHeadquarters, + &i.CompanyLogo, + &i.CompanyWebsite, + &i.PrimaryContactName, + &i.PrimaryContactEmail, + &i.PrimaryContactPhone, + &i.CompanyAddress, + &i.CompanyCity, + &i.CompanyPostalCode, + &i.CompanyCountry, + &i.CompanyRegistrationNumber, + &i.RegistrationCountry, + &i.TaxID, + &i.IncorporationDate, + &i.AccountStatus, + &i.KybStatus, + &i.KybVerifiedAt, + &i.KybVerificationMethod, + &i.KybVerificationProvider, + &i.KybRejectionReason, + &i.LegalEntityType, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getCompanyEmployeeByID = `-- name: GetCompanyEmployeeByID :one +SELECT ce.id, ce.company_id, ce.user_id, ce.employee_id, ce.department, ce.position, ce.employment_status, ce.employment_type, ce.start_date, ce.end_date, ce.manager_id, ce.salary_amount, ce.salary_currency, ce.salary_frequency, ce.hourly_rate, ce.payment_method, ce.payment_split, ce.tax_information, ce.created_at, ce.updated_at, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM company_employees ce +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE ce.id = $1 +` + +type GetCompanyEmployeeByIDRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + UserID pgtype.UUID `json:"user_id"` + EmployeeID pgtype.Text `json:"employee_id"` + Department pgtype.Text `json:"department"` + Position pgtype.Text `json:"position"` + EmploymentStatus pgtype.Text `json:"employment_status"` + EmploymentType pgtype.Text `json:"employment_type"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` + ManagerID pgtype.UUID `json:"manager_id"` + SalaryAmount pgtype.Numeric `json:"salary_amount"` + SalaryCurrency pgtype.Text `json:"salary_currency"` + SalaryFrequency pgtype.Text `json:"salary_frequency"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + PaymentMethod pgtype.Text `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + TaxInformation []byte `json:"tax_information"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + Email pgtype.Text `json:"email"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` +} + +func (q *Queries) GetCompanyEmployeeByID(ctx context.Context, id uuid.UUID) (GetCompanyEmployeeByIDRow, error) { + row := q.db.QueryRow(ctx, getCompanyEmployeeByID, id) + var i GetCompanyEmployeeByIDRow + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.UserID, + &i.EmployeeID, + &i.Department, + &i.Position, + &i.EmploymentStatus, + &i.EmploymentType, + &i.StartDate, + &i.EndDate, + &i.ManagerID, + &i.SalaryAmount, + &i.SalaryCurrency, + &i.SalaryFrequency, + &i.HourlyRate, + &i.PaymentMethod, + &i.PaymentSplit, + &i.TaxInformation, + &i.CreatedAt, + &i.UpdatedAt, + &i.Email, + &i.FirstName, + &i.LastName, + ) + return i, err +} + +const getCompanyEmployeesByCompany = `-- name: GetCompanyEmployeesByCompany :many +SELECT ce.id, ce.company_id, ce.user_id, ce.employee_id, ce.department, ce.position, ce.employment_status, ce.employment_type, ce.start_date, ce.end_date, ce.manager_id, ce.salary_amount, ce.salary_currency, ce.salary_frequency, ce.hourly_rate, ce.payment_method, ce.payment_split, ce.tax_information, ce.created_at, ce.updated_at, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM company_employees ce +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE ce.company_id = $1 +ORDER BY ce.created_at DESC +` + +type GetCompanyEmployeesByCompanyRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + UserID pgtype.UUID `json:"user_id"` + EmployeeID pgtype.Text `json:"employee_id"` + Department pgtype.Text `json:"department"` + Position pgtype.Text `json:"position"` + EmploymentStatus pgtype.Text `json:"employment_status"` + EmploymentType pgtype.Text `json:"employment_type"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` + ManagerID pgtype.UUID `json:"manager_id"` + SalaryAmount pgtype.Numeric `json:"salary_amount"` + SalaryCurrency pgtype.Text `json:"salary_currency"` + SalaryFrequency pgtype.Text `json:"salary_frequency"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + PaymentMethod pgtype.Text `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + TaxInformation []byte `json:"tax_information"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + Email pgtype.Text `json:"email"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` +} + +func (q *Queries) GetCompanyEmployeesByCompany(ctx context.Context, companyID uuid.UUID) ([]GetCompanyEmployeesByCompanyRow, error) { + rows, err := q.db.Query(ctx, getCompanyEmployeesByCompany, companyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetCompanyEmployeesByCompanyRow{} + for rows.Next() { + var i GetCompanyEmployeesByCompanyRow + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.UserID, + &i.EmployeeID, + &i.Department, + &i.Position, + &i.EmploymentStatus, + &i.EmploymentType, + &i.StartDate, + &i.EndDate, + &i.ManagerID, + &i.SalaryAmount, + &i.SalaryCurrency, + &i.SalaryFrequency, + &i.HourlyRate, + &i.PaymentMethod, + &i.PaymentSplit, + &i.TaxInformation, + &i.CreatedAt, + &i.UpdatedAt, + &i.Email, + &i.FirstName, + &i.LastName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getCompanyUser = `-- name: GetCompanyUser :one +SELECT cu.id, cu.company_id, cu.user_id, cu.role, cu.department, cu.job_title, cu.is_administrator, cu.can_manage_payroll, cu.can_manage_invoices, cu.can_manage_employees, cu.can_manage_company_settings, cu.can_manage_bank_accounts, cu.can_manage_wallets, cu.permissions, cu.is_active, cu.added_by, cu.created_at, cu.updated_at, u.email, u.account_status, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM company_users cu +JOIN users u ON cu.user_id = u.id +LEFT JOIN company_staff_profiles csp ON cu.id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE cu.company_id = $1 AND cu.user_id = $2 +` + +type GetCompanyUserParams struct { + CompanyID uuid.UUID `json:"company_id"` + UserID uuid.UUID `json:"user_id"` +} + +type GetCompanyUserRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + UserID uuid.UUID `json:"user_id"` + Role string `json:"role"` + Department pgtype.Text `json:"department"` + JobTitle pgtype.Text `json:"job_title"` + IsAdministrator pgtype.Bool `json:"is_administrator"` + CanManagePayroll pgtype.Bool `json:"can_manage_payroll"` + CanManageInvoices pgtype.Bool `json:"can_manage_invoices"` + CanManageEmployees pgtype.Bool `json:"can_manage_employees"` + CanManageCompanySettings pgtype.Bool `json:"can_manage_company_settings"` + CanManageBankAccounts pgtype.Bool `json:"can_manage_bank_accounts"` + CanManageWallets pgtype.Bool `json:"can_manage_wallets"` + Permissions []byte `json:"permissions"` + IsActive pgtype.Bool `json:"is_active"` + AddedBy pgtype.UUID `json:"added_by"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + Email string `json:"email"` + AccountStatus pgtype.Text `json:"account_status"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` +} + +func (q *Queries) GetCompanyUser(ctx context.Context, arg GetCompanyUserParams) (GetCompanyUserRow, error) { + row := q.db.QueryRow(ctx, getCompanyUser, arg.CompanyID, arg.UserID) + var i GetCompanyUserRow + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.UserID, + &i.Role, + &i.Department, + &i.JobTitle, + &i.IsAdministrator, + &i.CanManagePayroll, + &i.CanManageInvoices, + &i.CanManageEmployees, + &i.CanManageCompanySettings, + &i.CanManageBankAccounts, + &i.CanManageWallets, + &i.Permissions, + &i.IsActive, + &i.AddedBy, + &i.CreatedAt, + &i.UpdatedAt, + &i.Email, + &i.AccountStatus, + &i.FirstName, + &i.LastName, + ) + return i, err +} + +const getCompanyUsersByCompany = `-- name: GetCompanyUsersByCompany :many +SELECT cu.id, cu.company_id, cu.user_id, cu.role, cu.department, cu.job_title, cu.is_administrator, cu.can_manage_payroll, cu.can_manage_invoices, cu.can_manage_employees, cu.can_manage_company_settings, cu.can_manage_bank_accounts, cu.can_manage_wallets, cu.permissions, cu.is_active, cu.added_by, cu.created_at, cu.updated_at, u.email, u.account_status, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM company_users cu +JOIN users u ON cu.user_id = u.id +LEFT JOIN company_staff_profiles csp ON cu.id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE cu.company_id = $1 AND cu.is_active = TRUE +ORDER BY cu.created_at DESC +` + +type GetCompanyUsersByCompanyRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + UserID uuid.UUID `json:"user_id"` + Role string `json:"role"` + Department pgtype.Text `json:"department"` + JobTitle pgtype.Text `json:"job_title"` + IsAdministrator pgtype.Bool `json:"is_administrator"` + CanManagePayroll pgtype.Bool `json:"can_manage_payroll"` + CanManageInvoices pgtype.Bool `json:"can_manage_invoices"` + CanManageEmployees pgtype.Bool `json:"can_manage_employees"` + CanManageCompanySettings pgtype.Bool `json:"can_manage_company_settings"` + CanManageBankAccounts pgtype.Bool `json:"can_manage_bank_accounts"` + CanManageWallets pgtype.Bool `json:"can_manage_wallets"` + Permissions []byte `json:"permissions"` + IsActive pgtype.Bool `json:"is_active"` + AddedBy pgtype.UUID `json:"added_by"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + Email string `json:"email"` + AccountStatus pgtype.Text `json:"account_status"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` +} + +func (q *Queries) GetCompanyUsersByCompany(ctx context.Context, companyID uuid.UUID) ([]GetCompanyUsersByCompanyRow, error) { + rows, err := q.db.Query(ctx, getCompanyUsersByCompany, companyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetCompanyUsersByCompanyRow{} + for rows.Next() { + var i GetCompanyUsersByCompanyRow + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.UserID, + &i.Role, + &i.Department, + &i.JobTitle, + &i.IsAdministrator, + &i.CanManagePayroll, + &i.CanManageInvoices, + &i.CanManageEmployees, + &i.CanManageCompanySettings, + &i.CanManageBankAccounts, + &i.CanManageWallets, + &i.Permissions, + &i.IsActive, + &i.AddedBy, + &i.CreatedAt, + &i.UpdatedAt, + &i.Email, + &i.AccountStatus, + &i.FirstName, + &i.LastName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateCompany = `-- name: UpdateCompany :one +UPDATE companies SET + company_name = COALESCE($1, company_name), + company_email = COALESCE($2, company_email), + company_phone = COALESCE($3, company_phone), + company_size = COALESCE($4, company_size), + company_industry = COALESCE($5, company_industry), + company_description = COALESCE($6, company_description), + company_headquarters = COALESCE($7, company_headquarters), + company_logo = COALESCE($8, company_logo), + company_website = COALESCE($9, company_website), + primary_contact_name = COALESCE($10, primary_contact_name), + primary_contact_email = COALESCE($11, primary_contact_email), + primary_contact_phone = COALESCE($12, primary_contact_phone), + company_address = COALESCE($13, company_address), + company_city = COALESCE($14, company_city), + company_postal_code = COALESCE($15, company_postal_code), + company_country = COALESCE($16, company_country), + company_registration_number = COALESCE($17, company_registration_number), + registration_country = COALESCE($18, registration_country), + tax_id = COALESCE($19, tax_id), + incorporation_date = COALESCE($20, incorporation_date), + account_status = COALESCE($21, account_status), + kyb_status = COALESCE($22, kyb_status), + kyb_verified_at = COALESCE($23, kyb_verified_at), + kyb_verification_method = COALESCE($24, kyb_verification_method), + kyb_verification_provider = COALESCE($25, kyb_verification_provider), + kyb_rejection_reason = COALESCE($26, kyb_rejection_reason), + legal_entity_type = COALESCE($27, legal_entity_type), + updated_at = NOW() +WHERE id = $28 +RETURNING id, owner_id, company_name, company_email, company_phone, company_size, company_industry, company_description, company_headquarters, company_logo, company_website, primary_contact_name, primary_contact_email, primary_contact_phone, company_address, company_city, company_postal_code, company_country, company_registration_number, registration_country, tax_id, incorporation_date, account_status, kyb_status, kyb_verified_at, kyb_verification_method, kyb_verification_provider, kyb_rejection_reason, legal_entity_type, created_at, updated_at +` + +type UpdateCompanyParams struct { + CompanyName string `json:"company_name"` + CompanyEmail pgtype.Text `json:"company_email"` + CompanyPhone pgtype.Text `json:"company_phone"` + CompanySize pgtype.Text `json:"company_size"` + CompanyIndustry pgtype.Text `json:"company_industry"` + CompanyDescription pgtype.Text `json:"company_description"` + CompanyHeadquarters pgtype.Text `json:"company_headquarters"` + CompanyLogo pgtype.Text `json:"company_logo"` + CompanyWebsite pgtype.Text `json:"company_website"` + PrimaryContactName pgtype.Text `json:"primary_contact_name"` + PrimaryContactEmail pgtype.Text `json:"primary_contact_email"` + PrimaryContactPhone pgtype.Text `json:"primary_contact_phone"` + CompanyAddress pgtype.Text `json:"company_address"` + CompanyCity pgtype.Text `json:"company_city"` + CompanyPostalCode pgtype.Text `json:"company_postal_code"` + CompanyCountry pgtype.Text `json:"company_country"` + CompanyRegistrationNumber pgtype.Text `json:"company_registration_number"` + RegistrationCountry pgtype.Text `json:"registration_country"` + TaxID pgtype.Text `json:"tax_id"` + IncorporationDate pgtype.Date `json:"incorporation_date"` + AccountStatus pgtype.Text `json:"account_status"` + KybStatus pgtype.Text `json:"kyb_status"` + KybVerifiedAt pgtype.Timestamptz `json:"kyb_verified_at"` + KybVerificationMethod pgtype.Text `json:"kyb_verification_method"` + KybVerificationProvider pgtype.Text `json:"kyb_verification_provider"` + KybRejectionReason pgtype.Text `json:"kyb_rejection_reason"` + LegalEntityType pgtype.Text `json:"legal_entity_type"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdateCompany(ctx context.Context, arg UpdateCompanyParams) (Companies, error) { + row := q.db.QueryRow(ctx, updateCompany, + arg.CompanyName, + arg.CompanyEmail, + arg.CompanyPhone, + arg.CompanySize, + arg.CompanyIndustry, + arg.CompanyDescription, + arg.CompanyHeadquarters, + arg.CompanyLogo, + arg.CompanyWebsite, + arg.PrimaryContactName, + arg.PrimaryContactEmail, + arg.PrimaryContactPhone, + arg.CompanyAddress, + arg.CompanyCity, + arg.CompanyPostalCode, + arg.CompanyCountry, + arg.CompanyRegistrationNumber, + arg.RegistrationCountry, + arg.TaxID, + arg.IncorporationDate, + arg.AccountStatus, + arg.KybStatus, + arg.KybVerifiedAt, + arg.KybVerificationMethod, + arg.KybVerificationProvider, + arg.KybRejectionReason, + arg.LegalEntityType, + arg.ID, + ) + var i Companies + err := row.Scan( + &i.ID, + &i.OwnerID, + &i.CompanyName, + &i.CompanyEmail, + &i.CompanyPhone, + &i.CompanySize, + &i.CompanyIndustry, + &i.CompanyDescription, + &i.CompanyHeadquarters, + &i.CompanyLogo, + &i.CompanyWebsite, + &i.PrimaryContactName, + &i.PrimaryContactEmail, + &i.PrimaryContactPhone, + &i.CompanyAddress, + &i.CompanyCity, + &i.CompanyPostalCode, + &i.CompanyCountry, + &i.CompanyRegistrationNumber, + &i.RegistrationCountry, + &i.TaxID, + &i.IncorporationDate, + &i.AccountStatus, + &i.KybStatus, + &i.KybVerifiedAt, + &i.KybVerificationMethod, + &i.KybVerificationProvider, + &i.KybRejectionReason, + &i.LegalEntityType, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateCompanyEmployee = `-- name: UpdateCompanyEmployee :one +UPDATE company_employees SET + employee_id = COALESCE($1, employee_id), + department = COALESCE($2, department), + position = COALESCE($3, position), + employment_status = COALESCE($4, employment_status), + employment_type = COALESCE($5, employment_type), + start_date = COALESCE($6, start_date), + end_date = COALESCE($7, end_date), + manager_id = COALESCE($8, manager_id), + salary_amount = COALESCE($9, salary_amount), + salary_currency = COALESCE($10, salary_currency), + salary_frequency = COALESCE($11, salary_frequency), + hourly_rate = COALESCE($12, hourly_rate), + payment_method = COALESCE($13, payment_method), + payment_split = COALESCE($14, payment_split), + tax_information = COALESCE($15, tax_information), + updated_at = NOW() +WHERE id = $16 +RETURNING id, company_id, user_id, employee_id, department, position, employment_status, employment_type, start_date, end_date, manager_id, salary_amount, salary_currency, salary_frequency, hourly_rate, payment_method, payment_split, tax_information, created_at, updated_at +` + +type UpdateCompanyEmployeeParams struct { + EmployeeID pgtype.Text `json:"employee_id"` + Department pgtype.Text `json:"department"` + Position pgtype.Text `json:"position"` + EmploymentStatus pgtype.Text `json:"employment_status"` + EmploymentType pgtype.Text `json:"employment_type"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` + ManagerID pgtype.UUID `json:"manager_id"` + SalaryAmount pgtype.Numeric `json:"salary_amount"` + SalaryCurrency pgtype.Text `json:"salary_currency"` + SalaryFrequency pgtype.Text `json:"salary_frequency"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + PaymentMethod pgtype.Text `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + TaxInformation []byte `json:"tax_information"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdateCompanyEmployee(ctx context.Context, arg UpdateCompanyEmployeeParams) (CompanyEmployees, error) { + row := q.db.QueryRow(ctx, updateCompanyEmployee, + arg.EmployeeID, + arg.Department, + arg.Position, + arg.EmploymentStatus, + arg.EmploymentType, + arg.StartDate, + arg.EndDate, + arg.ManagerID, + arg.SalaryAmount, + arg.SalaryCurrency, + arg.SalaryFrequency, + arg.HourlyRate, + arg.PaymentMethod, + arg.PaymentSplit, + arg.TaxInformation, + arg.ID, + ) + var i CompanyEmployees + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.UserID, + &i.EmployeeID, + &i.Department, + &i.Position, + &i.EmploymentStatus, + &i.EmploymentType, + &i.StartDate, + &i.EndDate, + &i.ManagerID, + &i.SalaryAmount, + &i.SalaryCurrency, + &i.SalaryFrequency, + &i.HourlyRate, + &i.PaymentMethod, + &i.PaymentSplit, + &i.TaxInformation, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateCompanyUser = `-- name: UpdateCompanyUser :one +UPDATE company_users SET + role = COALESCE($1, role), + department = COALESCE($2, department), + job_title = COALESCE($3, job_title), + is_administrator = COALESCE($4, is_administrator), + can_manage_payroll = COALESCE($5, can_manage_payroll), + can_manage_invoices = COALESCE($6, can_manage_invoices), + can_manage_employees = COALESCE($7, can_manage_employees), + can_manage_company_settings = COALESCE($8, can_manage_company_settings), + can_manage_bank_accounts = COALESCE($9, can_manage_bank_accounts), + can_manage_wallets = COALESCE($10, can_manage_wallets), + permissions = COALESCE($11, permissions), + is_active = COALESCE($12, is_active), + updated_at = NOW() +WHERE company_id = $13 AND user_id = $14 +RETURNING id, company_id, user_id, role, department, job_title, is_administrator, can_manage_payroll, can_manage_invoices, can_manage_employees, can_manage_company_settings, can_manage_bank_accounts, can_manage_wallets, permissions, is_active, added_by, created_at, updated_at +` + +type UpdateCompanyUserParams struct { + Role string `json:"role"` + Department pgtype.Text `json:"department"` + JobTitle pgtype.Text `json:"job_title"` + IsAdministrator pgtype.Bool `json:"is_administrator"` + CanManagePayroll pgtype.Bool `json:"can_manage_payroll"` + CanManageInvoices pgtype.Bool `json:"can_manage_invoices"` + CanManageEmployees pgtype.Bool `json:"can_manage_employees"` + CanManageCompanySettings pgtype.Bool `json:"can_manage_company_settings"` + CanManageBankAccounts pgtype.Bool `json:"can_manage_bank_accounts"` + CanManageWallets pgtype.Bool `json:"can_manage_wallets"` + Permissions []byte `json:"permissions"` + IsActive pgtype.Bool `json:"is_active"` + CompanyID uuid.UUID `json:"company_id"` + UserID uuid.UUID `json:"user_id"` +} + +func (q *Queries) UpdateCompanyUser(ctx context.Context, arg UpdateCompanyUserParams) (CompanyUsers, error) { + row := q.db.QueryRow(ctx, updateCompanyUser, + arg.Role, + arg.Department, + arg.JobTitle, + arg.IsAdministrator, + arg.CanManagePayroll, + arg.CanManageInvoices, + arg.CanManageEmployees, + arg.CanManageCompanySettings, + arg.CanManageBankAccounts, + arg.CanManageWallets, + arg.Permissions, + arg.IsActive, + arg.CompanyID, + arg.UserID, + ) + var i CompanyUsers + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.UserID, + &i.Role, + &i.Department, + &i.JobTitle, + &i.IsAdministrator, + &i.CanManagePayroll, + &i.CanManageInvoices, + &i.CanManageEmployees, + &i.CanManageCompanySettings, + &i.CanManageBankAccounts, + &i.CanManageWallets, + &i.Permissions, + &i.IsActive, + &i.AddedBy, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/db/sqlc/compliance.sql.go b/db/sqlc/compliance.sql.go new file mode 100644 index 0000000..082b8a9 --- /dev/null +++ b/db/sqlc/compliance.sql.go @@ -0,0 +1,1250 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.29.0 +// source: compliance.sql + +package sqlc + +import ( + "context" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" +) + +const createCompanyCountryKYBStatus = `-- name: CreateCompanyCountryKYBStatus :one +INSERT INTO company_country_kyb_status ( + id, + company_id, + country_id, + verification_status, + verification_level, + verification_date, + expiry_date, + rejection_reason, + notes, + risk_rating, + restricted_features, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + COALESCE($4, 'pending'), + $5, + $6, + $7, + $8, + $9, + $10, + $11, + COALESCE($12, NOW()), + COALESCE($13, NOW()) +) RETURNING id, company_id, country_id, verification_status, verification_level, verification_date, expiry_date, rejection_reason, notes, risk_rating, restricted_features, created_at, updated_at +` + +type CreateCompanyCountryKYBStatusParams struct { + ID interface{} `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + CountryID uuid.UUID `json:"country_id"` + VerificationStatus interface{} `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationDate pgtype.Timestamptz `json:"verification_date"` + ExpiryDate pgtype.Timestamptz `json:"expiry_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Notes pgtype.Text `json:"notes"` + RiskRating pgtype.Text `json:"risk_rating"` + RestrictedFeatures []byte `json:"restricted_features"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateCompanyCountryKYBStatus(ctx context.Context, arg CreateCompanyCountryKYBStatusParams) (CompanyCountryKybStatus, error) { + row := q.db.QueryRow(ctx, createCompanyCountryKYBStatus, + arg.ID, + arg.CompanyID, + arg.CountryID, + arg.VerificationStatus, + arg.VerificationLevel, + arg.VerificationDate, + arg.ExpiryDate, + arg.RejectionReason, + arg.Notes, + arg.RiskRating, + arg.RestrictedFeatures, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i CompanyCountryKybStatus + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.CountryID, + &i.VerificationStatus, + &i.VerificationLevel, + &i.VerificationDate, + &i.ExpiryDate, + &i.RejectionReason, + &i.Notes, + &i.RiskRating, + &i.RestrictedFeatures, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createKYBDocument = `-- name: CreateKYBDocument :one +INSERT INTO kyb_documents ( + id, + company_id, + country_id, + document_type, + document_number, + document_country, + issue_date, + expiry_date, + document_url, + ipfs_hash, + verification_status, + verification_level, + verification_notes, + verified_by, + verified_at, + rejection_reason, + metadata, + meets_requirements, + requirement_id, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + $7, + $8, + $9, + $10, + COALESCE($11, 'pending'), + $12, + $13, + $14, + $15, + $16, + $17, + COALESCE($18, FALSE), + $19, + COALESCE($20, NOW()), + COALESCE($21, NOW()) +) RETURNING id, company_id, country_id, document_type, document_number, document_country, issue_date, expiry_date, document_url, ipfs_hash, verification_status, verification_level, verification_notes, verified_by, verified_at, rejection_reason, metadata, meets_requirements, requirement_id, created_at, updated_at +` + +type CreateKYBDocumentParams struct { + ID interface{} `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + CountryID uuid.UUID `json:"country_id"` + DocumentType string `json:"document_type"` + DocumentNumber pgtype.Text `json:"document_number"` + DocumentCountry pgtype.Text `json:"document_country"` + IssueDate pgtype.Date `json:"issue_date"` + ExpiryDate pgtype.Date `json:"expiry_date"` + DocumentUrl pgtype.Text `json:"document_url"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + VerificationStatus interface{} `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationNotes pgtype.Text `json:"verification_notes"` + VerifiedBy pgtype.UUID `json:"verified_by"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Metadata []byte `json:"metadata"` + MeetsRequirements interface{} `json:"meets_requirements"` + RequirementID pgtype.UUID `json:"requirement_id"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateKYBDocument(ctx context.Context, arg CreateKYBDocumentParams) (KybDocuments, error) { + row := q.db.QueryRow(ctx, createKYBDocument, + arg.ID, + arg.CompanyID, + arg.CountryID, + arg.DocumentType, + arg.DocumentNumber, + arg.DocumentCountry, + arg.IssueDate, + arg.ExpiryDate, + arg.DocumentUrl, + arg.IpfsHash, + arg.VerificationStatus, + arg.VerificationLevel, + arg.VerificationNotes, + arg.VerifiedBy, + arg.VerifiedAt, + arg.RejectionReason, + arg.Metadata, + arg.MeetsRequirements, + arg.RequirementID, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i KybDocuments + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.CountryID, + &i.DocumentType, + &i.DocumentNumber, + &i.DocumentCountry, + &i.IssueDate, + &i.ExpiryDate, + &i.DocumentUrl, + &i.IpfsHash, + &i.VerificationStatus, + &i.VerificationLevel, + &i.VerificationNotes, + &i.VerifiedBy, + &i.VerifiedAt, + &i.RejectionReason, + &i.Metadata, + &i.MeetsRequirements, + &i.RequirementID, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createKYCDocument = `-- name: CreateKYCDocument :one +INSERT INTO kyc_documents ( + id, + user_id, + country_id, + document_type, + document_number, + document_country, + issue_date, + expiry_date, + document_url, + ipfs_hash, + verification_status, + verification_level, + verification_notes, + verified_by, + verified_at, + rejection_reason, + metadata, + meets_requirements, + requirement_id, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + $7, + $8, + $9, + $10, + COALESCE($11, 'pending'), + $12, + $13, + $14, + $15, + $16, + $17, + COALESCE($18, FALSE), + $19, + COALESCE($20, NOW()), + COALESCE($21, NOW()) +) RETURNING id, user_id, country_id, document_type, document_number, document_country, issue_date, expiry_date, document_url, ipfs_hash, verification_status, verification_level, verification_notes, verified_by, verified_at, rejection_reason, metadata, meets_requirements, requirement_id, created_at, updated_at +` + +type CreateKYCDocumentParams struct { + ID interface{} `json:"id"` + UserID uuid.UUID `json:"user_id"` + CountryID uuid.UUID `json:"country_id"` + DocumentType string `json:"document_type"` + DocumentNumber pgtype.Text `json:"document_number"` + DocumentCountry pgtype.Text `json:"document_country"` + IssueDate pgtype.Date `json:"issue_date"` + ExpiryDate pgtype.Date `json:"expiry_date"` + DocumentUrl pgtype.Text `json:"document_url"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + VerificationStatus interface{} `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationNotes pgtype.Text `json:"verification_notes"` + VerifiedBy pgtype.UUID `json:"verified_by"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Metadata []byte `json:"metadata"` + MeetsRequirements interface{} `json:"meets_requirements"` + RequirementID pgtype.UUID `json:"requirement_id"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateKYCDocument(ctx context.Context, arg CreateKYCDocumentParams) (KycDocuments, error) { + row := q.db.QueryRow(ctx, createKYCDocument, + arg.ID, + arg.UserID, + arg.CountryID, + arg.DocumentType, + arg.DocumentNumber, + arg.DocumentCountry, + arg.IssueDate, + arg.ExpiryDate, + arg.DocumentUrl, + arg.IpfsHash, + arg.VerificationStatus, + arg.VerificationLevel, + arg.VerificationNotes, + arg.VerifiedBy, + arg.VerifiedAt, + arg.RejectionReason, + arg.Metadata, + arg.MeetsRequirements, + arg.RequirementID, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i KycDocuments + err := row.Scan( + &i.ID, + &i.UserID, + &i.CountryID, + &i.DocumentType, + &i.DocumentNumber, + &i.DocumentCountry, + &i.IssueDate, + &i.ExpiryDate, + &i.DocumentUrl, + &i.IpfsHash, + &i.VerificationStatus, + &i.VerificationLevel, + &i.VerificationNotes, + &i.VerifiedBy, + &i.VerifiedAt, + &i.RejectionReason, + &i.Metadata, + &i.MeetsRequirements, + &i.RequirementID, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createSupportedCountry = `-- name: CreateSupportedCountry :one +INSERT INTO supported_countries ( + id, + country_code, + country_name, + region, + currency_code, + currency_symbol, + is_active, + is_high_risk, + requires_enhanced_kyc, + requires_enhanced_kyb, + timezone, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + COALESCE($7, TRUE), + COALESCE($8, FALSE), + COALESCE($9, FALSE), + COALESCE($10, FALSE), + $11, + COALESCE($12, NOW()), + COALESCE($13, NOW()) +) RETURNING id, country_code, country_name, region, currency_code, currency_symbol, is_active, is_high_risk, requires_enhanced_kyc, requires_enhanced_kyb, timezone, created_at, updated_at +` + +type CreateSupportedCountryParams struct { + ID interface{} `json:"id"` + CountryCode string `json:"country_code"` + CountryName string `json:"country_name"` + Region pgtype.Text `json:"region"` + CurrencyCode pgtype.Text `json:"currency_code"` + CurrencySymbol pgtype.Text `json:"currency_symbol"` + IsActive interface{} `json:"is_active"` + IsHighRisk interface{} `json:"is_high_risk"` + RequiresEnhancedKyc interface{} `json:"requires_enhanced_kyc"` + RequiresEnhancedKyb interface{} `json:"requires_enhanced_kyb"` + Timezone pgtype.Text `json:"timezone"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateSupportedCountry(ctx context.Context, arg CreateSupportedCountryParams) (SupportedCountries, error) { + row := q.db.QueryRow(ctx, createSupportedCountry, + arg.ID, + arg.CountryCode, + arg.CountryName, + arg.Region, + arg.CurrencyCode, + arg.CurrencySymbol, + arg.IsActive, + arg.IsHighRisk, + arg.RequiresEnhancedKyc, + arg.RequiresEnhancedKyb, + arg.Timezone, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i SupportedCountries + err := row.Scan( + &i.ID, + &i.CountryCode, + &i.CountryName, + &i.Region, + &i.CurrencyCode, + &i.CurrencySymbol, + &i.IsActive, + &i.IsHighRisk, + &i.RequiresEnhancedKyc, + &i.RequiresEnhancedKyb, + &i.Timezone, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createUserCountryKYCStatus = `-- name: CreateUserCountryKYCStatus :one +INSERT INTO user_country_kyc_status ( + id, + user_id, + country_id, + verification_status, + verification_level, + verification_date, + expiry_date, + rejection_reason, + notes, + risk_rating, + restricted_features, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + COALESCE($4, 'pending'), + $5, + $6, + $7, + $8, + $9, + $10, + $11, + COALESCE($12, NOW()), + COALESCE($13, NOW()) +) RETURNING id, user_id, country_id, verification_status, verification_level, verification_date, expiry_date, rejection_reason, notes, risk_rating, restricted_features, created_at, updated_at +` + +type CreateUserCountryKYCStatusParams struct { + ID interface{} `json:"id"` + UserID uuid.UUID `json:"user_id"` + CountryID uuid.UUID `json:"country_id"` + VerificationStatus interface{} `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationDate pgtype.Timestamptz `json:"verification_date"` + ExpiryDate pgtype.Timestamptz `json:"expiry_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Notes pgtype.Text `json:"notes"` + RiskRating pgtype.Text `json:"risk_rating"` + RestrictedFeatures []byte `json:"restricted_features"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateUserCountryKYCStatus(ctx context.Context, arg CreateUserCountryKYCStatusParams) (UserCountryKycStatus, error) { + row := q.db.QueryRow(ctx, createUserCountryKYCStatus, + arg.ID, + arg.UserID, + arg.CountryID, + arg.VerificationStatus, + arg.VerificationLevel, + arg.VerificationDate, + arg.ExpiryDate, + arg.RejectionReason, + arg.Notes, + arg.RiskRating, + arg.RestrictedFeatures, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i UserCountryKycStatus + err := row.Scan( + &i.ID, + &i.UserID, + &i.CountryID, + &i.VerificationStatus, + &i.VerificationLevel, + &i.VerificationDate, + &i.ExpiryDate, + &i.RejectionReason, + &i.Notes, + &i.RiskRating, + &i.RestrictedFeatures, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getCompanyKYBStatus = `-- name: GetCompanyKYBStatus :one +SELECT ckbs.id, ckbs.company_id, ckbs.country_id, ckbs.verification_status, ckbs.verification_level, ckbs.verification_date, ckbs.expiry_date, ckbs.rejection_reason, ckbs.notes, ckbs.risk_rating, ckbs.restricted_features, ckbs.created_at, ckbs.updated_at, sc.country_name +FROM company_country_kyb_status ckbs +JOIN supported_countries sc ON ckbs.country_id = sc.id +WHERE ckbs.company_id = $1 AND ckbs.country_id = $2 +` + +type GetCompanyKYBStatusParams struct { + CompanyID uuid.UUID `json:"company_id"` + CountryID uuid.UUID `json:"country_id"` +} + +type GetCompanyKYBStatusRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + CountryID uuid.UUID `json:"country_id"` + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationDate pgtype.Timestamptz `json:"verification_date"` + ExpiryDate pgtype.Timestamptz `json:"expiry_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Notes pgtype.Text `json:"notes"` + RiskRating pgtype.Text `json:"risk_rating"` + RestrictedFeatures []byte `json:"restricted_features"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + CountryName string `json:"country_name"` +} + +func (q *Queries) GetCompanyKYBStatus(ctx context.Context, arg GetCompanyKYBStatusParams) (GetCompanyKYBStatusRow, error) { + row := q.db.QueryRow(ctx, getCompanyKYBStatus, arg.CompanyID, arg.CountryID) + var i GetCompanyKYBStatusRow + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.CountryID, + &i.VerificationStatus, + &i.VerificationLevel, + &i.VerificationDate, + &i.ExpiryDate, + &i.RejectionReason, + &i.Notes, + &i.RiskRating, + &i.RestrictedFeatures, + &i.CreatedAt, + &i.UpdatedAt, + &i.CountryName, + ) + return i, err +} + +const getKYBCountryRequirements = `-- name: GetKYBCountryRequirements :many +SELECT id, country_id, document_type, business_type, is_required, requirement_description, acceptable_document_formats, verification_level, additional_attributes, is_active, created_at, updated_at FROM kyb_country_requirements +WHERE country_id = $1 AND is_active = TRUE +ORDER BY document_type +` + +func (q *Queries) GetKYBCountryRequirements(ctx context.Context, countryID uuid.UUID) ([]KybCountryRequirements, error) { + rows, err := q.db.Query(ctx, getKYBCountryRequirements, countryID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []KybCountryRequirements{} + for rows.Next() { + var i KybCountryRequirements + if err := rows.Scan( + &i.ID, + &i.CountryID, + &i.DocumentType, + &i.BusinessType, + &i.IsRequired, + &i.RequirementDescription, + &i.AcceptableDocumentFormats, + &i.VerificationLevel, + &i.AdditionalAttributes, + &i.IsActive, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getKYBDocumentsByCompany = `-- name: GetKYBDocumentsByCompany :many +SELECT kbd.id, kbd.company_id, kbd.country_id, kbd.document_type, kbd.document_number, kbd.document_country, kbd.issue_date, kbd.expiry_date, kbd.document_url, kbd.ipfs_hash, kbd.verification_status, kbd.verification_level, kbd.verification_notes, kbd.verified_by, kbd.verified_at, kbd.rejection_reason, kbd.metadata, kbd.meets_requirements, kbd.requirement_id, kbd.created_at, kbd.updated_at, sc.country_name, kbcr.document_type as required_document_type +FROM kyb_documents kbd +JOIN supported_countries sc ON kbd.country_id = sc.id +LEFT JOIN kyb_country_requirements kbcr ON kbd.requirement_id = kbcr.id +WHERE kbd.company_id = $1 +ORDER BY kbd.created_at DESC +` + +type GetKYBDocumentsByCompanyRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + CountryID uuid.UUID `json:"country_id"` + DocumentType string `json:"document_type"` + DocumentNumber pgtype.Text `json:"document_number"` + DocumentCountry pgtype.Text `json:"document_country"` + IssueDate pgtype.Date `json:"issue_date"` + ExpiryDate pgtype.Date `json:"expiry_date"` + DocumentUrl pgtype.Text `json:"document_url"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationNotes pgtype.Text `json:"verification_notes"` + VerifiedBy pgtype.UUID `json:"verified_by"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Metadata []byte `json:"metadata"` + MeetsRequirements pgtype.Bool `json:"meets_requirements"` + RequirementID pgtype.UUID `json:"requirement_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + CountryName string `json:"country_name"` + RequiredDocumentType pgtype.Text `json:"required_document_type"` +} + +func (q *Queries) GetKYBDocumentsByCompany(ctx context.Context, companyID uuid.UUID) ([]GetKYBDocumentsByCompanyRow, error) { + rows, err := q.db.Query(ctx, getKYBDocumentsByCompany, companyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetKYBDocumentsByCompanyRow{} + for rows.Next() { + var i GetKYBDocumentsByCompanyRow + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.CountryID, + &i.DocumentType, + &i.DocumentNumber, + &i.DocumentCountry, + &i.IssueDate, + &i.ExpiryDate, + &i.DocumentUrl, + &i.IpfsHash, + &i.VerificationStatus, + &i.VerificationLevel, + &i.VerificationNotes, + &i.VerifiedBy, + &i.VerifiedAt, + &i.RejectionReason, + &i.Metadata, + &i.MeetsRequirements, + &i.RequirementID, + &i.CreatedAt, + &i.UpdatedAt, + &i.CountryName, + &i.RequiredDocumentType, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getKYCCountryRequirements = `-- name: GetKYCCountryRequirements :many +SELECT id, country_id, document_type, is_required, requirement_description, acceptable_document_formats, verification_level, additional_attributes, is_active, created_at, updated_at FROM kyc_country_requirements +WHERE country_id = $1 AND is_active = TRUE +ORDER BY document_type +` + +func (q *Queries) GetKYCCountryRequirements(ctx context.Context, countryID uuid.UUID) ([]KycCountryRequirements, error) { + rows, err := q.db.Query(ctx, getKYCCountryRequirements, countryID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []KycCountryRequirements{} + for rows.Next() { + var i KycCountryRequirements + if err := rows.Scan( + &i.ID, + &i.CountryID, + &i.DocumentType, + &i.IsRequired, + &i.RequirementDescription, + &i.AcceptableDocumentFormats, + &i.VerificationLevel, + &i.AdditionalAttributes, + &i.IsActive, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getKYCDocumentsByCountry = `-- name: GetKYCDocumentsByCountry :many +SELECT kd.id, kd.user_id, kd.country_id, kd.document_type, kd.document_number, kd.document_country, kd.issue_date, kd.expiry_date, kd.document_url, kd.ipfs_hash, kd.verification_status, kd.verification_level, kd.verification_notes, kd.verified_by, kd.verified_at, kd.rejection_reason, kd.metadata, kd.meets_requirements, kd.requirement_id, kd.created_at, kd.updated_at, sc.country_name, kcr.document_type as required_document_type +FROM kyc_documents kd +JOIN supported_countries sc ON kd.country_id = sc.id +LEFT JOIN kyc_country_requirements kcr ON kd.requirement_id = kcr.id +WHERE kd.user_id = $1 AND kd.country_id = $2 +ORDER BY kd.created_at DESC +` + +type GetKYCDocumentsByCountryParams struct { + UserID uuid.UUID `json:"user_id"` + CountryID uuid.UUID `json:"country_id"` +} + +type GetKYCDocumentsByCountryRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + CountryID uuid.UUID `json:"country_id"` + DocumentType string `json:"document_type"` + DocumentNumber pgtype.Text `json:"document_number"` + DocumentCountry pgtype.Text `json:"document_country"` + IssueDate pgtype.Date `json:"issue_date"` + ExpiryDate pgtype.Date `json:"expiry_date"` + DocumentUrl pgtype.Text `json:"document_url"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationNotes pgtype.Text `json:"verification_notes"` + VerifiedBy pgtype.UUID `json:"verified_by"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Metadata []byte `json:"metadata"` + MeetsRequirements pgtype.Bool `json:"meets_requirements"` + RequirementID pgtype.UUID `json:"requirement_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + CountryName string `json:"country_name"` + RequiredDocumentType pgtype.Text `json:"required_document_type"` +} + +func (q *Queries) GetKYCDocumentsByCountry(ctx context.Context, arg GetKYCDocumentsByCountryParams) ([]GetKYCDocumentsByCountryRow, error) { + rows, err := q.db.Query(ctx, getKYCDocumentsByCountry, arg.UserID, arg.CountryID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetKYCDocumentsByCountryRow{} + for rows.Next() { + var i GetKYCDocumentsByCountryRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.CountryID, + &i.DocumentType, + &i.DocumentNumber, + &i.DocumentCountry, + &i.IssueDate, + &i.ExpiryDate, + &i.DocumentUrl, + &i.IpfsHash, + &i.VerificationStatus, + &i.VerificationLevel, + &i.VerificationNotes, + &i.VerifiedBy, + &i.VerifiedAt, + &i.RejectionReason, + &i.Metadata, + &i.MeetsRequirements, + &i.RequirementID, + &i.CreatedAt, + &i.UpdatedAt, + &i.CountryName, + &i.RequiredDocumentType, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getKYCDocumentsByUser = `-- name: GetKYCDocumentsByUser :many +SELECT kd.id, kd.user_id, kd.country_id, kd.document_type, kd.document_number, kd.document_country, kd.issue_date, kd.expiry_date, kd.document_url, kd.ipfs_hash, kd.verification_status, kd.verification_level, kd.verification_notes, kd.verified_by, kd.verified_at, kd.rejection_reason, kd.metadata, kd.meets_requirements, kd.requirement_id, kd.created_at, kd.updated_at, sc.country_name, kcr.document_type as required_document_type +FROM kyc_documents kd +JOIN supported_countries sc ON kd.country_id = sc.id +LEFT JOIN kyc_country_requirements kcr ON kd.requirement_id = kcr.id +WHERE kd.user_id = $1 +ORDER BY kd.created_at DESC +` + +type GetKYCDocumentsByUserRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + CountryID uuid.UUID `json:"country_id"` + DocumentType string `json:"document_type"` + DocumentNumber pgtype.Text `json:"document_number"` + DocumentCountry pgtype.Text `json:"document_country"` + IssueDate pgtype.Date `json:"issue_date"` + ExpiryDate pgtype.Date `json:"expiry_date"` + DocumentUrl pgtype.Text `json:"document_url"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationNotes pgtype.Text `json:"verification_notes"` + VerifiedBy pgtype.UUID `json:"verified_by"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Metadata []byte `json:"metadata"` + MeetsRequirements pgtype.Bool `json:"meets_requirements"` + RequirementID pgtype.UUID `json:"requirement_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + CountryName string `json:"country_name"` + RequiredDocumentType pgtype.Text `json:"required_document_type"` +} + +func (q *Queries) GetKYCDocumentsByUser(ctx context.Context, userID uuid.UUID) ([]GetKYCDocumentsByUserRow, error) { + rows, err := q.db.Query(ctx, getKYCDocumentsByUser, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetKYCDocumentsByUserRow{} + for rows.Next() { + var i GetKYCDocumentsByUserRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.CountryID, + &i.DocumentType, + &i.DocumentNumber, + &i.DocumentCountry, + &i.IssueDate, + &i.ExpiryDate, + &i.DocumentUrl, + &i.IpfsHash, + &i.VerificationStatus, + &i.VerificationLevel, + &i.VerificationNotes, + &i.VerifiedBy, + &i.VerifiedAt, + &i.RejectionReason, + &i.Metadata, + &i.MeetsRequirements, + &i.RequirementID, + &i.CreatedAt, + &i.UpdatedAt, + &i.CountryName, + &i.RequiredDocumentType, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getSupportedCountries = `-- name: GetSupportedCountries :many +SELECT id, country_code, country_name, region, currency_code, currency_symbol, is_active, is_high_risk, requires_enhanced_kyc, requires_enhanced_kyb, timezone, created_at, updated_at FROM supported_countries +WHERE is_active = TRUE +ORDER BY country_name +` + +func (q *Queries) GetSupportedCountries(ctx context.Context) ([]SupportedCountries, error) { + rows, err := q.db.Query(ctx, getSupportedCountries) + if err != nil { + return nil, err + } + defer rows.Close() + items := []SupportedCountries{} + for rows.Next() { + var i SupportedCountries + if err := rows.Scan( + &i.ID, + &i.CountryCode, + &i.CountryName, + &i.Region, + &i.CurrencyCode, + &i.CurrencySymbol, + &i.IsActive, + &i.IsHighRisk, + &i.RequiresEnhancedKyc, + &i.RequiresEnhancedKyb, + &i.Timezone, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getSupportedCountryByCode = `-- name: GetSupportedCountryByCode :one +SELECT id, country_code, country_name, region, currency_code, currency_symbol, is_active, is_high_risk, requires_enhanced_kyc, requires_enhanced_kyb, timezone, created_at, updated_at FROM supported_countries +WHERE country_code = $1 AND is_active = TRUE +` + +func (q *Queries) GetSupportedCountryByCode(ctx context.Context, countryCode string) (SupportedCountries, error) { + row := q.db.QueryRow(ctx, getSupportedCountryByCode, countryCode) + var i SupportedCountries + err := row.Scan( + &i.ID, + &i.CountryCode, + &i.CountryName, + &i.Region, + &i.CurrencyCode, + &i.CurrencySymbol, + &i.IsActive, + &i.IsHighRisk, + &i.RequiresEnhancedKyc, + &i.RequiresEnhancedKyb, + &i.Timezone, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getUserKYCStatus = `-- name: GetUserKYCStatus :one +SELECT ukcs.id, ukcs.user_id, ukcs.country_id, ukcs.verification_status, ukcs.verification_level, ukcs.verification_date, ukcs.expiry_date, ukcs.rejection_reason, ukcs.notes, ukcs.risk_rating, ukcs.restricted_features, ukcs.created_at, ukcs.updated_at, sc.country_name +FROM user_country_kyc_status ukcs +JOIN supported_countries sc ON ukcs.country_id = sc.id +WHERE ukcs.user_id = $1 AND ukcs.country_id = $2 +` + +type GetUserKYCStatusParams struct { + UserID uuid.UUID `json:"user_id"` + CountryID uuid.UUID `json:"country_id"` +} + +type GetUserKYCStatusRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + CountryID uuid.UUID `json:"country_id"` + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationDate pgtype.Timestamptz `json:"verification_date"` + ExpiryDate pgtype.Timestamptz `json:"expiry_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Notes pgtype.Text `json:"notes"` + RiskRating pgtype.Text `json:"risk_rating"` + RestrictedFeatures []byte `json:"restricted_features"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + CountryName string `json:"country_name"` +} + +func (q *Queries) GetUserKYCStatus(ctx context.Context, arg GetUserKYCStatusParams) (GetUserKYCStatusRow, error) { + row := q.db.QueryRow(ctx, getUserKYCStatus, arg.UserID, arg.CountryID) + var i GetUserKYCStatusRow + err := row.Scan( + &i.ID, + &i.UserID, + &i.CountryID, + &i.VerificationStatus, + &i.VerificationLevel, + &i.VerificationDate, + &i.ExpiryDate, + &i.RejectionReason, + &i.Notes, + &i.RiskRating, + &i.RestrictedFeatures, + &i.CreatedAt, + &i.UpdatedAt, + &i.CountryName, + ) + return i, err +} + +const getUserKYCStatusByCountryCode = `-- name: GetUserKYCStatusByCountryCode :one +SELECT ukcs.id, ukcs.user_id, ukcs.country_id, ukcs.verification_status, ukcs.verification_level, ukcs.verification_date, ukcs.expiry_date, ukcs.rejection_reason, ukcs.notes, ukcs.risk_rating, ukcs.restricted_features, ukcs.created_at, ukcs.updated_at, sc.country_name +FROM user_country_kyc_status ukcs +JOIN supported_countries sc ON ukcs.country_id = sc.id +WHERE ukcs.user_id = $1 AND sc.country_code = $2 +` + +type GetUserKYCStatusByCountryCodeParams struct { + UserID uuid.UUID `json:"user_id"` + CountryCode string `json:"country_code"` +} + +type GetUserKYCStatusByCountryCodeRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + CountryID uuid.UUID `json:"country_id"` + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationDate pgtype.Timestamptz `json:"verification_date"` + ExpiryDate pgtype.Timestamptz `json:"expiry_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Notes pgtype.Text `json:"notes"` + RiskRating pgtype.Text `json:"risk_rating"` + RestrictedFeatures []byte `json:"restricted_features"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + CountryName string `json:"country_name"` +} + +func (q *Queries) GetUserKYCStatusByCountryCode(ctx context.Context, arg GetUserKYCStatusByCountryCodeParams) (GetUserKYCStatusByCountryCodeRow, error) { + row := q.db.QueryRow(ctx, getUserKYCStatusByCountryCode, arg.UserID, arg.CountryCode) + var i GetUserKYCStatusByCountryCodeRow + err := row.Scan( + &i.ID, + &i.UserID, + &i.CountryID, + &i.VerificationStatus, + &i.VerificationLevel, + &i.VerificationDate, + &i.ExpiryDate, + &i.RejectionReason, + &i.Notes, + &i.RiskRating, + &i.RestrictedFeatures, + &i.CreatedAt, + &i.UpdatedAt, + &i.CountryName, + ) + return i, err +} + +const updateCompanyKYBStatus = `-- name: UpdateCompanyKYBStatus :one +UPDATE company_country_kyb_status SET + verification_status = COALESCE($1, verification_status), + verification_level = COALESCE($2, verification_level), + verification_date = COALESCE($3, verification_date), + expiry_date = COALESCE($4, expiry_date), + rejection_reason = COALESCE($5, rejection_reason), + notes = COALESCE($6, notes), + risk_rating = COALESCE($7, risk_rating), + restricted_features = COALESCE($8, restricted_features), + updated_at = NOW() +WHERE company_id = $9 AND country_id = $10 +RETURNING id, company_id, country_id, verification_status, verification_level, verification_date, expiry_date, rejection_reason, notes, risk_rating, restricted_features, created_at, updated_at +` + +type UpdateCompanyKYBStatusParams struct { + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationDate pgtype.Timestamptz `json:"verification_date"` + ExpiryDate pgtype.Timestamptz `json:"expiry_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Notes pgtype.Text `json:"notes"` + RiskRating pgtype.Text `json:"risk_rating"` + RestrictedFeatures []byte `json:"restricted_features"` + CompanyID uuid.UUID `json:"company_id"` + CountryID uuid.UUID `json:"country_id"` +} + +func (q *Queries) UpdateCompanyKYBStatus(ctx context.Context, arg UpdateCompanyKYBStatusParams) (CompanyCountryKybStatus, error) { + row := q.db.QueryRow(ctx, updateCompanyKYBStatus, + arg.VerificationStatus, + arg.VerificationLevel, + arg.VerificationDate, + arg.ExpiryDate, + arg.RejectionReason, + arg.Notes, + arg.RiskRating, + arg.RestrictedFeatures, + arg.CompanyID, + arg.CountryID, + ) + var i CompanyCountryKybStatus + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.CountryID, + &i.VerificationStatus, + &i.VerificationLevel, + &i.VerificationDate, + &i.ExpiryDate, + &i.RejectionReason, + &i.Notes, + &i.RiskRating, + &i.RestrictedFeatures, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateKYCDocument = `-- name: UpdateKYCDocument :one +UPDATE kyc_documents SET + document_number = COALESCE($1, document_number), + document_country = COALESCE($2, document_country), + issue_date = COALESCE($3, issue_date), + expiry_date = COALESCE($4, expiry_date), + document_url = COALESCE($5, document_url), + ipfs_hash = COALESCE($6, ipfs_hash), + verification_status = COALESCE($7, verification_status), + verification_level = COALESCE($8, verification_level), + verification_notes = COALESCE($9, verification_notes), + verified_by = COALESCE($10, verified_by), + verified_at = COALESCE($11, verified_at), + rejection_reason = COALESCE($12, rejection_reason), + metadata = COALESCE($13, metadata), + meets_requirements = COALESCE($14, meets_requirements), + updated_at = NOW() +WHERE id = $15 +RETURNING id, user_id, country_id, document_type, document_number, document_country, issue_date, expiry_date, document_url, ipfs_hash, verification_status, verification_level, verification_notes, verified_by, verified_at, rejection_reason, metadata, meets_requirements, requirement_id, created_at, updated_at +` + +type UpdateKYCDocumentParams struct { + DocumentNumber pgtype.Text `json:"document_number"` + DocumentCountry pgtype.Text `json:"document_country"` + IssueDate pgtype.Date `json:"issue_date"` + ExpiryDate pgtype.Date `json:"expiry_date"` + DocumentUrl pgtype.Text `json:"document_url"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationNotes pgtype.Text `json:"verification_notes"` + VerifiedBy pgtype.UUID `json:"verified_by"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Metadata []byte `json:"metadata"` + MeetsRequirements pgtype.Bool `json:"meets_requirements"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdateKYCDocument(ctx context.Context, arg UpdateKYCDocumentParams) (KycDocuments, error) { + row := q.db.QueryRow(ctx, updateKYCDocument, + arg.DocumentNumber, + arg.DocumentCountry, + arg.IssueDate, + arg.ExpiryDate, + arg.DocumentUrl, + arg.IpfsHash, + arg.VerificationStatus, + arg.VerificationLevel, + arg.VerificationNotes, + arg.VerifiedBy, + arg.VerifiedAt, + arg.RejectionReason, + arg.Metadata, + arg.MeetsRequirements, + arg.ID, + ) + var i KycDocuments + err := row.Scan( + &i.ID, + &i.UserID, + &i.CountryID, + &i.DocumentType, + &i.DocumentNumber, + &i.DocumentCountry, + &i.IssueDate, + &i.ExpiryDate, + &i.DocumentUrl, + &i.IpfsHash, + &i.VerificationStatus, + &i.VerificationLevel, + &i.VerificationNotes, + &i.VerifiedBy, + &i.VerifiedAt, + &i.RejectionReason, + &i.Metadata, + &i.MeetsRequirements, + &i.RequirementID, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateUserKYCStatus = `-- name: UpdateUserKYCStatus :one +UPDATE user_country_kyc_status SET + verification_status = COALESCE($1, verification_status), + verification_level = COALESCE($2, verification_level), + verification_date = COALESCE($3, verification_date), + expiry_date = COALESCE($4, expiry_date), + rejection_reason = COALESCE($5, rejection_reason), + notes = COALESCE($6, notes), + risk_rating = COALESCE($7, risk_rating), + restricted_features = COALESCE($8, restricted_features), + updated_at = NOW() +WHERE user_id = $9 AND country_id = $10 +RETURNING id, user_id, country_id, verification_status, verification_level, verification_date, expiry_date, rejection_reason, notes, risk_rating, restricted_features, created_at, updated_at +` + +type UpdateUserKYCStatusParams struct { + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationDate pgtype.Timestamptz `json:"verification_date"` + ExpiryDate pgtype.Timestamptz `json:"expiry_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Notes pgtype.Text `json:"notes"` + RiskRating pgtype.Text `json:"risk_rating"` + RestrictedFeatures []byte `json:"restricted_features"` + UserID uuid.UUID `json:"user_id"` + CountryID uuid.UUID `json:"country_id"` +} + +func (q *Queries) UpdateUserKYCStatus(ctx context.Context, arg UpdateUserKYCStatusParams) (UserCountryKycStatus, error) { + row := q.db.QueryRow(ctx, updateUserKYCStatus, + arg.VerificationStatus, + arg.VerificationLevel, + arg.VerificationDate, + arg.ExpiryDate, + arg.RejectionReason, + arg.Notes, + arg.RiskRating, + arg.RestrictedFeatures, + arg.UserID, + arg.CountryID, + ) + var i UserCountryKycStatus + err := row.Scan( + &i.ID, + &i.UserID, + &i.CountryID, + &i.VerificationStatus, + &i.VerificationLevel, + &i.VerificationDate, + &i.ExpiryDate, + &i.RejectionReason, + &i.Notes, + &i.RiskRating, + &i.RestrictedFeatures, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/db/sqlc/invoices.sql.go b/db/sqlc/invoices.sql.go new file mode 100644 index 0000000..be94907 --- /dev/null +++ b/db/sqlc/invoices.sql.go @@ -0,0 +1,1255 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.29.0 +// source: invoices.sql + +package sqlc + +import ( + "context" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" + "github.com/shopspring/decimal" +) + +const createInvoice = `-- name: CreateInvoice :one +INSERT INTO invoices ( + id, + invoice_number, + issuer_id, + recipient_id, + title, + description, + issue_date, + due_date, + total_amount, + currency, + status, + payment_method, + recipient_wallet_address, + recipient_bank_account_id, + transaction_hash, + payment_date, + rejection_reason, + ipfs_hash, + smart_contract_address, + chain_id, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + $7, + $8, + $9, + $10, + COALESCE($11, 'draft'), + $12, + $13, + $14, + $15, + $16, + $17, + $18, + $19, + $20, + COALESCE($21, NOW()), + COALESCE($22, NOW()) +) RETURNING id, invoice_number, issuer_id, recipient_id, title, description, issue_date, due_date, total_amount, currency, status, payment_method, recipient_wallet_address, recipient_bank_account_id, transaction_hash, payment_date, rejection_reason, ipfs_hash, smart_contract_address, chain_id, created_at, updated_at +` + +type CreateInvoiceParams struct { + ID interface{} `json:"id"` + InvoiceNumber string `json:"invoice_number"` + IssuerID uuid.UUID `json:"issuer_id"` + RecipientID uuid.UUID `json:"recipient_id"` + Title string `json:"title"` + Description pgtype.Text `json:"description"` + IssueDate pgtype.Date `json:"issue_date"` + DueDate pgtype.Date `json:"due_date"` + TotalAmount decimal.Decimal `json:"total_amount"` + Currency string `json:"currency"` + Status interface{} `json:"status"` + PaymentMethod pgtype.Text `json:"payment_method"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + PaymentDate pgtype.Timestamptz `json:"payment_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateInvoice(ctx context.Context, arg CreateInvoiceParams) (Invoices, error) { + row := q.db.QueryRow(ctx, createInvoice, + arg.ID, + arg.InvoiceNumber, + arg.IssuerID, + arg.RecipientID, + arg.Title, + arg.Description, + arg.IssueDate, + arg.DueDate, + arg.TotalAmount, + arg.Currency, + arg.Status, + arg.PaymentMethod, + arg.RecipientWalletAddress, + arg.RecipientBankAccountID, + arg.TransactionHash, + arg.PaymentDate, + arg.RejectionReason, + arg.IpfsHash, + arg.SmartContractAddress, + arg.ChainID, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i Invoices + err := row.Scan( + &i.ID, + &i.InvoiceNumber, + &i.IssuerID, + &i.RecipientID, + &i.Title, + &i.Description, + &i.IssueDate, + &i.DueDate, + &i.TotalAmount, + &i.Currency, + &i.Status, + &i.PaymentMethod, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.TransactionHash, + &i.PaymentDate, + &i.RejectionReason, + &i.IpfsHash, + &i.SmartContractAddress, + &i.ChainID, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createInvoiceItem = `-- name: CreateInvoiceItem :one +INSERT INTO invoice_items ( + id, + invoice_id, + description, + quantity, + unit_price, + amount, + tax_rate, + tax_amount, + discount_percentage, + discount_amount, + total_amount, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + COALESCE($4, 1), + $5, + $6, + COALESCE($7, 0), + COALESCE($8, 0), + COALESCE($9, 0), + COALESCE($10, 0), + $11, + COALESCE($12, NOW()), + COALESCE($13, NOW()) +) RETURNING id, invoice_id, description, quantity, unit_price, amount, tax_rate, tax_amount, discount_percentage, discount_amount, total_amount, created_at, updated_at +` + +type CreateInvoiceItemParams struct { + ID interface{} `json:"id"` + InvoiceID uuid.UUID `json:"invoice_id"` + Description string `json:"description"` + Quantity interface{} `json:"quantity"` + UnitPrice decimal.Decimal `json:"unit_price"` + Amount decimal.Decimal `json:"amount"` + TaxRate interface{} `json:"tax_rate"` + TaxAmount interface{} `json:"tax_amount"` + DiscountPercentage interface{} `json:"discount_percentage"` + DiscountAmount interface{} `json:"discount_amount"` + TotalAmount decimal.Decimal `json:"total_amount"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateInvoiceItem(ctx context.Context, arg CreateInvoiceItemParams) (InvoiceItems, error) { + row := q.db.QueryRow(ctx, createInvoiceItem, + arg.ID, + arg.InvoiceID, + arg.Description, + arg.Quantity, + arg.UnitPrice, + arg.Amount, + arg.TaxRate, + arg.TaxAmount, + arg.DiscountPercentage, + arg.DiscountAmount, + arg.TotalAmount, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i InvoiceItems + err := row.Scan( + &i.ID, + &i.InvoiceID, + &i.Description, + &i.Quantity, + &i.UnitPrice, + &i.Amount, + &i.TaxRate, + &i.TaxAmount, + &i.DiscountPercentage, + &i.DiscountAmount, + &i.TotalAmount, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteInvoiceItem = `-- name: DeleteInvoiceItem :exec +DELETE FROM invoice_items WHERE id = $1 +` + +func (q *Queries) DeleteInvoiceItem(ctx context.Context, id uuid.UUID) error { + _, err := q.db.Exec(ctx, deleteInvoiceItem, id) + return err +} + +const getCompanyReceivedInvoices = `-- name: GetCompanyReceivedInvoices :many +SELECT i.id, i.invoice_number, i.issuer_id, i.recipient_id, i.title, i.description, i.issue_date, i.due_date, i.total_amount, i.currency, i.status, i.payment_method, i.recipient_wallet_address, i.recipient_bank_account_id, i.transaction_hash, i.payment_date, i.rejection_reason, i.ipfs_hash, i.smart_contract_address, i.chain_id, i.created_at, i.updated_at, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE i.recipient_id = $1 +ORDER BY i.created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetCompanyReceivedInvoicesParams struct { + CompanyID uuid.UUID `json:"company_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetCompanyReceivedInvoicesRow struct { + ID uuid.UUID `json:"id"` + InvoiceNumber string `json:"invoice_number"` + IssuerID uuid.UUID `json:"issuer_id"` + RecipientID uuid.UUID `json:"recipient_id"` + Title string `json:"title"` + Description pgtype.Text `json:"description"` + IssueDate pgtype.Date `json:"issue_date"` + DueDate pgtype.Date `json:"due_date"` + TotalAmount decimal.Decimal `json:"total_amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentMethod pgtype.Text `json:"payment_method"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + PaymentDate pgtype.Timestamptz `json:"payment_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + IssuerEmail string `json:"issuer_email"` + IssuerFirstName pgtype.Text `json:"issuer_first_name"` + IssuerLastName pgtype.Text `json:"issuer_last_name"` +} + +func (q *Queries) GetCompanyReceivedInvoices(ctx context.Context, arg GetCompanyReceivedInvoicesParams) ([]GetCompanyReceivedInvoicesRow, error) { + rows, err := q.db.Query(ctx, getCompanyReceivedInvoices, arg.CompanyID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetCompanyReceivedInvoicesRow{} + for rows.Next() { + var i GetCompanyReceivedInvoicesRow + if err := rows.Scan( + &i.ID, + &i.InvoiceNumber, + &i.IssuerID, + &i.RecipientID, + &i.Title, + &i.Description, + &i.IssueDate, + &i.DueDate, + &i.TotalAmount, + &i.Currency, + &i.Status, + &i.PaymentMethod, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.TransactionHash, + &i.PaymentDate, + &i.RejectionReason, + &i.IpfsHash, + &i.SmartContractAddress, + &i.ChainID, + &i.CreatedAt, + &i.UpdatedAt, + &i.IssuerEmail, + &i.IssuerFirstName, + &i.IssuerLastName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getCompanySentInvoices = `-- name: GetCompanySentInvoices :many +SELECT i.id, i.invoice_number, i.issuer_id, i.recipient_id, i.title, i.description, i.issue_date, i.due_date, i.total_amount, i.currency, i.status, i.payment_method, i.recipient_wallet_address, i.recipient_bank_account_id, i.transaction_hash, i.payment_date, i.rejection_reason, i.ipfs_hash, i.smart_contract_address, i.chain_id, i.created_at, i.updated_at, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN companies recipient ON i.recipient_id = recipient.id +JOIN company_users cu ON cu.company_id = recipient.id +WHERE cu.user_id = $1 AND i.issuer_id = $1 +ORDER BY i.created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetCompanySentInvoicesParams struct { + UserID uuid.UUID `json:"user_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetCompanySentInvoicesRow struct { + ID uuid.UUID `json:"id"` + InvoiceNumber string `json:"invoice_number"` + IssuerID uuid.UUID `json:"issuer_id"` + RecipientID uuid.UUID `json:"recipient_id"` + Title string `json:"title"` + Description pgtype.Text `json:"description"` + IssueDate pgtype.Date `json:"issue_date"` + DueDate pgtype.Date `json:"due_date"` + TotalAmount decimal.Decimal `json:"total_amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentMethod pgtype.Text `json:"payment_method"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + PaymentDate pgtype.Timestamptz `json:"payment_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + RecipientCompanyName string `json:"recipient_company_name"` +} + +func (q *Queries) GetCompanySentInvoices(ctx context.Context, arg GetCompanySentInvoicesParams) ([]GetCompanySentInvoicesRow, error) { + rows, err := q.db.Query(ctx, getCompanySentInvoices, arg.UserID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetCompanySentInvoicesRow{} + for rows.Next() { + var i GetCompanySentInvoicesRow + if err := rows.Scan( + &i.ID, + &i.InvoiceNumber, + &i.IssuerID, + &i.RecipientID, + &i.Title, + &i.Description, + &i.IssueDate, + &i.DueDate, + &i.TotalAmount, + &i.Currency, + &i.Status, + &i.PaymentMethod, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.TransactionHash, + &i.PaymentDate, + &i.RejectionReason, + &i.IpfsHash, + &i.SmartContractAddress, + &i.ChainID, + &i.CreatedAt, + &i.UpdatedAt, + &i.RecipientCompanyName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getInvoiceByID = `-- name: GetInvoiceByID :one +SELECT i.id, i.invoice_number, i.issuer_id, i.recipient_id, i.title, i.description, i.issue_date, i.due_date, i.total_amount, i.currency, i.status, i.payment_method, i.recipient_wallet_address, i.recipient_bank_account_id, i.transaction_hash, i.payment_date, i.rejection_reason, i.ipfs_hash, i.smart_contract_address, i.chain_id, i.created_at, i.updated_at, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +JOIN companies recipient ON i.recipient_id = recipient.id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE i.id = $1 +` + +type GetInvoiceByIDRow struct { + ID uuid.UUID `json:"id"` + InvoiceNumber string `json:"invoice_number"` + IssuerID uuid.UUID `json:"issuer_id"` + RecipientID uuid.UUID `json:"recipient_id"` + Title string `json:"title"` + Description pgtype.Text `json:"description"` + IssueDate pgtype.Date `json:"issue_date"` + DueDate pgtype.Date `json:"due_date"` + TotalAmount decimal.Decimal `json:"total_amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentMethod pgtype.Text `json:"payment_method"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + PaymentDate pgtype.Timestamptz `json:"payment_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + IssuerEmail string `json:"issuer_email"` + IssuerFirstName pgtype.Text `json:"issuer_first_name"` + IssuerLastName pgtype.Text `json:"issuer_last_name"` + RecipientCompanyName string `json:"recipient_company_name"` +} + +func (q *Queries) GetInvoiceByID(ctx context.Context, id uuid.UUID) (GetInvoiceByIDRow, error) { + row := q.db.QueryRow(ctx, getInvoiceByID, id) + var i GetInvoiceByIDRow + err := row.Scan( + &i.ID, + &i.InvoiceNumber, + &i.IssuerID, + &i.RecipientID, + &i.Title, + &i.Description, + &i.IssueDate, + &i.DueDate, + &i.TotalAmount, + &i.Currency, + &i.Status, + &i.PaymentMethod, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.TransactionHash, + &i.PaymentDate, + &i.RejectionReason, + &i.IpfsHash, + &i.SmartContractAddress, + &i.ChainID, + &i.CreatedAt, + &i.UpdatedAt, + &i.IssuerEmail, + &i.IssuerFirstName, + &i.IssuerLastName, + &i.RecipientCompanyName, + ) + return i, err +} + +const getInvoiceByNumber = `-- name: GetInvoiceByNumber :one +SELECT i.id, i.invoice_number, i.issuer_id, i.recipient_id, i.title, i.description, i.issue_date, i.due_date, i.total_amount, i.currency, i.status, i.payment_method, i.recipient_wallet_address, i.recipient_bank_account_id, i.transaction_hash, i.payment_date, i.rejection_reason, i.ipfs_hash, i.smart_contract_address, i.chain_id, i.created_at, i.updated_at, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +JOIN companies recipient ON i.recipient_id = recipient.id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE i.invoice_number = $1 +` + +type GetInvoiceByNumberRow struct { + ID uuid.UUID `json:"id"` + InvoiceNumber string `json:"invoice_number"` + IssuerID uuid.UUID `json:"issuer_id"` + RecipientID uuid.UUID `json:"recipient_id"` + Title string `json:"title"` + Description pgtype.Text `json:"description"` + IssueDate pgtype.Date `json:"issue_date"` + DueDate pgtype.Date `json:"due_date"` + TotalAmount decimal.Decimal `json:"total_amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentMethod pgtype.Text `json:"payment_method"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + PaymentDate pgtype.Timestamptz `json:"payment_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + IssuerEmail string `json:"issuer_email"` + IssuerFirstName pgtype.Text `json:"issuer_first_name"` + IssuerLastName pgtype.Text `json:"issuer_last_name"` + RecipientCompanyName string `json:"recipient_company_name"` +} + +func (q *Queries) GetInvoiceByNumber(ctx context.Context, invoiceNumber string) (GetInvoiceByNumberRow, error) { + row := q.db.QueryRow(ctx, getInvoiceByNumber, invoiceNumber) + var i GetInvoiceByNumberRow + err := row.Scan( + &i.ID, + &i.InvoiceNumber, + &i.IssuerID, + &i.RecipientID, + &i.Title, + &i.Description, + &i.IssueDate, + &i.DueDate, + &i.TotalAmount, + &i.Currency, + &i.Status, + &i.PaymentMethod, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.TransactionHash, + &i.PaymentDate, + &i.RejectionReason, + &i.IpfsHash, + &i.SmartContractAddress, + &i.ChainID, + &i.CreatedAt, + &i.UpdatedAt, + &i.IssuerEmail, + &i.IssuerFirstName, + &i.IssuerLastName, + &i.RecipientCompanyName, + ) + return i, err +} + +const getInvoiceItems = `-- name: GetInvoiceItems :many +SELECT id, invoice_id, description, quantity, unit_price, amount, tax_rate, tax_amount, discount_percentage, discount_amount, total_amount, created_at, updated_at FROM invoice_items +WHERE invoice_id = $1 +ORDER BY created_at +` + +func (q *Queries) GetInvoiceItems(ctx context.Context, invoiceID uuid.UUID) ([]InvoiceItems, error) { + rows, err := q.db.Query(ctx, getInvoiceItems, invoiceID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []InvoiceItems{} + for rows.Next() { + var i InvoiceItems + if err := rows.Scan( + &i.ID, + &i.InvoiceID, + &i.Description, + &i.Quantity, + &i.UnitPrice, + &i.Amount, + &i.TaxRate, + &i.TaxAmount, + &i.DiscountPercentage, + &i.DiscountAmount, + &i.TotalAmount, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getInvoicesByStatus = `-- name: GetInvoicesByStatus :many +SELECT i.id, i.invoice_number, i.issuer_id, i.recipient_id, i.title, i.description, i.issue_date, i.due_date, i.total_amount, i.currency, i.status, i.payment_method, i.recipient_wallet_address, i.recipient_bank_account_id, i.transaction_hash, i.payment_date, i.rejection_reason, i.ipfs_hash, i.smart_contract_address, i.chain_id, i.created_at, i.updated_at, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +JOIN companies recipient ON i.recipient_id = recipient.id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE i.status = $1 + AND ($2::uuid IS NULL OR i.recipient_id = $2) + AND ($3::uuid IS NULL OR i.issuer_id = $3) +ORDER BY i.created_at DESC +LIMIT $5 OFFSET $4 +` + +type GetInvoicesByStatusParams struct { + Status pgtype.Text `json:"status"` + CompanyID uuid.UUID `json:"company_id"` + UserID uuid.UUID `json:"user_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetInvoicesByStatusRow struct { + ID uuid.UUID `json:"id"` + InvoiceNumber string `json:"invoice_number"` + IssuerID uuid.UUID `json:"issuer_id"` + RecipientID uuid.UUID `json:"recipient_id"` + Title string `json:"title"` + Description pgtype.Text `json:"description"` + IssueDate pgtype.Date `json:"issue_date"` + DueDate pgtype.Date `json:"due_date"` + TotalAmount decimal.Decimal `json:"total_amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentMethod pgtype.Text `json:"payment_method"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + PaymentDate pgtype.Timestamptz `json:"payment_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + IssuerEmail string `json:"issuer_email"` + IssuerFirstName pgtype.Text `json:"issuer_first_name"` + IssuerLastName pgtype.Text `json:"issuer_last_name"` + RecipientCompanyName string `json:"recipient_company_name"` +} + +func (q *Queries) GetInvoicesByStatus(ctx context.Context, arg GetInvoicesByStatusParams) ([]GetInvoicesByStatusRow, error) { + rows, err := q.db.Query(ctx, getInvoicesByStatus, + arg.Status, + arg.CompanyID, + arg.UserID, + arg.OffsetVal, + arg.LimitVal, + ) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetInvoicesByStatusRow{} + for rows.Next() { + var i GetInvoicesByStatusRow + if err := rows.Scan( + &i.ID, + &i.InvoiceNumber, + &i.IssuerID, + &i.RecipientID, + &i.Title, + &i.Description, + &i.IssueDate, + &i.DueDate, + &i.TotalAmount, + &i.Currency, + &i.Status, + &i.PaymentMethod, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.TransactionHash, + &i.PaymentDate, + &i.RejectionReason, + &i.IpfsHash, + &i.SmartContractAddress, + &i.ChainID, + &i.CreatedAt, + &i.UpdatedAt, + &i.IssuerEmail, + &i.IssuerFirstName, + &i.IssuerLastName, + &i.RecipientCompanyName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getInvoicesForApproval = `-- name: GetInvoicesForApproval :many +SELECT i.id, i.invoice_number, i.issuer_id, i.recipient_id, i.title, i.description, i.issue_date, i.due_date, i.total_amount, i.currency, i.status, i.payment_method, i.recipient_wallet_address, i.recipient_bank_account_id, i.transaction_hash, i.payment_date, i.rejection_reason, i.ipfs_hash, i.smart_contract_address, i.chain_id, i.created_at, i.updated_at, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +JOIN company_users cu ON cu.company_id = i.recipient_id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE cu.user_id = $1 + AND i.status = 'pending' + AND (cu.can_manage_invoices = TRUE OR cu.is_administrator = TRUE) +ORDER BY i.created_at +` + +type GetInvoicesForApprovalRow struct { + ID uuid.UUID `json:"id"` + InvoiceNumber string `json:"invoice_number"` + IssuerID uuid.UUID `json:"issuer_id"` + RecipientID uuid.UUID `json:"recipient_id"` + Title string `json:"title"` + Description pgtype.Text `json:"description"` + IssueDate pgtype.Date `json:"issue_date"` + DueDate pgtype.Date `json:"due_date"` + TotalAmount decimal.Decimal `json:"total_amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentMethod pgtype.Text `json:"payment_method"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + PaymentDate pgtype.Timestamptz `json:"payment_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + IssuerEmail string `json:"issuer_email"` + IssuerFirstName pgtype.Text `json:"issuer_first_name"` + IssuerLastName pgtype.Text `json:"issuer_last_name"` +} + +func (q *Queries) GetInvoicesForApproval(ctx context.Context, userID uuid.UUID) ([]GetInvoicesForApprovalRow, error) { + rows, err := q.db.Query(ctx, getInvoicesForApproval, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetInvoicesForApprovalRow{} + for rows.Next() { + var i GetInvoicesForApprovalRow + if err := rows.Scan( + &i.ID, + &i.InvoiceNumber, + &i.IssuerID, + &i.RecipientID, + &i.Title, + &i.Description, + &i.IssueDate, + &i.DueDate, + &i.TotalAmount, + &i.Currency, + &i.Status, + &i.PaymentMethod, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.TransactionHash, + &i.PaymentDate, + &i.RejectionReason, + &i.IpfsHash, + &i.SmartContractAddress, + &i.ChainID, + &i.CreatedAt, + &i.UpdatedAt, + &i.IssuerEmail, + &i.IssuerFirstName, + &i.IssuerLastName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getOverdueInvoices = `-- name: GetOverdueInvoices :many +SELECT i.id, i.invoice_number, i.issuer_id, i.recipient_id, i.title, i.description, i.issue_date, i.due_date, i.total_amount, i.currency, i.status, i.payment_method, i.recipient_wallet_address, i.recipient_bank_account_id, i.transaction_hash, i.payment_date, i.rejection_reason, i.ipfs_hash, i.smart_contract_address, i.chain_id, i.created_at, i.updated_at, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +JOIN companies recipient ON i.recipient_id = recipient.id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE i.due_date < CURRENT_DATE + AND i.status NOT IN ('paid', 'cancelled') + AND ($1::uuid IS NULL OR i.recipient_id = $1) + AND ($2::uuid IS NULL OR i.issuer_id = $2) +ORDER BY i.due_date +` + +type GetOverdueInvoicesParams struct { + CompanyID uuid.UUID `json:"company_id"` + UserID uuid.UUID `json:"user_id"` +} + +type GetOverdueInvoicesRow struct { + ID uuid.UUID `json:"id"` + InvoiceNumber string `json:"invoice_number"` + IssuerID uuid.UUID `json:"issuer_id"` + RecipientID uuid.UUID `json:"recipient_id"` + Title string `json:"title"` + Description pgtype.Text `json:"description"` + IssueDate pgtype.Date `json:"issue_date"` + DueDate pgtype.Date `json:"due_date"` + TotalAmount decimal.Decimal `json:"total_amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentMethod pgtype.Text `json:"payment_method"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + PaymentDate pgtype.Timestamptz `json:"payment_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + IssuerEmail string `json:"issuer_email"` + IssuerFirstName pgtype.Text `json:"issuer_first_name"` + IssuerLastName pgtype.Text `json:"issuer_last_name"` + RecipientCompanyName string `json:"recipient_company_name"` +} + +func (q *Queries) GetOverdueInvoices(ctx context.Context, arg GetOverdueInvoicesParams) ([]GetOverdueInvoicesRow, error) { + rows, err := q.db.Query(ctx, getOverdueInvoices, arg.CompanyID, arg.UserID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetOverdueInvoicesRow{} + for rows.Next() { + var i GetOverdueInvoicesRow + if err := rows.Scan( + &i.ID, + &i.InvoiceNumber, + &i.IssuerID, + &i.RecipientID, + &i.Title, + &i.Description, + &i.IssueDate, + &i.DueDate, + &i.TotalAmount, + &i.Currency, + &i.Status, + &i.PaymentMethod, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.TransactionHash, + &i.PaymentDate, + &i.RejectionReason, + &i.IpfsHash, + &i.SmartContractAddress, + &i.ChainID, + &i.CreatedAt, + &i.UpdatedAt, + &i.IssuerEmail, + &i.IssuerFirstName, + &i.IssuerLastName, + &i.RecipientCompanyName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserInvoices = `-- name: GetUserInvoices :many +SELECT i.id, i.invoice_number, i.issuer_id, i.recipient_id, i.title, i.description, i.issue_date, i.due_date, i.total_amount, i.currency, i.status, i.payment_method, i.recipient_wallet_address, i.recipient_bank_account_id, i.transaction_hash, i.payment_date, i.rejection_reason, i.ipfs_hash, i.smart_contract_address, i.chain_id, i.created_at, i.updated_at, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN companies recipient ON i.recipient_id = recipient.id +WHERE i.issuer_id = $1 +ORDER BY i.created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetUserInvoicesParams struct { + UserID uuid.UUID `json:"user_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetUserInvoicesRow struct { + ID uuid.UUID `json:"id"` + InvoiceNumber string `json:"invoice_number"` + IssuerID uuid.UUID `json:"issuer_id"` + RecipientID uuid.UUID `json:"recipient_id"` + Title string `json:"title"` + Description pgtype.Text `json:"description"` + IssueDate pgtype.Date `json:"issue_date"` + DueDate pgtype.Date `json:"due_date"` + TotalAmount decimal.Decimal `json:"total_amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentMethod pgtype.Text `json:"payment_method"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + PaymentDate pgtype.Timestamptz `json:"payment_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + RecipientCompanyName string `json:"recipient_company_name"` +} + +func (q *Queries) GetUserInvoices(ctx context.Context, arg GetUserInvoicesParams) ([]GetUserInvoicesRow, error) { + rows, err := q.db.Query(ctx, getUserInvoices, arg.UserID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetUserInvoicesRow{} + for rows.Next() { + var i GetUserInvoicesRow + if err := rows.Scan( + &i.ID, + &i.InvoiceNumber, + &i.IssuerID, + &i.RecipientID, + &i.Title, + &i.Description, + &i.IssueDate, + &i.DueDate, + &i.TotalAmount, + &i.Currency, + &i.Status, + &i.PaymentMethod, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.TransactionHash, + &i.PaymentDate, + &i.RejectionReason, + &i.IpfsHash, + &i.SmartContractAddress, + &i.ChainID, + &i.CreatedAt, + &i.UpdatedAt, + &i.RecipientCompanyName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const searchInvoices = `-- name: SearchInvoices :many +SELECT i.id, i.invoice_number, i.issuer_id, i.recipient_id, i.title, i.description, i.issue_date, i.due_date, i.total_amount, i.currency, i.status, i.payment_method, i.recipient_wallet_address, i.recipient_bank_account_id, i.transaction_hash, i.payment_date, i.rejection_reason, i.ipfs_hash, i.smart_contract_address, i.chain_id, i.created_at, i.updated_at, + issuer.email as issuer_email, + COALESCE(issuer_profile.first_name, issuer_personal.first_name) as issuer_first_name, + COALESCE(issuer_profile.last_name, issuer_personal.last_name) as issuer_last_name, + recipient.company_name as recipient_company_name +FROM invoices i +JOIN users issuer ON i.issuer_id = issuer.id +JOIN companies recipient ON i.recipient_id = recipient.id +LEFT JOIN company_staff_profiles issuer_profile ON issuer.id = issuer_profile.id +LEFT JOIN personal_users issuer_personal ON issuer.id = issuer_personal.id +WHERE (i.issuer_id = $1 OR i.recipient_id IN ( + SELECT company_id FROM company_users WHERE user_id = $1 +)) +AND ( + i.invoice_number ILIKE '%' || $2 || '%' OR + i.title ILIKE '%' || $2 || '%' OR + recipient.company_name ILIKE '%' || $2 || '%' +) +ORDER BY i.created_at DESC +LIMIT $4 OFFSET $3 +` + +type SearchInvoicesParams struct { + UserID uuid.UUID `json:"user_id"` + SearchTerm pgtype.Text `json:"search_term"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type SearchInvoicesRow struct { + ID uuid.UUID `json:"id"` + InvoiceNumber string `json:"invoice_number"` + IssuerID uuid.UUID `json:"issuer_id"` + RecipientID uuid.UUID `json:"recipient_id"` + Title string `json:"title"` + Description pgtype.Text `json:"description"` + IssueDate pgtype.Date `json:"issue_date"` + DueDate pgtype.Date `json:"due_date"` + TotalAmount decimal.Decimal `json:"total_amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentMethod pgtype.Text `json:"payment_method"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + PaymentDate pgtype.Timestamptz `json:"payment_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + IssuerEmail string `json:"issuer_email"` + IssuerFirstName pgtype.Text `json:"issuer_first_name"` + IssuerLastName pgtype.Text `json:"issuer_last_name"` + RecipientCompanyName string `json:"recipient_company_name"` +} + +func (q *Queries) SearchInvoices(ctx context.Context, arg SearchInvoicesParams) ([]SearchInvoicesRow, error) { + rows, err := q.db.Query(ctx, searchInvoices, + arg.UserID, + arg.SearchTerm, + arg.OffsetVal, + arg.LimitVal, + ) + if err != nil { + return nil, err + } + defer rows.Close() + items := []SearchInvoicesRow{} + for rows.Next() { + var i SearchInvoicesRow + if err := rows.Scan( + &i.ID, + &i.InvoiceNumber, + &i.IssuerID, + &i.RecipientID, + &i.Title, + &i.Description, + &i.IssueDate, + &i.DueDate, + &i.TotalAmount, + &i.Currency, + &i.Status, + &i.PaymentMethod, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.TransactionHash, + &i.PaymentDate, + &i.RejectionReason, + &i.IpfsHash, + &i.SmartContractAddress, + &i.ChainID, + &i.CreatedAt, + &i.UpdatedAt, + &i.IssuerEmail, + &i.IssuerFirstName, + &i.IssuerLastName, + &i.RecipientCompanyName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateInvoice = `-- name: UpdateInvoice :one +UPDATE invoices SET + title = COALESCE($1, title), + description = COALESCE($2, description), + issue_date = COALESCE($3, issue_date), + due_date = COALESCE($4, due_date), + total_amount = COALESCE($5, total_amount), + currency = COALESCE($6, currency), + status = COALESCE($7, status), + payment_method = COALESCE($8, payment_method), + recipient_wallet_address = COALESCE($9, recipient_wallet_address), + recipient_bank_account_id = COALESCE($10, recipient_bank_account_id), + transaction_hash = COALESCE($11, transaction_hash), + payment_date = COALESCE($12, payment_date), + rejection_reason = COALESCE($13, rejection_reason), + ipfs_hash = COALESCE($14, ipfs_hash), + smart_contract_address = COALESCE($15, smart_contract_address), + chain_id = COALESCE($16, chain_id), + updated_at = NOW() +WHERE id = $17 +RETURNING id, invoice_number, issuer_id, recipient_id, title, description, issue_date, due_date, total_amount, currency, status, payment_method, recipient_wallet_address, recipient_bank_account_id, transaction_hash, payment_date, rejection_reason, ipfs_hash, smart_contract_address, chain_id, created_at, updated_at +` + +type UpdateInvoiceParams struct { + Title string `json:"title"` + Description pgtype.Text `json:"description"` + IssueDate pgtype.Date `json:"issue_date"` + DueDate pgtype.Date `json:"due_date"` + TotalAmount decimal.Decimal `json:"total_amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentMethod pgtype.Text `json:"payment_method"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + PaymentDate pgtype.Timestamptz `json:"payment_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdateInvoice(ctx context.Context, arg UpdateInvoiceParams) (Invoices, error) { + row := q.db.QueryRow(ctx, updateInvoice, + arg.Title, + arg.Description, + arg.IssueDate, + arg.DueDate, + arg.TotalAmount, + arg.Currency, + arg.Status, + arg.PaymentMethod, + arg.RecipientWalletAddress, + arg.RecipientBankAccountID, + arg.TransactionHash, + arg.PaymentDate, + arg.RejectionReason, + arg.IpfsHash, + arg.SmartContractAddress, + arg.ChainID, + arg.ID, + ) + var i Invoices + err := row.Scan( + &i.ID, + &i.InvoiceNumber, + &i.IssuerID, + &i.RecipientID, + &i.Title, + &i.Description, + &i.IssueDate, + &i.DueDate, + &i.TotalAmount, + &i.Currency, + &i.Status, + &i.PaymentMethod, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.TransactionHash, + &i.PaymentDate, + &i.RejectionReason, + &i.IpfsHash, + &i.SmartContractAddress, + &i.ChainID, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateInvoiceItem = `-- name: UpdateInvoiceItem :one +UPDATE invoice_items SET + description = COALESCE($1, description), + quantity = COALESCE($2, quantity), + unit_price = COALESCE($3, unit_price), + amount = COALESCE($4, amount), + tax_rate = COALESCE($5, tax_rate), + tax_amount = COALESCE($6, tax_amount), + discount_percentage = COALESCE($7, discount_percentage), + discount_amount = COALESCE($8, discount_amount), + total_amount = COALESCE($9, total_amount), + updated_at = NOW() +WHERE id = $10 +RETURNING id, invoice_id, description, quantity, unit_price, amount, tax_rate, tax_amount, discount_percentage, discount_amount, total_amount, created_at, updated_at +` + +type UpdateInvoiceItemParams struct { + Description string `json:"description"` + Quantity decimal.Decimal `json:"quantity"` + UnitPrice decimal.Decimal `json:"unit_price"` + Amount decimal.Decimal `json:"amount"` + TaxRate pgtype.Numeric `json:"tax_rate"` + TaxAmount pgtype.Numeric `json:"tax_amount"` + DiscountPercentage pgtype.Numeric `json:"discount_percentage"` + DiscountAmount pgtype.Numeric `json:"discount_amount"` + TotalAmount decimal.Decimal `json:"total_amount"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdateInvoiceItem(ctx context.Context, arg UpdateInvoiceItemParams) (InvoiceItems, error) { + row := q.db.QueryRow(ctx, updateInvoiceItem, + arg.Description, + arg.Quantity, + arg.UnitPrice, + arg.Amount, + arg.TaxRate, + arg.TaxAmount, + arg.DiscountPercentage, + arg.DiscountAmount, + arg.TotalAmount, + arg.ID, + ) + var i InvoiceItems + err := row.Scan( + &i.ID, + &i.InvoiceID, + &i.Description, + &i.Quantity, + &i.UnitPrice, + &i.Amount, + &i.TaxRate, + &i.TaxAmount, + &i.DiscountPercentage, + &i.DiscountAmount, + &i.TotalAmount, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/db/sqlc/models.go b/db/sqlc/models.go index 23fe097..4647855 100644 --- a/db/sqlc/models.go +++ b/db/sqlc/models.go @@ -5,192 +5,962 @@ package sqlc import ( - "database/sql/driver" - "fmt" - "net/netip" "time" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" + "github.com/shopspring/decimal" ) -type OtpPurpose string +type ActivityLogs struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + ActivityType string `json:"activity_type"` + Description pgtype.Text `json:"description"` + Metadata []byte `json:"metadata"` + IpAddress pgtype.Text `json:"ip_address"` + UserAgent pgtype.Text `json:"user_agent"` + CreatedAt pgtype.Timestamptz `json:"created_at"` +} -const ( - OtpPurposeEmailVerification OtpPurpose = "email_verification" - OtpPurposePasswordReset OtpPurpose = "password_reset" - OtpPurposePhoneVerification OtpPurpose = "phone_verification" - OtpPurposeAccountRecovery OtpPurpose = "account_recovery" - OtpPurposeTwoFactorAuth OtpPurpose = "two_factor_auth" - OtpPurposeLoginConfirmation OtpPurpose = "login_confirmation" -) +type ApiKeys struct { + ID uuid.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + ApiKeyHash string `json:"api_key_hash"` + Name string `json:"name"` + Permissions []byte `json:"permissions"` + ExpiresAt pgtype.Timestamptz `json:"expires_at"` + IsActive pgtype.Bool `json:"is_active"` + LastUsedAt pgtype.Timestamptz `json:"last_used_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} -func (e *OtpPurpose) Scan(src interface{}) error { - switch s := src.(type) { - case []byte: - *e = OtpPurpose(s) - case string: - *e = OtpPurpose(s) - default: - return fmt.Errorf("unsupported scan type for OtpPurpose: %T", src) - } - return nil -} - -type NullOtpPurpose struct { - OtpPurpose OtpPurpose `json:"otp_purpose"` - Valid bool `json:"valid"` -} - -// Scan implements the Scanner interface. -func (ns *NullOtpPurpose) Scan(value interface{}) error { - if value == nil { - ns.OtpPurpose, ns.Valid = "", false - return nil - } - ns.Valid = true - return ns.OtpPurpose.Scan(value) -} - -// Value implements the driver Valuer interface. -func (ns NullOtpPurpose) Value() (driver.Value, error) { - if !ns.Valid { - return nil, nil - } - return string(ns.OtpPurpose), nil -} - -type Kyc struct { - ID uuid.UUID `json:"id"` - UserID uuid.UUID `json:"user_id"` - FaceVerification bool `json:"face_verification"` - IdentityVerification bool `json:"identity_verification"` - VerificationType string `json:"verification_type"` - VerificationNumber string `json:"verification_number"` - VerificationStatus string `json:"verification_status"` - UpdatedAt time.Time `json:"updated_at"` - CreatedAt time.Time `json:"created_at"` -} - -type OtpVerifications struct { +type AuditLogs struct { ID uuid.UUID `json:"id"` UserID pgtype.UUID `json:"user_id"` - OtpCode string `json:"otp_code"` - HashedOtp string `json:"hashed_otp"` - Purpose OtpPurpose `json:"purpose"` - ContactMethod pgtype.Text `json:"contact_method"` - AttemptsMade int32 `json:"attempts_made"` - MaxAttempts int32 `json:"max_attempts"` - IsVerified bool `json:"is_verified"` - CreatedAt time.Time `json:"created_at"` - ExpiresAt time.Time `json:"expires_at"` - VerifiedAt pgtype.Timestamptz `json:"verified_at"` - IpAddress *netip.Addr `json:"ip_address"` + CompanyID pgtype.UUID `json:"company_id"` + Action string `json:"action"` + EntityType string `json:"entity_type"` + EntityID uuid.UUID `json:"entity_id"` + PreviousState []byte `json:"previous_state"` + NewState []byte `json:"new_state"` + IpAddress pgtype.Text `json:"ip_address"` UserAgent pgtype.Text `json:"user_agent"` - DeviceID pgtype.UUID `json:"device_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` +} + +type BankAccounts struct { + ID uuid.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + AccountNumber string `json:"account_number"` + AccountHolderName string `json:"account_holder_name"` + BankName string `json:"bank_name"` + BankCode pgtype.Text `json:"bank_code"` + RoutingNumber pgtype.Text `json:"routing_number"` + SwiftCode pgtype.Text `json:"swift_code"` + Iban pgtype.Text `json:"iban"` + AccountType string `json:"account_type"` + Currency string `json:"currency"` + Country string `json:"country"` + IsDefault pgtype.Bool `json:"is_default"` + IsVerified pgtype.Bool `json:"is_verified"` + VerificationMethod pgtype.Text `json:"verification_method"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type Companies struct { + ID uuid.UUID `json:"id"` + OwnerID uuid.UUID `json:"owner_id"` + CompanyName string `json:"company_name"` + CompanyEmail pgtype.Text `json:"company_email"` + CompanyPhone pgtype.Text `json:"company_phone"` + CompanySize pgtype.Text `json:"company_size"` + CompanyIndustry pgtype.Text `json:"company_industry"` + CompanyDescription pgtype.Text `json:"company_description"` + CompanyHeadquarters pgtype.Text `json:"company_headquarters"` + CompanyLogo pgtype.Text `json:"company_logo"` + CompanyWebsite pgtype.Text `json:"company_website"` + PrimaryContactName pgtype.Text `json:"primary_contact_name"` + PrimaryContactEmail pgtype.Text `json:"primary_contact_email"` + PrimaryContactPhone pgtype.Text `json:"primary_contact_phone"` + CompanyAddress pgtype.Text `json:"company_address"` + CompanyCity pgtype.Text `json:"company_city"` + CompanyPostalCode pgtype.Text `json:"company_postal_code"` + CompanyCountry pgtype.Text `json:"company_country"` + CompanyRegistrationNumber pgtype.Text `json:"company_registration_number"` + RegistrationCountry pgtype.Text `json:"registration_country"` + TaxID pgtype.Text `json:"tax_id"` + IncorporationDate pgtype.Date `json:"incorporation_date"` + AccountStatus pgtype.Text `json:"account_status"` + KybStatus pgtype.Text `json:"kyb_status"` + KybVerifiedAt pgtype.Timestamptz `json:"kyb_verified_at"` + KybVerificationMethod pgtype.Text `json:"kyb_verification_method"` + KybVerificationProvider pgtype.Text `json:"kyb_verification_provider"` + KybRejectionReason pgtype.Text `json:"kyb_rejection_reason"` + LegalEntityType pgtype.Text `json:"legal_entity_type"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type CompanyCountryKybStatus struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + CountryID uuid.UUID `json:"country_id"` + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationDate pgtype.Timestamptz `json:"verification_date"` + ExpiryDate pgtype.Timestamptz `json:"expiry_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Notes pgtype.Text `json:"notes"` + RiskRating pgtype.Text `json:"risk_rating"` + RestrictedFeatures []byte `json:"restricted_features"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type CompanyEmployees struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + UserID pgtype.UUID `json:"user_id"` + EmployeeID pgtype.Text `json:"employee_id"` + Department pgtype.Text `json:"department"` + Position pgtype.Text `json:"position"` + EmploymentStatus pgtype.Text `json:"employment_status"` + EmploymentType pgtype.Text `json:"employment_type"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` + ManagerID pgtype.UUID `json:"manager_id"` + SalaryAmount pgtype.Numeric `json:"salary_amount"` + SalaryCurrency pgtype.Text `json:"salary_currency"` + SalaryFrequency pgtype.Text `json:"salary_frequency"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + PaymentMethod pgtype.Text `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + TaxInformation []byte `json:"tax_information"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type CompanyFeatureFlags struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + FlagKey string `json:"flag_key"` + IsEnabled bool `json:"is_enabled"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type CompanySettings struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + SettingKey string `json:"setting_key"` + SettingValue pgtype.Text `json:"setting_value"` + DataType string `json:"data_type"` + Description pgtype.Text `json:"description"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type CompanyStaffProfiles struct { + ID uuid.UUID `json:"id"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` + ProfilePicture pgtype.Text `json:"profile_picture"` + PhoneNumber pgtype.Text `json:"phone_number"` + Email pgtype.Text `json:"email"` + Department pgtype.Text `json:"department"` + JobTitle pgtype.Text `json:"job_title"` + ReportsTo pgtype.UUID `json:"reports_to"` + HireDate pgtype.Date `json:"hire_date"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type CompanyUsers struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + UserID uuid.UUID `json:"user_id"` + Role string `json:"role"` + Department pgtype.Text `json:"department"` + JobTitle pgtype.Text `json:"job_title"` + IsAdministrator pgtype.Bool `json:"is_administrator"` + CanManagePayroll pgtype.Bool `json:"can_manage_payroll"` + CanManageInvoices pgtype.Bool `json:"can_manage_invoices"` + CanManageEmployees pgtype.Bool `json:"can_manage_employees"` + CanManageCompanySettings pgtype.Bool `json:"can_manage_company_settings"` + CanManageBankAccounts pgtype.Bool `json:"can_manage_bank_accounts"` + CanManageWallets pgtype.Bool `json:"can_manage_wallets"` + Permissions []byte `json:"permissions"` + IsActive pgtype.Bool `json:"is_active"` + AddedBy pgtype.UUID `json:"added_by"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type CompanyWallets struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + WalletAddress string `json:"wallet_address"` + WalletType string `json:"wallet_type"` + ChainID int32 `json:"chain_id"` + IsDefault pgtype.Bool `json:"is_default"` + MultisigConfig []byte `json:"multisig_config"` + RequiredApprovals pgtype.Int4 `json:"required_approvals"` + WalletName pgtype.Text `json:"wallet_name"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type ComplianceRules struct { + ID uuid.UUID `json:"id"` + CountryID uuid.UUID `json:"country_id"` + RuleType string `json:"rule_type"` + EntityType string `json:"entity_type"` + ThresholdAmount pgtype.Numeric `json:"threshold_amount"` + ThresholdCurrency pgtype.Text `json:"threshold_currency"` + RuleDescription pgtype.Text `json:"rule_description"` + RegulatoryReference pgtype.Text `json:"regulatory_reference"` + ActionRequired pgtype.Text `json:"action_required"` + IsActive pgtype.Bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type ContractTemplates struct { + ID uuid.UUID `json:"id"` + CreatorID uuid.UUID `json:"creator_id"` + CompanyID pgtype.UUID `json:"company_id"` + Name string `json:"name"` + Description pgtype.Text `json:"description"` + TemplateType string `json:"template_type"` + TemplateContent []byte `json:"template_content"` + IsPublic pgtype.Bool `json:"is_public"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type Contracts struct { + ID uuid.UUID `json:"id"` + TemplateID pgtype.UUID `json:"template_id"` + CompanyID uuid.UUID `json:"company_id"` + EmployeeID pgtype.UUID `json:"employee_id"` + FreelancerID pgtype.UUID `json:"freelancer_id"` + ContractTitle string `json:"contract_title"` + ContractType string `json:"contract_type"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` + Status pgtype.Text `json:"status"` + PaymentTerms []byte `json:"payment_terms"` + ContractDocumentUrl pgtype.Text `json:"contract_document_url"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type ExchangeRates struct { + ID uuid.UUID `json:"id"` + BaseCurrency string `json:"base_currency"` + QuoteCurrency string `json:"quote_currency"` + Rate decimal.Decimal `json:"rate"` + Source string `json:"source"` + Timestamp time.Time `json:"timestamp"` + CreatedAt pgtype.Timestamptz `json:"created_at"` +} + +type ExpenseCategories struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + Name string `json:"name"` + Description pgtype.Text `json:"description"` + IsActive pgtype.Bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type Expenses struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + CompanyID uuid.UUID `json:"company_id"` + CategoryID uuid.UUID `json:"category_id"` + Amount decimal.Decimal `json:"amount"` + Currency string `json:"currency"` + ExpenseDate pgtype.Date `json:"expense_date"` + Description pgtype.Text `json:"description"` + ReceiptUrl pgtype.Text `json:"receipt_url"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + Status pgtype.Text `json:"status"` + PaymentTransactionID pgtype.UUID `json:"payment_transaction_id"` + ApprovedBy pgtype.UUID `json:"approved_by"` + ApprovedAt pgtype.Timestamptz `json:"approved_at"` + RejectedReason pgtype.Text `json:"rejected_reason"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type FeatureFlags struct { + ID uuid.UUID `json:"id"` + FlagKey string `json:"flag_key"` + Description pgtype.Text `json:"description"` + IsEnabled pgtype.Bool `json:"is_enabled"` + RolloutPercentage pgtype.Int4 `json:"rollout_percentage"` + Conditions []byte `json:"conditions"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type FiatTransactions struct { + ID uuid.UUID `json:"id"` + BankAccountID uuid.UUID `json:"bank_account_id"` + TransactionReference string `json:"transaction_reference"` + TransactionType string `json:"transaction_type"` + Amount decimal.Decimal `json:"amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentProvider pgtype.Text `json:"payment_provider"` + PaymentMethod pgtype.Text `json:"payment_method"` + ProviderReference pgtype.Text `json:"provider_reference"` + ProviderFee pgtype.Numeric `json:"provider_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + Metadata []byte `json:"metadata"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type IntegrationConnections struct { + ID uuid.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + IntegrationType string `json:"integration_type"` + Provider string `json:"provider"` + AccessToken pgtype.Text `json:"access_token"` + RefreshToken pgtype.Text `json:"refresh_token"` + TokenExpiresAt pgtype.Timestamptz `json:"token_expires_at"` + ConnectionData []byte `json:"connection_data"` + IsActive pgtype.Bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type InvoiceItems struct { + ID uuid.UUID `json:"id"` + InvoiceID uuid.UUID `json:"invoice_id"` + Description string `json:"description"` + Quantity decimal.Decimal `json:"quantity"` + UnitPrice decimal.Decimal `json:"unit_price"` + Amount decimal.Decimal `json:"amount"` + TaxRate pgtype.Numeric `json:"tax_rate"` + TaxAmount pgtype.Numeric `json:"tax_amount"` + DiscountPercentage pgtype.Numeric `json:"discount_percentage"` + DiscountAmount pgtype.Numeric `json:"discount_amount"` + TotalAmount decimal.Decimal `json:"total_amount"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type Invoices struct { + ID uuid.UUID `json:"id"` + InvoiceNumber string `json:"invoice_number"` + IssuerID uuid.UUID `json:"issuer_id"` + RecipientID uuid.UUID `json:"recipient_id"` + Title string `json:"title"` + Description pgtype.Text `json:"description"` + IssueDate pgtype.Date `json:"issue_date"` + DueDate pgtype.Date `json:"due_date"` + TotalAmount decimal.Decimal `json:"total_amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentMethod pgtype.Text `json:"payment_method"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + PaymentDate pgtype.Timestamptz `json:"payment_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type KybCountryRequirements struct { + ID uuid.UUID `json:"id"` + CountryID uuid.UUID `json:"country_id"` + DocumentType string `json:"document_type"` + BusinessType pgtype.Text `json:"business_type"` + IsRequired pgtype.Bool `json:"is_required"` + RequirementDescription pgtype.Text `json:"requirement_description"` + AcceptableDocumentFormats pgtype.Text `json:"acceptable_document_formats"` + VerificationLevel pgtype.Text `json:"verification_level"` + AdditionalAttributes []byte `json:"additional_attributes"` + IsActive pgtype.Bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type KybDocuments struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + CountryID uuid.UUID `json:"country_id"` + DocumentType string `json:"document_type"` + DocumentNumber pgtype.Text `json:"document_number"` + DocumentCountry pgtype.Text `json:"document_country"` + IssueDate pgtype.Date `json:"issue_date"` + ExpiryDate pgtype.Date `json:"expiry_date"` + DocumentUrl pgtype.Text `json:"document_url"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationNotes pgtype.Text `json:"verification_notes"` + VerifiedBy pgtype.UUID `json:"verified_by"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Metadata []byte `json:"metadata"` + MeetsRequirements pgtype.Bool `json:"meets_requirements"` + RequirementID pgtype.UUID `json:"requirement_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type KybVerificationAttempts struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + VerificationProvider string `json:"verification_provider"` + VerificationReference pgtype.Text `json:"verification_reference"` + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationResult pgtype.Text `json:"verification_result"` + ResponseData []byte `json:"response_data"` + ErrorMessage pgtype.Text `json:"error_message"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type KycCountryRequirements struct { + ID uuid.UUID `json:"id"` + CountryID uuid.UUID `json:"country_id"` + DocumentType string `json:"document_type"` + IsRequired pgtype.Bool `json:"is_required"` + RequirementDescription pgtype.Text `json:"requirement_description"` + AcceptableDocumentFormats pgtype.Text `json:"acceptable_document_formats"` + VerificationLevel pgtype.Text `json:"verification_level"` + AdditionalAttributes []byte `json:"additional_attributes"` + IsActive pgtype.Bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type KycDocuments struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + CountryID uuid.UUID `json:"country_id"` + DocumentType string `json:"document_type"` + DocumentNumber pgtype.Text `json:"document_number"` + DocumentCountry pgtype.Text `json:"document_country"` + IssueDate pgtype.Date `json:"issue_date"` + ExpiryDate pgtype.Date `json:"expiry_date"` + DocumentUrl pgtype.Text `json:"document_url"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationNotes pgtype.Text `json:"verification_notes"` + VerifiedBy pgtype.UUID `json:"verified_by"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Metadata []byte `json:"metadata"` + MeetsRequirements pgtype.Bool `json:"meets_requirements"` + RequirementID pgtype.UUID `json:"requirement_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type KycVerificationAttempts struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + VerificationProvider string `json:"verification_provider"` + VerificationReference pgtype.Text `json:"verification_reference"` + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationResult pgtype.Text `json:"verification_result"` + ResponseData []byte `json:"response_data"` + ErrorMessage pgtype.Text `json:"error_message"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type LeaveBalances struct { + ID uuid.UUID `json:"id"` + EmployeeID uuid.UUID `json:"employee_id"` + LeaveTypeID uuid.UUID `json:"leave_type_id"` + Balance pgtype.Numeric `json:"balance"` + Accrued pgtype.Numeric `json:"accrued"` + Used pgtype.Numeric `json:"used"` + LastAccrualDate pgtype.Date `json:"last_accrual_date"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type LeaveRequests struct { + ID uuid.UUID `json:"id"` + EmployeeID uuid.UUID `json:"employee_id"` + LeaveTypeID uuid.UUID `json:"leave_type_id"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` + Days decimal.Decimal `json:"days"` + Reason pgtype.Text `json:"reason"` + Status pgtype.Text `json:"status"` + ApprovedBy pgtype.UUID `json:"approved_by"` + ApprovedAt pgtype.Timestamptz `json:"approved_at"` + RejectedReason pgtype.Text `json:"rejected_reason"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type LeaveTypes struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + Name string `json:"name"` + Description pgtype.Text `json:"description"` + IsPaid pgtype.Bool `json:"is_paid"` + AccrualRate pgtype.Numeric `json:"accrual_rate"` + AccrualPeriod pgtype.Text `json:"accrual_period"` + MaximumBalance pgtype.Numeric `json:"maximum_balance"` + IsActive pgtype.Bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type NotificationTemplates struct { + ID uuid.UUID `json:"id"` + TemplateName string `json:"template_name"` + TemplateType string `json:"template_type"` + Subject pgtype.Text `json:"subject"` + Content string `json:"content"` + Variables []byte `json:"variables"` + IsActive pgtype.Bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type Notifications struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + TemplateID pgtype.UUID `json:"template_id"` + NotificationType string `json:"notification_type"` + Title string `json:"title"` + Content string `json:"content"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + IsRead pgtype.Bool `json:"is_read"` + ReadAt pgtype.Timestamptz `json:"read_at"` + DeliveryStatus pgtype.Text `json:"delivery_status"` + Priority pgtype.Text `json:"priority"` + CreatedAt pgtype.Timestamptz `json:"created_at"` +} + +type PaymentRequests struct { + ID uuid.UUID `json:"id"` + CreatorID uuid.UUID `json:"creator_id"` + RecipientID pgtype.UUID `json:"recipient_id"` + CompanyID pgtype.UUID `json:"company_id"` + RequestTitle string `json:"request_title"` + Description pgtype.Text `json:"description"` + Amount decimal.Decimal `json:"amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + ExpiryDate pgtype.Timestamptz `json:"expiry_date"` + PaymentLink pgtype.Text `json:"payment_link"` + QrCodeUrl pgtype.Text `json:"qr_code_url"` + PaymentMethod pgtype.Text `json:"payment_method"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + PaidAt pgtype.Timestamptz `json:"paid_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type PayrollItems struct { + ID uuid.UUID `json:"id"` + PayrollID uuid.UUID `json:"payroll_id"` + EmployeeID uuid.UUID `json:"employee_id"` + BaseAmount decimal.Decimal `json:"base_amount"` + BaseCurrency string `json:"base_currency"` + PaymentAmount decimal.Decimal `json:"payment_amount"` + PaymentCurrency string `json:"payment_currency"` + ExchangeRate pgtype.Numeric `json:"exchange_rate"` + PaymentMethod string `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + Status pgtype.Text `json:"status"` + TransactionHash pgtype.Text `json:"transaction_hash"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + Notes pgtype.Text `json:"notes"` + TimesheetID pgtype.UUID `json:"timesheet_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type PayrollPeriods struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + PeriodName string `json:"period_name"` + Frequency string `json:"frequency"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` + PaymentDate pgtype.Date `json:"payment_date"` + Status pgtype.Text `json:"status"` + IsRecurring pgtype.Bool `json:"is_recurring"` + NextPeriodID pgtype.UUID `json:"next_period_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type Payrolls struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + PeriodID uuid.UUID `json:"period_id"` + Name string `json:"name"` + Description pgtype.Text `json:"description"` + TotalAmount pgtype.Numeric `json:"total_amount"` + BaseCurrency string `json:"base_currency"` + Status pgtype.Text `json:"status"` + ExecutionType pgtype.Text `json:"execution_type"` + ScheduledExecutionTime pgtype.Timestamptz `json:"scheduled_execution_time"` + ExecutedAt pgtype.Timestamptz `json:"executed_at"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + CreatedBy uuid.UUID `json:"created_by"` + ApprovedBy pgtype.UUID `json:"approved_by"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type Permissions struct { + ID uuid.UUID `json:"id"` + PermissionKey string `json:"permission_key"` + Description pgtype.Text `json:"description"` + Category string `json:"category"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type PersonalUsers struct { + ID uuid.UUID `json:"id"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` + ProfilePicture pgtype.Text `json:"profile_picture"` + PhoneNumber pgtype.Text `json:"phone_number"` + PhoneNumberVerified pgtype.Bool `json:"phone_number_verified"` + PhoneNumberVerifiedAt pgtype.Timestamptz `json:"phone_number_verified_at"` + Nationality pgtype.Text `json:"nationality"` + ResidentialCountry pgtype.Text `json:"residential_country"` + UserAddress pgtype.Text `json:"user_address"` + UserCity pgtype.Text `json:"user_city"` + UserPostalCode pgtype.Text `json:"user_postal_code"` + Gender pgtype.Text `json:"gender"` + DateOfBirth pgtype.Date `json:"date_of_birth"` + JobRole pgtype.Text `json:"job_role"` + PersonalAccountType pgtype.Text `json:"personal_account_type"` + EmploymentType pgtype.Text `json:"employment_type"` + TaxID pgtype.Text `json:"tax_id"` + DefaultPaymentCurrency pgtype.Text `json:"default_payment_currency"` + DefaultPaymentMethod pgtype.Text `json:"default_payment_method"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + Specialization pgtype.Text `json:"specialization"` + KycStatus pgtype.Text `json:"kyc_status"` + KycVerifiedAt pgtype.Timestamptz `json:"kyc_verified_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type RolePermissions struct { + ID uuid.UUID `json:"id"` + RoleID uuid.UUID `json:"role_id"` + PermissionID uuid.UUID `json:"permission_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` +} + +type Roles struct { + ID uuid.UUID `json:"id"` + CompanyID pgtype.UUID `json:"company_id"` + RoleName string `json:"role_name"` + Description pgtype.Text `json:"description"` + IsSystemRole pgtype.Bool `json:"is_system_role"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` } type SecurityEvents struct { - ID uuid.UUID `json:"id"` - UserID uuid.UUID `json:"user_id"` - EventType string `json:"event_type"` - IpAddress string `json:"ip_address"` - UserAgent pgtype.Text `json:"user_agent"` - Metadata []byte `json:"metadata"` - Timestamp pgtype.Timestamp `json:"timestamp"` + ID uuid.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + EventType string `json:"event_type"` + Severity string `json:"severity"` + IpAddress pgtype.Text `json:"ip_address"` + UserAgent pgtype.Text `json:"user_agent"` + Metadata []byte `json:"metadata"` + CreatedAt pgtype.Timestamptz `json:"created_at"` } type Sessions struct { - ID uuid.UUID `json:"id"` - UserID uuid.UUID `json:"user_id"` - RefreshToken string `json:"refresh_token"` - UserAgent string `json:"user_agent"` - LastUsedAt pgtype.Timestamp `json:"last_used_at"` - WebOauthClientID pgtype.Text `json:"web_oauth_client_id"` - OauthAccessToken pgtype.Text `json:"oauth_access_token"` - OauthIDToken pgtype.Text `json:"oauth_id_token"` - UserLoginType string `json:"user_login_type"` - MfaEnabled bool `json:"mfa_enabled"` - ClientIp string `json:"client_ip"` - IsBlocked bool `json:"is_blocked"` - ExpiresAt pgtype.Timestamp `json:"expires_at"` - CreatedAt pgtype.Timestamp `json:"created_at"` -} - -type Transactions struct { - ID uuid.UUID `json:"id"` - UserID uuid.UUID `json:"user_id"` - TxHash string `json:"tx_hash"` - TransactionPinHash string `json:"transaction_pin_hash"` - Status string `json:"status"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` -} - -type UserDeviceTokens struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + RefreshToken pgtype.Text `json:"refresh_token"` + UserAgent pgtype.Text `json:"user_agent"` + ClientIp pgtype.Text `json:"client_ip"` + LastUsedAt pgtype.Timestamptz `json:"last_used_at"` + WebOauthClientID pgtype.Text `json:"web_oauth_client_id"` + OauthAccessToken pgtype.Text `json:"oauth_access_token"` + OauthIDToken pgtype.Text `json:"oauth_id_token"` + UserLoginType pgtype.Text `json:"user_login_type"` + MfaVerified pgtype.Bool `json:"mfa_verified"` + IsBlocked pgtype.Bool `json:"is_blocked"` + ExpiresAt pgtype.Timestamptz `json:"expires_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` +} + +type SupportedCountries struct { + ID uuid.UUID `json:"id"` + CountryCode string `json:"country_code"` + CountryName string `json:"country_name"` + Region pgtype.Text `json:"region"` + CurrencyCode pgtype.Text `json:"currency_code"` + CurrencySymbol pgtype.Text `json:"currency_symbol"` + IsActive pgtype.Bool `json:"is_active"` + IsHighRisk pgtype.Bool `json:"is_high_risk"` + RequiresEnhancedKyc pgtype.Bool `json:"requires_enhanced_kyc"` + RequiresEnhancedKyb pgtype.Bool `json:"requires_enhanced_kyb"` + Timezone pgtype.Text `json:"timezone"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type SupportedNetworks struct { + ID uuid.UUID `json:"id"` + Name string `json:"name"` + ChainID int32 `json:"chain_id"` + NetworkType string `json:"network_type"` + CurrencySymbol string `json:"currency_symbol"` + BlockExplorerUrl pgtype.Text `json:"block_explorer_url"` + RpcUrl pgtype.Text `json:"rpc_url"` + IsEvmCompatible pgtype.Bool `json:"is_evm_compatible"` + IsActive pgtype.Bool `json:"is_active"` + TransactionSpeed pgtype.Text `json:"transaction_speed"` + AverageBlockTime pgtype.Int4 `json:"average_block_time"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type SupportedTokens struct { + ID uuid.UUID `json:"id"` + NetworkID uuid.UUID `json:"network_id"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals int32 `json:"decimals"` + ContractAddress pgtype.Text `json:"contract_address"` + TokenType string `json:"token_type"` + LogoUrl pgtype.Text `json:"logo_url"` + IsStablecoin pgtype.Bool `json:"is_stablecoin"` + IsActive pgtype.Bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type SystemSettings struct { + ID uuid.UUID `json:"id"` + SettingKey string `json:"setting_key"` + SettingValue pgtype.Text `json:"setting_value"` + DataType string `json:"data_type"` + Description pgtype.Text `json:"description"` + IsSensitive pgtype.Bool `json:"is_sensitive"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type TaxCalculations struct { + ID uuid.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + ReferenceType string `json:"reference_type"` + ReferenceID uuid.UUID `json:"reference_id"` + TaxRateID uuid.UUID `json:"tax_rate_id"` + TaxableAmount decimal.Decimal `json:"taxable_amount"` + TaxAmount decimal.Decimal `json:"tax_amount"` + CalculationDate pgtype.Date `json:"calculation_date"` + TaxPeriod string `json:"tax_period"` + Status pgtype.Text `json:"status"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type TaxDocuments struct { + ID uuid.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + CountryID uuid.UUID `json:"country_id"` + DocumentType string `json:"document_type"` + TaxYear int32 `json:"tax_year"` + DocumentUrl pgtype.Text `json:"document_url"` + IpfsHash pgtype.Text `json:"ipfs_hash"` + Status pgtype.Text `json:"status"` + ExpiresAt pgtype.Date `json:"expires_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type TaxRates struct { + ID uuid.UUID `json:"id"` + CountryID uuid.UUID `json:"country_id"` + Region pgtype.Text `json:"region"` + TaxType string `json:"tax_type"` + Rate decimal.Decimal `json:"rate"` + EffectiveDate pgtype.Date `json:"effective_date"` + ExpiryDate pgtype.Date `json:"expiry_date"` + Description pgtype.Text `json:"description"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type TimesheetEntries struct { + ID uuid.UUID `json:"id"` + TimesheetID uuid.UUID `json:"timesheet_id"` + Date pgtype.Date `json:"date"` + StartTime pgtype.Time `json:"start_time"` + EndTime pgtype.Time `json:"end_time"` + Hours decimal.Decimal `json:"hours"` + IsBillable pgtype.Bool `json:"is_billable"` + IsOvertime pgtype.Bool `json:"is_overtime"` + Project pgtype.Text `json:"project"` + Task pgtype.Text `json:"task"` + Description pgtype.Text `json:"description"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type Timesheets struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + EmployeeID uuid.UUID `json:"employee_id"` + PeriodID pgtype.UUID `json:"period_id"` + Status pgtype.Text `json:"status"` + TotalHours pgtype.Numeric `json:"total_hours"` + BillableHours pgtype.Numeric `json:"billable_hours"` + OvertimeHours pgtype.Numeric `json:"overtime_hours"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + RateCurrency pgtype.Text `json:"rate_currency"` + TotalAmount pgtype.Numeric `json:"total_amount"` + SubmittedAt pgtype.Timestamptz `json:"submitted_at"` + ApprovedAt pgtype.Timestamptz `json:"approved_at"` + ApprovedBy pgtype.UUID `json:"approved_by"` + RejectionReason pgtype.Text `json:"rejection_reason"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type UserCountryKycStatus struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + CountryID uuid.UUID `json:"country_id"` + VerificationStatus pgtype.Text `json:"verification_status"` + VerificationLevel pgtype.Text `json:"verification_level"` + VerificationDate pgtype.Timestamptz `json:"verification_date"` + ExpiryDate pgtype.Timestamptz `json:"expiry_date"` + RejectionReason pgtype.Text `json:"rejection_reason"` + Notes pgtype.Text `json:"notes"` + RiskRating pgtype.Text `json:"risk_rating"` + RestrictedFeatures []byte `json:"restricted_features"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type UserDevices struct { ID uuid.UUID `json:"id"` UserID uuid.UUID `json:"user_id"` - DeviceToken string `json:"device_token"` - Platform string `json:"platform"` + DeviceToken pgtype.Text `json:"device_token"` + Platform pgtype.Text `json:"platform"` DeviceType pgtype.Text `json:"device_type"` DeviceModel pgtype.Text `json:"device_model"` OsName pgtype.Text `json:"os_name"` OsVersion pgtype.Text `json:"os_version"` PushNotificationToken pgtype.Text `json:"push_notification_token"` - IsActive bool `json:"is_active"` - IsVerified bool `json:"is_verified"` + IsActive pgtype.Bool `json:"is_active"` + IsVerified pgtype.Bool `json:"is_verified"` LastUsedAt pgtype.Timestamptz `json:"last_used_at"` - FirstRegisteredAt time.Time `json:"first_registered_at"` AppVersion pgtype.Text `json:"app_version"` ClientIp pgtype.Text `json:"client_ip"` ExpiresAt pgtype.Timestamptz `json:"expires_at"` - IsRevoked bool `json:"is_revoked"` + IsRevoked pgtype.Bool `json:"is_revoked"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type UserFeatureFlags struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + FlagKey string `json:"flag_key"` + IsEnabled bool `json:"is_enabled"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type UserRoles struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + RoleID uuid.UUID `json:"role_id"` + CompanyID pgtype.UUID `json:"company_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type UserSettings struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + SettingKey string `json:"setting_key"` + SettingValue pgtype.Text `json:"setting_value"` + DataType string `json:"data_type"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` } type UserWallets struct { - ID uuid.UUID `json:"id"` - UserID uuid.UUID `json:"user_id"` - Address string `json:"address"` - Type string `json:"type"` - Chain string `json:"chain"` - IsDefault bool `json:"is_default"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + WalletAddress string `json:"wallet_address"` + WalletType string `json:"wallet_type"` + ChainID int32 `json:"chain_id"` + IsDefault pgtype.Bool `json:"is_default"` + IsVerified pgtype.Bool `json:"is_verified"` + VerificationMethod pgtype.Text `json:"verification_method"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + Nickname pgtype.Text `json:"nickname"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` } type Users struct { - ID uuid.UUID `json:"id"` - Email string `json:"email"` - PasswordHash pgtype.Text `json:"password_hash"` - ProfilePicture pgtype.Text `json:"profile_picture"` - // business, personal - AccountType string `json:"account_type"` - Gender pgtype.Text `json:"gender"` - // contractor, freelancer, employee - PersonalAccountType string `json:"personal_account_type"` - PhoneNumber pgtype.Text `json:"phone_number"` - PhoneNumberVerified pgtype.Bool `json:"phone_number_verified"` - PhoneNumberVerifiedAt pgtype.Timestamptz `json:"phone_number_verified_at"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - Nationality string `json:"nationality"` - ResidentialCountry pgtype.Text `json:"residential_country"` - JobRole pgtype.Text `json:"job_role"` - CompanyName pgtype.Text `json:"company_name"` - CompanySize pgtype.Text `json:"company_size"` - CompanyIndustry pgtype.Text `json:"company_industry"` - CompanyDescription pgtype.Text `json:"company_description"` - CompanyHeadquarters pgtype.Text `json:"company_headquarters"` - UserAddress pgtype.Text `json:"user_address"` - UserCity pgtype.Text `json:"user_city"` - UserPostalCode pgtype.Text `json:"user_postal_code"` - EmployeeType pgtype.Text `json:"employee_type"` - AuthProvider pgtype.Text `json:"auth_provider"` - ProviderID string `json:"provider_id"` - CompanyWebsite pgtype.Text `json:"company_website"` - EmploymentType pgtype.Text `json:"employment_type"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + ID uuid.UUID `json:"id"` + Email string `json:"email"` + PasswordHash pgtype.Text `json:"password_hash"` + AuthProvider pgtype.Text `json:"auth_provider"` + ProviderID pgtype.Text `json:"provider_id"` + EmailVerified pgtype.Bool `json:"email_verified"` + EmailVerifiedAt pgtype.Timestamptz `json:"email_verified_at"` + AccountType string `json:"account_type"` + AccountStatus pgtype.Text `json:"account_status"` + TwoFactorEnabled pgtype.Bool `json:"two_factor_enabled"` + TwoFactorMethod pgtype.Text `json:"two_factor_method"` + UserLoginType pgtype.Text `json:"user_login_type"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + LastLoginAt pgtype.Timestamptz `json:"last_login_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` } type Waitlist struct { @@ -207,3 +977,38 @@ type Waitlist struct { CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } + +type WalletTransactions struct { + ID uuid.UUID `json:"id"` + WalletAddress string `json:"wallet_address"` + TransactionHash string `json:"transaction_hash"` + ChainID int32 `json:"chain_id"` + BlockNumber pgtype.Int8 `json:"block_number"` + FromAddress string `json:"from_address"` + ToAddress string `json:"to_address"` + TokenAddress pgtype.Text `json:"token_address"` + TokenSymbol pgtype.Text `json:"token_symbol"` + Amount decimal.Decimal `json:"amount"` + TransactionType string `json:"transaction_type"` + TransactionStatus pgtype.Text `json:"transaction_status"` + GasPrice pgtype.Numeric `json:"gas_price"` + GasUsed pgtype.Int8 `json:"gas_used"` + TransactionFee pgtype.Numeric `json:"transaction_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type Webhooks struct { + ID uuid.UUID `json:"id"` + UserID pgtype.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` + WebhookUrl string `json:"webhook_url"` + EventTypes []string `json:"event_types"` + SecretKey string `json:"secret_key"` + Description pgtype.Text `json:"description"` + IsActive pgtype.Bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} diff --git a/db/sqlc/notifications.sql.go b/db/sqlc/notifications.sql.go new file mode 100644 index 0000000..4b07957 --- /dev/null +++ b/db/sqlc/notifications.sql.go @@ -0,0 +1,1126 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.29.0 +// source: notifications.sql + +package sqlc + +import ( + "context" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" +) + +const createNotification = `-- name: CreateNotification :one +INSERT INTO notifications ( + id, + user_id, + template_id, + notification_type, + title, + content, + reference_type, + reference_id, + is_read, + read_at, + delivery_status, + priority, + created_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + $7, + $8, + COALESCE($9, FALSE), + $10, + COALESCE($11, 'pending'), + COALESCE($12, 'normal'), + COALESCE($13, NOW()) +) RETURNING id, user_id, template_id, notification_type, title, content, reference_type, reference_id, is_read, read_at, delivery_status, priority, created_at +` + +type CreateNotificationParams struct { + ID interface{} `json:"id"` + UserID uuid.UUID `json:"user_id"` + TemplateID pgtype.UUID `json:"template_id"` + NotificationType string `json:"notification_type"` + Title string `json:"title"` + Content string `json:"content"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + IsRead interface{} `json:"is_read"` + ReadAt pgtype.Timestamptz `json:"read_at"` + DeliveryStatus interface{} `json:"delivery_status"` + Priority interface{} `json:"priority"` + CreatedAt interface{} `json:"created_at"` +} + +func (q *Queries) CreateNotification(ctx context.Context, arg CreateNotificationParams) (Notifications, error) { + row := q.db.QueryRow(ctx, createNotification, + arg.ID, + arg.UserID, + arg.TemplateID, + arg.NotificationType, + arg.Title, + arg.Content, + arg.ReferenceType, + arg.ReferenceID, + arg.IsRead, + arg.ReadAt, + arg.DeliveryStatus, + arg.Priority, + arg.CreatedAt, + ) + var i Notifications + err := row.Scan( + &i.ID, + &i.UserID, + &i.TemplateID, + &i.NotificationType, + &i.Title, + &i.Content, + &i.ReferenceType, + &i.ReferenceID, + &i.IsRead, + &i.ReadAt, + &i.DeliveryStatus, + &i.Priority, + &i.CreatedAt, + ) + return i, err +} + +const createNotificationTemplate = `-- name: CreateNotificationTemplate :one +INSERT INTO notification_templates ( + id, + template_name, + template_type, + subject, + content, + variables, + is_active, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + COALESCE($7, TRUE), + COALESCE($8, NOW()), + COALESCE($9, NOW()) +) RETURNING id, template_name, template_type, subject, content, variables, is_active, created_at, updated_at +` + +type CreateNotificationTemplateParams struct { + ID interface{} `json:"id"` + TemplateName string `json:"template_name"` + TemplateType string `json:"template_type"` + Subject pgtype.Text `json:"subject"` + Content string `json:"content"` + Variables []byte `json:"variables"` + IsActive interface{} `json:"is_active"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateNotificationTemplate(ctx context.Context, arg CreateNotificationTemplateParams) (NotificationTemplates, error) { + row := q.db.QueryRow(ctx, createNotificationTemplate, + arg.ID, + arg.TemplateName, + arg.TemplateType, + arg.Subject, + arg.Content, + arg.Variables, + arg.IsActive, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i NotificationTemplates + err := row.Scan( + &i.ID, + &i.TemplateName, + &i.TemplateType, + &i.Subject, + &i.Content, + &i.Variables, + &i.IsActive, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createPermission = `-- name: CreatePermission :one +INSERT INTO permissions ( + id, + permission_key, + description, + category, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + COALESCE($5, NOW()), + COALESCE($6, NOW()) +) RETURNING id, permission_key, description, category, created_at, updated_at +` + +type CreatePermissionParams struct { + ID interface{} `json:"id"` + PermissionKey string `json:"permission_key"` + Description pgtype.Text `json:"description"` + Category string `json:"category"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreatePermission(ctx context.Context, arg CreatePermissionParams) (Permissions, error) { + row := q.db.QueryRow(ctx, createPermission, + arg.ID, + arg.PermissionKey, + arg.Description, + arg.Category, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i Permissions + err := row.Scan( + &i.ID, + &i.PermissionKey, + &i.Description, + &i.Category, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createRole = `-- name: CreateRole :one +INSERT INTO roles ( + id, + company_id, + role_name, + description, + is_system_role, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + COALESCE($5, FALSE), + COALESCE($6, NOW()), + COALESCE($7, NOW()) +) RETURNING id, company_id, role_name, description, is_system_role, created_at, updated_at +` + +type CreateRoleParams struct { + ID interface{} `json:"id"` + CompanyID pgtype.UUID `json:"company_id"` + RoleName string `json:"role_name"` + Description pgtype.Text `json:"description"` + IsSystemRole interface{} `json:"is_system_role"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateRole(ctx context.Context, arg CreateRoleParams) (Roles, error) { + row := q.db.QueryRow(ctx, createRole, + arg.ID, + arg.CompanyID, + arg.RoleName, + arg.Description, + arg.IsSystemRole, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i Roles + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.RoleName, + &i.Description, + &i.IsSystemRole, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createRolePermission = `-- name: CreateRolePermission :one +INSERT INTO role_permissions ( + id, + role_id, + permission_id, + created_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + COALESCE($4, NOW()) +) RETURNING id, role_id, permission_id, created_at +` + +type CreateRolePermissionParams struct { + ID interface{} `json:"id"` + RoleID uuid.UUID `json:"role_id"` + PermissionID uuid.UUID `json:"permission_id"` + CreatedAt interface{} `json:"created_at"` +} + +func (q *Queries) CreateRolePermission(ctx context.Context, arg CreateRolePermissionParams) (RolePermissions, error) { + row := q.db.QueryRow(ctx, createRolePermission, + arg.ID, + arg.RoleID, + arg.PermissionID, + arg.CreatedAt, + ) + var i RolePermissions + err := row.Scan( + &i.ID, + &i.RoleID, + &i.PermissionID, + &i.CreatedAt, + ) + return i, err +} + +const createUserRole = `-- name: CreateUserRole :one +INSERT INTO user_roles ( + id, + user_id, + role_id, + company_id, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + COALESCE($5, NOW()), + COALESCE($6, NOW()) +) RETURNING id, user_id, role_id, company_id, created_at, updated_at +` + +type CreateUserRoleParams struct { + ID interface{} `json:"id"` + UserID uuid.UUID `json:"user_id"` + RoleID uuid.UUID `json:"role_id"` + CompanyID pgtype.UUID `json:"company_id"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateUserRole(ctx context.Context, arg CreateUserRoleParams) (UserRoles, error) { + row := q.db.QueryRow(ctx, createUserRole, + arg.ID, + arg.UserID, + arg.RoleID, + arg.CompanyID, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i UserRoles + err := row.Scan( + &i.ID, + &i.UserID, + &i.RoleID, + &i.CompanyID, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteNotification = `-- name: DeleteNotification :exec +DELETE FROM notifications +WHERE id = $1 AND user_id = $2 +` + +type DeleteNotificationParams struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` +} + +func (q *Queries) DeleteNotification(ctx context.Context, arg DeleteNotificationParams) error { + _, err := q.db.Exec(ctx, deleteNotification, arg.ID, arg.UserID) + return err +} + +const deleteRole = `-- name: DeleteRole :exec +DELETE FROM roles +WHERE id = $1 AND is_system_role = FALSE +` + +func (q *Queries) DeleteRole(ctx context.Context, id uuid.UUID) error { + _, err := q.db.Exec(ctx, deleteRole, id) + return err +} + +const deleteRolePermission = `-- name: DeleteRolePermission :exec +DELETE FROM role_permissions +WHERE role_id = $1 AND permission_id = $2 +` + +type DeleteRolePermissionParams struct { + RoleID uuid.UUID `json:"role_id"` + PermissionID uuid.UUID `json:"permission_id"` +} + +func (q *Queries) DeleteRolePermission(ctx context.Context, arg DeleteRolePermissionParams) error { + _, err := q.db.Exec(ctx, deleteRolePermission, arg.RoleID, arg.PermissionID) + return err +} + +const deleteUserRole = `-- name: DeleteUserRole :exec +DELETE FROM user_roles +WHERE user_id = $1 AND role_id = $2 + AND ($3::uuid IS NULL OR company_id = $3) +` + +type DeleteUserRoleParams struct { + UserID uuid.UUID `json:"user_id"` + RoleID uuid.UUID `json:"role_id"` + CompanyID uuid.UUID `json:"company_id"` +} + +func (q *Queries) DeleteUserRole(ctx context.Context, arg DeleteUserRoleParams) error { + _, err := q.db.Exec(ctx, deleteUserRole, arg.UserID, arg.RoleID, arg.CompanyID) + return err +} + +const getAllPermissions = `-- name: GetAllPermissions :many +SELECT id, permission_key, description, category, created_at, updated_at FROM permissions +ORDER BY category, permission_key +` + +func (q *Queries) GetAllPermissions(ctx context.Context) ([]Permissions, error) { + rows, err := q.db.Query(ctx, getAllPermissions) + if err != nil { + return nil, err + } + defer rows.Close() + items := []Permissions{} + for rows.Next() { + var i Permissions + if err := rows.Scan( + &i.ID, + &i.PermissionKey, + &i.Description, + &i.Category, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getNotificationCount = `-- name: GetNotificationCount :one +SELECT + COUNT(*) as total_count, + COUNT(*) FILTER (WHERE is_read = FALSE) as unread_count +FROM notifications +WHERE user_id = $1 +` + +type GetNotificationCountRow struct { + TotalCount int64 `json:"total_count"` + UnreadCount int64 `json:"unread_count"` +} + +func (q *Queries) GetNotificationCount(ctx context.Context, userID uuid.UUID) (GetNotificationCountRow, error) { + row := q.db.QueryRow(ctx, getNotificationCount, userID) + var i GetNotificationCountRow + err := row.Scan(&i.TotalCount, &i.UnreadCount) + return i, err +} + +const getNotificationTemplateByName = `-- name: GetNotificationTemplateByName :one +SELECT id, template_name, template_type, subject, content, variables, is_active, created_at, updated_at FROM notification_templates +WHERE template_name = $1 AND is_active = TRUE +` + +func (q *Queries) GetNotificationTemplateByName(ctx context.Context, templateName string) (NotificationTemplates, error) { + row := q.db.QueryRow(ctx, getNotificationTemplateByName, templateName) + var i NotificationTemplates + err := row.Scan( + &i.ID, + &i.TemplateName, + &i.TemplateType, + &i.Subject, + &i.Content, + &i.Variables, + &i.IsActive, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getNotificationTemplatesByType = `-- name: GetNotificationTemplatesByType :many +SELECT id, template_name, template_type, subject, content, variables, is_active, created_at, updated_at FROM notification_templates +WHERE template_type = $1 AND is_active = TRUE +ORDER BY template_name +` + +func (q *Queries) GetNotificationTemplatesByType(ctx context.Context, templateType string) ([]NotificationTemplates, error) { + rows, err := q.db.Query(ctx, getNotificationTemplatesByType, templateType) + if err != nil { + return nil, err + } + defer rows.Close() + items := []NotificationTemplates{} + for rows.Next() { + var i NotificationTemplates + if err := rows.Scan( + &i.ID, + &i.TemplateName, + &i.TemplateType, + &i.Subject, + &i.Content, + &i.Variables, + &i.IsActive, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getNotificationsByType = `-- name: GetNotificationsByType :many +SELECT n.id, n.user_id, n.template_id, n.notification_type, n.title, n.content, n.reference_type, n.reference_id, n.is_read, n.read_at, n.delivery_status, n.priority, n.created_at, nt.template_name +FROM notifications n +LEFT JOIN notification_templates nt ON n.template_id = nt.id +WHERE n.user_id = $1 AND n.notification_type = $2 +ORDER BY n.created_at DESC +LIMIT $4 OFFSET $3 +` + +type GetNotificationsByTypeParams struct { + UserID uuid.UUID `json:"user_id"` + NotificationType string `json:"notification_type"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetNotificationsByTypeRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + TemplateID pgtype.UUID `json:"template_id"` + NotificationType string `json:"notification_type"` + Title string `json:"title"` + Content string `json:"content"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + IsRead pgtype.Bool `json:"is_read"` + ReadAt pgtype.Timestamptz `json:"read_at"` + DeliveryStatus pgtype.Text `json:"delivery_status"` + Priority pgtype.Text `json:"priority"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + TemplateName pgtype.Text `json:"template_name"` +} + +func (q *Queries) GetNotificationsByType(ctx context.Context, arg GetNotificationsByTypeParams) ([]GetNotificationsByTypeRow, error) { + rows, err := q.db.Query(ctx, getNotificationsByType, + arg.UserID, + arg.NotificationType, + arg.OffsetVal, + arg.LimitVal, + ) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetNotificationsByTypeRow{} + for rows.Next() { + var i GetNotificationsByTypeRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.TemplateID, + &i.NotificationType, + &i.Title, + &i.Content, + &i.ReferenceType, + &i.ReferenceID, + &i.IsRead, + &i.ReadAt, + &i.DeliveryStatus, + &i.Priority, + &i.CreatedAt, + &i.TemplateName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPermissionsByCategory = `-- name: GetPermissionsByCategory :many +SELECT id, permission_key, description, category, created_at, updated_at FROM permissions +WHERE category = $1 +ORDER BY permission_key +` + +func (q *Queries) GetPermissionsByCategory(ctx context.Context, category string) ([]Permissions, error) { + rows, err := q.db.Query(ctx, getPermissionsByCategory, category) + if err != nil { + return nil, err + } + defer rows.Close() + items := []Permissions{} + for rows.Next() { + var i Permissions + if err := rows.Scan( + &i.ID, + &i.PermissionKey, + &i.Description, + &i.Category, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getRoleByID = `-- name: GetRoleByID :one +SELECT id, company_id, role_name, description, is_system_role, created_at, updated_at FROM roles WHERE id = $1 +` + +func (q *Queries) GetRoleByID(ctx context.Context, id uuid.UUID) (Roles, error) { + row := q.db.QueryRow(ctx, getRoleByID, id) + var i Roles + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.RoleName, + &i.Description, + &i.IsSystemRole, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getRolePermissions = `-- name: GetRolePermissions :many +SELECT rp.id, rp.role_id, rp.permission_id, rp.created_at, p.permission_key, p.description, p.category +FROM role_permissions rp +JOIN permissions p ON rp.permission_id = p.id +WHERE rp.role_id = $1 +ORDER BY p.category, p.permission_key +` + +type GetRolePermissionsRow struct { + ID uuid.UUID `json:"id"` + RoleID uuid.UUID `json:"role_id"` + PermissionID uuid.UUID `json:"permission_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + PermissionKey string `json:"permission_key"` + Description pgtype.Text `json:"description"` + Category string `json:"category"` +} + +func (q *Queries) GetRolePermissions(ctx context.Context, roleID uuid.UUID) ([]GetRolePermissionsRow, error) { + rows, err := q.db.Query(ctx, getRolePermissions, roleID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetRolePermissionsRow{} + for rows.Next() { + var i GetRolePermissionsRow + if err := rows.Scan( + &i.ID, + &i.RoleID, + &i.PermissionID, + &i.CreatedAt, + &i.PermissionKey, + &i.Description, + &i.Category, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getRolesByCompany = `-- name: GetRolesByCompany :many +SELECT id, company_id, role_name, description, is_system_role, created_at, updated_at FROM roles +WHERE company_id = $1 OR is_system_role = TRUE +ORDER BY is_system_role DESC, role_name +` + +func (q *Queries) GetRolesByCompany(ctx context.Context, companyID pgtype.UUID) ([]Roles, error) { + rows, err := q.db.Query(ctx, getRolesByCompany, companyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []Roles{} + for rows.Next() { + var i Roles + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.RoleName, + &i.Description, + &i.IsSystemRole, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUnreadNotifications = `-- name: GetUnreadNotifications :many +SELECT n.id, n.user_id, n.template_id, n.notification_type, n.title, n.content, n.reference_type, n.reference_id, n.is_read, n.read_at, n.delivery_status, n.priority, n.created_at, nt.template_name +FROM notifications n +LEFT JOIN notification_templates nt ON n.template_id = nt.id +WHERE n.user_id = $1 AND n.is_read = FALSE +ORDER BY n.created_at DESC +` + +type GetUnreadNotificationsRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + TemplateID pgtype.UUID `json:"template_id"` + NotificationType string `json:"notification_type"` + Title string `json:"title"` + Content string `json:"content"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + IsRead pgtype.Bool `json:"is_read"` + ReadAt pgtype.Timestamptz `json:"read_at"` + DeliveryStatus pgtype.Text `json:"delivery_status"` + Priority pgtype.Text `json:"priority"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + TemplateName pgtype.Text `json:"template_name"` +} + +func (q *Queries) GetUnreadNotifications(ctx context.Context, userID uuid.UUID) ([]GetUnreadNotificationsRow, error) { + rows, err := q.db.Query(ctx, getUnreadNotifications, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetUnreadNotificationsRow{} + for rows.Next() { + var i GetUnreadNotificationsRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.TemplateID, + &i.NotificationType, + &i.Title, + &i.Content, + &i.ReferenceType, + &i.ReferenceID, + &i.IsRead, + &i.ReadAt, + &i.DeliveryStatus, + &i.Priority, + &i.CreatedAt, + &i.TemplateName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserNotifications = `-- name: GetUserNotifications :many +SELECT n.id, n.user_id, n.template_id, n.notification_type, n.title, n.content, n.reference_type, n.reference_id, n.is_read, n.read_at, n.delivery_status, n.priority, n.created_at, nt.template_name +FROM notifications n +LEFT JOIN notification_templates nt ON n.template_id = nt.id +WHERE n.user_id = $1 +ORDER BY n.created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetUserNotificationsParams struct { + UserID uuid.UUID `json:"user_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetUserNotificationsRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + TemplateID pgtype.UUID `json:"template_id"` + NotificationType string `json:"notification_type"` + Title string `json:"title"` + Content string `json:"content"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + IsRead pgtype.Bool `json:"is_read"` + ReadAt pgtype.Timestamptz `json:"read_at"` + DeliveryStatus pgtype.Text `json:"delivery_status"` + Priority pgtype.Text `json:"priority"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + TemplateName pgtype.Text `json:"template_name"` +} + +func (q *Queries) GetUserNotifications(ctx context.Context, arg GetUserNotificationsParams) ([]GetUserNotificationsRow, error) { + rows, err := q.db.Query(ctx, getUserNotifications, arg.UserID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetUserNotificationsRow{} + for rows.Next() { + var i GetUserNotificationsRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.TemplateID, + &i.NotificationType, + &i.Title, + &i.Content, + &i.ReferenceType, + &i.ReferenceID, + &i.IsRead, + &i.ReadAt, + &i.DeliveryStatus, + &i.Priority, + &i.CreatedAt, + &i.TemplateName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserPermissions = `-- name: GetUserPermissions :many +SELECT DISTINCT p.permission_key, p.description, p.category +FROM user_roles ur +JOIN role_permissions rp ON ur.role_id = rp.role_id +JOIN permissions p ON rp.permission_id = p.id +WHERE ur.user_id = $1 + AND ($2::uuid IS NULL OR ur.company_id = $2) +ORDER BY p.category, p.permission_key +` + +type GetUserPermissionsParams struct { + UserID uuid.UUID `json:"user_id"` + CompanyID uuid.UUID `json:"company_id"` +} + +type GetUserPermissionsRow struct { + PermissionKey string `json:"permission_key"` + Description pgtype.Text `json:"description"` + Category string `json:"category"` +} + +func (q *Queries) GetUserPermissions(ctx context.Context, arg GetUserPermissionsParams) ([]GetUserPermissionsRow, error) { + rows, err := q.db.Query(ctx, getUserPermissions, arg.UserID, arg.CompanyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetUserPermissionsRow{} + for rows.Next() { + var i GetUserPermissionsRow + if err := rows.Scan(&i.PermissionKey, &i.Description, &i.Category); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserRoles = `-- name: GetUserRoles :many +SELECT ur.id, ur.user_id, ur.role_id, ur.company_id, ur.created_at, ur.updated_at, r.role_name, r.description, c.company_name +FROM user_roles ur +JOIN roles r ON ur.role_id = r.id +LEFT JOIN companies c ON ur.company_id = c.id +WHERE ur.user_id = $1 +ORDER BY c.company_name, r.role_name +` + +type GetUserRolesRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + RoleID uuid.UUID `json:"role_id"` + CompanyID pgtype.UUID `json:"company_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + RoleName string `json:"role_name"` + Description pgtype.Text `json:"description"` + CompanyName pgtype.Text `json:"company_name"` +} + +func (q *Queries) GetUserRoles(ctx context.Context, userID uuid.UUID) ([]GetUserRolesRow, error) { + rows, err := q.db.Query(ctx, getUserRoles, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetUserRolesRow{} + for rows.Next() { + var i GetUserRolesRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.RoleID, + &i.CompanyID, + &i.CreatedAt, + &i.UpdatedAt, + &i.RoleName, + &i.Description, + &i.CompanyName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserRolesByCompany = `-- name: GetUserRolesByCompany :many +SELECT ur.id, ur.user_id, ur.role_id, ur.company_id, ur.created_at, ur.updated_at, r.role_name, r.description +FROM user_roles ur +JOIN roles r ON ur.role_id = r.id +WHERE ur.user_id = $1 AND ur.company_id = $2 +ORDER BY r.role_name +` + +type GetUserRolesByCompanyParams struct { + UserID uuid.UUID `json:"user_id"` + CompanyID pgtype.UUID `json:"company_id"` +} + +type GetUserRolesByCompanyRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + RoleID uuid.UUID `json:"role_id"` + CompanyID pgtype.UUID `json:"company_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + RoleName string `json:"role_name"` + Description pgtype.Text `json:"description"` +} + +func (q *Queries) GetUserRolesByCompany(ctx context.Context, arg GetUserRolesByCompanyParams) ([]GetUserRolesByCompanyRow, error) { + rows, err := q.db.Query(ctx, getUserRolesByCompany, arg.UserID, arg.CompanyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetUserRolesByCompanyRow{} + for rows.Next() { + var i GetUserRolesByCompanyRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.RoleID, + &i.CompanyID, + &i.CreatedAt, + &i.UpdatedAt, + &i.RoleName, + &i.Description, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUsersWithRole = `-- name: GetUsersWithRole :many +SELECT ur.id, ur.user_id, ur.role_id, ur.company_id, ur.created_at, ur.updated_at, u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM user_roles ur +JOIN users u ON ur.user_id = u.id +LEFT JOIN company_staff_profiles csp ON u.id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE ur.role_id = $1 + AND ($2::uuid IS NULL OR ur.company_id = $2) +ORDER BY u.email +` + +type GetUsersWithRoleParams struct { + RoleID uuid.UUID `json:"role_id"` + CompanyID uuid.UUID `json:"company_id"` +} + +type GetUsersWithRoleRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + RoleID uuid.UUID `json:"role_id"` + CompanyID pgtype.UUID `json:"company_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + Email string `json:"email"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` +} + +func (q *Queries) GetUsersWithRole(ctx context.Context, arg GetUsersWithRoleParams) ([]GetUsersWithRoleRow, error) { + rows, err := q.db.Query(ctx, getUsersWithRole, arg.RoleID, arg.CompanyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetUsersWithRoleRow{} + for rows.Next() { + var i GetUsersWithRoleRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.RoleID, + &i.CompanyID, + &i.CreatedAt, + &i.UpdatedAt, + &i.Email, + &i.FirstName, + &i.LastName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const markAllNotificationsAsRead = `-- name: MarkAllNotificationsAsRead :exec +UPDATE notifications SET + is_read = TRUE, + read_at = NOW() +WHERE user_id = $1 AND is_read = FALSE +` + +func (q *Queries) MarkAllNotificationsAsRead(ctx context.Context, userID uuid.UUID) error { + _, err := q.db.Exec(ctx, markAllNotificationsAsRead, userID) + return err +} + +const markNotificationAsRead = `-- name: MarkNotificationAsRead :one +UPDATE notifications SET + is_read = TRUE, + read_at = NOW() +WHERE id = $1 AND user_id = $2 +RETURNING id, user_id, template_id, notification_type, title, content, reference_type, reference_id, is_read, read_at, delivery_status, priority, created_at +` + +type MarkNotificationAsReadParams struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` +} + +func (q *Queries) MarkNotificationAsRead(ctx context.Context, arg MarkNotificationAsReadParams) (Notifications, error) { + row := q.db.QueryRow(ctx, markNotificationAsRead, arg.ID, arg.UserID) + var i Notifications + err := row.Scan( + &i.ID, + &i.UserID, + &i.TemplateID, + &i.NotificationType, + &i.Title, + &i.Content, + &i.ReferenceType, + &i.ReferenceID, + &i.IsRead, + &i.ReadAt, + &i.DeliveryStatus, + &i.Priority, + &i.CreatedAt, + ) + return i, err +} + +const updateRole = `-- name: UpdateRole :one +UPDATE roles SET + role_name = COALESCE($1, role_name), + description = COALESCE($2, description), + updated_at = NOW() +WHERE id = $3 AND is_system_role = FALSE +RETURNING id, company_id, role_name, description, is_system_role, created_at, updated_at +` + +type UpdateRoleParams struct { + RoleName string `json:"role_name"` + Description pgtype.Text `json:"description"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdateRole(ctx context.Context, arg UpdateRoleParams) (Roles, error) { + row := q.db.QueryRow(ctx, updateRole, arg.RoleName, arg.Description, arg.ID) + var i Roles + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.RoleName, + &i.Description, + &i.IsSystemRole, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/db/sqlc/otp_verifications.sql.go b/db/sqlc/otp_verifications.sql.go deleted file mode 100644 index 4bef739..0000000 --- a/db/sqlc/otp_verifications.sql.go +++ /dev/null @@ -1,304 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.29.0 -// source: otp_verifications.sql - -package sqlc - -import ( - "context" - "net/netip" - "time" - - "github.com/google/uuid" - "github.com/jackc/pgx/v5/pgtype" -) - -const countActiveOTPsForUser = `-- name: CountActiveOTPsForUser :one -SELECT COUNT(*) -FROM otp_verifications -WHERE user_id = $1 - AND purpose = $2 - AND is_verified = false - AND expires_at > NOW() -` - -type CountActiveOTPsForUserParams struct { - UserID pgtype.UUID `json:"user_id"` - Purpose OtpPurpose `json:"purpose"` -} - -func (q *Queries) CountActiveOTPsForUser(ctx context.Context, arg CountActiveOTPsForUserParams) (int64, error) { - row := q.db.QueryRow(ctx, countActiveOTPsForUser, arg.UserID, arg.Purpose) - var count int64 - err := row.Scan(&count) - return count, err -} - -const createOTPVerification = `-- name: CreateOTPVerification :one -INSERT INTO otp_verifications ( - user_id, - otp_code, - hashed_otp, - purpose, - contact_method, - attempts_made, - max_attempts, - expires_at, - ip_address, - user_agent, - device_id -) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11 -) RETURNING id, user_id, otp_code, hashed_otp, purpose, contact_method, attempts_made, max_attempts, is_verified, created_at, expires_at, verified_at, ip_address, user_agent, device_id -` - -type CreateOTPVerificationParams struct { - UserID pgtype.UUID `json:"user_id"` - OtpCode string `json:"otp_code"` - HashedOtp string `json:"hashed_otp"` - Purpose OtpPurpose `json:"purpose"` - ContactMethod pgtype.Text `json:"contact_method"` - AttemptsMade int32 `json:"attempts_made"` - MaxAttempts int32 `json:"max_attempts"` - ExpiresAt time.Time `json:"expires_at"` - IpAddress *netip.Addr `json:"ip_address"` - UserAgent pgtype.Text `json:"user_agent"` - DeviceID pgtype.UUID `json:"device_id"` -} - -func (q *Queries) CreateOTPVerification(ctx context.Context, arg CreateOTPVerificationParams) (OtpVerifications, error) { - row := q.db.QueryRow(ctx, createOTPVerification, - arg.UserID, - arg.OtpCode, - arg.HashedOtp, - arg.Purpose, - arg.ContactMethod, - arg.AttemptsMade, - arg.MaxAttempts, - arg.ExpiresAt, - arg.IpAddress, - arg.UserAgent, - arg.DeviceID, - ) - var i OtpVerifications - err := row.Scan( - &i.ID, - &i.UserID, - &i.OtpCode, - &i.HashedOtp, - &i.Purpose, - &i.ContactMethod, - &i.AttemptsMade, - &i.MaxAttempts, - &i.IsVerified, - &i.CreatedAt, - &i.ExpiresAt, - &i.VerifiedAt, - &i.IpAddress, - &i.UserAgent, - &i.DeviceID, - ) - return i, err -} - -const deleteExpiredOTPs = `-- name: DeleteExpiredOTPs :exec -DELETE FROM otp_verifications -WHERE expires_at < NOW() -` - -func (q *Queries) DeleteExpiredOTPs(ctx context.Context) error { - _, err := q.db.Exec(ctx, deleteExpiredOTPs) - return err -} - -const getOTPVerificationByID = `-- name: GetOTPVerificationByID :one -SELECT id, user_id, otp_code, hashed_otp, purpose, contact_method, attempts_made, max_attempts, is_verified, created_at, expires_at, verified_at, ip_address, user_agent, device_id FROM otp_verifications -WHERE id = $1 -` - -func (q *Queries) GetOTPVerificationByID(ctx context.Context, id uuid.UUID) (OtpVerifications, error) { - row := q.db.QueryRow(ctx, getOTPVerificationByID, id) - var i OtpVerifications - err := row.Scan( - &i.ID, - &i.UserID, - &i.OtpCode, - &i.HashedOtp, - &i.Purpose, - &i.ContactMethod, - &i.AttemptsMade, - &i.MaxAttempts, - &i.IsVerified, - &i.CreatedAt, - &i.ExpiresAt, - &i.VerifiedAt, - &i.IpAddress, - &i.UserAgent, - &i.DeviceID, - ) - return i, err -} - -const getOTPVerificationByUserAndPurpose = `-- name: GetOTPVerificationByUserAndPurpose :one -SELECT id, user_id, otp_code, hashed_otp, purpose, contact_method, attempts_made, max_attempts, is_verified, created_at, expires_at, verified_at, ip_address, user_agent, device_id FROM otp_verifications -WHERE user_id = $1 - AND purpose = $2 - AND is_verified = false - AND expires_at > NOW() -ORDER BY created_at DESC -LIMIT 1 -` - -type GetOTPVerificationByUserAndPurposeParams struct { - UserID pgtype.UUID `json:"user_id"` - Purpose OtpPurpose `json:"purpose"` -} - -func (q *Queries) GetOTPVerificationByUserAndPurpose(ctx context.Context, arg GetOTPVerificationByUserAndPurposeParams) (OtpVerifications, error) { - row := q.db.QueryRow(ctx, getOTPVerificationByUserAndPurpose, arg.UserID, arg.Purpose) - var i OtpVerifications - err := row.Scan( - &i.ID, - &i.UserID, - &i.OtpCode, - &i.HashedOtp, - &i.Purpose, - &i.ContactMethod, - &i.AttemptsMade, - &i.MaxAttempts, - &i.IsVerified, - &i.CreatedAt, - &i.ExpiresAt, - &i.VerifiedAt, - &i.IpAddress, - &i.UserAgent, - &i.DeviceID, - ) - return i, err -} - -const getUnverifiedOTPsForUser = `-- name: GetUnverifiedOTPsForUser :many -SELECT id, user_id, otp_code, hashed_otp, purpose, contact_method, attempts_made, max_attempts, is_verified, created_at, expires_at, verified_at, ip_address, user_agent, device_id FROM otp_verifications -WHERE user_id = $1 - AND is_verified = false - AND expires_at > NOW() -ORDER BY created_at DESC -` - -func (q *Queries) GetUnverifiedOTPsForUser(ctx context.Context, userID pgtype.UUID) ([]OtpVerifications, error) { - rows, err := q.db.Query(ctx, getUnverifiedOTPsForUser, userID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []OtpVerifications{} - for rows.Next() { - var i OtpVerifications - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.OtpCode, - &i.HashedOtp, - &i.Purpose, - &i.ContactMethod, - &i.AttemptsMade, - &i.MaxAttempts, - &i.IsVerified, - &i.CreatedAt, - &i.ExpiresAt, - &i.VerifiedAt, - &i.IpAddress, - &i.UserAgent, - &i.DeviceID, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const inValidateOTP = `-- name: InValidateOTP :exec -UPDATE otp_verifications -SET is_verified = false -WHERE id = $1 -` - -func (q *Queries) InValidateOTP(ctx context.Context, id uuid.UUID) error { - _, err := q.db.Exec(ctx, inValidateOTP, id) - return err -} - -const updateOTPAttempts = `-- name: UpdateOTPAttempts :one -UPDATE otp_verifications -SET attempts_made = attempts_made + 1 -WHERE id = $1 -RETURNING id, user_id, otp_code, hashed_otp, purpose, contact_method, attempts_made, max_attempts, is_verified, created_at, expires_at, verified_at, ip_address, user_agent, device_id -` - -func (q *Queries) UpdateOTPAttempts(ctx context.Context, id uuid.UUID) (OtpVerifications, error) { - row := q.db.QueryRow(ctx, updateOTPAttempts, id) - var i OtpVerifications - err := row.Scan( - &i.ID, - &i.UserID, - &i.OtpCode, - &i.HashedOtp, - &i.Purpose, - &i.ContactMethod, - &i.AttemptsMade, - &i.MaxAttempts, - &i.IsVerified, - &i.CreatedAt, - &i.ExpiresAt, - &i.VerifiedAt, - &i.IpAddress, - &i.UserAgent, - &i.DeviceID, - ) - return i, err -} - -const verifyOTP = `-- name: VerifyOTP :one -UPDATE otp_verifications -SET - is_verified = true, - verified_at = NOW() -WHERE id = $1 - AND otp_code = $2 - AND expires_at > NOW() - AND attempts_made <= max_attempts -RETURNING id, user_id, otp_code, hashed_otp, purpose, contact_method, attempts_made, max_attempts, is_verified, created_at, expires_at, verified_at, ip_address, user_agent, device_id -` - -type VerifyOTPParams struct { - ID uuid.UUID `json:"id"` - OtpCode string `json:"otp_code"` -} - -func (q *Queries) VerifyOTP(ctx context.Context, arg VerifyOTPParams) (OtpVerifications, error) { - row := q.db.QueryRow(ctx, verifyOTP, arg.ID, arg.OtpCode) - var i OtpVerifications - err := row.Scan( - &i.ID, - &i.UserID, - &i.OtpCode, - &i.HashedOtp, - &i.Purpose, - &i.ContactMethod, - &i.AttemptsMade, - &i.MaxAttempts, - &i.IsVerified, - &i.CreatedAt, - &i.ExpiresAt, - &i.VerifiedAt, - &i.IpAddress, - &i.UserAgent, - &i.DeviceID, - ) - return i, err -} diff --git a/db/sqlc/payroll.sql.go b/db/sqlc/payroll.sql.go new file mode 100644 index 0000000..5a8d9fd --- /dev/null +++ b/db/sqlc/payroll.sql.go @@ -0,0 +1,1330 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.29.0 +// source: payroll.sql + +package sqlc + +import ( + "context" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" + "github.com/shopspring/decimal" +) + +const createPayroll = `-- name: CreatePayroll :one +INSERT INTO payrolls ( + id, + company_id, + period_id, + name, + description, + total_amount, + base_currency, + status, + execution_type, + scheduled_execution_time, + executed_at, + smart_contract_address, + chain_id, + transaction_hash, + created_by, + approved_by, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + COALESCE($6, 0), + $7, + COALESCE($8, 'draft'), + COALESCE($9, 'manual'), + $10, + $11, + $12, + $13, + $14, + $15, + $16, + COALESCE($17, NOW()), + COALESCE($18, NOW()) +) RETURNING id, company_id, period_id, name, description, total_amount, base_currency, status, execution_type, scheduled_execution_time, executed_at, smart_contract_address, chain_id, transaction_hash, created_by, approved_by, created_at, updated_at +` + +type CreatePayrollParams struct { + ID interface{} `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + PeriodID uuid.UUID `json:"period_id"` + Name string `json:"name"` + Description pgtype.Text `json:"description"` + TotalAmount interface{} `json:"total_amount"` + BaseCurrency string `json:"base_currency"` + Status interface{} `json:"status"` + ExecutionType interface{} `json:"execution_type"` + ScheduledExecutionTime pgtype.Timestamptz `json:"scheduled_execution_time"` + ExecutedAt pgtype.Timestamptz `json:"executed_at"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + CreatedBy uuid.UUID `json:"created_by"` + ApprovedBy pgtype.UUID `json:"approved_by"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreatePayroll(ctx context.Context, arg CreatePayrollParams) (Payrolls, error) { + row := q.db.QueryRow(ctx, createPayroll, + arg.ID, + arg.CompanyID, + arg.PeriodID, + arg.Name, + arg.Description, + arg.TotalAmount, + arg.BaseCurrency, + arg.Status, + arg.ExecutionType, + arg.ScheduledExecutionTime, + arg.ExecutedAt, + arg.SmartContractAddress, + arg.ChainID, + arg.TransactionHash, + arg.CreatedBy, + arg.ApprovedBy, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i Payrolls + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.PeriodID, + &i.Name, + &i.Description, + &i.TotalAmount, + &i.BaseCurrency, + &i.Status, + &i.ExecutionType, + &i.ScheduledExecutionTime, + &i.ExecutedAt, + &i.SmartContractAddress, + &i.ChainID, + &i.TransactionHash, + &i.CreatedBy, + &i.ApprovedBy, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createPayrollItem = `-- name: CreatePayrollItem :one +INSERT INTO payroll_items ( + id, + payroll_id, + employee_id, + base_amount, + base_currency, + payment_amount, + payment_currency, + exchange_rate, + payment_method, + payment_split, + status, + transaction_hash, + recipient_wallet_address, + recipient_bank_account_id, + notes, + timesheet_id, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + $7, + COALESCE($8, 1), + $9, + $10, + COALESCE($11, 'pending'), + $12, + $13, + $14, + $15, + $16, + COALESCE($17, NOW()), + COALESCE($18, NOW()) +) RETURNING id, payroll_id, employee_id, base_amount, base_currency, payment_amount, payment_currency, exchange_rate, payment_method, payment_split, status, transaction_hash, recipient_wallet_address, recipient_bank_account_id, notes, timesheet_id, created_at, updated_at +` + +type CreatePayrollItemParams struct { + ID interface{} `json:"id"` + PayrollID uuid.UUID `json:"payroll_id"` + EmployeeID uuid.UUID `json:"employee_id"` + BaseAmount decimal.Decimal `json:"base_amount"` + BaseCurrency string `json:"base_currency"` + PaymentAmount decimal.Decimal `json:"payment_amount"` + PaymentCurrency string `json:"payment_currency"` + ExchangeRate interface{} `json:"exchange_rate"` + PaymentMethod string `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + Status interface{} `json:"status"` + TransactionHash pgtype.Text `json:"transaction_hash"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + Notes pgtype.Text `json:"notes"` + TimesheetID pgtype.UUID `json:"timesheet_id"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreatePayrollItem(ctx context.Context, arg CreatePayrollItemParams) (PayrollItems, error) { + row := q.db.QueryRow(ctx, createPayrollItem, + arg.ID, + arg.PayrollID, + arg.EmployeeID, + arg.BaseAmount, + arg.BaseCurrency, + arg.PaymentAmount, + arg.PaymentCurrency, + arg.ExchangeRate, + arg.PaymentMethod, + arg.PaymentSplit, + arg.Status, + arg.TransactionHash, + arg.RecipientWalletAddress, + arg.RecipientBankAccountID, + arg.Notes, + arg.TimesheetID, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i PayrollItems + err := row.Scan( + &i.ID, + &i.PayrollID, + &i.EmployeeID, + &i.BaseAmount, + &i.BaseCurrency, + &i.PaymentAmount, + &i.PaymentCurrency, + &i.ExchangeRate, + &i.PaymentMethod, + &i.PaymentSplit, + &i.Status, + &i.TransactionHash, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.Notes, + &i.TimesheetID, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createPayrollPeriod = `-- name: CreatePayrollPeriod :one +INSERT INTO payroll_periods ( + id, + company_id, + period_name, + frequency, + start_date, + end_date, + payment_date, + status, + is_recurring, + next_period_id, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + $7, + COALESCE($8, 'draft'), + COALESCE($9, FALSE), + $10, + COALESCE($11, NOW()), + COALESCE($12, NOW()) +) RETURNING id, company_id, period_name, frequency, start_date, end_date, payment_date, status, is_recurring, next_period_id, created_at, updated_at +` + +type CreatePayrollPeriodParams struct { + ID interface{} `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + PeriodName string `json:"period_name"` + Frequency string `json:"frequency"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` + PaymentDate pgtype.Date `json:"payment_date"` + Status interface{} `json:"status"` + IsRecurring interface{} `json:"is_recurring"` + NextPeriodID pgtype.UUID `json:"next_period_id"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreatePayrollPeriod(ctx context.Context, arg CreatePayrollPeriodParams) (PayrollPeriods, error) { + row := q.db.QueryRow(ctx, createPayrollPeriod, + arg.ID, + arg.CompanyID, + arg.PeriodName, + arg.Frequency, + arg.StartDate, + arg.EndDate, + arg.PaymentDate, + arg.Status, + arg.IsRecurring, + arg.NextPeriodID, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i PayrollPeriods + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.PeriodName, + &i.Frequency, + &i.StartDate, + &i.EndDate, + &i.PaymentDate, + &i.Status, + &i.IsRecurring, + &i.NextPeriodID, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getActivePayrollPeriods = `-- name: GetActivePayrollPeriods :many +SELECT id, company_id, period_name, frequency, start_date, end_date, payment_date, status, is_recurring, next_period_id, created_at, updated_at FROM payroll_periods +WHERE company_id = $1 AND status = 'active' +ORDER BY start_date DESC +` + +func (q *Queries) GetActivePayrollPeriods(ctx context.Context, companyID uuid.UUID) ([]PayrollPeriods, error) { + rows, err := q.db.Query(ctx, getActivePayrollPeriods, companyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []PayrollPeriods{} + for rows.Next() { + var i PayrollPeriods + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.PeriodName, + &i.Frequency, + &i.StartDate, + &i.EndDate, + &i.PaymentDate, + &i.Status, + &i.IsRecurring, + &i.NextPeriodID, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPayrollApprovalQueue = `-- name: GetPayrollApprovalQueue :many +SELECT pi.id, pi.payroll_id, pi.employee_id, pi.base_amount, pi.base_currency, pi.payment_amount, pi.payment_currency, pi.exchange_rate, pi.payment_method, pi.payment_split, pi.status, pi.transaction_hash, pi.recipient_wallet_address, pi.recipient_bank_account_id, pi.notes, pi.timesheet_id, pi.created_at, pi.updated_at, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name, + p.name as payroll_name +FROM payroll_items pi +JOIN company_employees ce ON pi.employee_id = ce.id +JOIN payrolls p ON pi.payroll_id = p.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE p.company_id = $1 AND pi.status = 'pending' +ORDER BY pi.created_at +` + +type GetPayrollApprovalQueueRow struct { + ID uuid.UUID `json:"id"` + PayrollID uuid.UUID `json:"payroll_id"` + EmployeeID uuid.UUID `json:"employee_id"` + BaseAmount decimal.Decimal `json:"base_amount"` + BaseCurrency string `json:"base_currency"` + PaymentAmount decimal.Decimal `json:"payment_amount"` + PaymentCurrency string `json:"payment_currency"` + ExchangeRate pgtype.Numeric `json:"exchange_rate"` + PaymentMethod string `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + Status pgtype.Text `json:"status"` + TransactionHash pgtype.Text `json:"transaction_hash"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + Notes pgtype.Text `json:"notes"` + TimesheetID pgtype.UUID `json:"timesheet_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + EmployeeID_2 pgtype.Text `json:"employee_id_2"` + Position pgtype.Text `json:"position"` + Email pgtype.Text `json:"email"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` + PayrollName string `json:"payroll_name"` +} + +func (q *Queries) GetPayrollApprovalQueue(ctx context.Context, companyID uuid.UUID) ([]GetPayrollApprovalQueueRow, error) { + rows, err := q.db.Query(ctx, getPayrollApprovalQueue, companyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetPayrollApprovalQueueRow{} + for rows.Next() { + var i GetPayrollApprovalQueueRow + if err := rows.Scan( + &i.ID, + &i.PayrollID, + &i.EmployeeID, + &i.BaseAmount, + &i.BaseCurrency, + &i.PaymentAmount, + &i.PaymentCurrency, + &i.ExchangeRate, + &i.PaymentMethod, + &i.PaymentSplit, + &i.Status, + &i.TransactionHash, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.Notes, + &i.TimesheetID, + &i.CreatedAt, + &i.UpdatedAt, + &i.EmployeeID_2, + &i.Position, + &i.Email, + &i.FirstName, + &i.LastName, + &i.PayrollName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPayrollByID = `-- name: GetPayrollByID :one +SELECT p.id, p.company_id, p.period_id, p.name, p.description, p.total_amount, p.base_currency, p.status, p.execution_type, p.scheduled_execution_time, p.executed_at, p.smart_contract_address, p.chain_id, p.transaction_hash, p.created_by, p.approved_by, p.created_at, p.updated_at, pp.period_name, pp.start_date, pp.end_date +FROM payrolls p +JOIN payroll_periods pp ON p.period_id = pp.id +WHERE p.id = $1 +` + +type GetPayrollByIDRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + PeriodID uuid.UUID `json:"period_id"` + Name string `json:"name"` + Description pgtype.Text `json:"description"` + TotalAmount pgtype.Numeric `json:"total_amount"` + BaseCurrency string `json:"base_currency"` + Status pgtype.Text `json:"status"` + ExecutionType pgtype.Text `json:"execution_type"` + ScheduledExecutionTime pgtype.Timestamptz `json:"scheduled_execution_time"` + ExecutedAt pgtype.Timestamptz `json:"executed_at"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + CreatedBy uuid.UUID `json:"created_by"` + ApprovedBy pgtype.UUID `json:"approved_by"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + PeriodName string `json:"period_name"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` +} + +func (q *Queries) GetPayrollByID(ctx context.Context, id uuid.UUID) (GetPayrollByIDRow, error) { + row := q.db.QueryRow(ctx, getPayrollByID, id) + var i GetPayrollByIDRow + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.PeriodID, + &i.Name, + &i.Description, + &i.TotalAmount, + &i.BaseCurrency, + &i.Status, + &i.ExecutionType, + &i.ScheduledExecutionTime, + &i.ExecutedAt, + &i.SmartContractAddress, + &i.ChainID, + &i.TransactionHash, + &i.CreatedBy, + &i.ApprovedBy, + &i.CreatedAt, + &i.UpdatedAt, + &i.PeriodName, + &i.StartDate, + &i.EndDate, + ) + return i, err +} + +const getPayrollItemByID = `-- name: GetPayrollItemByID :one +SELECT pi.id, pi.payroll_id, pi.employee_id, pi.base_amount, pi.base_currency, pi.payment_amount, pi.payment_currency, pi.exchange_rate, pi.payment_method, pi.payment_split, pi.status, pi.transaction_hash, pi.recipient_wallet_address, pi.recipient_bank_account_id, pi.notes, pi.timesheet_id, pi.created_at, pi.updated_at, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM payroll_items pi +JOIN company_employees ce ON pi.employee_id = ce.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE pi.id = $1 +` + +type GetPayrollItemByIDRow struct { + ID uuid.UUID `json:"id"` + PayrollID uuid.UUID `json:"payroll_id"` + EmployeeID uuid.UUID `json:"employee_id"` + BaseAmount decimal.Decimal `json:"base_amount"` + BaseCurrency string `json:"base_currency"` + PaymentAmount decimal.Decimal `json:"payment_amount"` + PaymentCurrency string `json:"payment_currency"` + ExchangeRate pgtype.Numeric `json:"exchange_rate"` + PaymentMethod string `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + Status pgtype.Text `json:"status"` + TransactionHash pgtype.Text `json:"transaction_hash"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + Notes pgtype.Text `json:"notes"` + TimesheetID pgtype.UUID `json:"timesheet_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + EmployeeID_2 pgtype.Text `json:"employee_id_2"` + Position pgtype.Text `json:"position"` + Email pgtype.Text `json:"email"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` +} + +func (q *Queries) GetPayrollItemByID(ctx context.Context, id uuid.UUID) (GetPayrollItemByIDRow, error) { + row := q.db.QueryRow(ctx, getPayrollItemByID, id) + var i GetPayrollItemByIDRow + err := row.Scan( + &i.ID, + &i.PayrollID, + &i.EmployeeID, + &i.BaseAmount, + &i.BaseCurrency, + &i.PaymentAmount, + &i.PaymentCurrency, + &i.ExchangeRate, + &i.PaymentMethod, + &i.PaymentSplit, + &i.Status, + &i.TransactionHash, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.Notes, + &i.TimesheetID, + &i.CreatedAt, + &i.UpdatedAt, + &i.EmployeeID_2, + &i.Position, + &i.Email, + &i.FirstName, + &i.LastName, + ) + return i, err +} + +const getPayrollItemsByEmployee = `-- name: GetPayrollItemsByEmployee :many +SELECT pi.id, pi.payroll_id, pi.employee_id, pi.base_amount, pi.base_currency, pi.payment_amount, pi.payment_currency, pi.exchange_rate, pi.payment_method, pi.payment_split, pi.status, pi.transaction_hash, pi.recipient_wallet_address, pi.recipient_bank_account_id, pi.notes, pi.timesheet_id, pi.created_at, pi.updated_at, p.name as payroll_name, pp.period_name +FROM payroll_items pi +JOIN payrolls p ON pi.payroll_id = p.id +JOIN payroll_periods pp ON p.period_id = pp.id +WHERE pi.employee_id = $1 +ORDER BY pi.created_at DESC +` + +type GetPayrollItemsByEmployeeRow struct { + ID uuid.UUID `json:"id"` + PayrollID uuid.UUID `json:"payroll_id"` + EmployeeID uuid.UUID `json:"employee_id"` + BaseAmount decimal.Decimal `json:"base_amount"` + BaseCurrency string `json:"base_currency"` + PaymentAmount decimal.Decimal `json:"payment_amount"` + PaymentCurrency string `json:"payment_currency"` + ExchangeRate pgtype.Numeric `json:"exchange_rate"` + PaymentMethod string `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + Status pgtype.Text `json:"status"` + TransactionHash pgtype.Text `json:"transaction_hash"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + Notes pgtype.Text `json:"notes"` + TimesheetID pgtype.UUID `json:"timesheet_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + PayrollName string `json:"payroll_name"` + PeriodName string `json:"period_name"` +} + +func (q *Queries) GetPayrollItemsByEmployee(ctx context.Context, employeeID uuid.UUID) ([]GetPayrollItemsByEmployeeRow, error) { + rows, err := q.db.Query(ctx, getPayrollItemsByEmployee, employeeID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetPayrollItemsByEmployeeRow{} + for rows.Next() { + var i GetPayrollItemsByEmployeeRow + if err := rows.Scan( + &i.ID, + &i.PayrollID, + &i.EmployeeID, + &i.BaseAmount, + &i.BaseCurrency, + &i.PaymentAmount, + &i.PaymentCurrency, + &i.ExchangeRate, + &i.PaymentMethod, + &i.PaymentSplit, + &i.Status, + &i.TransactionHash, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.Notes, + &i.TimesheetID, + &i.CreatedAt, + &i.UpdatedAt, + &i.PayrollName, + &i.PeriodName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPayrollItemsByPayroll = `-- name: GetPayrollItemsByPayroll :many +SELECT pi.id, pi.payroll_id, pi.employee_id, pi.base_amount, pi.base_currency, pi.payment_amount, pi.payment_currency, pi.exchange_rate, pi.payment_method, pi.payment_split, pi.status, pi.transaction_hash, pi.recipient_wallet_address, pi.recipient_bank_account_id, pi.notes, pi.timesheet_id, pi.created_at, pi.updated_at, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name +FROM payroll_items pi +JOIN company_employees ce ON pi.employee_id = ce.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE pi.payroll_id = $1 +ORDER BY pi.created_at +` + +type GetPayrollItemsByPayrollRow struct { + ID uuid.UUID `json:"id"` + PayrollID uuid.UUID `json:"payroll_id"` + EmployeeID uuid.UUID `json:"employee_id"` + BaseAmount decimal.Decimal `json:"base_amount"` + BaseCurrency string `json:"base_currency"` + PaymentAmount decimal.Decimal `json:"payment_amount"` + PaymentCurrency string `json:"payment_currency"` + ExchangeRate pgtype.Numeric `json:"exchange_rate"` + PaymentMethod string `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + Status pgtype.Text `json:"status"` + TransactionHash pgtype.Text `json:"transaction_hash"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + Notes pgtype.Text `json:"notes"` + TimesheetID pgtype.UUID `json:"timesheet_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + EmployeeID_2 pgtype.Text `json:"employee_id_2"` + Position pgtype.Text `json:"position"` + Email pgtype.Text `json:"email"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` +} + +func (q *Queries) GetPayrollItemsByPayroll(ctx context.Context, payrollID uuid.UUID) ([]GetPayrollItemsByPayrollRow, error) { + rows, err := q.db.Query(ctx, getPayrollItemsByPayroll, payrollID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetPayrollItemsByPayrollRow{} + for rows.Next() { + var i GetPayrollItemsByPayrollRow + if err := rows.Scan( + &i.ID, + &i.PayrollID, + &i.EmployeeID, + &i.BaseAmount, + &i.BaseCurrency, + &i.PaymentAmount, + &i.PaymentCurrency, + &i.ExchangeRate, + &i.PaymentMethod, + &i.PaymentSplit, + &i.Status, + &i.TransactionHash, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.Notes, + &i.TimesheetID, + &i.CreatedAt, + &i.UpdatedAt, + &i.EmployeeID_2, + &i.Position, + &i.Email, + &i.FirstName, + &i.LastName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPayrollPeriodByID = `-- name: GetPayrollPeriodByID :one +SELECT id, company_id, period_name, frequency, start_date, end_date, payment_date, status, is_recurring, next_period_id, created_at, updated_at FROM payroll_periods WHERE id = $1 +` + +func (q *Queries) GetPayrollPeriodByID(ctx context.Context, id uuid.UUID) (PayrollPeriods, error) { + row := q.db.QueryRow(ctx, getPayrollPeriodByID, id) + var i PayrollPeriods + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.PeriodName, + &i.Frequency, + &i.StartDate, + &i.EndDate, + &i.PaymentDate, + &i.Status, + &i.IsRecurring, + &i.NextPeriodID, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getPayrollPeriodsByCompany = `-- name: GetPayrollPeriodsByCompany :many +SELECT id, company_id, period_name, frequency, start_date, end_date, payment_date, status, is_recurring, next_period_id, created_at, updated_at FROM payroll_periods +WHERE company_id = $1 +ORDER BY start_date DESC +` + +func (q *Queries) GetPayrollPeriodsByCompany(ctx context.Context, companyID uuid.UUID) ([]PayrollPeriods, error) { + rows, err := q.db.Query(ctx, getPayrollPeriodsByCompany, companyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []PayrollPeriods{} + for rows.Next() { + var i PayrollPeriods + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.PeriodName, + &i.Frequency, + &i.StartDate, + &i.EndDate, + &i.PaymentDate, + &i.Status, + &i.IsRecurring, + &i.NextPeriodID, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPayrollsByCompany = `-- name: GetPayrollsByCompany :many +SELECT p.id, p.company_id, p.period_id, p.name, p.description, p.total_amount, p.base_currency, p.status, p.execution_type, p.scheduled_execution_time, p.executed_at, p.smart_contract_address, p.chain_id, p.transaction_hash, p.created_by, p.approved_by, p.created_at, p.updated_at, pp.period_name, pp.start_date, pp.end_date +FROM payrolls p +JOIN payroll_periods pp ON p.period_id = pp.id +WHERE p.company_id = $1 +ORDER BY p.created_at DESC +` + +type GetPayrollsByCompanyRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + PeriodID uuid.UUID `json:"period_id"` + Name string `json:"name"` + Description pgtype.Text `json:"description"` + TotalAmount pgtype.Numeric `json:"total_amount"` + BaseCurrency string `json:"base_currency"` + Status pgtype.Text `json:"status"` + ExecutionType pgtype.Text `json:"execution_type"` + ScheduledExecutionTime pgtype.Timestamptz `json:"scheduled_execution_time"` + ExecutedAt pgtype.Timestamptz `json:"executed_at"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + CreatedBy uuid.UUID `json:"created_by"` + ApprovedBy pgtype.UUID `json:"approved_by"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + PeriodName string `json:"period_name"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` +} + +func (q *Queries) GetPayrollsByCompany(ctx context.Context, companyID uuid.UUID) ([]GetPayrollsByCompanyRow, error) { + rows, err := q.db.Query(ctx, getPayrollsByCompany, companyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetPayrollsByCompanyRow{} + for rows.Next() { + var i GetPayrollsByCompanyRow + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.PeriodID, + &i.Name, + &i.Description, + &i.TotalAmount, + &i.BaseCurrency, + &i.Status, + &i.ExecutionType, + &i.ScheduledExecutionTime, + &i.ExecutedAt, + &i.SmartContractAddress, + &i.ChainID, + &i.TransactionHash, + &i.CreatedBy, + &i.ApprovedBy, + &i.CreatedAt, + &i.UpdatedAt, + &i.PeriodName, + &i.StartDate, + &i.EndDate, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getPayrollsByStatus = `-- name: GetPayrollsByStatus :many +SELECT p.id, p.company_id, p.period_id, p.name, p.description, p.total_amount, p.base_currency, p.status, p.execution_type, p.scheduled_execution_time, p.executed_at, p.smart_contract_address, p.chain_id, p.transaction_hash, p.created_by, p.approved_by, p.created_at, p.updated_at, pp.period_name, pp.start_date, pp.end_date +FROM payrolls p +JOIN payroll_periods pp ON p.period_id = pp.id +WHERE p.company_id = $1 AND p.status = $2 +ORDER BY p.created_at DESC +` + +type GetPayrollsByStatusParams struct { + CompanyID uuid.UUID `json:"company_id"` + Status pgtype.Text `json:"status"` +} + +type GetPayrollsByStatusRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + PeriodID uuid.UUID `json:"period_id"` + Name string `json:"name"` + Description pgtype.Text `json:"description"` + TotalAmount pgtype.Numeric `json:"total_amount"` + BaseCurrency string `json:"base_currency"` + Status pgtype.Text `json:"status"` + ExecutionType pgtype.Text `json:"execution_type"` + ScheduledExecutionTime pgtype.Timestamptz `json:"scheduled_execution_time"` + ExecutedAt pgtype.Timestamptz `json:"executed_at"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + CreatedBy uuid.UUID `json:"created_by"` + ApprovedBy pgtype.UUID `json:"approved_by"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + PeriodName string `json:"period_name"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` +} + +func (q *Queries) GetPayrollsByStatus(ctx context.Context, arg GetPayrollsByStatusParams) ([]GetPayrollsByStatusRow, error) { + rows, err := q.db.Query(ctx, getPayrollsByStatus, arg.CompanyID, arg.Status) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetPayrollsByStatusRow{} + for rows.Next() { + var i GetPayrollsByStatusRow + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.PeriodID, + &i.Name, + &i.Description, + &i.TotalAmount, + &i.BaseCurrency, + &i.Status, + &i.ExecutionType, + &i.ScheduledExecutionTime, + &i.ExecutedAt, + &i.SmartContractAddress, + &i.ChainID, + &i.TransactionHash, + &i.CreatedBy, + &i.ApprovedBy, + &i.CreatedAt, + &i.UpdatedAt, + &i.PeriodName, + &i.StartDate, + &i.EndDate, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUpcomingPayments = `-- name: GetUpcomingPayments :many +SELECT pi.id, pi.payroll_id, pi.employee_id, pi.base_amount, pi.base_currency, pi.payment_amount, pi.payment_currency, pi.exchange_rate, pi.payment_method, pi.payment_split, pi.status, pi.transaction_hash, pi.recipient_wallet_address, pi.recipient_bank_account_id, pi.notes, pi.timesheet_id, pi.created_at, pi.updated_at, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name, + p.name as payroll_name, + pp.payment_date +FROM payroll_items pi +JOIN company_employees ce ON pi.employee_id = ce.id +JOIN payrolls p ON pi.payroll_id = p.id +JOIN payroll_periods pp ON p.period_id = pp.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +WHERE ce.user_id = $1 + AND pi.status IN ('approved', 'processing') + AND pp.payment_date >= CURRENT_DATE +ORDER BY pp.payment_date +` + +type GetUpcomingPaymentsRow struct { + ID uuid.UUID `json:"id"` + PayrollID uuid.UUID `json:"payroll_id"` + EmployeeID uuid.UUID `json:"employee_id"` + BaseAmount decimal.Decimal `json:"base_amount"` + BaseCurrency string `json:"base_currency"` + PaymentAmount decimal.Decimal `json:"payment_amount"` + PaymentCurrency string `json:"payment_currency"` + ExchangeRate pgtype.Numeric `json:"exchange_rate"` + PaymentMethod string `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + Status pgtype.Text `json:"status"` + TransactionHash pgtype.Text `json:"transaction_hash"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + Notes pgtype.Text `json:"notes"` + TimesheetID pgtype.UUID `json:"timesheet_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + EmployeeID_2 pgtype.Text `json:"employee_id_2"` + Position pgtype.Text `json:"position"` + Email pgtype.Text `json:"email"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` + PayrollName string `json:"payroll_name"` + PaymentDate pgtype.Date `json:"payment_date"` +} + +func (q *Queries) GetUpcomingPayments(ctx context.Context, userID pgtype.UUID) ([]GetUpcomingPaymentsRow, error) { + rows, err := q.db.Query(ctx, getUpcomingPayments, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetUpcomingPaymentsRow{} + for rows.Next() { + var i GetUpcomingPaymentsRow + if err := rows.Scan( + &i.ID, + &i.PayrollID, + &i.EmployeeID, + &i.BaseAmount, + &i.BaseCurrency, + &i.PaymentAmount, + &i.PaymentCurrency, + &i.ExchangeRate, + &i.PaymentMethod, + &i.PaymentSplit, + &i.Status, + &i.TransactionHash, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.Notes, + &i.TimesheetID, + &i.CreatedAt, + &i.UpdatedAt, + &i.EmployeeID_2, + &i.Position, + &i.Email, + &i.FirstName, + &i.LastName, + &i.PayrollName, + &i.PaymentDate, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserPayrollHistory = `-- name: GetUserPayrollHistory :many +SELECT pi.id, pi.payroll_id, pi.employee_id, pi.base_amount, pi.base_currency, pi.payment_amount, pi.payment_currency, pi.exchange_rate, pi.payment_method, pi.payment_split, pi.status, pi.transaction_hash, pi.recipient_wallet_address, pi.recipient_bank_account_id, pi.notes, pi.timesheet_id, pi.created_at, pi.updated_at, p.name as payroll_name, pp.period_name, c.company_name +FROM payroll_items pi +JOIN payrolls p ON pi.payroll_id = p.id +JOIN payroll_periods pp ON p.period_id = pp.id +JOIN companies c ON p.company_id = c.id +JOIN company_employees ce ON pi.employee_id = ce.id +WHERE ce.user_id = $1 +ORDER BY pi.created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetUserPayrollHistoryParams struct { + UserID pgtype.UUID `json:"user_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetUserPayrollHistoryRow struct { + ID uuid.UUID `json:"id"` + PayrollID uuid.UUID `json:"payroll_id"` + EmployeeID uuid.UUID `json:"employee_id"` + BaseAmount decimal.Decimal `json:"base_amount"` + BaseCurrency string `json:"base_currency"` + PaymentAmount decimal.Decimal `json:"payment_amount"` + PaymentCurrency string `json:"payment_currency"` + ExchangeRate pgtype.Numeric `json:"exchange_rate"` + PaymentMethod string `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + Status pgtype.Text `json:"status"` + TransactionHash pgtype.Text `json:"transaction_hash"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + Notes pgtype.Text `json:"notes"` + TimesheetID pgtype.UUID `json:"timesheet_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + PayrollName string `json:"payroll_name"` + PeriodName string `json:"period_name"` + CompanyName string `json:"company_name"` +} + +func (q *Queries) GetUserPayrollHistory(ctx context.Context, arg GetUserPayrollHistoryParams) ([]GetUserPayrollHistoryRow, error) { + rows, err := q.db.Query(ctx, getUserPayrollHistory, arg.UserID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetUserPayrollHistoryRow{} + for rows.Next() { + var i GetUserPayrollHistoryRow + if err := rows.Scan( + &i.ID, + &i.PayrollID, + &i.EmployeeID, + &i.BaseAmount, + &i.BaseCurrency, + &i.PaymentAmount, + &i.PaymentCurrency, + &i.ExchangeRate, + &i.PaymentMethod, + &i.PaymentSplit, + &i.Status, + &i.TransactionHash, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.Notes, + &i.TimesheetID, + &i.CreatedAt, + &i.UpdatedAt, + &i.PayrollName, + &i.PeriodName, + &i.CompanyName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updatePayroll = `-- name: UpdatePayroll :one +UPDATE payrolls SET + name = COALESCE($1, name), + description = COALESCE($2, description), + total_amount = COALESCE($3, total_amount), + base_currency = COALESCE($4, base_currency), + status = COALESCE($5, status), + execution_type = COALESCE($6, execution_type), + scheduled_execution_time = COALESCE($7, scheduled_execution_time), + executed_at = COALESCE($8, executed_at), + smart_contract_address = COALESCE($9, smart_contract_address), + chain_id = COALESCE($10, chain_id), + transaction_hash = COALESCE($11, transaction_hash), + approved_by = COALESCE($12, approved_by), + updated_at = NOW() +WHERE id = $13 +RETURNING id, company_id, period_id, name, description, total_amount, base_currency, status, execution_type, scheduled_execution_time, executed_at, smart_contract_address, chain_id, transaction_hash, created_by, approved_by, created_at, updated_at +` + +type UpdatePayrollParams struct { + Name string `json:"name"` + Description pgtype.Text `json:"description"` + TotalAmount pgtype.Numeric `json:"total_amount"` + BaseCurrency string `json:"base_currency"` + Status pgtype.Text `json:"status"` + ExecutionType pgtype.Text `json:"execution_type"` + ScheduledExecutionTime pgtype.Timestamptz `json:"scheduled_execution_time"` + ExecutedAt pgtype.Timestamptz `json:"executed_at"` + SmartContractAddress pgtype.Text `json:"smart_contract_address"` + ChainID pgtype.Int4 `json:"chain_id"` + TransactionHash pgtype.Text `json:"transaction_hash"` + ApprovedBy pgtype.UUID `json:"approved_by"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdatePayroll(ctx context.Context, arg UpdatePayrollParams) (Payrolls, error) { + row := q.db.QueryRow(ctx, updatePayroll, + arg.Name, + arg.Description, + arg.TotalAmount, + arg.BaseCurrency, + arg.Status, + arg.ExecutionType, + arg.ScheduledExecutionTime, + arg.ExecutedAt, + arg.SmartContractAddress, + arg.ChainID, + arg.TransactionHash, + arg.ApprovedBy, + arg.ID, + ) + var i Payrolls + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.PeriodID, + &i.Name, + &i.Description, + &i.TotalAmount, + &i.BaseCurrency, + &i.Status, + &i.ExecutionType, + &i.ScheduledExecutionTime, + &i.ExecutedAt, + &i.SmartContractAddress, + &i.ChainID, + &i.TransactionHash, + &i.CreatedBy, + &i.ApprovedBy, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updatePayrollItem = `-- name: UpdatePayrollItem :one +UPDATE payroll_items SET + base_amount = COALESCE($1, base_amount), + base_currency = COALESCE($2, base_currency), + payment_amount = COALESCE($3, payment_amount), + payment_currency = COALESCE($4, payment_currency), + exchange_rate = COALESCE($5, exchange_rate), + payment_method = COALESCE($6, payment_method), + payment_split = COALESCE($7, payment_split), + status = COALESCE($8, status), + transaction_hash = COALESCE($9, transaction_hash), + recipient_wallet_address = COALESCE($10, recipient_wallet_address), + recipient_bank_account_id = COALESCE($11, recipient_bank_account_id), + notes = COALESCE($12, notes), + timesheet_id = COALESCE($13, timesheet_id), + updated_at = NOW() +WHERE id = $14 +RETURNING id, payroll_id, employee_id, base_amount, base_currency, payment_amount, payment_currency, exchange_rate, payment_method, payment_split, status, transaction_hash, recipient_wallet_address, recipient_bank_account_id, notes, timesheet_id, created_at, updated_at +` + +type UpdatePayrollItemParams struct { + BaseAmount decimal.Decimal `json:"base_amount"` + BaseCurrency string `json:"base_currency"` + PaymentAmount decimal.Decimal `json:"payment_amount"` + PaymentCurrency string `json:"payment_currency"` + ExchangeRate pgtype.Numeric `json:"exchange_rate"` + PaymentMethod string `json:"payment_method"` + PaymentSplit []byte `json:"payment_split"` + Status pgtype.Text `json:"status"` + TransactionHash pgtype.Text `json:"transaction_hash"` + RecipientWalletAddress pgtype.Text `json:"recipient_wallet_address"` + RecipientBankAccountID pgtype.UUID `json:"recipient_bank_account_id"` + Notes pgtype.Text `json:"notes"` + TimesheetID pgtype.UUID `json:"timesheet_id"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdatePayrollItem(ctx context.Context, arg UpdatePayrollItemParams) (PayrollItems, error) { + row := q.db.QueryRow(ctx, updatePayrollItem, + arg.BaseAmount, + arg.BaseCurrency, + arg.PaymentAmount, + arg.PaymentCurrency, + arg.ExchangeRate, + arg.PaymentMethod, + arg.PaymentSplit, + arg.Status, + arg.TransactionHash, + arg.RecipientWalletAddress, + arg.RecipientBankAccountID, + arg.Notes, + arg.TimesheetID, + arg.ID, + ) + var i PayrollItems + err := row.Scan( + &i.ID, + &i.PayrollID, + &i.EmployeeID, + &i.BaseAmount, + &i.BaseCurrency, + &i.PaymentAmount, + &i.PaymentCurrency, + &i.ExchangeRate, + &i.PaymentMethod, + &i.PaymentSplit, + &i.Status, + &i.TransactionHash, + &i.RecipientWalletAddress, + &i.RecipientBankAccountID, + &i.Notes, + &i.TimesheetID, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updatePayrollPeriod = `-- name: UpdatePayrollPeriod :one +UPDATE payroll_periods SET + period_name = COALESCE($1, period_name), + frequency = COALESCE($2, frequency), + start_date = COALESCE($3, start_date), + end_date = COALESCE($4, end_date), + payment_date = COALESCE($5, payment_date), + status = COALESCE($6, status), + is_recurring = COALESCE($7, is_recurring), + next_period_id = COALESCE($8, next_period_id), + updated_at = NOW() +WHERE id = $9 +RETURNING id, company_id, period_name, frequency, start_date, end_date, payment_date, status, is_recurring, next_period_id, created_at, updated_at +` + +type UpdatePayrollPeriodParams struct { + PeriodName string `json:"period_name"` + Frequency string `json:"frequency"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` + PaymentDate pgtype.Date `json:"payment_date"` + Status pgtype.Text `json:"status"` + IsRecurring pgtype.Bool `json:"is_recurring"` + NextPeriodID pgtype.UUID `json:"next_period_id"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdatePayrollPeriod(ctx context.Context, arg UpdatePayrollPeriodParams) (PayrollPeriods, error) { + row := q.db.QueryRow(ctx, updatePayrollPeriod, + arg.PeriodName, + arg.Frequency, + arg.StartDate, + arg.EndDate, + arg.PaymentDate, + arg.Status, + arg.IsRecurring, + arg.NextPeriodID, + arg.ID, + ) + var i PayrollPeriods + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.PeriodName, + &i.Frequency, + &i.StartDate, + &i.EndDate, + &i.PaymentDate, + &i.Status, + &i.IsRecurring, + &i.NextPeriodID, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/db/sqlc/querier.go b/db/sqlc/querier.go index 6daf17a..2d557f2 100644 --- a/db/sqlc/querier.go +++ b/db/sqlc/querier.go @@ -1,160 +1,5 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.29.0 +// Code generated by MockGen. DO NOT EDIT. +// Source: db/sqlc/querier.go +// Package sqlc is a generated GoMock package. package sqlc - -import ( - "context" - - "github.com/google/uuid" - "github.com/jackc/pgx/v5/pgtype" -) - -type Querier interface { - // Blocks all sessions for a specific user - BlockAllUserSessions(ctx context.Context, userID uuid.UUID) error - // Blocks all expired sessions - BlockExpiredSessions(ctx context.Context) error - // Blocks a session (marks it as invalid) - BlockSession(ctx context.Context, id uuid.UUID) error - CheckEmailExists(ctx context.Context, email string) (bool, error) - CountActiveDeviceTokensForUser(ctx context.Context, userID uuid.UUID) (int64, error) - CountActiveOTPsForUser(ctx context.Context, arg CountActiveOTPsForUserParams) (int64, error) - // Counts the number of active sessions - CountActiveSessions(ctx context.Context) (int64, error) - // Counts the number of active sessions for a specific user - CountActiveSessionsByUserID(ctx context.Context, userID uuid.UUID) (int64, error) - // Counts the number of users matching a search query - CountSearchUsers(ctx context.Context, dollar_1 pgtype.Text) (int64, error) - // Counts the number of waitlist entries matching a search query - CountSearchWaitlist(ctx context.Context, dollar_1 pgtype.Text) (int64, error) - // Counts the total number of users (useful for pagination) - CountUsers(ctx context.Context) (int64, error) - // Counts users filtered by account type - CountUsersByAccountType(ctx context.Context, accountType string) (int64, error) - // Counts the total number of waitlist entries matching filters - CountWaitlistEntries(ctx context.Context, arg CountWaitlistEntriesParams) (int64, error) - CreateOTPVerification(ctx context.Context, arg CreateOTPVerificationParams) (OtpVerifications, error) - CreateSecurityEvent(ctx context.Context, arg CreateSecurityEventParams) (SecurityEvents, error) - // Creates a new session and returns the created session record - CreateSession(ctx context.Context, arg CreateSessionParams) (Sessions, error) - // Creates a new user record and returns the created user - CreateUser(ctx context.Context, arg CreateUserParams) (Users, error) - CreateUserDeviceToken(ctx context.Context, arg CreateUserDeviceTokenParams) (UserDeviceTokens, error) - CreateUserWallet(ctx context.Context, arg CreateUserWalletParams) (UserWallets, error) - // Creates a new waitlist entry and returns the created entry - CreateWaitlistEntry(ctx context.Context, arg CreateWaitlistEntryParams) (Waitlist, error) - DeleteExpiredDeviceTokens(ctx context.Context) error - DeleteExpiredOTPs(ctx context.Context) error - // Cleans up expired sessions that are older than the specified date - DeleteExpiredSessions(ctx context.Context, expiresAt pgtype.Timestamp) error - // Deletes a session by its ID - DeleteSession(ctx context.Context, id uuid.UUID) error - // Deletes all sessions for a specific user - DeleteSessionsByUserID(ctx context.Context, userID uuid.UUID) error - // Permanently deletes a transaction record - DeleteTransaction(ctx context.Context, id uuid.UUID) error - // Deletes all transactions for a specific user - DeleteTransactionsByUserID(ctx context.Context, userID uuid.UUID) error - // Permanently deletes a user record - DeleteUser(ctx context.Context, id uuid.UUID) error - DeleteUserWallet(ctx context.Context, id uuid.UUID) error - // Permanently deletes a waitlist entry - DeleteWaitlistEntry(ctx context.Context, id uuid.UUID) error - // Retrieves all waitlist entries for export - ExportWaitlistEntries(ctx context.Context) ([]Waitlist, error) - GetActiveDeviceTokensForUser(ctx context.Context, userID uuid.UUID) ([]UserDeviceTokens, error) - // Retrieves active (non-expired, non-blocked) sessions with pagination - GetActiveSessions(ctx context.Context, arg GetActiveSessionsParams) ([]Sessions, error) - // Retrieves active sessions for a specific user - GetActiveSessionsByUserID(ctx context.Context, userID uuid.UUID) ([]Sessions, error) - GetDeviceTokensByPlatform(ctx context.Context, arg GetDeviceTokensByPlatformParams) ([]UserDeviceTokens, error) - GetOTPVerificationByID(ctx context.Context, id uuid.UUID) (OtpVerifications, error) - GetOTPVerificationByUserAndPurpose(ctx context.Context, arg GetOTPVerificationByUserAndPurposeParams) (OtpVerifications, error) - GetRecentLoginEventsByUserID(ctx context.Context, arg GetRecentLoginEventsByUserIDParams) ([]SecurityEvents, error) - GetSecurityEventsByUserIDAndType(ctx context.Context, arg GetSecurityEventsByUserIDAndTypeParams) ([]SecurityEvents, error) - // Retrieves a session by its ID - GetSessionByID(ctx context.Context, id uuid.UUID) (Sessions, error) - // Retrieves a session by refresh token - GetSessionByRefreshToken(ctx context.Context, refreshToken string) (Sessions, error) - // Retrieves all sessions for a specific user - GetSessionsByUserID(ctx context.Context, userID uuid.UUID) ([]Sessions, error) - // Retrieves a single transaction by its ID - GetTransactionByID(ctx context.Context, id uuid.UUID) (Transactions, error) - // Retrieves a single transaction by its transaction hash - GetTransactionByTxHash(ctx context.Context, txHash string) (Transactions, error) - // Retrieves transactions by status - GetTransactionsByStatus(ctx context.Context, arg GetTransactionsByStatusParams) ([]Transactions, error) - // Retrieves all transactions for a specific user - GetTransactionsByUserID(ctx context.Context, userID uuid.UUID) ([]Transactions, error) - // Retrieves transactions for a specific user with a specific status - GetTransactionsByUserIDAndStatus(ctx context.Context, arg GetTransactionsByUserIDAndStatusParams) ([]Transactions, error) - GetUnverifiedOTPsForUser(ctx context.Context, userID pgtype.UUID) ([]OtpVerifications, error) - GetUser(ctx context.Context, dollar_1 uuid.UUID) (Users, error) - // Retrieves a single user by their email address - GetUserByEmail(ctx context.Context, email string) (Users, error) - GetUserDeviceTokenByDeviceToken(ctx context.Context, deviceToken string) (UserDeviceTokens, error) - GetUserDeviceTokenByID(ctx context.Context, id uuid.UUID) (UserDeviceTokens, error) - // Retrieves a single waitlist entry by email address - GetWaitlistEntryByEmail(ctx context.Context, email string) (Waitlist, error) - // Retrieves a single waitlist entry by ID - GetWaitlistEntryByID(ctx context.Context, id uuid.UUID) (Waitlist, error) - // Retrieves a single waitlist entry by referral code - GetWaitlistEntryByReferralCode(ctx context.Context, referralCode string) (Waitlist, error) - // Gets the position of an entry in the waitlist (by signup date) - GetWaitlistPosition(ctx context.Context, id uuid.UUID) (int64, error) - // Gets waitlist statistics grouped by referral source - GetWaitlistStatsBySource(ctx context.Context) ([]GetWaitlistStatsBySourceRow, error) - // Gets waitlist statistics grouped by status - GetWaitlistStatsByStatus(ctx context.Context) ([]GetWaitlistStatsByStatusRow, error) - GetWalletByAddress(ctx context.Context, address string) (UserWallets, error) - GetWalletsByUserID(ctx context.Context, userID uuid.UUID) ([]UserWallets, error) - InValidateOTP(ctx context.Context, id uuid.UUID) error - // Lists users with pagination support - ListUsers(ctx context.Context, arg ListUsersParams) ([]Users, error) - // Lists users filtered by account type with pagination - ListUsersByAccountType(ctx context.Context, arg ListUsersByAccountTypeParams) ([]Users, error) - // Lists waitlist entries with pagination and filtering support - ListWaitlistEntries(ctx context.Context, arg ListWaitlistEntriesParams) ([]Waitlist, error) - RevokeDeviceToken(ctx context.Context, id uuid.UUID) (UserDeviceTokens, error) - SearchDeviceTokens(ctx context.Context, arg SearchDeviceTokensParams) ([]UserDeviceTokens, error) - // Searches for users by name, email, or nationality with pagination - SearchUsers(ctx context.Context, arg SearchUsersParams) ([]Users, error) - // Searches for waitlist entries by email or name with pagination - SearchWaitlist(ctx context.Context, arg SearchWaitlistParams) ([]Waitlist, error) - UpdateDeviceTokenDetails(ctx context.Context, arg UpdateDeviceTokenDetailsParams) (UserDeviceTokens, error) - UpdateDeviceTokenLastUsed(ctx context.Context, arg UpdateDeviceTokenLastUsedParams) (UserDeviceTokens, error) - UpdateDeviceTokenPushNotificationToken(ctx context.Context, arg UpdateDeviceTokenPushNotificationTokenParams) (UserDeviceTokens, error) - UpdateOTPAttempts(ctx context.Context, id uuid.UUID) (OtpVerifications, error) - // Updates just the refresh token of a session - UpdateRefreshToken(ctx context.Context, arg UpdateRefreshTokenParams) (Sessions, error) - // Updates session details - UpdateSession(ctx context.Context, arg UpdateSessionParams) (Sessions, error) - UpdateSessionRefreshToken(ctx context.Context, arg UpdateSessionRefreshTokenParams) (Sessions, error) - // Updates transaction details and returns the updated transaction - UpdateTransaction(ctx context.Context, arg UpdateTransactionParams) (Transactions, error) - // Updates the status of a transaction and returns the updated transaction - UpdateTransactionStatus(ctx context.Context, arg UpdateTransactionStatusParams) (Transactions, error) - // Updates user details and returns the updated user - UpdateUser(ctx context.Context, arg UpdateUserParams) (Users, error) - // Updates a user's address - UpdateUserAddress(ctx context.Context, arg UpdateUserAddressParams) (Users, error) - // Updates a user's company details - UpdateUserCompanyDetails(ctx context.Context, arg UpdateUserCompanyDetailsParams) (Users, error) - // Updates a user's email address with validation that the new email is unique - UpdateUserEmail(ctx context.Context, arg UpdateUserEmailParams) (Users, error) - // Updates a user's job role - UpdateUserJobRole(ctx context.Context, arg UpdateUserJobRoleParams) (Users, error) - // Updates a user's password - UpdateUserPassword(ctx context.Context, arg UpdateUserPasswordParams) error - // Updates a user's personal details - UpdateUserPersonalDetails(ctx context.Context, arg UpdateUserPersonalDetailsParams) (Users, error) - // Updates a user's profile information - UpdateUserProfile(ctx context.Context, arg UpdateUserProfileParams) (Users, error) - UpdateUserWallet(ctx context.Context, arg UpdateUserWalletParams) (UserWallets, error) - UpsertUserDeviceToken(ctx context.Context, arg UpsertUserDeviceTokenParams) (UserDeviceTokens, error) - VerifyOTP(ctx context.Context, arg VerifyOTPParams) (OtpVerifications, error) -} - -var _ Querier = (*Queries)(nil) diff --git a/db/sqlc/security_events.sql.go b/db/sqlc/security_events.sql.go deleted file mode 100644 index ba793cf..0000000 --- a/db/sqlc/security_events.sql.go +++ /dev/null @@ -1,143 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.29.0 -// source: security_events.sql - -package sqlc - -import ( - "context" - - "github.com/google/uuid" - "github.com/jackc/pgx/v5/pgtype" -) - -const createSecurityEvent = `-- name: CreateSecurityEvent :one -INSERT INTO security_events ( - id, user_id, event_type, ip_address, user_agent, metadata, timestamp -) VALUES ( - $1, $2, $3, $4, $5, $6, $7 -) -RETURNING id, user_id, event_type, ip_address, user_agent, metadata, timestamp -` - -type CreateSecurityEventParams struct { - ID uuid.UUID `json:"id"` - UserID uuid.UUID `json:"user_id"` - EventType string `json:"event_type"` - IpAddress string `json:"ip_address"` - UserAgent pgtype.Text `json:"user_agent"` - Metadata []byte `json:"metadata"` - Timestamp pgtype.Timestamp `json:"timestamp"` -} - -func (q *Queries) CreateSecurityEvent(ctx context.Context, arg CreateSecurityEventParams) (SecurityEvents, error) { - row := q.db.QueryRow(ctx, createSecurityEvent, - arg.ID, - arg.UserID, - arg.EventType, - arg.IpAddress, - arg.UserAgent, - arg.Metadata, - arg.Timestamp, - ) - var i SecurityEvents - err := row.Scan( - &i.ID, - &i.UserID, - &i.EventType, - &i.IpAddress, - &i.UserAgent, - &i.Metadata, - &i.Timestamp, - ) - return i, err -} - -const getRecentLoginEventsByUserID = `-- name: GetRecentLoginEventsByUserID :many -SELECT id, user_id, event_type, ip_address, user_agent, metadata, timestamp FROM security_events -WHERE user_id = $1 AND event_type = 'login' -ORDER BY timestamp DESC -LIMIT $2 -` - -type GetRecentLoginEventsByUserIDParams struct { - UserID uuid.UUID `json:"user_id"` - Limit int32 `json:"limit"` -} - -func (q *Queries) GetRecentLoginEventsByUserID(ctx context.Context, arg GetRecentLoginEventsByUserIDParams) ([]SecurityEvents, error) { - rows, err := q.db.Query(ctx, getRecentLoginEventsByUserID, arg.UserID, arg.Limit) - if err != nil { - return nil, err - } - defer rows.Close() - items := []SecurityEvents{} - for rows.Next() { - var i SecurityEvents - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.EventType, - &i.IpAddress, - &i.UserAgent, - &i.Metadata, - &i.Timestamp, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const getSecurityEventsByUserIDAndType = `-- name: GetSecurityEventsByUserIDAndType :many -SELECT id, user_id, event_type, ip_address, user_agent, metadata, timestamp FROM security_events -WHERE user_id = $1 - AND event_type = $2 - AND timestamp BETWEEN $3 AND $4 -ORDER BY timestamp DESC -` - -type GetSecurityEventsByUserIDAndTypeParams struct { - UserID uuid.UUID `json:"user_id"` - EventType string `json:"event_type"` - Timestamp pgtype.Timestamp `json:"timestamp"` - Timestamp_2 pgtype.Timestamp `json:"timestamp_2"` -} - -func (q *Queries) GetSecurityEventsByUserIDAndType(ctx context.Context, arg GetSecurityEventsByUserIDAndTypeParams) ([]SecurityEvents, error) { - rows, err := q.db.Query(ctx, getSecurityEventsByUserIDAndType, - arg.UserID, - arg.EventType, - arg.Timestamp, - arg.Timestamp_2, - ) - if err != nil { - return nil, err - } - defer rows.Close() - items := []SecurityEvents{} - for rows.Next() { - var i SecurityEvents - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.EventType, - &i.IpAddress, - &i.UserAgent, - &i.Metadata, - &i.Timestamp, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} diff --git a/db/sqlc/seed.go b/db/sqlc/seed.go deleted file mode 100644 index 94665ea..0000000 --- a/db/sqlc/seed.go +++ /dev/null @@ -1,928 +0,0 @@ -package sqlc - -import ( - "context" - "fmt" - "log" - "math/rand" - "strings" - "time" - - "github.com/google/uuid" - "github.com/jackc/pgx/v5/pgtype" - "golang.org/x/crypto/bcrypt" -) - -// SeedSize defines the volume of data to be generated -type SeedSize string - -const ( - SeedSizeSmall SeedSize = "small" // Few records for quick testing - SeedSizeMedium SeedSize = "medium" // Moderate data volume - SeedSizeLarge SeedSize = "large" // Large dataset for performance testing -) - -// SeedOptions configures the seeding behavior -type SeedOptions struct { - Size SeedSize // Size of the dataset to generate - Tables []string // Specific tables to seed (empty means all) - PreserveData []string // Tables to preserve existing data - RandomSeed int64 // Seed for random generator (0 means use time) - CleanBeforeRun bool // Whether to clean tables before seeding - Verbose bool // Enable verbose output - UserCount int // Number of users to generate - UserRoleRatios map[string]int // Distribution of user roles - TransactionDays int // How many days of transaction history to generate -} - -// DefaultSeedOptions returns default seeding options -func DefaultSeedOptions() SeedOptions { - return SeedOptions{ - Size: SeedSizeMedium, - Tables: []string{}, - PreserveData: []string{}, - RandomSeed: 0, - CleanBeforeRun: true, - Verbose: true, - UserCount: 10, - UserRoleRatios: map[string]int{"personal": 8, "business": 2}, - TransactionDays: 30, - } -} - -// Seeder handles database seeding operations -type Seeder struct { - queries *Queries - options SeedOptions - randGen *rand.Rand - users []Users // Store generated users for relationships -} - -// NewSeeder creates a new database seeder -func NewSeeder(queries *Queries, options SeedOptions) *Seeder { - // Set up deterministic random number generator - var seed int64 - if options.RandomSeed == 0 { - seed = time.Now().UnixNano() - } else { - seed = options.RandomSeed - } - - // Initialize random generator with seed for reproducibility - source := rand.NewSource(seed) - generator := rand.New(source) - - // Set counts based on size - switch options.Size { - case SeedSizeSmall: - if options.UserCount == 10 { // Only override if not explicitly specified - options.UserCount = 5 - } - case SeedSizeLarge: - if options.UserCount == 10 { // Only override if not explicitly specified - options.UserCount = 50 - } - } - - return &Seeder{ - queries: queries, - options: options, - randGen: generator, - users: []Users{}, - } -} - -// SeedDB populates the database according to the configured options -func (s *Seeder) SeedDB(ctx context.Context) error { - log.Println("Starting database seeding...") - startTime := time.Now() - - // Clean tables if requested - if s.options.CleanBeforeRun { - if err := s.cleanTables(ctx); err != nil { - return fmt.Errorf("failed to clean tables: %w", err) - } - } - - // Determine tables to seed - tables := s.getTablesToSeed() - - // Seed tables in the correct order to maintain referential integrity - var err error - if contains(tables, "users") { - if err = s.seedUsers(ctx); err != nil { - return fmt.Errorf("failed to seed users: %w", err) - } - } - - if contains(tables, "sessions") { - if err = s.seedSessions(ctx); err != nil { - return fmt.Errorf("failed to seed sessions: %w", err) - } - } - - if contains(tables, "otp_verifications") { - if err = s.seedOTPVerifications(ctx); err != nil { - return fmt.Errorf("failed to seed OTP verifications: %w", err) - } - } - - if contains(tables, "user_device_tokens") { - if err = s.seedUserDeviceTokens(ctx); err != nil { - return fmt.Errorf("failed to seed user device tokens: %w", err) - } - } - - if contains(tables, "kyc_records") { - if err = s.seedKYCRecords(ctx); err != nil { - return fmt.Errorf("failed to seed KYC records: %w", err) - } - } - - if contains(tables, "transactions") { - if err = s.seedTransactions(ctx); err != nil { - return fmt.Errorf("failed to seed transactions: %w", err) - } - } - - duration := time.Since(startTime) - log.Printf("Database seeding completed in %s", duration) - return nil -} - -// getTablesToSeed returns the list of tables to seed based on options -func (s *Seeder) getTablesToSeed() []string { - if len(s.options.Tables) == 0 { - // If no specific tables are requested, seed all tables - return []string{ - "users", - "sessions", - "otp_verifications", - "user_device_tokens", - "kyc_records", - "transactions", - } - } - return s.options.Tables -} - -// cleanTables removes existing data from tables -func (s *Seeder) cleanTables(ctx context.Context) error { - log.Println("Cleaning tables before seeding...") - - // Define tables to clean in reverse dependency order - tables := []string{ - "transactions", - "kyc_records", - "user_device_tokens", - "otp_verifications", - "sessions", - "users", - } - - // Filter out tables that should be preserved - var tablesToClean []string - for _, table := range tables { - if !contains(s.options.PreserveData, table) { - tablesToClean = append(tablesToClean, table) - } - } - - // Create a connection for executing raw SQL - conn := s.queries.db - - // Disable foreign key checks temporarily - if _, err := conn.Exec(ctx, "SET session_replication_role = 'replica';"); err != nil { - return err - } - - // Clean each table - for _, table := range tablesToClean { - if _, err := conn.Exec(ctx, fmt.Sprintf("TRUNCATE TABLE %s CASCADE;", table)); err != nil { - return err - } - if s.options.Verbose { - log.Printf("Cleaned table: %s", table) - } - } - - // Re-enable foreign key checks - if _, err := conn.Exec(ctx, "SET session_replication_role = 'origin';"); err != nil { - return err - } - - return nil -} - -// seedUsers creates user records -func (s *Seeder) seedUsers(ctx context.Context) error { - log.Printf("Seeding %d users...", s.options.UserCount) - - // Sample data for generating realistic user profiles - firstNames := []string{"James", "Mary", "John", "Patricia", "Robert", "Jennifer", "Michael", "Linda", "William", "Elizabeth", - "David", "Barbara", "Richard", "Susan", "Joseph", "Jessica", "Thomas", "Sarah", "Charles", "Karen", - "Olivia", "Emma", "Ava", "Charlotte", "Sophia", "Amelia", "Isabella", "Mia", "Evelyn", "Harper"} - - lastNames := []string{"Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis", "Rodriguez", "Martinez", - "Hernandez", "Lopez", "Gonzalez", "Wilson", "Anderson", "Thomas", "Taylor", "Moore", "Jackson", "Martin", - "Lee", "Perez", "Thompson", "White", "Harris", "Sanchez", "Clark", "Lewis", "Robinson", "Walker"} - - nationalities := []string{"US", "UK", "CA", "AU", "DE", "FR", "JP", "CN", "IN", "BR", "MX", "ZA", "NG", "KE", "EG", "AE"} - - countries := []string{"United States", "United Kingdom", "Canada", "Australia", "Germany", "France", "Japan", "China", "India", "Brazil", - "Mexico", "South Africa", "Nigeria", "Kenya", "Egypt", "United Arab Emirates"} - - jobRoles := []string{"Software Engineer", "Product Manager", "Data Scientist", "UI/UX Designer", "DevOps Engineer", - "Project Manager", "Marketing Specialist", "Sales Representative", "Financial Analyst", "Customer Support", - "Content Writer", "Graphic Designer", "HR Manager", "Business Analyst", "QA Engineer"} - - personalAccountTypes := []string{"contractor", "freelancer", "employee"} - - // Generate users - for i := 0; i < s.options.UserCount; i++ { - // Determine account type based on ratios - var accountType string - if s.randGen.Float32() < float32(s.options.UserRoleRatios["business"])/float32(s.options.UserRoleRatios["business"]+s.options.UserRoleRatios["personal"]) { - accountType = "business" - } else { - accountType = "personal" - } - - firstName := firstNames[s.randGen.Intn(len(firstNames))] - lastName := lastNames[s.randGen.Intn(len(lastNames))] - email := fmt.Sprintf("%s.%s.%d@example.com", strings.ToLower(firstName), strings.ToLower(lastName), s.randGen.Intn(1000)) - - // Generate password hash for "password" - hashedPassword, err := bcrypt.GenerateFromPassword([]byte("password"), bcrypt.DefaultCost) - if err != nil { - return fmt.Errorf("failed to hash password: %w", err) - } - - // Create pgtype fields - passwordHash := pgtype.Text{String: string(hashedPassword), Valid: true} - - // Choose a random profile picture URL 50% of the time - var profilePicture string - if s.randGen.Float32() < 0.5 { - profilePicture = fmt.Sprintf("https://randomuser.me/api/portraits/%s/%d.jpg", - []string{"men", "women"}[s.randGen.Intn(2)], - s.randGen.Intn(99)) - } else { - profilePicture = "" - } - - // Gender (60% specified, 40% not) - var gender pgtype.Text - if s.randGen.Float32() < 0.6 { - gender = pgtype.Text{ - String: []string{"male", "female", "non-binary", "prefer not to say"}[s.randGen.Intn(4)], - Valid: true, - } - } else { - gender = pgtype.Text{Valid: false} - } - - // For personal accounts, assign a personal account type - var personalAccountType string - if accountType == "personal" { - personalAccountType = personalAccountTypes[s.randGen.Intn(len(personalAccountTypes))] - } else { - personalAccountType = "" // Empty for business accounts - } - - // Random data for the remaining fields - nationality := nationalities[s.randGen.Intn(len(nationalities))] - residentialCountry := pgtype.Text{String: countries[s.randGen.Intn(len(countries))], Valid: true} - jobRole := pgtype.Text{String: jobRoles[s.randGen.Intn(len(jobRoles))], Valid: true} - - // Company website only for business accounts and some freelancers - - // Create user with the generated data - user, err := s.queries.CreateUser(ctx, CreateUserParams{ - ID: uuid.New(), - Email: email, - PasswordHash: passwordHash, - ProfilePicture: profilePicture, - AccountType: accountType, - Gender: gender, - PersonalAccountType: personalAccountType, - FirstName: firstName, - LastName: lastName, - Nationality: nationality, - ResidentialCountry: residentialCountry, - JobRole: jobRole, - - UpdatedAt: time.Now(), - CreatedAt: time.Now(), - }) - - if err != nil { - return fmt.Errorf("failed to create user %s: %w", email, err) - } - - // Store user for relationships - s.users = append(s.users, user) - - if s.options.Verbose && (i+1)%5 == 0 { - log.Printf("Created %d/%d users", i+1, s.options.UserCount) - } - } - - log.Printf("Successfully seeded %d users", len(s.users)) - return nil -} - -// seedSessions creates session records for users -func (s *Seeder) seedSessions(ctx context.Context) error { - if len(s.users) == 0 { - return fmt.Errorf("no users available for creating sessions") - } - - log.Println("Seeding user sessions...") - - // User agents to make data more realistic - userAgents := []string{ - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:95.0) Gecko/20100101 Firefox/95.0", - "Mozilla/5.0 (iPhone; CPU iPhone OS 15_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1", - "Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.104 Mobile Safari/537.36", - } - - // Login types - loginTypes := []string{"email", "google", "apple", "github"} - - // Client IPs - clientIPs := []string{ - "192.168.1.1", "10.0.0.1", "172.16.0.1", - "203.0.113.1", "198.51.100.1", "192.0.2.1", - } - - // Each user has 1-3 sessions - totalSessions := 0 - for _, user := range s.users { - sessionsCount := 1 + s.randGen.Intn(3) - - for j := 0; j < sessionsCount; j++ { - userAgent := userAgents[s.randGen.Intn(len(userAgents))] - loginType := loginTypes[s.randGen.Intn(len(loginTypes))] - clientIp := clientIPs[s.randGen.Intn(len(clientIPs))] - - // Create OAuth fields for OAuth login types - var webOauthClientID, oauthAccessToken, oauthIDToken pgtype.Text - if loginType == "google" || loginType == "apple" || loginType == "github" { - webOauthClientID = pgtype.Text{ - String: fmt.Sprintf("%s_client_%d", loginType, s.randGen.Intn(999999)), - Valid: true, - } - oauthAccessToken = pgtype.Text{ - String: fmt.Sprintf("access_token_%s_%d", loginType, s.randGen.Intn(999999)), - Valid: true, - } - oauthIDToken = pgtype.Text{ - String: fmt.Sprintf("id_token_%s_%d", loginType, s.randGen.Intn(999999)), - Valid: true, - } - } - - // Set expiration to be between 1 day and 30 days in the future - expiryDays := 1 + s.randGen.Intn(29) - expiresAt := time.Now().Add(time.Duration(expiryDays) * 24 * time.Hour) - - // MFA is enabled for 30% of sessions - mfaEnabled := s.randGen.Float32() < 0.3 - - // 5% of sessions are blocked - isBlocked := s.randGen.Float32() < 0.05 - - _, err := s.queries.CreateSession(ctx, CreateSessionParams{ - ID: uuid.New(), - UserID: user.ID, - RefreshToken: fmt.Sprintf("refresh_token_%s", uuid.New().String()), - UserAgent: userAgent, - WebOauthClientID: webOauthClientID, - OauthAccessToken: oauthAccessToken, - OauthIDToken: oauthIDToken, - UserLoginType: loginType, - MfaEnabled: mfaEnabled, - ClientIp: clientIp, - IsBlocked: isBlocked, - ExpiresAt: pgtype.Timestamp{Time: expiresAt, Valid: true}, - }) - - if err != nil { - return fmt.Errorf("failed to create session for user %s: %w", user.Email, err) - } - - totalSessions++ - } - } - - log.Printf("Successfully seeded %d sessions", totalSessions) - return nil -} - -// seedOTPVerifications creates OTP verification records -func (s *Seeder) seedOTPVerifications(ctx context.Context) error { - if len(s.users) == 0 { - return fmt.Errorf("no users available for creating OTP verifications") - } - - log.Println("Seeding OTP verifications...") - - // OTP purposes - otpPurposes := []OtpPurpose{ - OtpPurposeEmailVerification, - OtpPurposePasswordReset, - OtpPurposePhoneVerification, - OtpPurposeAccountRecovery, - OtpPurposeTwoFactorAuth, - OtpPurposeLoginConfirmation, - } - - // Contact methods - contactMethods := []string{"email", "sms", "app"} - - totalOtps := 0 - - // Create OTPs for a subset of users (70%) - for _, user := range s.users { - if s.randGen.Float32() > 0.7 { - continue - } - - // 1-3 OTPs per user - otpCount := 1 + s.randGen.Intn(3) - - for j := 0; j < otpCount; j++ { - // Generate random 6-digit OTP - otpCode := fmt.Sprintf("%06d", s.randGen.Intn(1000000)) - - // Hash the OTP (simulating how it would be stored in real system) - hashedOtp, err := bcrypt.GenerateFromPassword([]byte(otpCode), bcrypt.DefaultCost) - if err != nil { - return fmt.Errorf("failed to hash OTP: %w", err) - } - - // Select purpose - purpose := otpPurposes[s.randGen.Intn(len(otpPurposes))] - - // Configure OTP parameters - userID := pgtype.UUID{ - Bytes: user.ID, - Valid: true, - } - - contactMethod := pgtype.Text{ - String: contactMethods[s.randGen.Intn(len(contactMethods))], - Valid: true, - } - - // Random number of attempts (0-3) - attemptsMade := int32(s.randGen.Intn(4)) - - // Create OTP verification - _, err = s.queries.CreateOTPVerification(ctx, CreateOTPVerificationParams{ - UserID: userID, - OtpCode: otpCode, - HashedOtp: string(hashedOtp), - Purpose: purpose, - ContactMethod: contactMethod, - AttemptsMade: attemptsMade, - MaxAttempts: 5, - }) - - if err != nil { - return fmt.Errorf("failed to create OTP verification: %w", err) - } - - totalOtps++ - } - } - - log.Printf("Successfully seeded %d OTP verifications", totalOtps) - return nil -} - -// seedUserDeviceTokens creates user device token records -func (s *Seeder) seedUserDeviceTokens(ctx context.Context) error { - if len(s.users) == 0 { - return fmt.Errorf("no users available for creating user device tokens") - } - - log.Println("Seeding user device tokens...") - - // Device platforms - platforms := []string{"ios", "android", "web"} - - // Device types - deviceTypes := []string{"mobile", "tablet", "desktop", "laptop"} - - // Device models - iosModels := []string{"iPhone 13 Pro", "iPhone 13", "iPhone 12 Pro", "iPhone SE", "iPad Pro", "iPad Air"} - androidModels := []string{"Samsung Galaxy S21", "Google Pixel 6", "OnePlus 9", "Xiaomi Mi 11", "Samsung Galaxy Tab S7"} - - // OS Versions - iosVersions := []string{"15.2", "15.1", "15.0", "14.8", "14.7"} - androidVersions := []string{"12", "11", "10", "9"} - - // App versions - appVersions := []string{"1.0.0", "1.1.0", "1.2.0", "1.2.1", "1.3.0"} - - totalDevices := 0 - - // Create device records for users - for _, user := range s.users { - // 1-3 devices per user - deviceCount := 1 + s.randGen.Intn(3) - - for j := 0; j < deviceCount; j++ { - platform := platforms[s.randGen.Intn(len(platforms))] - - deviceType := pgtype.Text{ - String: deviceTypes[s.randGen.Intn(len(deviceTypes))], - Valid: true, - } - - // Select model based on platform - var deviceModel pgtype.Text - var osName pgtype.Text - var osVersion pgtype.Text - - if platform == "ios" { - deviceModel = pgtype.Text{ - String: iosModels[s.randGen.Intn(len(iosModels))], - Valid: true, - } - osName = pgtype.Text{ - String: "iOS", - Valid: true, - } - osVersion = pgtype.Text{ - String: iosVersions[s.randGen.Intn(len(iosVersions))], - Valid: true, - } - } else if platform == "android" { - deviceModel = pgtype.Text{ - String: androidModels[s.randGen.Intn(len(androidModels))], - Valid: true, - } - osName = pgtype.Text{ - String: "Android", - Valid: true, - } - osVersion = pgtype.Text{ - String: androidVersions[s.randGen.Intn(len(androidVersions))], - Valid: true, - } - } else { - // Web platform - deviceModel = pgtype.Text{Valid: false} - osName = pgtype.Text{ - String: []string{"Windows", "macOS", "Linux"}[s.randGen.Intn(3)], - Valid: true, - } - osVersion = pgtype.Text{Valid: false} - } - - // 95% of devices are active and verified - isActive := s.randGen.Float32() < 0.95 - isVerified := s.randGen.Float32() < 0.95 - - // App version - appVersion := pgtype.Text{ - String: appVersions[s.randGen.Intn(len(appVersions))], - Valid: true, - } - - // Client IP - clientIp := pgtype.Text{ - String: fmt.Sprintf("192.168.%d.%d", s.randGen.Intn(255), s.randGen.Intn(255)), - Valid: true, - } - - // Push notification token for mobile devices - var pushToken pgtype.Text - if platform == "ios" || platform == "android" { - pushToken = pgtype.Text{ - String: fmt.Sprintf("push_token_%s_%d", platform, s.randGen.Intn(999999)), - Valid: true, - } - } else { - pushToken = pgtype.Text{Valid: false} - } - - // Set expiration (some may be expired) - var expiresAt pgtype.Timestamptz - if s.randGen.Float32() < 0.9 { - // 90% are not expired - expiresAt = pgtype.Timestamptz{ - Time: time.Now().Add(time.Duration(s.randGen.Intn(365)) * 24 * time.Hour), - Valid: true, - } - } else { - // 10% are expired - expiresAt = pgtype.Timestamptz{ - Time: time.Now().Add(-time.Duration(s.randGen.Intn(30)) * 24 * time.Hour), - Valid: true, - } - } - - // Generate device token - deviceToken := fmt.Sprintf("device_token_%s_%s", platform, uuid.New().String()) - - // Create device token record based on the actual struct definition - _, err := s.queries.CreateUserDeviceToken(ctx, CreateUserDeviceTokenParams{ - ID: uuid.New(), - UserID: user.ID, - DeviceToken: deviceToken, - Column4: platform, // Platform - Column5: deviceType.String, // DeviceType - Column6: deviceModel.String, // DeviceModel - Column7: osName.String, // OsName - Column8: osVersion.String, // OsVersion - PushNotificationToken: pushToken, - Column10: isActive, // IsActive - Column11: isVerified, // IsVerified - AppVersion: appVersion, - ClientIp: clientIp, - ExpiresAt: expiresAt, - }) - - if err != nil { - return fmt.Errorf("failed to create user device token for user %s: %w", user.Email, err) - } - - totalDevices++ - } - } - - log.Printf("Successfully seeded %d user device tokens", totalDevices) - return nil -} - -// seedKYCRecords creates KYC verification records for users -func (s *Seeder) seedKYCRecords(ctx context.Context) error { - if len(s.users) == 0 { - return fmt.Errorf("no users available for creating KYC records") - } - - log.Println("Seeding KYC records...") - - // KYC verification levels - verificationLevels := []string{"basic", "intermediate", "advanced"} - - // ID document types - idTypes := []string{"passport", "national_id", "driving_license", "voter_card", "residence_permit"} - - // Countries for documents - countries := []string{"US", "UK", "CA", "AU", "DE", "FR", "JP", "CN", "IN", "BR", "MX", "ZA", "NG", "KE", "EG", "AE"} - - // Verifier names - verifiers := []string{"Manual Review", "IDCheck", "VerifyPlus", "GlobalID", "TrustVerify", "SecureKYC"} - - totalKYCRecords := 0 - - // Create KYC records for a subset of users (80%) - for _, user := range s.users { - // Skip some users to simulate incomplete KYC - if s.randGen.Float32() > 0.8 { - continue - } - - // Select KYC status (70% approved, 30% other statuses) - var status string - if s.randGen.Float32() < 0.7 { - status = "approved" - } else { - // Choose a non-approved status - nonApprovedStatuses := []string{"pending", "rejected", "expired", "requires_action"} - status = nonApprovedStatuses[s.randGen.Intn(len(nonApprovedStatuses))] - } - - // Verification level (depends on status) - var verificationLevel string - if status == "approved" { - // For approved records, assign a verification level based on probabilities - levelProbabilities := []float32{0.3, 0.4, 0.3} // basic, intermediate, advanced - randValue := s.randGen.Float32() - - if randValue < levelProbabilities[0] { - verificationLevel = verificationLevels[0] - } else if randValue < levelProbabilities[0]+levelProbabilities[1] { - verificationLevel = verificationLevels[1] - } else { - verificationLevel = verificationLevels[2] - } - } else if status == "pending" || status == "requires_action" { - // Pending/requires_action usually have a target level - verificationLevel = verificationLevels[s.randGen.Intn(len(verificationLevels))] - } else { - // Rejected/expired might not have a level - if s.randGen.Float32() < 0.5 { - verificationLevel = verificationLevels[s.randGen.Intn(len(verificationLevels))] - } else { - verificationLevel = "" - } - } - - // ID document details - idType := idTypes[s.randGen.Intn(len(idTypes))] - country := countries[s.randGen.Intn(len(countries))] - - // Document submission date - submissionDate := time.Now().AddDate(0, -s.randGen.Intn(6), -s.randGen.Intn(30)) - - // Verification date (if approved or rejected) - var verificationDate time.Time - if status == "approved" || status == "rejected" { - // Verification happened 1-7 days after submission - verificationDays := 1 + s.randGen.Intn(6) - verificationDate = submissionDate.AddDate(0, 0, verificationDays) - } - - // Comments for rejected or requires_action - var comments string - if status == "rejected" { - rejectionReasons := []string{ - "Document illegible", "Document expired", "Information mismatch", - "Suspected forgery", "Incomplete submission", "Failed verification checks", - } - comments = rejectionReasons[s.randGen.Intn(len(rejectionReasons))] - } else if status == "requires_action" { - actionReasons := []string{ - "Additional document required", "Please resubmit with better quality", - "Address verification needed", "Please complete the missing information", - } - comments = actionReasons[s.randGen.Intn(len(actionReasons))] - } else { - comments = "" - } - - // Verifier - verifier := verifiers[s.randGen.Intn(len(verifiers))] - - // Placeholder for KYC record creation - // Note: We're logging KYC details since the actual CreateKYCRecord - // method is not available. In a real implementation, this would call the database. - if s.options.Verbose { - log.Printf("Would create KYC record: ID=%s, User=%s, Status=%s, Level=%s, "+ - "Document=%s (%s), Submitted=%s, Verified=%s, Verifier=%s, Comments='%s'", - uuid.New().String(), user.Email, status, verificationLevel, - idType, country, submissionDate.Format(time.RFC3339), - verificationDate.Format(time.RFC3339), verifier, comments) - } - - totalKYCRecords++ - } - - log.Printf("Successfully simulated %d KYC records", totalKYCRecords) - log.Printf("Note: KYC record seeding is implemented as a placeholder. To enable actual database writes,") - log.Printf("implement the CreateKYCRecord method in your database queries.") - return nil -} - -// seedTransactions creates transaction records for users -func (s *Seeder) seedTransactions(ctx context.Context) error { - if len(s.users) == 0 { - return fmt.Errorf("no users available for creating transactions") - } - - log.Println("Seeding transactions...") - - // Determine number of days to generate transactions for - txDays := 30 // Default for medium size - if s.options.TransactionDays > 0 { - txDays = s.options.TransactionDays - } else { - // Set based on size - switch s.options.Size { - case SeedSizeSmall: - txDays = 7 - case SeedSizeMedium: - txDays = 30 - case SeedSizeLarge: - txDays = 90 - } - } - - // Transaction types - transactionTypes := []string{"deposit", "withdrawal", "transfer", "payment"} - - // Transaction statuses - statuses := []string{"pending", "completed", "failed", "cancelled", "refunded"} - - // Currency codes - currencies := []string{"USD", "EUR", "GBP", "JPY", "NGN", "KES", "ZAR", "AED"} - - // Payment methods - paymentMethods := []string{ - "bank_transfer", "credit_card", "debit_card", "crypto", "mobile_money", - "paypal", "venmo", "cash", "cheque", - } - - // Transaction descriptions - descriptions := []string{ - "Monthly subscription", "Service payment", "Product purchase", - "Salary payment", "Freelance work", "Consulting fees", - "Refund", "Investment return", "Loan repayment", - "Travel expenses", "Utility bill", "Rent payment", - "Groceries", "Health insurance", "Educational fees", - } - - // Generate random transaction data - startDate := time.Now().AddDate(0, 0, -txDays) - - totalTransactions := 0 - - // Create transactions for each user - for _, user := range s.users { - // Number of transactions varies by user activity level - // Assuming between 5-20 transactions per user per month, scaled by the txDays parameter - txCount := 5 + s.randGen.Intn(15) - txCount = txCount * txDays / 30 // Scale based on transaction days - - for j := 0; j < txCount; j++ { - // Generate transaction date within the specified range - daysOffset := s.randGen.Intn(txDays) - txDate := startDate.AddDate(0, 0, daysOffset) - - // Select transaction type - txType := transactionTypes[s.randGen.Intn(len(transactionTypes))] - - // Set status (80% completed, 20% other statuses) - var status string - if s.randGen.Float32() < 0.8 { - status = "completed" - } else { - status = statuses[s.randGen.Intn(len(statuses))] - } - - // Generate amount (between 10 and 1000, with 2 decimal places) - amount := float64(10+s.randGen.Intn(99100)) / 100.0 - - // Currency (USD more common than others) - var currency string - if s.randGen.Float32() < 0.6 { - currency = "USD" - } else { - currency = currencies[s.randGen.Intn(len(currencies))] - } - - // Payment method - paymentMethod := paymentMethods[s.randGen.Intn(len(paymentMethods))] - - // Transaction description - description := descriptions[s.randGen.Intn(len(descriptions))] - if txType == "transfer" { - // For transfers, add recipient information - recipientIndex := s.randGen.Intn(len(s.users)) - recipientUser := s.users[recipientIndex] - description = fmt.Sprintf("Transfer to %s %s", recipientUser.FirstName, recipientUser.LastName) - } - - // Reference number - referenceNumber := fmt.Sprintf("TX-%s-%d", txType[:3], s.randGen.Intn(1000000)) - - // Fee (0-2% of amount) - feePercent := float64(s.randGen.Intn(200)) / 10000.0 - fee := amount * feePercent - - // Placeholder for transaction creation - // Note: We're logging transaction details since the actual CreateTransaction - // method is not available. In a real implementation, this would call the database. - if s.options.Verbose { - log.Printf("Would create transaction: ID=%s, User=%s, Type=%s, Status=%s, Amount=%.2f %s, "+ - "Method=%s, Description='%s', Reference=%s, Fee=%.2f, Date=%s", - uuid.New().String(), user.Email, txType, status, amount, currency, - paymentMethod, description, referenceNumber, fee, txDate.Format(time.RFC3339)) - } - - // Increment counter for the output message - totalTransactions++ - } - } - - log.Printf("Successfully simulated %d transactions over a %d day period", totalTransactions, txDays) - log.Printf("Note: Transaction seeding is implemented as a placeholder. To enable actual database writes,") - log.Printf("implement the CreateTransaction method in your database queries.") - return nil -} - -// Helper function to check if a slice contains a string -func contains(slice []string, item string) bool { - for _, s := range slice { - if s == item { - return true - } - } - return false -} - -// SeedDB is a convenience function that creates a seeder with default options -// and seeds the database -func SeedDB(ctx context.Context, queries *Queries) error { - options := DefaultSeedOptions() - seeder := NewSeeder(queries, options) - return seeder.SeedDB(ctx) -} diff --git a/db/sqlc/sessions.sql.go b/db/sqlc/sessions.sql.go deleted file mode 100644 index eaa0a9a..0000000 --- a/db/sqlc/sessions.sql.go +++ /dev/null @@ -1,510 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.29.0 -// source: sessions.sql - -package sqlc - -import ( - "context" - - "github.com/google/uuid" - "github.com/jackc/pgx/v5/pgtype" -) - -const blockAllUserSessions = `-- name: BlockAllUserSessions :exec -UPDATE sessions -SET is_blocked = true -WHERE user_id = $1 -` - -// Blocks all sessions for a specific user -func (q *Queries) BlockAllUserSessions(ctx context.Context, userID uuid.UUID) error { - _, err := q.db.Exec(ctx, blockAllUserSessions, userID) - return err -} - -const blockExpiredSessions = `-- name: BlockExpiredSessions :exec -UPDATE sessions -SET is_blocked = true -WHERE expires_at <= now() AND is_blocked = false -` - -// Blocks all expired sessions -func (q *Queries) BlockExpiredSessions(ctx context.Context) error { - _, err := q.db.Exec(ctx, blockExpiredSessions) - return err -} - -const blockSession = `-- name: BlockSession :exec -UPDATE sessions -SET is_blocked = true -WHERE id = $1 -` - -// Blocks a session (marks it as invalid) -func (q *Queries) BlockSession(ctx context.Context, id uuid.UUID) error { - _, err := q.db.Exec(ctx, blockSession, id) - return err -} - -const countActiveSessions = `-- name: CountActiveSessions :one -SELECT COUNT(*) FROM sessions -WHERE is_blocked = false AND expires_at > now() -` - -// Counts the number of active sessions -func (q *Queries) CountActiveSessions(ctx context.Context) (int64, error) { - row := q.db.QueryRow(ctx, countActiveSessions) - var count int64 - err := row.Scan(&count) - return count, err -} - -const countActiveSessionsByUserID = `-- name: CountActiveSessionsByUserID :one -SELECT COUNT(*) FROM sessions -WHERE user_id = $1 AND is_blocked = false AND expires_at > now() -` - -// Counts the number of active sessions for a specific user -func (q *Queries) CountActiveSessionsByUserID(ctx context.Context, userID uuid.UUID) (int64, error) { - row := q.db.QueryRow(ctx, countActiveSessionsByUserID, userID) - var count int64 - err := row.Scan(&count) - return count, err -} - -const createSession = `-- name: CreateSession :one -INSERT INTO sessions ( - id, - user_id, - refresh_token, - user_agent, - web_oauth_client_id, - oauth_access_token, - oauth_id_token, - user_login_type, - last_used_at, - mfa_enabled, - client_ip, - is_blocked, - expires_at, - created_at -) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, COALESCE($14, now()) -) RETURNING id, user_id, refresh_token, user_agent, last_used_at, web_oauth_client_id, oauth_access_token, oauth_id_token, user_login_type, mfa_enabled, client_ip, is_blocked, expires_at, created_at -` - -type CreateSessionParams struct { - ID uuid.UUID `json:"id"` - UserID uuid.UUID `json:"user_id"` - RefreshToken string `json:"refresh_token"` - UserAgent string `json:"user_agent"` - WebOauthClientID pgtype.Text `json:"web_oauth_client_id"` - OauthAccessToken pgtype.Text `json:"oauth_access_token"` - OauthIDToken pgtype.Text `json:"oauth_id_token"` - UserLoginType string `json:"user_login_type"` - LastUsedAt pgtype.Timestamp `json:"last_used_at"` - MfaEnabled bool `json:"mfa_enabled"` - ClientIp string `json:"client_ip"` - IsBlocked bool `json:"is_blocked"` - ExpiresAt pgtype.Timestamp `json:"expires_at"` - Column14 interface{} `json:"column_14"` -} - -// Creates a new session and returns the created session record -func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) (Sessions, error) { - row := q.db.QueryRow(ctx, createSession, - arg.ID, - arg.UserID, - arg.RefreshToken, - arg.UserAgent, - arg.WebOauthClientID, - arg.OauthAccessToken, - arg.OauthIDToken, - arg.UserLoginType, - arg.LastUsedAt, - arg.MfaEnabled, - arg.ClientIp, - arg.IsBlocked, - arg.ExpiresAt, - arg.Column14, - ) - var i Sessions - err := row.Scan( - &i.ID, - &i.UserID, - &i.RefreshToken, - &i.UserAgent, - &i.LastUsedAt, - &i.WebOauthClientID, - &i.OauthAccessToken, - &i.OauthIDToken, - &i.UserLoginType, - &i.MfaEnabled, - &i.ClientIp, - &i.IsBlocked, - &i.ExpiresAt, - &i.CreatedAt, - ) - return i, err -} - -const deleteExpiredSessions = `-- name: DeleteExpiredSessions :exec -DELETE FROM sessions -WHERE expires_at < $1 -` - -// Cleans up expired sessions that are older than the specified date -func (q *Queries) DeleteExpiredSessions(ctx context.Context, expiresAt pgtype.Timestamp) error { - _, err := q.db.Exec(ctx, deleteExpiredSessions, expiresAt) - return err -} - -const deleteSession = `-- name: DeleteSession :exec -DELETE FROM sessions -WHERE id = $1 -` - -// Deletes a session by its ID -func (q *Queries) DeleteSession(ctx context.Context, id uuid.UUID) error { - _, err := q.db.Exec(ctx, deleteSession, id) - return err -} - -const deleteSessionsByUserID = `-- name: DeleteSessionsByUserID :exec -DELETE FROM sessions -WHERE user_id = $1 -` - -// Deletes all sessions for a specific user -func (q *Queries) DeleteSessionsByUserID(ctx context.Context, userID uuid.UUID) error { - _, err := q.db.Exec(ctx, deleteSessionsByUserID, userID) - return err -} - -const getActiveSessions = `-- name: GetActiveSessions :many -SELECT id, user_id, refresh_token, user_agent, last_used_at, web_oauth_client_id, oauth_access_token, oauth_id_token, user_login_type, mfa_enabled, client_ip, is_blocked, expires_at, created_at FROM sessions -WHERE is_blocked = false AND expires_at > now() -ORDER BY created_at DESC -LIMIT $1 -OFFSET $2 -` - -type GetActiveSessionsParams struct { - Limit int32 `json:"limit"` - Offset int32 `json:"offset"` -} - -// Retrieves active (non-expired, non-blocked) sessions with pagination -func (q *Queries) GetActiveSessions(ctx context.Context, arg GetActiveSessionsParams) ([]Sessions, error) { - rows, err := q.db.Query(ctx, getActiveSessions, arg.Limit, arg.Offset) - if err != nil { - return nil, err - } - defer rows.Close() - items := []Sessions{} - for rows.Next() { - var i Sessions - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.RefreshToken, - &i.UserAgent, - &i.LastUsedAt, - &i.WebOauthClientID, - &i.OauthAccessToken, - &i.OauthIDToken, - &i.UserLoginType, - &i.MfaEnabled, - &i.ClientIp, - &i.IsBlocked, - &i.ExpiresAt, - &i.CreatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const getActiveSessionsByUserID = `-- name: GetActiveSessionsByUserID :many -SELECT id, user_id, refresh_token, user_agent, last_used_at, web_oauth_client_id, oauth_access_token, oauth_id_token, user_login_type, mfa_enabled, client_ip, is_blocked, expires_at, created_at FROM sessions -WHERE user_id = $1 AND is_blocked = false AND expires_at > now() -ORDER BY created_at DESC -` - -// Retrieves active sessions for a specific user -func (q *Queries) GetActiveSessionsByUserID(ctx context.Context, userID uuid.UUID) ([]Sessions, error) { - rows, err := q.db.Query(ctx, getActiveSessionsByUserID, userID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []Sessions{} - for rows.Next() { - var i Sessions - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.RefreshToken, - &i.UserAgent, - &i.LastUsedAt, - &i.WebOauthClientID, - &i.OauthAccessToken, - &i.OauthIDToken, - &i.UserLoginType, - &i.MfaEnabled, - &i.ClientIp, - &i.IsBlocked, - &i.ExpiresAt, - &i.CreatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const getSessionByID = `-- name: GetSessionByID :one -SELECT id, user_id, refresh_token, user_agent, last_used_at, web_oauth_client_id, oauth_access_token, oauth_id_token, user_login_type, mfa_enabled, client_ip, is_blocked, expires_at, created_at FROM sessions -WHERE id = $1 -LIMIT 1 -` - -// Retrieves a session by its ID -func (q *Queries) GetSessionByID(ctx context.Context, id uuid.UUID) (Sessions, error) { - row := q.db.QueryRow(ctx, getSessionByID, id) - var i Sessions - err := row.Scan( - &i.ID, - &i.UserID, - &i.RefreshToken, - &i.UserAgent, - &i.LastUsedAt, - &i.WebOauthClientID, - &i.OauthAccessToken, - &i.OauthIDToken, - &i.UserLoginType, - &i.MfaEnabled, - &i.ClientIp, - &i.IsBlocked, - &i.ExpiresAt, - &i.CreatedAt, - ) - return i, err -} - -const getSessionByRefreshToken = `-- name: GetSessionByRefreshToken :one -SELECT id, user_id, refresh_token, user_agent, last_used_at, web_oauth_client_id, oauth_access_token, oauth_id_token, user_login_type, mfa_enabled, client_ip, is_blocked, expires_at, created_at FROM sessions -WHERE refresh_token = $1 -LIMIT 1 -` - -// Retrieves a session by refresh token -func (q *Queries) GetSessionByRefreshToken(ctx context.Context, refreshToken string) (Sessions, error) { - row := q.db.QueryRow(ctx, getSessionByRefreshToken, refreshToken) - var i Sessions - err := row.Scan( - &i.ID, - &i.UserID, - &i.RefreshToken, - &i.UserAgent, - &i.LastUsedAt, - &i.WebOauthClientID, - &i.OauthAccessToken, - &i.OauthIDToken, - &i.UserLoginType, - &i.MfaEnabled, - &i.ClientIp, - &i.IsBlocked, - &i.ExpiresAt, - &i.CreatedAt, - ) - return i, err -} - -const getSessionsByUserID = `-- name: GetSessionsByUserID :many -SELECT id, user_id, refresh_token, user_agent, last_used_at, web_oauth_client_id, oauth_access_token, oauth_id_token, user_login_type, mfa_enabled, client_ip, is_blocked, expires_at, created_at FROM sessions -WHERE user_id = $1 -ORDER BY created_at DESC -` - -// Retrieves all sessions for a specific user -func (q *Queries) GetSessionsByUserID(ctx context.Context, userID uuid.UUID) ([]Sessions, error) { - rows, err := q.db.Query(ctx, getSessionsByUserID, userID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []Sessions{} - for rows.Next() { - var i Sessions - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.RefreshToken, - &i.UserAgent, - &i.LastUsedAt, - &i.WebOauthClientID, - &i.OauthAccessToken, - &i.OauthIDToken, - &i.UserLoginType, - &i.MfaEnabled, - &i.ClientIp, - &i.IsBlocked, - &i.ExpiresAt, - &i.CreatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const updateRefreshToken = `-- name: UpdateRefreshToken :one -UPDATE sessions -SET refresh_token = $2 -WHERE id = $1 -RETURNING id, user_id, refresh_token, user_agent, last_used_at, web_oauth_client_id, oauth_access_token, oauth_id_token, user_login_type, mfa_enabled, client_ip, is_blocked, expires_at, created_at -` - -type UpdateRefreshTokenParams struct { - ID uuid.UUID `json:"id"` - RefreshToken string `json:"refresh_token"` -} - -// Updates just the refresh token of a session -func (q *Queries) UpdateRefreshToken(ctx context.Context, arg UpdateRefreshTokenParams) (Sessions, error) { - row := q.db.QueryRow(ctx, updateRefreshToken, arg.ID, arg.RefreshToken) - var i Sessions - err := row.Scan( - &i.ID, - &i.UserID, - &i.RefreshToken, - &i.UserAgent, - &i.LastUsedAt, - &i.WebOauthClientID, - &i.OauthAccessToken, - &i.OauthIDToken, - &i.UserLoginType, - &i.MfaEnabled, - &i.ClientIp, - &i.IsBlocked, - &i.ExpiresAt, - &i.CreatedAt, - ) - return i, err -} - -const updateSession = `-- name: UpdateSession :one -UPDATE sessions -SET - user_agent = COALESCE($2, user_agent), - web_oauth_client_id = $3, - oauth_access_token = $4, - oauth_id_token = $5, - mfa_enabled = COALESCE($6, mfa_enabled), - client_ip = COALESCE($7, client_ip), - is_blocked = COALESCE($8, is_blocked), - expires_at = COALESCE($9, expires_at), - last_used_at = COALESCE($10, last_used_at) -WHERE id = $1 -RETURNING id, user_id, refresh_token, user_agent, last_used_at, web_oauth_client_id, oauth_access_token, oauth_id_token, user_login_type, mfa_enabled, client_ip, is_blocked, expires_at, created_at -` - -type UpdateSessionParams struct { - ID uuid.UUID `json:"id"` - UserAgent string `json:"user_agent"` - WebOauthClientID pgtype.Text `json:"web_oauth_client_id"` - OauthAccessToken pgtype.Text `json:"oauth_access_token"` - OauthIDToken pgtype.Text `json:"oauth_id_token"` - MfaEnabled bool `json:"mfa_enabled"` - ClientIp string `json:"client_ip"` - IsBlocked bool `json:"is_blocked"` - ExpiresAt pgtype.Timestamp `json:"expires_at"` - LastUsedAt pgtype.Timestamp `json:"last_used_at"` -} - -// Updates session details -func (q *Queries) UpdateSession(ctx context.Context, arg UpdateSessionParams) (Sessions, error) { - row := q.db.QueryRow(ctx, updateSession, - arg.ID, - arg.UserAgent, - arg.WebOauthClientID, - arg.OauthAccessToken, - arg.OauthIDToken, - arg.MfaEnabled, - arg.ClientIp, - arg.IsBlocked, - arg.ExpiresAt, - arg.LastUsedAt, - ) - var i Sessions - err := row.Scan( - &i.ID, - &i.UserID, - &i.RefreshToken, - &i.UserAgent, - &i.LastUsedAt, - &i.WebOauthClientID, - &i.OauthAccessToken, - &i.OauthIDToken, - &i.UserLoginType, - &i.MfaEnabled, - &i.ClientIp, - &i.IsBlocked, - &i.ExpiresAt, - &i.CreatedAt, - ) - return i, err -} - -const updateSessionRefreshToken = `-- name: UpdateSessionRefreshToken :one -UPDATE sessions -SET - refresh_token = $2, - last_used_at = $3 -WHERE id = $1 -RETURNING id, user_id, refresh_token, user_agent, last_used_at, web_oauth_client_id, oauth_access_token, oauth_id_token, user_login_type, mfa_enabled, client_ip, is_blocked, expires_at, created_at -` - -type UpdateSessionRefreshTokenParams struct { - ID uuid.UUID `json:"id"` - RefreshToken string `json:"refresh_token"` - LastUsedAt pgtype.Timestamp `json:"last_used_at"` -} - -func (q *Queries) UpdateSessionRefreshToken(ctx context.Context, arg UpdateSessionRefreshTokenParams) (Sessions, error) { - row := q.db.QueryRow(ctx, updateSessionRefreshToken, arg.ID, arg.RefreshToken, arg.LastUsedAt) - var i Sessions - err := row.Scan( - &i.ID, - &i.UserID, - &i.RefreshToken, - &i.UserAgent, - &i.LastUsedAt, - &i.WebOauthClientID, - &i.OauthAccessToken, - &i.OauthIDToken, - &i.UserLoginType, - &i.MfaEnabled, - &i.ClientIp, - &i.IsBlocked, - &i.ExpiresAt, - &i.CreatedAt, - ) - return i, err -} diff --git a/db/sqlc/settings.sql.go b/db/sqlc/settings.sql.go new file mode 100644 index 0000000..d359765 --- /dev/null +++ b/db/sqlc/settings.sql.go @@ -0,0 +1,996 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.29.0 +// source: settings.sql + +package sqlc + +import ( + "context" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" +) + +const createCompanyFeatureFlag = `-- name: CreateCompanyFeatureFlag :one +INSERT INTO company_feature_flags ( + id, + company_id, + flag_key, + is_enabled, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + COALESCE($5, NOW()), + COALESCE($6, NOW()) +) RETURNING id, company_id, flag_key, is_enabled, created_at, updated_at +` + +type CreateCompanyFeatureFlagParams struct { + ID interface{} `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + FlagKey string `json:"flag_key"` + IsEnabled bool `json:"is_enabled"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateCompanyFeatureFlag(ctx context.Context, arg CreateCompanyFeatureFlagParams) (CompanyFeatureFlags, error) { + row := q.db.QueryRow(ctx, createCompanyFeatureFlag, + arg.ID, + arg.CompanyID, + arg.FlagKey, + arg.IsEnabled, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i CompanyFeatureFlags + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.FlagKey, + &i.IsEnabled, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createCompanySetting = `-- name: CreateCompanySetting :one +INSERT INTO company_settings ( + id, + company_id, + setting_key, + setting_value, + data_type, + description, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + COALESCE($5, 'string'), + $6, + COALESCE($7, NOW()), + COALESCE($8, NOW()) +) RETURNING id, company_id, setting_key, setting_value, data_type, description, created_at, updated_at +` + +type CreateCompanySettingParams struct { + ID interface{} `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + SettingKey string `json:"setting_key"` + SettingValue pgtype.Text `json:"setting_value"` + DataType interface{} `json:"data_type"` + Description pgtype.Text `json:"description"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateCompanySetting(ctx context.Context, arg CreateCompanySettingParams) (CompanySettings, error) { + row := q.db.QueryRow(ctx, createCompanySetting, + arg.ID, + arg.CompanyID, + arg.SettingKey, + arg.SettingValue, + arg.DataType, + arg.Description, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i CompanySettings + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.SettingKey, + &i.SettingValue, + &i.DataType, + &i.Description, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createFeatureFlag = `-- name: CreateFeatureFlag :one +INSERT INTO feature_flags ( + id, + flag_key, + description, + is_enabled, + rollout_percentage, + conditions, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + COALESCE($4, FALSE), + COALESCE($5, 0), + $6, + COALESCE($7, NOW()), + COALESCE($8, NOW()) +) RETURNING id, flag_key, description, is_enabled, rollout_percentage, conditions, created_at, updated_at +` + +type CreateFeatureFlagParams struct { + ID interface{} `json:"id"` + FlagKey string `json:"flag_key"` + Description pgtype.Text `json:"description"` + IsEnabled interface{} `json:"is_enabled"` + RolloutPercentage interface{} `json:"rollout_percentage"` + Conditions []byte `json:"conditions"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateFeatureFlag(ctx context.Context, arg CreateFeatureFlagParams) (FeatureFlags, error) { + row := q.db.QueryRow(ctx, createFeatureFlag, + arg.ID, + arg.FlagKey, + arg.Description, + arg.IsEnabled, + arg.RolloutPercentage, + arg.Conditions, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i FeatureFlags + err := row.Scan( + &i.ID, + &i.FlagKey, + &i.Description, + &i.IsEnabled, + &i.RolloutPercentage, + &i.Conditions, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createSystemSetting = `-- name: CreateSystemSetting :one +INSERT INTO system_settings ( + id, + setting_key, + setting_value, + data_type, + description, + is_sensitive, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + COALESCE($4, 'string'), + $5, + COALESCE($6, FALSE), + COALESCE($7, NOW()), + COALESCE($8, NOW()) +) RETURNING id, setting_key, setting_value, data_type, description, is_sensitive, created_at, updated_at +` + +type CreateSystemSettingParams struct { + ID interface{} `json:"id"` + SettingKey string `json:"setting_key"` + SettingValue pgtype.Text `json:"setting_value"` + DataType interface{} `json:"data_type"` + Description pgtype.Text `json:"description"` + IsSensitive interface{} `json:"is_sensitive"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateSystemSetting(ctx context.Context, arg CreateSystemSettingParams) (SystemSettings, error) { + row := q.db.QueryRow(ctx, createSystemSetting, + arg.ID, + arg.SettingKey, + arg.SettingValue, + arg.DataType, + arg.Description, + arg.IsSensitive, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i SystemSettings + err := row.Scan( + &i.ID, + &i.SettingKey, + &i.SettingValue, + &i.DataType, + &i.Description, + &i.IsSensitive, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createUserFeatureFlag = `-- name: CreateUserFeatureFlag :one +INSERT INTO user_feature_flags ( + id, + user_id, + flag_key, + is_enabled, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + COALESCE($5, NOW()), + COALESCE($6, NOW()) +) RETURNING id, user_id, flag_key, is_enabled, created_at, updated_at +` + +type CreateUserFeatureFlagParams struct { + ID interface{} `json:"id"` + UserID uuid.UUID `json:"user_id"` + FlagKey string `json:"flag_key"` + IsEnabled bool `json:"is_enabled"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateUserFeatureFlag(ctx context.Context, arg CreateUserFeatureFlagParams) (UserFeatureFlags, error) { + row := q.db.QueryRow(ctx, createUserFeatureFlag, + arg.ID, + arg.UserID, + arg.FlagKey, + arg.IsEnabled, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i UserFeatureFlags + err := row.Scan( + &i.ID, + &i.UserID, + &i.FlagKey, + &i.IsEnabled, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createUserSetting = `-- name: CreateUserSetting :one +INSERT INTO user_settings ( + id, + user_id, + setting_key, + setting_value, + data_type, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + COALESCE($5, 'string'), + COALESCE($6, NOW()), + COALESCE($7, NOW()) +) RETURNING id, user_id, setting_key, setting_value, data_type, created_at, updated_at +` + +type CreateUserSettingParams struct { + ID interface{} `json:"id"` + UserID uuid.UUID `json:"user_id"` + SettingKey string `json:"setting_key"` + SettingValue pgtype.Text `json:"setting_value"` + DataType interface{} `json:"data_type"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateUserSetting(ctx context.Context, arg CreateUserSettingParams) (UserSettings, error) { + row := q.db.QueryRow(ctx, createUserSetting, + arg.ID, + arg.UserID, + arg.SettingKey, + arg.SettingValue, + arg.DataType, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i UserSettings + err := row.Scan( + &i.ID, + &i.UserID, + &i.SettingKey, + &i.SettingValue, + &i.DataType, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteCompanySetting = `-- name: DeleteCompanySetting :exec +DELETE FROM company_settings +WHERE company_id = $1 AND setting_key = $2 +` + +type DeleteCompanySettingParams struct { + CompanyID uuid.UUID `json:"company_id"` + SettingKey string `json:"setting_key"` +} + +func (q *Queries) DeleteCompanySetting(ctx context.Context, arg DeleteCompanySettingParams) error { + _, err := q.db.Exec(ctx, deleteCompanySetting, arg.CompanyID, arg.SettingKey) + return err +} + +const deleteSystemSetting = `-- name: DeleteSystemSetting :exec +DELETE FROM system_settings WHERE setting_key = $1 +` + +func (q *Queries) DeleteSystemSetting(ctx context.Context, settingKey string) error { + _, err := q.db.Exec(ctx, deleteSystemSetting, settingKey) + return err +} + +const deleteUserSetting = `-- name: DeleteUserSetting :exec +DELETE FROM user_settings +WHERE user_id = $1 AND setting_key = $2 +` + +type DeleteUserSettingParams struct { + UserID uuid.UUID `json:"user_id"` + SettingKey string `json:"setting_key"` +} + +func (q *Queries) DeleteUserSetting(ctx context.Context, arg DeleteUserSettingParams) error { + _, err := q.db.Exec(ctx, deleteUserSetting, arg.UserID, arg.SettingKey) + return err +} + +const getAllFeatureFlags = `-- name: GetAllFeatureFlags :many +SELECT id, flag_key, description, is_enabled, rollout_percentage, conditions, created_at, updated_at FROM feature_flags ORDER BY flag_key +` + +func (q *Queries) GetAllFeatureFlags(ctx context.Context) ([]FeatureFlags, error) { + rows, err := q.db.Query(ctx, getAllFeatureFlags) + if err != nil { + return nil, err + } + defer rows.Close() + items := []FeatureFlags{} + for rows.Next() { + var i FeatureFlags + if err := rows.Scan( + &i.ID, + &i.FlagKey, + &i.Description, + &i.IsEnabled, + &i.RolloutPercentage, + &i.Conditions, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAllSystemSettings = `-- name: GetAllSystemSettings :many +SELECT id, setting_key, setting_value, data_type, description, is_sensitive, created_at, updated_at FROM system_settings +ORDER BY setting_key +` + +func (q *Queries) GetAllSystemSettings(ctx context.Context) ([]SystemSettings, error) { + rows, err := q.db.Query(ctx, getAllSystemSettings) + if err != nil { + return nil, err + } + defer rows.Close() + items := []SystemSettings{} + for rows.Next() { + var i SystemSettings + if err := rows.Scan( + &i.ID, + &i.SettingKey, + &i.SettingValue, + &i.DataType, + &i.Description, + &i.IsSensitive, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getCompanyFeatureFlag = `-- name: GetCompanyFeatureFlag :one +SELECT id, company_id, flag_key, is_enabled, created_at, updated_at FROM company_feature_flags +WHERE company_id = $1 AND flag_key = $2 +` + +type GetCompanyFeatureFlagParams struct { + CompanyID uuid.UUID `json:"company_id"` + FlagKey string `json:"flag_key"` +} + +func (q *Queries) GetCompanyFeatureFlag(ctx context.Context, arg GetCompanyFeatureFlagParams) (CompanyFeatureFlags, error) { + row := q.db.QueryRow(ctx, getCompanyFeatureFlag, arg.CompanyID, arg.FlagKey) + var i CompanyFeatureFlags + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.FlagKey, + &i.IsEnabled, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getCompanyFeatureFlags = `-- name: GetCompanyFeatureFlags :many +SELECT cff.id, cff.company_id, cff.flag_key, cff.is_enabled, cff.created_at, cff.updated_at, ff.description +FROM company_feature_flags cff +JOIN feature_flags ff ON cff.flag_key = ff.flag_key +WHERE cff.company_id = $1 +ORDER BY cff.flag_key +` + +type GetCompanyFeatureFlagsRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + FlagKey string `json:"flag_key"` + IsEnabled bool `json:"is_enabled"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + Description pgtype.Text `json:"description"` +} + +func (q *Queries) GetCompanyFeatureFlags(ctx context.Context, companyID uuid.UUID) ([]GetCompanyFeatureFlagsRow, error) { + rows, err := q.db.Query(ctx, getCompanyFeatureFlags, companyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetCompanyFeatureFlagsRow{} + for rows.Next() { + var i GetCompanyFeatureFlagsRow + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.FlagKey, + &i.IsEnabled, + &i.CreatedAt, + &i.UpdatedAt, + &i.Description, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getCompanySetting = `-- name: GetCompanySetting :one +SELECT id, company_id, setting_key, setting_value, data_type, description, created_at, updated_at FROM company_settings +WHERE company_id = $1 AND setting_key = $2 +` + +type GetCompanySettingParams struct { + CompanyID uuid.UUID `json:"company_id"` + SettingKey string `json:"setting_key"` +} + +func (q *Queries) GetCompanySetting(ctx context.Context, arg GetCompanySettingParams) (CompanySettings, error) { + row := q.db.QueryRow(ctx, getCompanySetting, arg.CompanyID, arg.SettingKey) + var i CompanySettings + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.SettingKey, + &i.SettingValue, + &i.DataType, + &i.Description, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getCompanySettings = `-- name: GetCompanySettings :many +SELECT id, company_id, setting_key, setting_value, data_type, description, created_at, updated_at FROM company_settings +WHERE company_id = $1 +ORDER BY setting_key +` + +func (q *Queries) GetCompanySettings(ctx context.Context, companyID uuid.UUID) ([]CompanySettings, error) { + rows, err := q.db.Query(ctx, getCompanySettings, companyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []CompanySettings{} + for rows.Next() { + var i CompanySettings + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.SettingKey, + &i.SettingValue, + &i.DataType, + &i.Description, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getFeatureFlag = `-- name: GetFeatureFlag :one +SELECT id, flag_key, description, is_enabled, rollout_percentage, conditions, created_at, updated_at FROM feature_flags WHERE flag_key = $1 +` + +func (q *Queries) GetFeatureFlag(ctx context.Context, flagKey string) (FeatureFlags, error) { + row := q.db.QueryRow(ctx, getFeatureFlag, flagKey) + var i FeatureFlags + err := row.Scan( + &i.ID, + &i.FlagKey, + &i.Description, + &i.IsEnabled, + &i.RolloutPercentage, + &i.Conditions, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getPublicSystemSettings = `-- name: GetPublicSystemSettings :many +SELECT setting_key, setting_value, data_type, description +FROM system_settings +WHERE is_sensitive = FALSE +ORDER BY setting_key +` + +type GetPublicSystemSettingsRow struct { + SettingKey string `json:"setting_key"` + SettingValue pgtype.Text `json:"setting_value"` + DataType string `json:"data_type"` + Description pgtype.Text `json:"description"` +} + +func (q *Queries) GetPublicSystemSettings(ctx context.Context) ([]GetPublicSystemSettingsRow, error) { + rows, err := q.db.Query(ctx, getPublicSystemSettings) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetPublicSystemSettingsRow{} + for rows.Next() { + var i GetPublicSystemSettingsRow + if err := rows.Scan( + &i.SettingKey, + &i.SettingValue, + &i.DataType, + &i.Description, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getSystemSetting = `-- name: GetSystemSetting :one +SELECT id, setting_key, setting_value, data_type, description, is_sensitive, created_at, updated_at FROM system_settings +WHERE setting_key = $1 +` + +func (q *Queries) GetSystemSetting(ctx context.Context, settingKey string) (SystemSettings, error) { + row := q.db.QueryRow(ctx, getSystemSetting, settingKey) + var i SystemSettings + err := row.Scan( + &i.ID, + &i.SettingKey, + &i.SettingValue, + &i.DataType, + &i.Description, + &i.IsSensitive, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getUserFeatureFlag = `-- name: GetUserFeatureFlag :one +SELECT id, user_id, flag_key, is_enabled, created_at, updated_at FROM user_feature_flags +WHERE user_id = $1 AND flag_key = $2 +` + +type GetUserFeatureFlagParams struct { + UserID uuid.UUID `json:"user_id"` + FlagKey string `json:"flag_key"` +} + +func (q *Queries) GetUserFeatureFlag(ctx context.Context, arg GetUserFeatureFlagParams) (UserFeatureFlags, error) { + row := q.db.QueryRow(ctx, getUserFeatureFlag, arg.UserID, arg.FlagKey) + var i UserFeatureFlags + err := row.Scan( + &i.ID, + &i.UserID, + &i.FlagKey, + &i.IsEnabled, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getUserFeatureFlags = `-- name: GetUserFeatureFlags :many +SELECT uff.id, uff.user_id, uff.flag_key, uff.is_enabled, uff.created_at, uff.updated_at, ff.description +FROM user_feature_flags uff +JOIN feature_flags ff ON uff.flag_key = ff.flag_key +WHERE uff.user_id = $1 +ORDER BY uff.flag_key +` + +type GetUserFeatureFlagsRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + FlagKey string `json:"flag_key"` + IsEnabled bool `json:"is_enabled"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + Description pgtype.Text `json:"description"` +} + +func (q *Queries) GetUserFeatureFlags(ctx context.Context, userID uuid.UUID) ([]GetUserFeatureFlagsRow, error) { + rows, err := q.db.Query(ctx, getUserFeatureFlags, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetUserFeatureFlagsRow{} + for rows.Next() { + var i GetUserFeatureFlagsRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.FlagKey, + &i.IsEnabled, + &i.CreatedAt, + &i.UpdatedAt, + &i.Description, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserSetting = `-- name: GetUserSetting :one +SELECT id, user_id, setting_key, setting_value, data_type, created_at, updated_at FROM user_settings +WHERE user_id = $1 AND setting_key = $2 +` + +type GetUserSettingParams struct { + UserID uuid.UUID `json:"user_id"` + SettingKey string `json:"setting_key"` +} + +func (q *Queries) GetUserSetting(ctx context.Context, arg GetUserSettingParams) (UserSettings, error) { + row := q.db.QueryRow(ctx, getUserSetting, arg.UserID, arg.SettingKey) + var i UserSettings + err := row.Scan( + &i.ID, + &i.UserID, + &i.SettingKey, + &i.SettingValue, + &i.DataType, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getUserSettings = `-- name: GetUserSettings :many +SELECT id, user_id, setting_key, setting_value, data_type, created_at, updated_at FROM user_settings +WHERE user_id = $1 +ORDER BY setting_key +` + +func (q *Queries) GetUserSettings(ctx context.Context, userID uuid.UUID) ([]UserSettings, error) { + rows, err := q.db.Query(ctx, getUserSettings, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []UserSettings{} + for rows.Next() { + var i UserSettings + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.SettingKey, + &i.SettingValue, + &i.DataType, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateCompanyFeatureFlag = `-- name: UpdateCompanyFeatureFlag :one +UPDATE company_feature_flags SET + is_enabled = $1, + updated_at = NOW() +WHERE company_id = $2 AND flag_key = $3 +RETURNING id, company_id, flag_key, is_enabled, created_at, updated_at +` + +type UpdateCompanyFeatureFlagParams struct { + IsEnabled bool `json:"is_enabled"` + CompanyID uuid.UUID `json:"company_id"` + FlagKey string `json:"flag_key"` +} + +func (q *Queries) UpdateCompanyFeatureFlag(ctx context.Context, arg UpdateCompanyFeatureFlagParams) (CompanyFeatureFlags, error) { + row := q.db.QueryRow(ctx, updateCompanyFeatureFlag, arg.IsEnabled, arg.CompanyID, arg.FlagKey) + var i CompanyFeatureFlags + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.FlagKey, + &i.IsEnabled, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateCompanySetting = `-- name: UpdateCompanySetting :one +UPDATE company_settings SET + setting_value = $1, + data_type = COALESCE($2, data_type), + description = COALESCE($3, description), + updated_at = NOW() +WHERE company_id = $4 AND setting_key = $5 +RETURNING id, company_id, setting_key, setting_value, data_type, description, created_at, updated_at +` + +type UpdateCompanySettingParams struct { + SettingValue pgtype.Text `json:"setting_value"` + DataType string `json:"data_type"` + Description pgtype.Text `json:"description"` + CompanyID uuid.UUID `json:"company_id"` + SettingKey string `json:"setting_key"` +} + +func (q *Queries) UpdateCompanySetting(ctx context.Context, arg UpdateCompanySettingParams) (CompanySettings, error) { + row := q.db.QueryRow(ctx, updateCompanySetting, + arg.SettingValue, + arg.DataType, + arg.Description, + arg.CompanyID, + arg.SettingKey, + ) + var i CompanySettings + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.SettingKey, + &i.SettingValue, + &i.DataType, + &i.Description, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateFeatureFlag = `-- name: UpdateFeatureFlag :one +UPDATE feature_flags SET + description = COALESCE($1, description), + is_enabled = COALESCE($2, is_enabled), + rollout_percentage = COALESCE($3, rollout_percentage), + conditions = COALESCE($4, conditions), + updated_at = NOW() +WHERE flag_key = $5 +RETURNING id, flag_key, description, is_enabled, rollout_percentage, conditions, created_at, updated_at +` + +type UpdateFeatureFlagParams struct { + Description pgtype.Text `json:"description"` + IsEnabled pgtype.Bool `json:"is_enabled"` + RolloutPercentage pgtype.Int4 `json:"rollout_percentage"` + Conditions []byte `json:"conditions"` + FlagKey string `json:"flag_key"` +} + +func (q *Queries) UpdateFeatureFlag(ctx context.Context, arg UpdateFeatureFlagParams) (FeatureFlags, error) { + row := q.db.QueryRow(ctx, updateFeatureFlag, + arg.Description, + arg.IsEnabled, + arg.RolloutPercentage, + arg.Conditions, + arg.FlagKey, + ) + var i FeatureFlags + err := row.Scan( + &i.ID, + &i.FlagKey, + &i.Description, + &i.IsEnabled, + &i.RolloutPercentage, + &i.Conditions, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateSystemSetting = `-- name: UpdateSystemSetting :one +UPDATE system_settings SET + setting_value = $1, + data_type = COALESCE($2, data_type), + description = COALESCE($3, description), + is_sensitive = COALESCE($4, is_sensitive), + updated_at = NOW() +WHERE setting_key = $5 +RETURNING id, setting_key, setting_value, data_type, description, is_sensitive, created_at, updated_at +` + +type UpdateSystemSettingParams struct { + SettingValue pgtype.Text `json:"setting_value"` + DataType string `json:"data_type"` + Description pgtype.Text `json:"description"` + IsSensitive pgtype.Bool `json:"is_sensitive"` + SettingKey string `json:"setting_key"` +} + +func (q *Queries) UpdateSystemSetting(ctx context.Context, arg UpdateSystemSettingParams) (SystemSettings, error) { + row := q.db.QueryRow(ctx, updateSystemSetting, + arg.SettingValue, + arg.DataType, + arg.Description, + arg.IsSensitive, + arg.SettingKey, + ) + var i SystemSettings + err := row.Scan( + &i.ID, + &i.SettingKey, + &i.SettingValue, + &i.DataType, + &i.Description, + &i.IsSensitive, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateUserFeatureFlag = `-- name: UpdateUserFeatureFlag :one +UPDATE user_feature_flags SET + is_enabled = $1, + updated_at = NOW() +WHERE user_id = $2 AND flag_key = $3 +RETURNING id, user_id, flag_key, is_enabled, created_at, updated_at +` + +type UpdateUserFeatureFlagParams struct { + IsEnabled bool `json:"is_enabled"` + UserID uuid.UUID `json:"user_id"` + FlagKey string `json:"flag_key"` +} + +func (q *Queries) UpdateUserFeatureFlag(ctx context.Context, arg UpdateUserFeatureFlagParams) (UserFeatureFlags, error) { + row := q.db.QueryRow(ctx, updateUserFeatureFlag, arg.IsEnabled, arg.UserID, arg.FlagKey) + var i UserFeatureFlags + err := row.Scan( + &i.ID, + &i.UserID, + &i.FlagKey, + &i.IsEnabled, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateUserSetting = `-- name: UpdateUserSetting :one +UPDATE user_settings SET + setting_value = $1, + data_type = COALESCE($2, data_type), + updated_at = NOW() +WHERE user_id = $3 AND setting_key = $4 +RETURNING id, user_id, setting_key, setting_value, data_type, created_at, updated_at +` + +type UpdateUserSettingParams struct { + SettingValue pgtype.Text `json:"setting_value"` + DataType string `json:"data_type"` + UserID uuid.UUID `json:"user_id"` + SettingKey string `json:"setting_key"` +} + +func (q *Queries) UpdateUserSetting(ctx context.Context, arg UpdateUserSettingParams) (UserSettings, error) { + row := q.db.QueryRow(ctx, updateUserSetting, + arg.SettingValue, + arg.DataType, + arg.UserID, + arg.SettingKey, + ) + var i UserSettings + err := row.Scan( + &i.ID, + &i.UserID, + &i.SettingKey, + &i.SettingValue, + &i.DataType, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/db/sqlc/store.go b/db/sqlc/store.go deleted file mode 100644 index 45019bf..0000000 --- a/db/sqlc/store.go +++ /dev/null @@ -1,46 +0,0 @@ -package sqlc - -import ( - "context" - - "github.com/jackc/pgx/v5/pgxpool" -) - -// Store provides all functions to execute DB queries and transactions -type Store interface { - Querier - ExecTx(ctx context.Context, fn func(Queries *Queries) error) error -} - -// SQLStore implements the Store interface -type SQLStore struct { - *Queries - connPool *pgxpool.Pool -} - -// NewStore creates a new store -func NewStore(connPool *pgxpool.Pool) Store { - return &SQLStore{ - Queries: New(connPool), - connPool: connPool, - } -} - -// ExecTx executes a function within a database transaction -func (store *SQLStore) ExecTx(ctx context.Context, fn func(q *Queries) error) error { - tx, err := store.connPool.Begin(ctx) - if err != nil { - return err - } - - q := New(tx) - err = fn(q) - if err != nil { - if rbErr := tx.Rollback(ctx); rbErr != nil { - return rbErr - } - return err - } - - return tx.Commit(ctx) -} diff --git a/db/sqlc/timesheets.sql.go b/db/sqlc/timesheets.sql.go new file mode 100644 index 0000000..d6cfe69 --- /dev/null +++ b/db/sqlc/timesheets.sql.go @@ -0,0 +1,974 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.29.0 +// source: timesheets.sql + +package sqlc + +import ( + "context" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" + "github.com/shopspring/decimal" +) + +const createTimesheet = `-- name: CreateTimesheet :one +INSERT INTO timesheets ( + id, + company_id, + employee_id, + period_id, + status, + total_hours, + billable_hours, + overtime_hours, + hourly_rate, + rate_currency, + total_amount, + submitted_at, + approved_at, + approved_by, + rejection_reason, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + COALESCE($5, 'draft'), + COALESCE($6, 0), + COALESCE($7, 0), + COALESCE($8, 0), + $9, + $10, + COALESCE($11, 0), + $12, + $13, + $14, + $15, + COALESCE($16, NOW()), + COALESCE($17, NOW()) +) RETURNING id, company_id, employee_id, period_id, status, total_hours, billable_hours, overtime_hours, hourly_rate, rate_currency, total_amount, submitted_at, approved_at, approved_by, rejection_reason, created_at, updated_at +` + +type CreateTimesheetParams struct { + ID interface{} `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + EmployeeID uuid.UUID `json:"employee_id"` + PeriodID pgtype.UUID `json:"period_id"` + Status interface{} `json:"status"` + TotalHours interface{} `json:"total_hours"` + BillableHours interface{} `json:"billable_hours"` + OvertimeHours interface{} `json:"overtime_hours"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + RateCurrency pgtype.Text `json:"rate_currency"` + TotalAmount interface{} `json:"total_amount"` + SubmittedAt pgtype.Timestamptz `json:"submitted_at"` + ApprovedAt pgtype.Timestamptz `json:"approved_at"` + ApprovedBy pgtype.UUID `json:"approved_by"` + RejectionReason pgtype.Text `json:"rejection_reason"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateTimesheet(ctx context.Context, arg CreateTimesheetParams) (Timesheets, error) { + row := q.db.QueryRow(ctx, createTimesheet, + arg.ID, + arg.CompanyID, + arg.EmployeeID, + arg.PeriodID, + arg.Status, + arg.TotalHours, + arg.BillableHours, + arg.OvertimeHours, + arg.HourlyRate, + arg.RateCurrency, + arg.TotalAmount, + arg.SubmittedAt, + arg.ApprovedAt, + arg.ApprovedBy, + arg.RejectionReason, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i Timesheets + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.EmployeeID, + &i.PeriodID, + &i.Status, + &i.TotalHours, + &i.BillableHours, + &i.OvertimeHours, + &i.HourlyRate, + &i.RateCurrency, + &i.TotalAmount, + &i.SubmittedAt, + &i.ApprovedAt, + &i.ApprovedBy, + &i.RejectionReason, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createTimesheetEntry = `-- name: CreateTimesheetEntry :one +INSERT INTO timesheet_entries ( + id, + timesheet_id, + date, + start_time, + end_time, + hours, + is_billable, + is_overtime, + project, + task, + description, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + COALESCE($7, TRUE), + COALESCE($8, FALSE), + $9, + $10, + $11, + COALESCE($12, NOW()), + COALESCE($13, NOW()) +) RETURNING id, timesheet_id, date, start_time, end_time, hours, is_billable, is_overtime, project, task, description, created_at, updated_at +` + +type CreateTimesheetEntryParams struct { + ID interface{} `json:"id"` + TimesheetID uuid.UUID `json:"timesheet_id"` + Date pgtype.Date `json:"date"` + StartTime pgtype.Time `json:"start_time"` + EndTime pgtype.Time `json:"end_time"` + Hours decimal.Decimal `json:"hours"` + IsBillable interface{} `json:"is_billable"` + IsOvertime interface{} `json:"is_overtime"` + Project pgtype.Text `json:"project"` + Task pgtype.Text `json:"task"` + Description pgtype.Text `json:"description"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateTimesheetEntry(ctx context.Context, arg CreateTimesheetEntryParams) (TimesheetEntries, error) { + row := q.db.QueryRow(ctx, createTimesheetEntry, + arg.ID, + arg.TimesheetID, + arg.Date, + arg.StartTime, + arg.EndTime, + arg.Hours, + arg.IsBillable, + arg.IsOvertime, + arg.Project, + arg.Task, + arg.Description, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i TimesheetEntries + err := row.Scan( + &i.ID, + &i.TimesheetID, + &i.Date, + &i.StartTime, + &i.EndTime, + &i.Hours, + &i.IsBillable, + &i.IsOvertime, + &i.Project, + &i.Task, + &i.Description, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteTimesheetEntry = `-- name: DeleteTimesheetEntry :exec +DELETE FROM timesheet_entries WHERE id = $1 +` + +func (q *Queries) DeleteTimesheetEntry(ctx context.Context, id uuid.UUID) error { + _, err := q.db.Exec(ctx, deleteTimesheetEntry, id) + return err +} + +const getCompanyTimesheetSummary = `-- name: GetCompanyTimesheetSummary :one +SELECT + COUNT(*) as total_timesheets, + SUM(total_hours) as total_hours, + SUM(billable_hours) as total_billable_hours, + SUM(overtime_hours) as total_overtime_hours, + SUM(total_amount) as total_amount +FROM timesheets +WHERE company_id = $1 + AND ($2::date IS NULL OR created_at >= $2) + AND ($3::date IS NULL OR created_at <= $3) +` + +type GetCompanyTimesheetSummaryParams struct { + CompanyID uuid.UUID `json:"company_id"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` +} + +type GetCompanyTimesheetSummaryRow struct { + TotalTimesheets int64 `json:"total_timesheets"` + TotalHours int64 `json:"total_hours"` + TotalBillableHours int64 `json:"total_billable_hours"` + TotalOvertimeHours int64 `json:"total_overtime_hours"` + TotalAmount int64 `json:"total_amount"` +} + +func (q *Queries) GetCompanyTimesheetSummary(ctx context.Context, arg GetCompanyTimesheetSummaryParams) (GetCompanyTimesheetSummaryRow, error) { + row := q.db.QueryRow(ctx, getCompanyTimesheetSummary, arg.CompanyID, arg.StartDate, arg.EndDate) + var i GetCompanyTimesheetSummaryRow + err := row.Scan( + &i.TotalTimesheets, + &i.TotalHours, + &i.TotalBillableHours, + &i.TotalOvertimeHours, + &i.TotalAmount, + ) + return i, err +} + +const getCompanyTimesheets = `-- name: GetCompanyTimesheets :many +SELECT t.id, t.company_id, t.employee_id, t.period_id, t.status, t.total_hours, t.billable_hours, t.overtime_hours, t.hourly_rate, t.rate_currency, t.total_amount, t.submitted_at, t.approved_at, t.approved_by, t.rejection_reason, t.created_at, t.updated_at, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name, + pp.period_name, pp.start_date, pp.end_date +FROM timesheets t +JOIN company_employees ce ON t.employee_id = ce.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +LEFT JOIN payroll_periods pp ON t.period_id = pp.id +WHERE t.company_id = $1 +ORDER BY t.created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetCompanyTimesheetsParams struct { + CompanyID uuid.UUID `json:"company_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetCompanyTimesheetsRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + EmployeeID uuid.UUID `json:"employee_id"` + PeriodID pgtype.UUID `json:"period_id"` + Status pgtype.Text `json:"status"` + TotalHours pgtype.Numeric `json:"total_hours"` + BillableHours pgtype.Numeric `json:"billable_hours"` + OvertimeHours pgtype.Numeric `json:"overtime_hours"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + RateCurrency pgtype.Text `json:"rate_currency"` + TotalAmount pgtype.Numeric `json:"total_amount"` + SubmittedAt pgtype.Timestamptz `json:"submitted_at"` + ApprovedAt pgtype.Timestamptz `json:"approved_at"` + ApprovedBy pgtype.UUID `json:"approved_by"` + RejectionReason pgtype.Text `json:"rejection_reason"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + EmployeeID_2 pgtype.Text `json:"employee_id_2"` + Position pgtype.Text `json:"position"` + Email pgtype.Text `json:"email"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` + PeriodName pgtype.Text `json:"period_name"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` +} + +func (q *Queries) GetCompanyTimesheets(ctx context.Context, arg GetCompanyTimesheetsParams) ([]GetCompanyTimesheetsRow, error) { + rows, err := q.db.Query(ctx, getCompanyTimesheets, arg.CompanyID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetCompanyTimesheetsRow{} + for rows.Next() { + var i GetCompanyTimesheetsRow + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.EmployeeID, + &i.PeriodID, + &i.Status, + &i.TotalHours, + &i.BillableHours, + &i.OvertimeHours, + &i.HourlyRate, + &i.RateCurrency, + &i.TotalAmount, + &i.SubmittedAt, + &i.ApprovedAt, + &i.ApprovedBy, + &i.RejectionReason, + &i.CreatedAt, + &i.UpdatedAt, + &i.EmployeeID_2, + &i.Position, + &i.Email, + &i.FirstName, + &i.LastName, + &i.PeriodName, + &i.StartDate, + &i.EndDate, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getEmployeeTimesheetSummary = `-- name: GetEmployeeTimesheetSummary :one +SELECT + COUNT(*) as total_timesheets, + SUM(total_hours) as total_hours, + SUM(billable_hours) as total_billable_hours, + SUM(overtime_hours) as total_overtime_hours, + SUM(total_amount) as total_amount +FROM timesheets +WHERE employee_id = $1 + AND ($2::date IS NULL OR created_at >= $2) + AND ($3::date IS NULL OR created_at <= $3) +` + +type GetEmployeeTimesheetSummaryParams struct { + EmployeeID uuid.UUID `json:"employee_id"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` +} + +type GetEmployeeTimesheetSummaryRow struct { + TotalTimesheets int64 `json:"total_timesheets"` + TotalHours int64 `json:"total_hours"` + TotalBillableHours int64 `json:"total_billable_hours"` + TotalOvertimeHours int64 `json:"total_overtime_hours"` + TotalAmount int64 `json:"total_amount"` +} + +func (q *Queries) GetEmployeeTimesheetSummary(ctx context.Context, arg GetEmployeeTimesheetSummaryParams) (GetEmployeeTimesheetSummaryRow, error) { + row := q.db.QueryRow(ctx, getEmployeeTimesheetSummary, arg.EmployeeID, arg.StartDate, arg.EndDate) + var i GetEmployeeTimesheetSummaryRow + err := row.Scan( + &i.TotalTimesheets, + &i.TotalHours, + &i.TotalBillableHours, + &i.TotalOvertimeHours, + &i.TotalAmount, + ) + return i, err +} + +const getTimesheetByID = `-- name: GetTimesheetByID :one +SELECT t.id, t.company_id, t.employee_id, t.period_id, t.status, t.total_hours, t.billable_hours, t.overtime_hours, t.hourly_rate, t.rate_currency, t.total_amount, t.submitted_at, t.approved_at, t.approved_by, t.rejection_reason, t.created_at, t.updated_at, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name, + pp.period_name, pp.start_date, pp.end_date +FROM timesheets t +JOIN company_employees ce ON t.employee_id = ce.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +LEFT JOIN payroll_periods pp ON t.period_id = pp.id +WHERE t.id = $1 +` + +type GetTimesheetByIDRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + EmployeeID uuid.UUID `json:"employee_id"` + PeriodID pgtype.UUID `json:"period_id"` + Status pgtype.Text `json:"status"` + TotalHours pgtype.Numeric `json:"total_hours"` + BillableHours pgtype.Numeric `json:"billable_hours"` + OvertimeHours pgtype.Numeric `json:"overtime_hours"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + RateCurrency pgtype.Text `json:"rate_currency"` + TotalAmount pgtype.Numeric `json:"total_amount"` + SubmittedAt pgtype.Timestamptz `json:"submitted_at"` + ApprovedAt pgtype.Timestamptz `json:"approved_at"` + ApprovedBy pgtype.UUID `json:"approved_by"` + RejectionReason pgtype.Text `json:"rejection_reason"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + EmployeeID_2 pgtype.Text `json:"employee_id_2"` + Position pgtype.Text `json:"position"` + Email pgtype.Text `json:"email"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` + PeriodName pgtype.Text `json:"period_name"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` +} + +func (q *Queries) GetTimesheetByID(ctx context.Context, id uuid.UUID) (GetTimesheetByIDRow, error) { + row := q.db.QueryRow(ctx, getTimesheetByID, id) + var i GetTimesheetByIDRow + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.EmployeeID, + &i.PeriodID, + &i.Status, + &i.TotalHours, + &i.BillableHours, + &i.OvertimeHours, + &i.HourlyRate, + &i.RateCurrency, + &i.TotalAmount, + &i.SubmittedAt, + &i.ApprovedAt, + &i.ApprovedBy, + &i.RejectionReason, + &i.CreatedAt, + &i.UpdatedAt, + &i.EmployeeID_2, + &i.Position, + &i.Email, + &i.FirstName, + &i.LastName, + &i.PeriodName, + &i.StartDate, + &i.EndDate, + ) + return i, err +} + +const getTimesheetEntries = `-- name: GetTimesheetEntries :many +SELECT id, timesheet_id, date, start_time, end_time, hours, is_billable, is_overtime, project, task, description, created_at, updated_at FROM timesheet_entries +WHERE timesheet_id = $1 +ORDER BY date, start_time +` + +func (q *Queries) GetTimesheetEntries(ctx context.Context, timesheetID uuid.UUID) ([]TimesheetEntries, error) { + rows, err := q.db.Query(ctx, getTimesheetEntries, timesheetID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []TimesheetEntries{} + for rows.Next() { + var i TimesheetEntries + if err := rows.Scan( + &i.ID, + &i.TimesheetID, + &i.Date, + &i.StartTime, + &i.EndTime, + &i.Hours, + &i.IsBillable, + &i.IsOvertime, + &i.Project, + &i.Task, + &i.Description, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTimesheetEntriesByDate = `-- name: GetTimesheetEntriesByDate :many +SELECT id, timesheet_id, date, start_time, end_time, hours, is_billable, is_overtime, project, task, description, created_at, updated_at FROM timesheet_entries +WHERE timesheet_id = $1 + AND date >= $2 + AND date <= $3 +ORDER BY date, start_time +` + +type GetTimesheetEntriesByDateParams struct { + TimesheetID uuid.UUID `json:"timesheet_id"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` +} + +func (q *Queries) GetTimesheetEntriesByDate(ctx context.Context, arg GetTimesheetEntriesByDateParams) ([]TimesheetEntries, error) { + rows, err := q.db.Query(ctx, getTimesheetEntriesByDate, arg.TimesheetID, arg.StartDate, arg.EndDate) + if err != nil { + return nil, err + } + defer rows.Close() + items := []TimesheetEntries{} + for rows.Next() { + var i TimesheetEntries + if err := rows.Scan( + &i.ID, + &i.TimesheetID, + &i.Date, + &i.StartTime, + &i.EndTime, + &i.Hours, + &i.IsBillable, + &i.IsOvertime, + &i.Project, + &i.Task, + &i.Description, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTimesheetProjects = `-- name: GetTimesheetProjects :many +SELECT DISTINCT project +FROM timesheet_entries +WHERE timesheet_id IN ( + SELECT id FROM timesheets WHERE company_id = $1 +) +AND project IS NOT NULL +ORDER BY project +` + +func (q *Queries) GetTimesheetProjects(ctx context.Context, companyID uuid.UUID) ([]pgtype.Text, error) { + rows, err := q.db.Query(ctx, getTimesheetProjects, companyID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []pgtype.Text{} + for rows.Next() { + var project pgtype.Text + if err := rows.Scan(&project); err != nil { + return nil, err + } + items = append(items, project) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTimesheetsByEmployee = `-- name: GetTimesheetsByEmployee :many +SELECT t.id, t.company_id, t.employee_id, t.period_id, t.status, t.total_hours, t.billable_hours, t.overtime_hours, t.hourly_rate, t.rate_currency, t.total_amount, t.submitted_at, t.approved_at, t.approved_by, t.rejection_reason, t.created_at, t.updated_at, + pp.period_name, pp.start_date, pp.end_date +FROM timesheets t +LEFT JOIN payroll_periods pp ON t.period_id = pp.id +WHERE t.employee_id = $1 +ORDER BY t.created_at DESC +` + +type GetTimesheetsByEmployeeRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + EmployeeID uuid.UUID `json:"employee_id"` + PeriodID pgtype.UUID `json:"period_id"` + Status pgtype.Text `json:"status"` + TotalHours pgtype.Numeric `json:"total_hours"` + BillableHours pgtype.Numeric `json:"billable_hours"` + OvertimeHours pgtype.Numeric `json:"overtime_hours"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + RateCurrency pgtype.Text `json:"rate_currency"` + TotalAmount pgtype.Numeric `json:"total_amount"` + SubmittedAt pgtype.Timestamptz `json:"submitted_at"` + ApprovedAt pgtype.Timestamptz `json:"approved_at"` + ApprovedBy pgtype.UUID `json:"approved_by"` + RejectionReason pgtype.Text `json:"rejection_reason"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + PeriodName pgtype.Text `json:"period_name"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` +} + +func (q *Queries) GetTimesheetsByEmployee(ctx context.Context, employeeID uuid.UUID) ([]GetTimesheetsByEmployeeRow, error) { + rows, err := q.db.Query(ctx, getTimesheetsByEmployee, employeeID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetTimesheetsByEmployeeRow{} + for rows.Next() { + var i GetTimesheetsByEmployeeRow + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.EmployeeID, + &i.PeriodID, + &i.Status, + &i.TotalHours, + &i.BillableHours, + &i.OvertimeHours, + &i.HourlyRate, + &i.RateCurrency, + &i.TotalAmount, + &i.SubmittedAt, + &i.ApprovedAt, + &i.ApprovedBy, + &i.RejectionReason, + &i.CreatedAt, + &i.UpdatedAt, + &i.PeriodName, + &i.StartDate, + &i.EndDate, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTimesheetsByStatus = `-- name: GetTimesheetsByStatus :many +SELECT t.id, t.company_id, t.employee_id, t.period_id, t.status, t.total_hours, t.billable_hours, t.overtime_hours, t.hourly_rate, t.rate_currency, t.total_amount, t.submitted_at, t.approved_at, t.approved_by, t.rejection_reason, t.created_at, t.updated_at, + ce.employee_id, ce.position, + u.email, + COALESCE(csp.first_name, pu.first_name) as first_name, + COALESCE(csp.last_name, pu.last_name) as last_name, + pp.period_name, pp.start_date, pp.end_date +FROM timesheets t +JOIN company_employees ce ON t.employee_id = ce.id +LEFT JOIN users u ON ce.user_id = u.id +LEFT JOIN company_staff_profiles csp ON ce.user_id = csp.id +LEFT JOIN personal_users pu ON u.id = pu.id +LEFT JOIN payroll_periods pp ON t.period_id = pp.id +WHERE t.company_id = $1 AND t.status = $2 +ORDER BY t.created_at DESC +` + +type GetTimesheetsByStatusParams struct { + CompanyID uuid.UUID `json:"company_id"` + Status pgtype.Text `json:"status"` +} + +type GetTimesheetsByStatusRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + EmployeeID uuid.UUID `json:"employee_id"` + PeriodID pgtype.UUID `json:"period_id"` + Status pgtype.Text `json:"status"` + TotalHours pgtype.Numeric `json:"total_hours"` + BillableHours pgtype.Numeric `json:"billable_hours"` + OvertimeHours pgtype.Numeric `json:"overtime_hours"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + RateCurrency pgtype.Text `json:"rate_currency"` + TotalAmount pgtype.Numeric `json:"total_amount"` + SubmittedAt pgtype.Timestamptz `json:"submitted_at"` + ApprovedAt pgtype.Timestamptz `json:"approved_at"` + ApprovedBy pgtype.UUID `json:"approved_by"` + RejectionReason pgtype.Text `json:"rejection_reason"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + EmployeeID_2 pgtype.Text `json:"employee_id_2"` + Position pgtype.Text `json:"position"` + Email pgtype.Text `json:"email"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` + PeriodName pgtype.Text `json:"period_name"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` +} + +func (q *Queries) GetTimesheetsByStatus(ctx context.Context, arg GetTimesheetsByStatusParams) ([]GetTimesheetsByStatusRow, error) { + rows, err := q.db.Query(ctx, getTimesheetsByStatus, arg.CompanyID, arg.Status) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetTimesheetsByStatusRow{} + for rows.Next() { + var i GetTimesheetsByStatusRow + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.EmployeeID, + &i.PeriodID, + &i.Status, + &i.TotalHours, + &i.BillableHours, + &i.OvertimeHours, + &i.HourlyRate, + &i.RateCurrency, + &i.TotalAmount, + &i.SubmittedAt, + &i.ApprovedAt, + &i.ApprovedBy, + &i.RejectionReason, + &i.CreatedAt, + &i.UpdatedAt, + &i.EmployeeID_2, + &i.Position, + &i.Email, + &i.FirstName, + &i.LastName, + &i.PeriodName, + &i.StartDate, + &i.EndDate, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserTimesheets = `-- name: GetUserTimesheets :many +SELECT t.id, t.company_id, t.employee_id, t.period_id, t.status, t.total_hours, t.billable_hours, t.overtime_hours, t.hourly_rate, t.rate_currency, t.total_amount, t.submitted_at, t.approved_at, t.approved_by, t.rejection_reason, t.created_at, t.updated_at, + ce.employee_id, + c.company_name, + pp.period_name, pp.start_date, pp.end_date +FROM timesheets t +JOIN company_employees ce ON t.employee_id = ce.id +JOIN companies c ON t.company_id = c.id +LEFT JOIN payroll_periods pp ON t.period_id = pp.id +WHERE ce.user_id = $1 +ORDER BY t.created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetUserTimesheetsParams struct { + UserID pgtype.UUID `json:"user_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetUserTimesheetsRow struct { + ID uuid.UUID `json:"id"` + CompanyID uuid.UUID `json:"company_id"` + EmployeeID uuid.UUID `json:"employee_id"` + PeriodID pgtype.UUID `json:"period_id"` + Status pgtype.Text `json:"status"` + TotalHours pgtype.Numeric `json:"total_hours"` + BillableHours pgtype.Numeric `json:"billable_hours"` + OvertimeHours pgtype.Numeric `json:"overtime_hours"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + RateCurrency pgtype.Text `json:"rate_currency"` + TotalAmount pgtype.Numeric `json:"total_amount"` + SubmittedAt pgtype.Timestamptz `json:"submitted_at"` + ApprovedAt pgtype.Timestamptz `json:"approved_at"` + ApprovedBy pgtype.UUID `json:"approved_by"` + RejectionReason pgtype.Text `json:"rejection_reason"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + EmployeeID_2 pgtype.Text `json:"employee_id_2"` + CompanyName string `json:"company_name"` + PeriodName pgtype.Text `json:"period_name"` + StartDate pgtype.Date `json:"start_date"` + EndDate pgtype.Date `json:"end_date"` +} + +func (q *Queries) GetUserTimesheets(ctx context.Context, arg GetUserTimesheetsParams) ([]GetUserTimesheetsRow, error) { + rows, err := q.db.Query(ctx, getUserTimesheets, arg.UserID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetUserTimesheetsRow{} + for rows.Next() { + var i GetUserTimesheetsRow + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.EmployeeID, + &i.PeriodID, + &i.Status, + &i.TotalHours, + &i.BillableHours, + &i.OvertimeHours, + &i.HourlyRate, + &i.RateCurrency, + &i.TotalAmount, + &i.SubmittedAt, + &i.ApprovedAt, + &i.ApprovedBy, + &i.RejectionReason, + &i.CreatedAt, + &i.UpdatedAt, + &i.EmployeeID_2, + &i.CompanyName, + &i.PeriodName, + &i.StartDate, + &i.EndDate, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateTimesheet = `-- name: UpdateTimesheet :one +UPDATE timesheets SET + period_id = COALESCE($1, period_id), + status = COALESCE($2, status), + total_hours = COALESCE($3, total_hours), + billable_hours = COALESCE($4, billable_hours), + overtime_hours = COALESCE($5, overtime_hours), + hourly_rate = COALESCE($6, hourly_rate), + rate_currency = COALESCE($7, rate_currency), + total_amount = COALESCE($8, total_amount), + submitted_at = COALESCE($9, submitted_at), + approved_at = COALESCE($10, approved_at), + approved_by = COALESCE($11, approved_by), + rejection_reason = COALESCE($12, rejection_reason), + updated_at = NOW() +WHERE id = $13 +RETURNING id, company_id, employee_id, period_id, status, total_hours, billable_hours, overtime_hours, hourly_rate, rate_currency, total_amount, submitted_at, approved_at, approved_by, rejection_reason, created_at, updated_at +` + +type UpdateTimesheetParams struct { + PeriodID pgtype.UUID `json:"period_id"` + Status pgtype.Text `json:"status"` + TotalHours pgtype.Numeric `json:"total_hours"` + BillableHours pgtype.Numeric `json:"billable_hours"` + OvertimeHours pgtype.Numeric `json:"overtime_hours"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + RateCurrency pgtype.Text `json:"rate_currency"` + TotalAmount pgtype.Numeric `json:"total_amount"` + SubmittedAt pgtype.Timestamptz `json:"submitted_at"` + ApprovedAt pgtype.Timestamptz `json:"approved_at"` + ApprovedBy pgtype.UUID `json:"approved_by"` + RejectionReason pgtype.Text `json:"rejection_reason"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdateTimesheet(ctx context.Context, arg UpdateTimesheetParams) (Timesheets, error) { + row := q.db.QueryRow(ctx, updateTimesheet, + arg.PeriodID, + arg.Status, + arg.TotalHours, + arg.BillableHours, + arg.OvertimeHours, + arg.HourlyRate, + arg.RateCurrency, + arg.TotalAmount, + arg.SubmittedAt, + arg.ApprovedAt, + arg.ApprovedBy, + arg.RejectionReason, + arg.ID, + ) + var i Timesheets + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.EmployeeID, + &i.PeriodID, + &i.Status, + &i.TotalHours, + &i.BillableHours, + &i.OvertimeHours, + &i.HourlyRate, + &i.RateCurrency, + &i.TotalAmount, + &i.SubmittedAt, + &i.ApprovedAt, + &i.ApprovedBy, + &i.RejectionReason, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateTimesheetEntry = `-- name: UpdateTimesheetEntry :one +UPDATE timesheet_entries SET + date = COALESCE($1, date), + start_time = COALESCE($2, start_time), + end_time = COALESCE($3, end_time), + hours = COALESCE($4, hours), + is_billable = COALESCE($5, is_billable), + is_overtime = COALESCE($6, is_overtime), + project = COALESCE($7, project), + task = COALESCE($8, task), + description = COALESCE($9, description), + updated_at = NOW() +WHERE id = $10 +RETURNING id, timesheet_id, date, start_time, end_time, hours, is_billable, is_overtime, project, task, description, created_at, updated_at +` + +type UpdateTimesheetEntryParams struct { + Date pgtype.Date `json:"date"` + StartTime pgtype.Time `json:"start_time"` + EndTime pgtype.Time `json:"end_time"` + Hours decimal.Decimal `json:"hours"` + IsBillable pgtype.Bool `json:"is_billable"` + IsOvertime pgtype.Bool `json:"is_overtime"` + Project pgtype.Text `json:"project"` + Task pgtype.Text `json:"task"` + Description pgtype.Text `json:"description"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdateTimesheetEntry(ctx context.Context, arg UpdateTimesheetEntryParams) (TimesheetEntries, error) { + row := q.db.QueryRow(ctx, updateTimesheetEntry, + arg.Date, + arg.StartTime, + arg.EndTime, + arg.Hours, + arg.IsBillable, + arg.IsOvertime, + arg.Project, + arg.Task, + arg.Description, + arg.ID, + ) + var i TimesheetEntries + err := row.Scan( + &i.ID, + &i.TimesheetID, + &i.Date, + &i.StartTime, + &i.EndTime, + &i.Hours, + &i.IsBillable, + &i.IsOvertime, + &i.Project, + &i.Task, + &i.Description, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/db/sqlc/transactions.sql.go b/db/sqlc/transactions.sql.go index a1f109d..23a2681 100644 --- a/db/sqlc/transactions.sql.go +++ b/db/sqlc/transactions.sql.go @@ -7,108 +7,823 @@ package sqlc import ( "context" + "time" "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" + "github.com/shopspring/decimal" ) -const deleteTransaction = `-- name: DeleteTransaction :exec -DELETE FROM transactions -WHERE id = $1 +const createExchangeRate = `-- name: CreateExchangeRate :one +INSERT INTO exchange_rates ( + id, + base_currency, + quote_currency, + rate, + source, + timestamp, + created_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + COALESCE($7, NOW()) +) RETURNING id, base_currency, quote_currency, rate, source, timestamp, created_at ` -// Permanently deletes a transaction record -func (q *Queries) DeleteTransaction(ctx context.Context, id uuid.UUID) error { - _, err := q.db.Exec(ctx, deleteTransaction, id) - return err +type CreateExchangeRateParams struct { + ID interface{} `json:"id"` + BaseCurrency string `json:"base_currency"` + QuoteCurrency string `json:"quote_currency"` + Rate decimal.Decimal `json:"rate"` + Source string `json:"source"` + Timestamp time.Time `json:"timestamp"` + CreatedAt interface{} `json:"created_at"` } -const deleteTransactionsByUserID = `-- name: DeleteTransactionsByUserID :exec -DELETE FROM transactions -WHERE user_id = $1 +func (q *Queries) CreateExchangeRate(ctx context.Context, arg CreateExchangeRateParams) (ExchangeRates, error) { + row := q.db.QueryRow(ctx, createExchangeRate, + arg.ID, + arg.BaseCurrency, + arg.QuoteCurrency, + arg.Rate, + arg.Source, + arg.Timestamp, + arg.CreatedAt, + ) + var i ExchangeRates + err := row.Scan( + &i.ID, + &i.BaseCurrency, + &i.QuoteCurrency, + &i.Rate, + &i.Source, + &i.Timestamp, + &i.CreatedAt, + ) + return i, err +} + +const createFiatTransaction = `-- name: CreateFiatTransaction :one +INSERT INTO fiat_transactions ( + id, + bank_account_id, + transaction_reference, + transaction_type, + amount, + currency, + status, + payment_provider, + payment_method, + provider_reference, + provider_fee, + reference_type, + reference_id, + metadata, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + COALESCE($7, 'pending'), + $8, + $9, + $10, + COALESCE($11, 0), + $12, + $13, + $14, + COALESCE($15, NOW()), + COALESCE($16, NOW()) +) RETURNING id, bank_account_id, transaction_reference, transaction_type, amount, currency, status, payment_provider, payment_method, provider_reference, provider_fee, reference_type, reference_id, metadata, created_at, updated_at ` -// Deletes all transactions for a specific user -func (q *Queries) DeleteTransactionsByUserID(ctx context.Context, userID uuid.UUID) error { - _, err := q.db.Exec(ctx, deleteTransactionsByUserID, userID) - return err +type CreateFiatTransactionParams struct { + ID interface{} `json:"id"` + BankAccountID uuid.UUID `json:"bank_account_id"` + TransactionReference string `json:"transaction_reference"` + TransactionType string `json:"transaction_type"` + Amount decimal.Decimal `json:"amount"` + Currency string `json:"currency"` + Status interface{} `json:"status"` + PaymentProvider pgtype.Text `json:"payment_provider"` + PaymentMethod pgtype.Text `json:"payment_method"` + ProviderReference pgtype.Text `json:"provider_reference"` + ProviderFee interface{} `json:"provider_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + Metadata []byte `json:"metadata"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` } -const getTransactionByID = `-- name: GetTransactionByID :one -SELECT id, user_id, tx_hash, transaction_pin_hash, status, created_at, updated_at FROM transactions -WHERE id = $1 -LIMIT 1 +func (q *Queries) CreateFiatTransaction(ctx context.Context, arg CreateFiatTransactionParams) (FiatTransactions, error) { + row := q.db.QueryRow(ctx, createFiatTransaction, + arg.ID, + arg.BankAccountID, + arg.TransactionReference, + arg.TransactionType, + arg.Amount, + arg.Currency, + arg.Status, + arg.PaymentProvider, + arg.PaymentMethod, + arg.ProviderReference, + arg.ProviderFee, + arg.ReferenceType, + arg.ReferenceID, + arg.Metadata, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i FiatTransactions + err := row.Scan( + &i.ID, + &i.BankAccountID, + &i.TransactionReference, + &i.TransactionType, + &i.Amount, + &i.Currency, + &i.Status, + &i.PaymentProvider, + &i.PaymentMethod, + &i.ProviderReference, + &i.ProviderFee, + &i.ReferenceType, + &i.ReferenceID, + &i.Metadata, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createWalletTransaction = `-- name: CreateWalletTransaction :one +INSERT INTO wallet_transactions ( + id, + wallet_address, + transaction_hash, + chain_id, + block_number, + from_address, + to_address, + token_address, + token_symbol, + amount, + transaction_type, + transaction_status, + gas_price, + gas_used, + transaction_fee, + reference_type, + reference_id, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + $7, + $8, + $9, + $10, + $11, + COALESCE($12, 'pending'), + $13, + $14, + $15, + $16, + $17, + COALESCE($18, NOW()), + COALESCE($19, NOW()) +) RETURNING id, wallet_address, transaction_hash, chain_id, block_number, from_address, to_address, token_address, token_symbol, amount, transaction_type, transaction_status, gas_price, gas_used, transaction_fee, reference_type, reference_id, created_at, updated_at ` -// Retrieves a single transaction by its ID -func (q *Queries) GetTransactionByID(ctx context.Context, id uuid.UUID) (Transactions, error) { - row := q.db.QueryRow(ctx, getTransactionByID, id) - var i Transactions +type CreateWalletTransactionParams struct { + ID interface{} `json:"id"` + WalletAddress string `json:"wallet_address"` + TransactionHash string `json:"transaction_hash"` + ChainID int32 `json:"chain_id"` + BlockNumber pgtype.Int8 `json:"block_number"` + FromAddress string `json:"from_address"` + ToAddress string `json:"to_address"` + TokenAddress pgtype.Text `json:"token_address"` + TokenSymbol pgtype.Text `json:"token_symbol"` + Amount decimal.Decimal `json:"amount"` + TransactionType string `json:"transaction_type"` + TransactionStatus interface{} `json:"transaction_status"` + GasPrice pgtype.Numeric `json:"gas_price"` + GasUsed pgtype.Int8 `json:"gas_used"` + TransactionFee pgtype.Numeric `json:"transaction_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateWalletTransaction(ctx context.Context, arg CreateWalletTransactionParams) (WalletTransactions, error) { + row := q.db.QueryRow(ctx, createWalletTransaction, + arg.ID, + arg.WalletAddress, + arg.TransactionHash, + arg.ChainID, + arg.BlockNumber, + arg.FromAddress, + arg.ToAddress, + arg.TokenAddress, + arg.TokenSymbol, + arg.Amount, + arg.TransactionType, + arg.TransactionStatus, + arg.GasPrice, + arg.GasUsed, + arg.TransactionFee, + arg.ReferenceType, + arg.ReferenceID, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i WalletTransactions err := row.Scan( &i.ID, - &i.UserID, - &i.TxHash, - &i.TransactionPinHash, - &i.Status, + &i.WalletAddress, + &i.TransactionHash, + &i.ChainID, + &i.BlockNumber, + &i.FromAddress, + &i.ToAddress, + &i.TokenAddress, + &i.TokenSymbol, + &i.Amount, + &i.TransactionType, + &i.TransactionStatus, + &i.GasPrice, + &i.GasUsed, + &i.TransactionFee, + &i.ReferenceType, + &i.ReferenceID, &i.CreatedAt, &i.UpdatedAt, ) return i, err } -const getTransactionByTxHash = `-- name: GetTransactionByTxHash :one -SELECT id, user_id, tx_hash, transaction_pin_hash, status, created_at, updated_at FROM transactions -WHERE tx_hash = $1 -LIMIT 1 +const getAllLatestExchangeRates = `-- name: GetAllLatestExchangeRates :many +SELECT DISTINCT ON (base_currency, quote_currency) id, base_currency, quote_currency, rate, source, timestamp, created_at +FROM exchange_rates +ORDER BY base_currency, quote_currency, timestamp DESC +` + +func (q *Queries) GetAllLatestExchangeRates(ctx context.Context) ([]ExchangeRates, error) { + rows, err := q.db.Query(ctx, getAllLatestExchangeRates) + if err != nil { + return nil, err + } + defer rows.Close() + items := []ExchangeRates{} + for rows.Next() { + var i ExchangeRates + if err := rows.Scan( + &i.ID, + &i.BaseCurrency, + &i.QuoteCurrency, + &i.Rate, + &i.Source, + &i.Timestamp, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getCompanyFiatTransactions = `-- name: GetCompanyFiatTransactions :many +SELECT ft.id, ft.bank_account_id, ft.transaction_reference, ft.transaction_type, ft.amount, ft.currency, ft.status, ft.payment_provider, ft.payment_method, ft.provider_reference, ft.provider_fee, ft.reference_type, ft.reference_id, ft.metadata, ft.created_at, ft.updated_at, ba.account_holder_name, ba.bank_name +FROM fiat_transactions ft +JOIN bank_accounts ba ON ft.bank_account_id = ba.id +WHERE ba.company_id = $1 +ORDER BY ft.created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetCompanyFiatTransactionsParams struct { + CompanyID pgtype.UUID `json:"company_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetCompanyFiatTransactionsRow struct { + ID uuid.UUID `json:"id"` + BankAccountID uuid.UUID `json:"bank_account_id"` + TransactionReference string `json:"transaction_reference"` + TransactionType string `json:"transaction_type"` + Amount decimal.Decimal `json:"amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentProvider pgtype.Text `json:"payment_provider"` + PaymentMethod pgtype.Text `json:"payment_method"` + ProviderReference pgtype.Text `json:"provider_reference"` + ProviderFee pgtype.Numeric `json:"provider_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + Metadata []byte `json:"metadata"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + AccountHolderName string `json:"account_holder_name"` + BankName string `json:"bank_name"` +} + +func (q *Queries) GetCompanyFiatTransactions(ctx context.Context, arg GetCompanyFiatTransactionsParams) ([]GetCompanyFiatTransactionsRow, error) { + rows, err := q.db.Query(ctx, getCompanyFiatTransactions, arg.CompanyID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetCompanyFiatTransactionsRow{} + for rows.Next() { + var i GetCompanyFiatTransactionsRow + if err := rows.Scan( + &i.ID, + &i.BankAccountID, + &i.TransactionReference, + &i.TransactionType, + &i.Amount, + &i.Currency, + &i.Status, + &i.PaymentProvider, + &i.PaymentMethod, + &i.ProviderReference, + &i.ProviderFee, + &i.ReferenceType, + &i.ReferenceID, + &i.Metadata, + &i.CreatedAt, + &i.UpdatedAt, + &i.AccountHolderName, + &i.BankName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getCompanyTransactions = `-- name: GetCompanyTransactions :many +SELECT wt.id, wt.wallet_address, wt.transaction_hash, wt.chain_id, wt.block_number, wt.from_address, wt.to_address, wt.token_address, wt.token_symbol, wt.amount, wt.transaction_type, wt.transaction_status, wt.gas_price, wt.gas_used, wt.transaction_fee, wt.reference_type, wt.reference_id, wt.created_at, wt.updated_at, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +JOIN company_wallets cw ON wt.wallet_address = cw.wallet_address AND wt.chain_id = cw.chain_id +WHERE cw.company_id = $1 +ORDER BY wt.created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetCompanyTransactionsParams struct { + CompanyID uuid.UUID `json:"company_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetCompanyTransactionsRow struct { + ID uuid.UUID `json:"id"` + WalletAddress string `json:"wallet_address"` + TransactionHash string `json:"transaction_hash"` + ChainID int32 `json:"chain_id"` + BlockNumber pgtype.Int8 `json:"block_number"` + FromAddress string `json:"from_address"` + ToAddress string `json:"to_address"` + TokenAddress pgtype.Text `json:"token_address"` + TokenSymbol pgtype.Text `json:"token_symbol"` + Amount decimal.Decimal `json:"amount"` + TransactionType string `json:"transaction_type"` + TransactionStatus pgtype.Text `json:"transaction_status"` + GasPrice pgtype.Numeric `json:"gas_price"` + GasUsed pgtype.Int8 `json:"gas_used"` + TransactionFee pgtype.Numeric `json:"transaction_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + NetworkName string `json:"network_name"` +} + +func (q *Queries) GetCompanyTransactions(ctx context.Context, arg GetCompanyTransactionsParams) ([]GetCompanyTransactionsRow, error) { + rows, err := q.db.Query(ctx, getCompanyTransactions, arg.CompanyID, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetCompanyTransactionsRow{} + for rows.Next() { + var i GetCompanyTransactionsRow + if err := rows.Scan( + &i.ID, + &i.WalletAddress, + &i.TransactionHash, + &i.ChainID, + &i.BlockNumber, + &i.FromAddress, + &i.ToAddress, + &i.TokenAddress, + &i.TokenSymbol, + &i.Amount, + &i.TransactionType, + &i.TransactionStatus, + &i.GasPrice, + &i.GasUsed, + &i.TransactionFee, + &i.ReferenceType, + &i.ReferenceID, + &i.CreatedAt, + &i.UpdatedAt, + &i.NetworkName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getExchangeRateHistory = `-- name: GetExchangeRateHistory :many +SELECT id, base_currency, quote_currency, rate, source, timestamp, created_at FROM exchange_rates +WHERE base_currency = $1 + AND quote_currency = $2 + AND timestamp >= $3 + AND timestamp <= $4 +ORDER BY timestamp DESC +` + +type GetExchangeRateHistoryParams struct { + BaseCurrency string `json:"base_currency"` + QuoteCurrency string `json:"quote_currency"` + StartTime time.Time `json:"start_time"` + EndTime time.Time `json:"end_time"` +} + +func (q *Queries) GetExchangeRateHistory(ctx context.Context, arg GetExchangeRateHistoryParams) ([]ExchangeRates, error) { + rows, err := q.db.Query(ctx, getExchangeRateHistory, + arg.BaseCurrency, + arg.QuoteCurrency, + arg.StartTime, + arg.EndTime, + ) + if err != nil { + return nil, err + } + defer rows.Close() + items := []ExchangeRates{} + for rows.Next() { + var i ExchangeRates + if err := rows.Scan( + &i.ID, + &i.BaseCurrency, + &i.QuoteCurrency, + &i.Rate, + &i.Source, + &i.Timestamp, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getFiatTransactionByReference = `-- name: GetFiatTransactionByReference :one +SELECT ft.id, ft.bank_account_id, ft.transaction_reference, ft.transaction_type, ft.amount, ft.currency, ft.status, ft.payment_provider, ft.payment_method, ft.provider_reference, ft.provider_fee, ft.reference_type, ft.reference_id, ft.metadata, ft.created_at, ft.updated_at, ba.account_holder_name, ba.bank_name +FROM fiat_transactions ft +JOIN bank_accounts ba ON ft.bank_account_id = ba.id +WHERE ft.transaction_reference = $1 ` -// Retrieves a single transaction by its transaction hash -func (q *Queries) GetTransactionByTxHash(ctx context.Context, txHash string) (Transactions, error) { - row := q.db.QueryRow(ctx, getTransactionByTxHash, txHash) - var i Transactions +type GetFiatTransactionByReferenceRow struct { + ID uuid.UUID `json:"id"` + BankAccountID uuid.UUID `json:"bank_account_id"` + TransactionReference string `json:"transaction_reference"` + TransactionType string `json:"transaction_type"` + Amount decimal.Decimal `json:"amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentProvider pgtype.Text `json:"payment_provider"` + PaymentMethod pgtype.Text `json:"payment_method"` + ProviderReference pgtype.Text `json:"provider_reference"` + ProviderFee pgtype.Numeric `json:"provider_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + Metadata []byte `json:"metadata"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + AccountHolderName string `json:"account_holder_name"` + BankName string `json:"bank_name"` +} + +func (q *Queries) GetFiatTransactionByReference(ctx context.Context, transactionReference string) (GetFiatTransactionByReferenceRow, error) { + row := q.db.QueryRow(ctx, getFiatTransactionByReference, transactionReference) + var i GetFiatTransactionByReferenceRow err := row.Scan( &i.ID, - &i.UserID, - &i.TxHash, - &i.TransactionPinHash, + &i.BankAccountID, + &i.TransactionReference, + &i.TransactionType, + &i.Amount, + &i.Currency, &i.Status, + &i.PaymentProvider, + &i.PaymentMethod, + &i.ProviderReference, + &i.ProviderFee, + &i.ReferenceType, + &i.ReferenceID, + &i.Metadata, &i.CreatedAt, &i.UpdatedAt, + &i.AccountHolderName, + &i.BankName, ) return i, err } -const getTransactionsByStatus = `-- name: GetTransactionsByStatus :many -SELECT id, user_id, tx_hash, transaction_pin_hash, status, created_at, updated_at FROM transactions -WHERE status = $1 -ORDER BY created_at DESC -LIMIT $2 -OFFSET $3 +const getFiatTransactionsByBankAccount = `-- name: GetFiatTransactionsByBankAccount :many +SELECT ft.id, ft.bank_account_id, ft.transaction_reference, ft.transaction_type, ft.amount, ft.currency, ft.status, ft.payment_provider, ft.payment_method, ft.provider_reference, ft.provider_fee, ft.reference_type, ft.reference_id, ft.metadata, ft.created_at, ft.updated_at, ba.account_holder_name, ba.bank_name +FROM fiat_transactions ft +JOIN bank_accounts ba ON ft.bank_account_id = ba.id +WHERE ft.bank_account_id = $1 +ORDER BY ft.created_at DESC +LIMIT $3 OFFSET $2 ` -type GetTransactionsByStatusParams struct { - Status string `json:"status"` - Limit int32 `json:"limit"` - Offset int32 `json:"offset"` +type GetFiatTransactionsByBankAccountParams struct { + BankAccountID uuid.UUID `json:"bank_account_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` } -// Retrieves transactions by status -func (q *Queries) GetTransactionsByStatus(ctx context.Context, arg GetTransactionsByStatusParams) ([]Transactions, error) { - rows, err := q.db.Query(ctx, getTransactionsByStatus, arg.Status, arg.Limit, arg.Offset) +type GetFiatTransactionsByBankAccountRow struct { + ID uuid.UUID `json:"id"` + BankAccountID uuid.UUID `json:"bank_account_id"` + TransactionReference string `json:"transaction_reference"` + TransactionType string `json:"transaction_type"` + Amount decimal.Decimal `json:"amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentProvider pgtype.Text `json:"payment_provider"` + PaymentMethod pgtype.Text `json:"payment_method"` + ProviderReference pgtype.Text `json:"provider_reference"` + ProviderFee pgtype.Numeric `json:"provider_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + Metadata []byte `json:"metadata"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + AccountHolderName string `json:"account_holder_name"` + BankName string `json:"bank_name"` +} + +func (q *Queries) GetFiatTransactionsByBankAccount(ctx context.Context, arg GetFiatTransactionsByBankAccountParams) ([]GetFiatTransactionsByBankAccountRow, error) { + rows, err := q.db.Query(ctx, getFiatTransactionsByBankAccount, arg.BankAccountID, arg.OffsetVal, arg.LimitVal) if err != nil { return nil, err } defer rows.Close() - items := []Transactions{} + items := []GetFiatTransactionsByBankAccountRow{} for rows.Next() { - var i Transactions + var i GetFiatTransactionsByBankAccountRow if err := rows.Scan( &i.ID, - &i.UserID, - &i.TxHash, - &i.TransactionPinHash, + &i.BankAccountID, + &i.TransactionReference, + &i.TransactionType, + &i.Amount, + &i.Currency, &i.Status, + &i.PaymentProvider, + &i.PaymentMethod, + &i.ProviderReference, + &i.ProviderFee, + &i.ReferenceType, + &i.ReferenceID, + &i.Metadata, + &i.CreatedAt, + &i.UpdatedAt, + &i.AccountHolderName, + &i.BankName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getLatestExchangeRate = `-- name: GetLatestExchangeRate :one +SELECT id, base_currency, quote_currency, rate, source, timestamp, created_at FROM exchange_rates +WHERE base_currency = $1 AND quote_currency = $2 +ORDER BY timestamp DESC +LIMIT 1 +` + +type GetLatestExchangeRateParams struct { + BaseCurrency string `json:"base_currency"` + QuoteCurrency string `json:"quote_currency"` +} + +func (q *Queries) GetLatestExchangeRate(ctx context.Context, arg GetLatestExchangeRateParams) (ExchangeRates, error) { + row := q.db.QueryRow(ctx, getLatestExchangeRate, arg.BaseCurrency, arg.QuoteCurrency) + var i ExchangeRates + err := row.Scan( + &i.ID, + &i.BaseCurrency, + &i.QuoteCurrency, + &i.Rate, + &i.Source, + &i.Timestamp, + &i.CreatedAt, + ) + return i, err +} + +const getPendingTransactions = `-- name: GetPendingTransactions :many +SELECT wt.id, wt.wallet_address, wt.transaction_hash, wt.chain_id, wt.block_number, wt.from_address, wt.to_address, wt.token_address, wt.token_symbol, wt.amount, wt.transaction_type, wt.transaction_status, wt.gas_price, wt.gas_used, wt.transaction_fee, wt.reference_type, wt.reference_id, wt.created_at, wt.updated_at, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +WHERE wt.transaction_status = 'pending' + AND ($1::uuid IS NULL OR wt.wallet_address IN ( + SELECT wallet_address FROM user_wallets WHERE user_id = $1 + )) +ORDER BY wt.created_at DESC +` + +type GetPendingTransactionsRow struct { + ID uuid.UUID `json:"id"` + WalletAddress string `json:"wallet_address"` + TransactionHash string `json:"transaction_hash"` + ChainID int32 `json:"chain_id"` + BlockNumber pgtype.Int8 `json:"block_number"` + FromAddress string `json:"from_address"` + ToAddress string `json:"to_address"` + TokenAddress pgtype.Text `json:"token_address"` + TokenSymbol pgtype.Text `json:"token_symbol"` + Amount decimal.Decimal `json:"amount"` + TransactionType string `json:"transaction_type"` + TransactionStatus pgtype.Text `json:"transaction_status"` + GasPrice pgtype.Numeric `json:"gas_price"` + GasUsed pgtype.Int8 `json:"gas_used"` + TransactionFee pgtype.Numeric `json:"transaction_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + NetworkName string `json:"network_name"` +} + +func (q *Queries) GetPendingTransactions(ctx context.Context, userID uuid.UUID) ([]GetPendingTransactionsRow, error) { + rows, err := q.db.Query(ctx, getPendingTransactions, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetPendingTransactionsRow{} + for rows.Next() { + var i GetPendingTransactionsRow + if err := rows.Scan( + &i.ID, + &i.WalletAddress, + &i.TransactionHash, + &i.ChainID, + &i.BlockNumber, + &i.FromAddress, + &i.ToAddress, + &i.TokenAddress, + &i.TokenSymbol, + &i.Amount, + &i.TransactionType, + &i.TransactionStatus, + &i.GasPrice, + &i.GasUsed, + &i.TransactionFee, + &i.ReferenceType, + &i.ReferenceID, + &i.CreatedAt, + &i.UpdatedAt, + &i.NetworkName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTransactionsByToken = `-- name: GetTransactionsByToken :many +SELECT wt.id, wt.wallet_address, wt.transaction_hash, wt.chain_id, wt.block_number, wt.from_address, wt.to_address, wt.token_address, wt.token_symbol, wt.amount, wt.transaction_type, wt.transaction_status, wt.gas_price, wt.gas_used, wt.transaction_fee, wt.reference_type, wt.reference_id, wt.created_at, wt.updated_at, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +WHERE wt.token_symbol = $1 + AND ($2::uuid IS NULL OR wt.wallet_address IN ( + SELECT wallet_address FROM user_wallets WHERE user_id = $2 + )) +ORDER BY wt.created_at DESC +LIMIT $4 OFFSET $3 +` + +type GetTransactionsByTokenParams struct { + TokenSymbol pgtype.Text `json:"token_symbol"` + UserID uuid.UUID `json:"user_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetTransactionsByTokenRow struct { + ID uuid.UUID `json:"id"` + WalletAddress string `json:"wallet_address"` + TransactionHash string `json:"transaction_hash"` + ChainID int32 `json:"chain_id"` + BlockNumber pgtype.Int8 `json:"block_number"` + FromAddress string `json:"from_address"` + ToAddress string `json:"to_address"` + TokenAddress pgtype.Text `json:"token_address"` + TokenSymbol pgtype.Text `json:"token_symbol"` + Amount decimal.Decimal `json:"amount"` + TransactionType string `json:"transaction_type"` + TransactionStatus pgtype.Text `json:"transaction_status"` + GasPrice pgtype.Numeric `json:"gas_price"` + GasUsed pgtype.Int8 `json:"gas_used"` + TransactionFee pgtype.Numeric `json:"transaction_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + NetworkName string `json:"network_name"` +} + +func (q *Queries) GetTransactionsByToken(ctx context.Context, arg GetTransactionsByTokenParams) ([]GetTransactionsByTokenRow, error) { + rows, err := q.db.Query(ctx, getTransactionsByToken, + arg.TokenSymbol, + arg.UserID, + arg.OffsetVal, + arg.LimitVal, + ) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetTransactionsByTokenRow{} + for rows.Next() { + var i GetTransactionsByTokenRow + if err := rows.Scan( + &i.ID, + &i.WalletAddress, + &i.TransactionHash, + &i.ChainID, + &i.BlockNumber, + &i.FromAddress, + &i.ToAddress, + &i.TokenAddress, + &i.TokenSymbol, + &i.Amount, + &i.TransactionType, + &i.TransactionStatus, + &i.GasPrice, + &i.GasUsed, + &i.TransactionFee, + &i.ReferenceType, + &i.ReferenceID, &i.CreatedAt, &i.UpdatedAt, + &i.NetworkName, ); err != nil { return nil, err } @@ -120,30 +835,70 @@ func (q *Queries) GetTransactionsByStatus(ctx context.Context, arg GetTransactio return items, nil } -const getTransactionsByUserID = `-- name: GetTransactionsByUserID :many -SELECT id, user_id, tx_hash, transaction_pin_hash, status, created_at, updated_at FROM transactions -WHERE user_id = $1 -ORDER BY created_at DESC +const getUserFiatTransactions = `-- name: GetUserFiatTransactions :many +SELECT ft.id, ft.bank_account_id, ft.transaction_reference, ft.transaction_type, ft.amount, ft.currency, ft.status, ft.payment_provider, ft.payment_method, ft.provider_reference, ft.provider_fee, ft.reference_type, ft.reference_id, ft.metadata, ft.created_at, ft.updated_at, ba.account_holder_name, ba.bank_name +FROM fiat_transactions ft +JOIN bank_accounts ba ON ft.bank_account_id = ba.id +WHERE ba.user_id = $1 +ORDER BY ft.created_at DESC +LIMIT $3 OFFSET $2 ` -// Retrieves all transactions for a specific user -func (q *Queries) GetTransactionsByUserID(ctx context.Context, userID uuid.UUID) ([]Transactions, error) { - rows, err := q.db.Query(ctx, getTransactionsByUserID, userID) +type GetUserFiatTransactionsParams struct { + UserID pgtype.UUID `json:"user_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetUserFiatTransactionsRow struct { + ID uuid.UUID `json:"id"` + BankAccountID uuid.UUID `json:"bank_account_id"` + TransactionReference string `json:"transaction_reference"` + TransactionType string `json:"transaction_type"` + Amount decimal.Decimal `json:"amount"` + Currency string `json:"currency"` + Status pgtype.Text `json:"status"` + PaymentProvider pgtype.Text `json:"payment_provider"` + PaymentMethod pgtype.Text `json:"payment_method"` + ProviderReference pgtype.Text `json:"provider_reference"` + ProviderFee pgtype.Numeric `json:"provider_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + Metadata []byte `json:"metadata"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + AccountHolderName string `json:"account_holder_name"` + BankName string `json:"bank_name"` +} + +func (q *Queries) GetUserFiatTransactions(ctx context.Context, arg GetUserFiatTransactionsParams) ([]GetUserFiatTransactionsRow, error) { + rows, err := q.db.Query(ctx, getUserFiatTransactions, arg.UserID, arg.OffsetVal, arg.LimitVal) if err != nil { return nil, err } defer rows.Close() - items := []Transactions{} + items := []GetUserFiatTransactionsRow{} for rows.Next() { - var i Transactions + var i GetUserFiatTransactionsRow if err := rows.Scan( &i.ID, - &i.UserID, - &i.TxHash, - &i.TransactionPinHash, + &i.BankAccountID, + &i.TransactionReference, + &i.TransactionType, + &i.Amount, + &i.Currency, &i.Status, + &i.PaymentProvider, + &i.PaymentMethod, + &i.ProviderReference, + &i.ProviderFee, + &i.ReferenceType, + &i.ReferenceID, + &i.Metadata, &i.CreatedAt, &i.UpdatedAt, + &i.AccountHolderName, + &i.BankName, ); err != nil { return nil, err } @@ -155,35 +910,75 @@ func (q *Queries) GetTransactionsByUserID(ctx context.Context, userID uuid.UUID) return items, nil } -const getTransactionsByUserIDAndStatus = `-- name: GetTransactionsByUserIDAndStatus :many -SELECT id, user_id, tx_hash, transaction_pin_hash, status, created_at, updated_at FROM transactions -WHERE user_id = $1 AND status = $2 -ORDER BY created_at DESC +const getUserTransactions = `-- name: GetUserTransactions :many +SELECT wt.id, wt.wallet_address, wt.transaction_hash, wt.chain_id, wt.block_number, wt.from_address, wt.to_address, wt.token_address, wt.token_symbol, wt.amount, wt.transaction_type, wt.transaction_status, wt.gas_price, wt.gas_used, wt.transaction_fee, wt.reference_type, wt.reference_id, wt.created_at, wt.updated_at, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +JOIN user_wallets uw ON wt.wallet_address = uw.wallet_address AND wt.chain_id = uw.chain_id +WHERE uw.user_id = $1 +ORDER BY wt.created_at DESC +LIMIT $3 OFFSET $2 ` -type GetTransactionsByUserIDAndStatusParams struct { - UserID uuid.UUID `json:"user_id"` - Status string `json:"status"` +type GetUserTransactionsParams struct { + UserID uuid.UUID `json:"user_id"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetUserTransactionsRow struct { + ID uuid.UUID `json:"id"` + WalletAddress string `json:"wallet_address"` + TransactionHash string `json:"transaction_hash"` + ChainID int32 `json:"chain_id"` + BlockNumber pgtype.Int8 `json:"block_number"` + FromAddress string `json:"from_address"` + ToAddress string `json:"to_address"` + TokenAddress pgtype.Text `json:"token_address"` + TokenSymbol pgtype.Text `json:"token_symbol"` + Amount decimal.Decimal `json:"amount"` + TransactionType string `json:"transaction_type"` + TransactionStatus pgtype.Text `json:"transaction_status"` + GasPrice pgtype.Numeric `json:"gas_price"` + GasUsed pgtype.Int8 `json:"gas_used"` + TransactionFee pgtype.Numeric `json:"transaction_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + NetworkName string `json:"network_name"` } -// Retrieves transactions for a specific user with a specific status -func (q *Queries) GetTransactionsByUserIDAndStatus(ctx context.Context, arg GetTransactionsByUserIDAndStatusParams) ([]Transactions, error) { - rows, err := q.db.Query(ctx, getTransactionsByUserIDAndStatus, arg.UserID, arg.Status) +func (q *Queries) GetUserTransactions(ctx context.Context, arg GetUserTransactionsParams) ([]GetUserTransactionsRow, error) { + rows, err := q.db.Query(ctx, getUserTransactions, arg.UserID, arg.OffsetVal, arg.LimitVal) if err != nil { return nil, err } defer rows.Close() - items := []Transactions{} + items := []GetUserTransactionsRow{} for rows.Next() { - var i Transactions + var i GetUserTransactionsRow if err := rows.Scan( &i.ID, - &i.UserID, - &i.TxHash, - &i.TransactionPinHash, - &i.Status, + &i.WalletAddress, + &i.TransactionHash, + &i.ChainID, + &i.BlockNumber, + &i.FromAddress, + &i.ToAddress, + &i.TokenAddress, + &i.TokenSymbol, + &i.Amount, + &i.TransactionType, + &i.TransactionStatus, + &i.GasPrice, + &i.GasUsed, + &i.TransactionFee, + &i.ReferenceType, + &i.ReferenceID, &i.CreatedAt, &i.UpdatedAt, + &i.NetworkName, ); err != nil { return nil, err } @@ -195,62 +990,333 @@ func (q *Queries) GetTransactionsByUserIDAndStatus(ctx context.Context, arg GetT return items, nil } -const updateTransaction = `-- name: UpdateTransaction :one -UPDATE transactions -SET - status = COALESCE($2, status), - transaction_pin_hash = COALESCE($3, transaction_pin_hash), - updated_at = now() -WHERE id = $1 -RETURNING id, user_id, tx_hash, transaction_pin_hash, status, created_at, updated_at +const getWalletTransactionByHash = `-- name: GetWalletTransactionByHash :one +SELECT wt.id, wt.wallet_address, wt.transaction_hash, wt.chain_id, wt.block_number, wt.from_address, wt.to_address, wt.token_address, wt.token_symbol, wt.amount, wt.transaction_type, wt.transaction_status, wt.gas_price, wt.gas_used, wt.transaction_fee, wt.reference_type, wt.reference_id, wt.created_at, wt.updated_at, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +WHERE wt.transaction_hash = $1 ` -type UpdateTransactionParams struct { - ID uuid.UUID `json:"id"` - Status string `json:"status"` - TransactionPinHash string `json:"transaction_pin_hash"` +type GetWalletTransactionByHashRow struct { + ID uuid.UUID `json:"id"` + WalletAddress string `json:"wallet_address"` + TransactionHash string `json:"transaction_hash"` + ChainID int32 `json:"chain_id"` + BlockNumber pgtype.Int8 `json:"block_number"` + FromAddress string `json:"from_address"` + ToAddress string `json:"to_address"` + TokenAddress pgtype.Text `json:"token_address"` + TokenSymbol pgtype.Text `json:"token_symbol"` + Amount decimal.Decimal `json:"amount"` + TransactionType string `json:"transaction_type"` + TransactionStatus pgtype.Text `json:"transaction_status"` + GasPrice pgtype.Numeric `json:"gas_price"` + GasUsed pgtype.Int8 `json:"gas_used"` + TransactionFee pgtype.Numeric `json:"transaction_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + NetworkName string `json:"network_name"` } -// Updates transaction details and returns the updated transaction -func (q *Queries) UpdateTransaction(ctx context.Context, arg UpdateTransactionParams) (Transactions, error) { - row := q.db.QueryRow(ctx, updateTransaction, arg.ID, arg.Status, arg.TransactionPinHash) - var i Transactions +func (q *Queries) GetWalletTransactionByHash(ctx context.Context, transactionHash string) (GetWalletTransactionByHashRow, error) { + row := q.db.QueryRow(ctx, getWalletTransactionByHash, transactionHash) + var i GetWalletTransactionByHashRow err := row.Scan( &i.ID, - &i.UserID, - &i.TxHash, - &i.TransactionPinHash, - &i.Status, + &i.WalletAddress, + &i.TransactionHash, + &i.ChainID, + &i.BlockNumber, + &i.FromAddress, + &i.ToAddress, + &i.TokenAddress, + &i.TokenSymbol, + &i.Amount, + &i.TransactionType, + &i.TransactionStatus, + &i.GasPrice, + &i.GasUsed, + &i.TransactionFee, + &i.ReferenceType, + &i.ReferenceID, &i.CreatedAt, &i.UpdatedAt, + &i.NetworkName, ) return i, err } -const updateTransactionStatus = `-- name: UpdateTransactionStatus :one -UPDATE transactions -SET - status = $2, - updated_at = now() -WHERE id = $1 -RETURNING id, user_id, tx_hash, transaction_pin_hash, status, created_at, updated_at +const getWalletTransactionsByAddress = `-- name: GetWalletTransactionsByAddress :many +SELECT wt.id, wt.wallet_address, wt.transaction_hash, wt.chain_id, wt.block_number, wt.from_address, wt.to_address, wt.token_address, wt.token_symbol, wt.amount, wt.transaction_type, wt.transaction_status, wt.gas_price, wt.gas_used, wt.transaction_fee, wt.reference_type, wt.reference_id, wt.created_at, wt.updated_at, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +WHERE wt.wallet_address = $1 +ORDER BY wt.created_at DESC +LIMIT $3 OFFSET $2 +` + +type GetWalletTransactionsByAddressParams struct { + WalletAddress string `json:"wallet_address"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetWalletTransactionsByAddressRow struct { + ID uuid.UUID `json:"id"` + WalletAddress string `json:"wallet_address"` + TransactionHash string `json:"transaction_hash"` + ChainID int32 `json:"chain_id"` + BlockNumber pgtype.Int8 `json:"block_number"` + FromAddress string `json:"from_address"` + ToAddress string `json:"to_address"` + TokenAddress pgtype.Text `json:"token_address"` + TokenSymbol pgtype.Text `json:"token_symbol"` + Amount decimal.Decimal `json:"amount"` + TransactionType string `json:"transaction_type"` + TransactionStatus pgtype.Text `json:"transaction_status"` + GasPrice pgtype.Numeric `json:"gas_price"` + GasUsed pgtype.Int8 `json:"gas_used"` + TransactionFee pgtype.Numeric `json:"transaction_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + NetworkName string `json:"network_name"` +} + +func (q *Queries) GetWalletTransactionsByAddress(ctx context.Context, arg GetWalletTransactionsByAddressParams) ([]GetWalletTransactionsByAddressRow, error) { + rows, err := q.db.Query(ctx, getWalletTransactionsByAddress, arg.WalletAddress, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetWalletTransactionsByAddressRow{} + for rows.Next() { + var i GetWalletTransactionsByAddressRow + if err := rows.Scan( + &i.ID, + &i.WalletAddress, + &i.TransactionHash, + &i.ChainID, + &i.BlockNumber, + &i.FromAddress, + &i.ToAddress, + &i.TokenAddress, + &i.TokenSymbol, + &i.Amount, + &i.TransactionType, + &i.TransactionStatus, + &i.GasPrice, + &i.GasUsed, + &i.TransactionFee, + &i.ReferenceType, + &i.ReferenceID, + &i.CreatedAt, + &i.UpdatedAt, + &i.NetworkName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getWalletTransactionsByNetwork = `-- name: GetWalletTransactionsByNetwork :many +SELECT wt.id, wt.wallet_address, wt.transaction_hash, wt.chain_id, wt.block_number, wt.from_address, wt.to_address, wt.token_address, wt.token_symbol, wt.amount, wt.transaction_type, wt.transaction_status, wt.gas_price, wt.gas_used, wt.transaction_fee, wt.reference_type, wt.reference_id, wt.created_at, wt.updated_at, sn.name as network_name +FROM wallet_transactions wt +JOIN supported_networks sn ON wt.chain_id = sn.chain_id +WHERE wt.chain_id = $1 + AND ($2::text IS NULL OR wt.wallet_address = $2) +ORDER BY wt.created_at DESC +LIMIT $4 OFFSET $3 +` + +type GetWalletTransactionsByNetworkParams struct { + ChainID int32 `json:"chain_id"` + WalletAddress string `json:"wallet_address"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type GetWalletTransactionsByNetworkRow struct { + ID uuid.UUID `json:"id"` + WalletAddress string `json:"wallet_address"` + TransactionHash string `json:"transaction_hash"` + ChainID int32 `json:"chain_id"` + BlockNumber pgtype.Int8 `json:"block_number"` + FromAddress string `json:"from_address"` + ToAddress string `json:"to_address"` + TokenAddress pgtype.Text `json:"token_address"` + TokenSymbol pgtype.Text `json:"token_symbol"` + Amount decimal.Decimal `json:"amount"` + TransactionType string `json:"transaction_type"` + TransactionStatus pgtype.Text `json:"transaction_status"` + GasPrice pgtype.Numeric `json:"gas_price"` + GasUsed pgtype.Int8 `json:"gas_used"` + TransactionFee pgtype.Numeric `json:"transaction_fee"` + ReferenceType pgtype.Text `json:"reference_type"` + ReferenceID pgtype.UUID `json:"reference_id"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + NetworkName string `json:"network_name"` +} + +func (q *Queries) GetWalletTransactionsByNetwork(ctx context.Context, arg GetWalletTransactionsByNetworkParams) ([]GetWalletTransactionsByNetworkRow, error) { + rows, err := q.db.Query(ctx, getWalletTransactionsByNetwork, + arg.ChainID, + arg.WalletAddress, + arg.OffsetVal, + arg.LimitVal, + ) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetWalletTransactionsByNetworkRow{} + for rows.Next() { + var i GetWalletTransactionsByNetworkRow + if err := rows.Scan( + &i.ID, + &i.WalletAddress, + &i.TransactionHash, + &i.ChainID, + &i.BlockNumber, + &i.FromAddress, + &i.ToAddress, + &i.TokenAddress, + &i.TokenSymbol, + &i.Amount, + &i.TransactionType, + &i.TransactionStatus, + &i.GasPrice, + &i.GasUsed, + &i.TransactionFee, + &i.ReferenceType, + &i.ReferenceID, + &i.CreatedAt, + &i.UpdatedAt, + &i.NetworkName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateFiatTransaction = `-- name: UpdateFiatTransaction :one +UPDATE fiat_transactions SET + status = COALESCE($1, status), + payment_provider = COALESCE($2, payment_provider), + payment_method = COALESCE($3, payment_method), + provider_reference = COALESCE($4, provider_reference), + provider_fee = COALESCE($5, provider_fee), + metadata = COALESCE($6, metadata), + updated_at = NOW() +WHERE transaction_reference = $7 +RETURNING id, bank_account_id, transaction_reference, transaction_type, amount, currency, status, payment_provider, payment_method, provider_reference, provider_fee, reference_type, reference_id, metadata, created_at, updated_at ` -type UpdateTransactionStatusParams struct { - ID uuid.UUID `json:"id"` - Status string `json:"status"` +type UpdateFiatTransactionParams struct { + Status pgtype.Text `json:"status"` + PaymentProvider pgtype.Text `json:"payment_provider"` + PaymentMethod pgtype.Text `json:"payment_method"` + ProviderReference pgtype.Text `json:"provider_reference"` + ProviderFee pgtype.Numeric `json:"provider_fee"` + Metadata []byte `json:"metadata"` + TransactionReference string `json:"transaction_reference"` } -// Updates the status of a transaction and returns the updated transaction -func (q *Queries) UpdateTransactionStatus(ctx context.Context, arg UpdateTransactionStatusParams) (Transactions, error) { - row := q.db.QueryRow(ctx, updateTransactionStatus, arg.ID, arg.Status) - var i Transactions +func (q *Queries) UpdateFiatTransaction(ctx context.Context, arg UpdateFiatTransactionParams) (FiatTransactions, error) { + row := q.db.QueryRow(ctx, updateFiatTransaction, + arg.Status, + arg.PaymentProvider, + arg.PaymentMethod, + arg.ProviderReference, + arg.ProviderFee, + arg.Metadata, + arg.TransactionReference, + ) + var i FiatTransactions err := row.Scan( &i.ID, - &i.UserID, - &i.TxHash, - &i.TransactionPinHash, + &i.BankAccountID, + &i.TransactionReference, + &i.TransactionType, + &i.Amount, + &i.Currency, &i.Status, + &i.PaymentProvider, + &i.PaymentMethod, + &i.ProviderReference, + &i.ProviderFee, + &i.ReferenceType, + &i.ReferenceID, + &i.Metadata, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateWalletTransaction = `-- name: UpdateWalletTransaction :one +UPDATE wallet_transactions SET + block_number = COALESCE($1, block_number), + transaction_status = COALESCE($2, transaction_status), + gas_price = COALESCE($3, gas_price), + gas_used = COALESCE($4, gas_used), + transaction_fee = COALESCE($5, transaction_fee), + updated_at = NOW() +WHERE transaction_hash = $6 +RETURNING id, wallet_address, transaction_hash, chain_id, block_number, from_address, to_address, token_address, token_symbol, amount, transaction_type, transaction_status, gas_price, gas_used, transaction_fee, reference_type, reference_id, created_at, updated_at +` + +type UpdateWalletTransactionParams struct { + BlockNumber pgtype.Int8 `json:"block_number"` + TransactionStatus pgtype.Text `json:"transaction_status"` + GasPrice pgtype.Numeric `json:"gas_price"` + GasUsed pgtype.Int8 `json:"gas_used"` + TransactionFee pgtype.Numeric `json:"transaction_fee"` + TransactionHash string `json:"transaction_hash"` +} + +func (q *Queries) UpdateWalletTransaction(ctx context.Context, arg UpdateWalletTransactionParams) (WalletTransactions, error) { + row := q.db.QueryRow(ctx, updateWalletTransaction, + arg.BlockNumber, + arg.TransactionStatus, + arg.GasPrice, + arg.GasUsed, + arg.TransactionFee, + arg.TransactionHash, + ) + var i WalletTransactions + err := row.Scan( + &i.ID, + &i.WalletAddress, + &i.TransactionHash, + &i.ChainID, + &i.BlockNumber, + &i.FromAddress, + &i.ToAddress, + &i.TokenAddress, + &i.TokenSymbol, + &i.Amount, + &i.TransactionType, + &i.TransactionStatus, + &i.GasPrice, + &i.GasUsed, + &i.TransactionFee, + &i.ReferenceType, + &i.ReferenceID, &i.CreatedAt, &i.UpdatedAt, ) diff --git a/db/sqlc/user_device.sql.go b/db/sqlc/user_device.sql.go deleted file mode 100644 index f06a23a..0000000 --- a/db/sqlc/user_device.sql.go +++ /dev/null @@ -1,633 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.29.0 -// source: user_device.sql - -package sqlc - -import ( - "context" - - "github.com/google/uuid" - "github.com/jackc/pgx/v5/pgtype" -) - -const countActiveDeviceTokensForUser = `-- name: CountActiveDeviceTokensForUser :one -SELECT COUNT(*) -FROM user_device_tokens -WHERE - user_id = $1 - AND is_active = true - AND (expires_at IS NULL OR expires_at > NOW()) -` - -func (q *Queries) CountActiveDeviceTokensForUser(ctx context.Context, userID uuid.UUID) (int64, error) { - row := q.db.QueryRow(ctx, countActiveDeviceTokensForUser, userID) - var count int64 - err := row.Scan(&count) - return count, err -} - -const createUserDeviceToken = `-- name: CreateUserDeviceToken :one -INSERT INTO user_device_tokens ( - id, - user_id, - device_token, - platform, - device_type, - device_model, - os_name, - os_version, - push_notification_token, - is_active, - is_verified, - app_version, - client_ip, - expires_at -) VALUES ( - $1, - $2, - $3, - COALESCE($4, 'unknown'), - COALESCE($5, 'unknown'), - COALESCE($6, 'unknown'), - COALESCE($7, 'unknown'), - COALESCE($8, 'unknown'), - $9, - COALESCE($10, true), - COALESCE($11, false), - $12, - $13, - $14 -) RETURNING id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, first_registered_at, app_version, client_ip, expires_at, is_revoked -` - -type CreateUserDeviceTokenParams struct { - ID uuid.UUID `json:"id"` - UserID uuid.UUID `json:"user_id"` - DeviceToken string `json:"device_token"` - Column4 interface{} `json:"column_4"` - Column5 interface{} `json:"column_5"` - Column6 interface{} `json:"column_6"` - Column7 interface{} `json:"column_7"` - Column8 interface{} `json:"column_8"` - PushNotificationToken pgtype.Text `json:"push_notification_token"` - Column10 interface{} `json:"column_10"` - Column11 interface{} `json:"column_11"` - AppVersion pgtype.Text `json:"app_version"` - ClientIp pgtype.Text `json:"client_ip"` - ExpiresAt pgtype.Timestamptz `json:"expires_at"` -} - -func (q *Queries) CreateUserDeviceToken(ctx context.Context, arg CreateUserDeviceTokenParams) (UserDeviceTokens, error) { - row := q.db.QueryRow(ctx, createUserDeviceToken, - arg.ID, - arg.UserID, - arg.DeviceToken, - arg.Column4, - arg.Column5, - arg.Column6, - arg.Column7, - arg.Column8, - arg.PushNotificationToken, - arg.Column10, - arg.Column11, - arg.AppVersion, - arg.ClientIp, - arg.ExpiresAt, - ) - var i UserDeviceTokens - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceToken, - &i.Platform, - &i.DeviceType, - &i.DeviceModel, - &i.OsName, - &i.OsVersion, - &i.PushNotificationToken, - &i.IsActive, - &i.IsVerified, - &i.LastUsedAt, - &i.FirstRegisteredAt, - &i.AppVersion, - &i.ClientIp, - &i.ExpiresAt, - &i.IsRevoked, - ) - return i, err -} - -const deleteExpiredDeviceTokens = `-- name: DeleteExpiredDeviceTokens :exec -DELETE FROM user_device_tokens -WHERE - expires_at < NOW() - AND is_active = false -` - -func (q *Queries) DeleteExpiredDeviceTokens(ctx context.Context) error { - _, err := q.db.Exec(ctx, deleteExpiredDeviceTokens) - return err -} - -const getActiveDeviceTokensForUser = `-- name: GetActiveDeviceTokensForUser :many -SELECT id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, first_registered_at, app_version, client_ip, expires_at, is_revoked FROM user_device_tokens -WHERE user_id = $1 - AND is_active = true - AND (expires_at IS NULL OR expires_at > NOW()) -ORDER BY first_registered_at DESC -` - -func (q *Queries) GetActiveDeviceTokensForUser(ctx context.Context, userID uuid.UUID) ([]UserDeviceTokens, error) { - rows, err := q.db.Query(ctx, getActiveDeviceTokensForUser, userID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []UserDeviceTokens{} - for rows.Next() { - var i UserDeviceTokens - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.DeviceToken, - &i.Platform, - &i.DeviceType, - &i.DeviceModel, - &i.OsName, - &i.OsVersion, - &i.PushNotificationToken, - &i.IsActive, - &i.IsVerified, - &i.LastUsedAt, - &i.FirstRegisteredAt, - &i.AppVersion, - &i.ClientIp, - &i.ExpiresAt, - &i.IsRevoked, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const getDeviceTokensByPlatform = `-- name: GetDeviceTokensByPlatform :many -SELECT id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, first_registered_at, app_version, client_ip, expires_at, is_revoked FROM user_device_tokens -WHERE - user_id = $1 - AND platform = $2 - AND is_active = true - AND (expires_at IS NULL OR expires_at > NOW()) -ORDER BY first_registered_at DESC -` - -type GetDeviceTokensByPlatformParams struct { - UserID uuid.UUID `json:"user_id"` - Platform string `json:"platform"` -} - -func (q *Queries) GetDeviceTokensByPlatform(ctx context.Context, arg GetDeviceTokensByPlatformParams) ([]UserDeviceTokens, error) { - rows, err := q.db.Query(ctx, getDeviceTokensByPlatform, arg.UserID, arg.Platform) - if err != nil { - return nil, err - } - defer rows.Close() - items := []UserDeviceTokens{} - for rows.Next() { - var i UserDeviceTokens - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.DeviceToken, - &i.Platform, - &i.DeviceType, - &i.DeviceModel, - &i.OsName, - &i.OsVersion, - &i.PushNotificationToken, - &i.IsActive, - &i.IsVerified, - &i.LastUsedAt, - &i.FirstRegisteredAt, - &i.AppVersion, - &i.ClientIp, - &i.ExpiresAt, - &i.IsRevoked, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const getUserDeviceTokenByDeviceToken = `-- name: GetUserDeviceTokenByDeviceToken :one -SELECT id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, first_registered_at, app_version, client_ip, expires_at, is_revoked FROM user_device_tokens -WHERE device_token = $1 -` - -func (q *Queries) GetUserDeviceTokenByDeviceToken(ctx context.Context, deviceToken string) (UserDeviceTokens, error) { - row := q.db.QueryRow(ctx, getUserDeviceTokenByDeviceToken, deviceToken) - var i UserDeviceTokens - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceToken, - &i.Platform, - &i.DeviceType, - &i.DeviceModel, - &i.OsName, - &i.OsVersion, - &i.PushNotificationToken, - &i.IsActive, - &i.IsVerified, - &i.LastUsedAt, - &i.FirstRegisteredAt, - &i.AppVersion, - &i.ClientIp, - &i.ExpiresAt, - &i.IsRevoked, - ) - return i, err -} - -const getUserDeviceTokenByID = `-- name: GetUserDeviceTokenByID :one -SELECT id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, first_registered_at, app_version, client_ip, expires_at, is_revoked FROM user_device_tokens -WHERE id = $1 -` - -func (q *Queries) GetUserDeviceTokenByID(ctx context.Context, id uuid.UUID) (UserDeviceTokens, error) { - row := q.db.QueryRow(ctx, getUserDeviceTokenByID, id) - var i UserDeviceTokens - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceToken, - &i.Platform, - &i.DeviceType, - &i.DeviceModel, - &i.OsName, - &i.OsVersion, - &i.PushNotificationToken, - &i.IsActive, - &i.IsVerified, - &i.LastUsedAt, - &i.FirstRegisteredAt, - &i.AppVersion, - &i.ClientIp, - &i.ExpiresAt, - &i.IsRevoked, - ) - return i, err -} - -const revokeDeviceToken = `-- name: RevokeDeviceToken :one -UPDATE user_device_tokens -SET - is_active = false, - is_revoked = true -WHERE id = $1 -RETURNING id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, first_registered_at, app_version, client_ip, expires_at, is_revoked -` - -func (q *Queries) RevokeDeviceToken(ctx context.Context, id uuid.UUID) (UserDeviceTokens, error) { - row := q.db.QueryRow(ctx, revokeDeviceToken, id) - var i UserDeviceTokens - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceToken, - &i.Platform, - &i.DeviceType, - &i.DeviceModel, - &i.OsName, - &i.OsVersion, - &i.PushNotificationToken, - &i.IsActive, - &i.IsVerified, - &i.LastUsedAt, - &i.FirstRegisteredAt, - &i.AppVersion, - &i.ClientIp, - &i.ExpiresAt, - &i.IsRevoked, - ) - return i, err -} - -const searchDeviceTokens = `-- name: SearchDeviceTokens :many -SELECT id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, first_registered_at, app_version, client_ip, expires_at, is_revoked FROM user_device_tokens -WHERE - user_id = $1 - AND ( - COALESCE(device_type, '') ILIKE '%' || $2 || '%' - OR COALESCE(device_model, '') ILIKE '%' || $2 || '%' - OR platform ILIKE '%' || $2 || '%' - ) -ORDER BY first_registered_at DESC -LIMIT $3 OFFSET $4 -` - -type SearchDeviceTokensParams struct { - UserID uuid.UUID `json:"user_id"` - Column2 pgtype.Text `json:"column_2"` - Limit int32 `json:"limit"` - Offset int32 `json:"offset"` -} - -func (q *Queries) SearchDeviceTokens(ctx context.Context, arg SearchDeviceTokensParams) ([]UserDeviceTokens, error) { - rows, err := q.db.Query(ctx, searchDeviceTokens, - arg.UserID, - arg.Column2, - arg.Limit, - arg.Offset, - ) - if err != nil { - return nil, err - } - defer rows.Close() - items := []UserDeviceTokens{} - for rows.Next() { - var i UserDeviceTokens - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.DeviceToken, - &i.Platform, - &i.DeviceType, - &i.DeviceModel, - &i.OsName, - &i.OsVersion, - &i.PushNotificationToken, - &i.IsActive, - &i.IsVerified, - &i.LastUsedAt, - &i.FirstRegisteredAt, - &i.AppVersion, - &i.ClientIp, - &i.ExpiresAt, - &i.IsRevoked, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const updateDeviceTokenDetails = `-- name: UpdateDeviceTokenDetails :one -UPDATE user_device_tokens -SET - platform = COALESCE($2, platform), - device_type = COALESCE($3, device_type), - device_model = COALESCE($4, device_model), - os_name = COALESCE($5, os_name), - os_version = COALESCE($6, os_version), - app_version = COALESCE($7, app_version), - client_ip = COALESCE($8, client_ip), - last_used_at = NOW(), - is_verified = COALESCE($9, is_verified) -WHERE id = $1 -RETURNING id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, first_registered_at, app_version, client_ip, expires_at, is_revoked -` - -type UpdateDeviceTokenDetailsParams struct { - ID uuid.UUID `json:"id"` - Platform string `json:"platform"` - DeviceType pgtype.Text `json:"device_type"` - DeviceModel pgtype.Text `json:"device_model"` - OsName pgtype.Text `json:"os_name"` - OsVersion pgtype.Text `json:"os_version"` - AppVersion pgtype.Text `json:"app_version"` - ClientIp pgtype.Text `json:"client_ip"` - IsVerified bool `json:"is_verified"` -} - -func (q *Queries) UpdateDeviceTokenDetails(ctx context.Context, arg UpdateDeviceTokenDetailsParams) (UserDeviceTokens, error) { - row := q.db.QueryRow(ctx, updateDeviceTokenDetails, - arg.ID, - arg.Platform, - arg.DeviceType, - arg.DeviceModel, - arg.OsName, - arg.OsVersion, - arg.AppVersion, - arg.ClientIp, - arg.IsVerified, - ) - var i UserDeviceTokens - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceToken, - &i.Platform, - &i.DeviceType, - &i.DeviceModel, - &i.OsName, - &i.OsVersion, - &i.PushNotificationToken, - &i.IsActive, - &i.IsVerified, - &i.LastUsedAt, - &i.FirstRegisteredAt, - &i.AppVersion, - &i.ClientIp, - &i.ExpiresAt, - &i.IsRevoked, - ) - return i, err -} - -const updateDeviceTokenLastUsed = `-- name: UpdateDeviceTokenLastUsed :one -UPDATE user_device_tokens -SET - last_used_at = NOW(), - client_ip = COALESCE($2, client_ip) -WHERE id = $1 -RETURNING id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, first_registered_at, app_version, client_ip, expires_at, is_revoked -` - -type UpdateDeviceTokenLastUsedParams struct { - ID uuid.UUID `json:"id"` - ClientIp pgtype.Text `json:"client_ip"` -} - -func (q *Queries) UpdateDeviceTokenLastUsed(ctx context.Context, arg UpdateDeviceTokenLastUsedParams) (UserDeviceTokens, error) { - row := q.db.QueryRow(ctx, updateDeviceTokenLastUsed, arg.ID, arg.ClientIp) - var i UserDeviceTokens - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceToken, - &i.Platform, - &i.DeviceType, - &i.DeviceModel, - &i.OsName, - &i.OsVersion, - &i.PushNotificationToken, - &i.IsActive, - &i.IsVerified, - &i.LastUsedAt, - &i.FirstRegisteredAt, - &i.AppVersion, - &i.ClientIp, - &i.ExpiresAt, - &i.IsRevoked, - ) - return i, err -} - -const updateDeviceTokenPushNotificationToken = `-- name: UpdateDeviceTokenPushNotificationToken :one -UPDATE user_device_tokens -SET - push_notification_token = $2, - is_verified = true -WHERE id = $1 -RETURNING id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, first_registered_at, app_version, client_ip, expires_at, is_revoked -` - -type UpdateDeviceTokenPushNotificationTokenParams struct { - ID uuid.UUID `json:"id"` - PushNotificationToken pgtype.Text `json:"push_notification_token"` -} - -func (q *Queries) UpdateDeviceTokenPushNotificationToken(ctx context.Context, arg UpdateDeviceTokenPushNotificationTokenParams) (UserDeviceTokens, error) { - row := q.db.QueryRow(ctx, updateDeviceTokenPushNotificationToken, arg.ID, arg.PushNotificationToken) - var i UserDeviceTokens - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceToken, - &i.Platform, - &i.DeviceType, - &i.DeviceModel, - &i.OsName, - &i.OsVersion, - &i.PushNotificationToken, - &i.IsActive, - &i.IsVerified, - &i.LastUsedAt, - &i.FirstRegisteredAt, - &i.AppVersion, - &i.ClientIp, - &i.ExpiresAt, - &i.IsRevoked, - ) - return i, err -} - -const upsertUserDeviceToken = `-- name: UpsertUserDeviceToken :one -INSERT INTO user_device_tokens ( - id, - user_id, - device_token, - platform, - device_type, - device_model, - os_name, - os_version, - push_notification_token, - is_active, - is_verified, - app_version, - client_ip, - expires_at -) VALUES ( - $1, - $2, - $3, - COALESCE($4, 'unknown'), - COALESCE($5, 'unknown'), - COALESCE($6, 'unknown'), - COALESCE($7, 'unknown'), - COALESCE($8, 'unknown'), - $9, - COALESCE($10, true), - COALESCE($11, false), - $12, - $13, - $14 -) ON CONFLICT (device_token) DO UPDATE SET - platform = COALESCE(EXCLUDED.platform, user_device_tokens.platform), - device_type = COALESCE(EXCLUDED.device_type, user_device_tokens.device_type), - device_model = COALESCE(EXCLUDED.device_model, user_device_tokens.device_model), - os_name = COALESCE(EXCLUDED.os_name, user_device_tokens.os_name), - os_version = COALESCE(EXCLUDED.os_version, user_device_tokens.os_version), - push_notification_token = COALESCE(EXCLUDED.push_notification_token, user_device_tokens.push_notification_token), - is_active = COALESCE(EXCLUDED.is_active, user_device_tokens.is_active), - is_verified = COALESCE(EXCLUDED.is_verified, user_device_tokens.is_verified), - app_version = COALESCE(EXCLUDED.app_version, user_device_tokens.app_version), - client_ip = COALESCE(EXCLUDED.client_ip, user_device_tokens.client_ip), - expires_at = COALESCE(EXCLUDED.expires_at, user_device_tokens.expires_at), - last_used_at = NOW() -RETURNING id, user_id, device_token, platform, device_type, device_model, os_name, os_version, push_notification_token, is_active, is_verified, last_used_at, first_registered_at, app_version, client_ip, expires_at, is_revoked -` - -type UpsertUserDeviceTokenParams struct { - ID uuid.UUID `json:"id"` - UserID uuid.UUID `json:"user_id"` - DeviceToken string `json:"device_token"` - Column4 interface{} `json:"column_4"` - Column5 interface{} `json:"column_5"` - Column6 interface{} `json:"column_6"` - Column7 interface{} `json:"column_7"` - Column8 interface{} `json:"column_8"` - PushNotificationToken pgtype.Text `json:"push_notification_token"` - Column10 interface{} `json:"column_10"` - Column11 interface{} `json:"column_11"` - AppVersion pgtype.Text `json:"app_version"` - ClientIp pgtype.Text `json:"client_ip"` - ExpiresAt pgtype.Timestamptz `json:"expires_at"` -} - -func (q *Queries) UpsertUserDeviceToken(ctx context.Context, arg UpsertUserDeviceTokenParams) (UserDeviceTokens, error) { - row := q.db.QueryRow(ctx, upsertUserDeviceToken, - arg.ID, - arg.UserID, - arg.DeviceToken, - arg.Column4, - arg.Column5, - arg.Column6, - arg.Column7, - arg.Column8, - arg.PushNotificationToken, - arg.Column10, - arg.Column11, - arg.AppVersion, - arg.ClientIp, - arg.ExpiresAt, - ) - var i UserDeviceTokens - err := row.Scan( - &i.ID, - &i.UserID, - &i.DeviceToken, - &i.Platform, - &i.DeviceType, - &i.DeviceModel, - &i.OsName, - &i.OsVersion, - &i.PushNotificationToken, - &i.IsActive, - &i.IsVerified, - &i.LastUsedAt, - &i.FirstRegisteredAt, - &i.AppVersion, - &i.ClientIp, - &i.ExpiresAt, - &i.IsRevoked, - ) - return i, err -} diff --git a/db/sqlc/user_wallets.sql.go b/db/sqlc/user_wallets.sql.go deleted file mode 100644 index bde14f9..0000000 --- a/db/sqlc/user_wallets.sql.go +++ /dev/null @@ -1,149 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.29.0 -// source: user_wallets.sql - -package sqlc - -import ( - "context" - - "github.com/google/uuid" - "github.com/jackc/pgx/v5/pgtype" -) - -const createUserWallet = `-- name: CreateUserWallet :one -INSERT INTO user_wallets ( - id, user_id, address, type, chain, is_default, created_at, updated_at -) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8 -) -RETURNING id, user_id, address, type, chain, is_default, created_at, updated_at -` - -type CreateUserWalletParams struct { - ID uuid.UUID `json:"id"` - UserID uuid.UUID `json:"user_id"` - Address string `json:"address"` - Type string `json:"type"` - Chain string `json:"chain"` - IsDefault bool `json:"is_default"` - CreatedAt pgtype.Timestamp `json:"created_at"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` -} - -func (q *Queries) CreateUserWallet(ctx context.Context, arg CreateUserWalletParams) (UserWallets, error) { - row := q.db.QueryRow(ctx, createUserWallet, - arg.ID, - arg.UserID, - arg.Address, - arg.Type, - arg.Chain, - arg.IsDefault, - arg.CreatedAt, - arg.UpdatedAt, - ) - var i UserWallets - err := row.Scan( - &i.ID, - &i.UserID, - &i.Address, - &i.Type, - &i.Chain, - &i.IsDefault, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const deleteUserWallet = `-- name: DeleteUserWallet :exec -DELETE FROM user_wallets WHERE id = $1 -` - -func (q *Queries) DeleteUserWallet(ctx context.Context, id uuid.UUID) error { - _, err := q.db.Exec(ctx, deleteUserWallet, id) - return err -} - -const getWalletByAddress = `-- name: GetWalletByAddress :one -SELECT id, user_id, address, type, chain, is_default, created_at, updated_at FROM user_wallets WHERE address = $1 -` - -func (q *Queries) GetWalletByAddress(ctx context.Context, address string) (UserWallets, error) { - row := q.db.QueryRow(ctx, getWalletByAddress, address) - var i UserWallets - err := row.Scan( - &i.ID, - &i.UserID, - &i.Address, - &i.Type, - &i.Chain, - &i.IsDefault, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const getWalletsByUserID = `-- name: GetWalletsByUserID :many -SELECT id, user_id, address, type, chain, is_default, created_at, updated_at FROM user_wallets WHERE user_id = $1 -` - -func (q *Queries) GetWalletsByUserID(ctx context.Context, userID uuid.UUID) ([]UserWallets, error) { - rows, err := q.db.Query(ctx, getWalletsByUserID, userID) - if err != nil { - return nil, err - } - defer rows.Close() - items := []UserWallets{} - for rows.Next() { - var i UserWallets - if err := rows.Scan( - &i.ID, - &i.UserID, - &i.Address, - &i.Type, - &i.Chain, - &i.IsDefault, - &i.CreatedAt, - &i.UpdatedAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - -const updateUserWallet = `-- name: UpdateUserWallet :one -UPDATE user_wallets -SET is_default = $2, updated_at = $3 -WHERE id = $1 -RETURNING id, user_id, address, type, chain, is_default, created_at, updated_at -` - -type UpdateUserWalletParams struct { - ID uuid.UUID `json:"id"` - IsDefault bool `json:"is_default"` - UpdatedAt pgtype.Timestamp `json:"updated_at"` -} - -func (q *Queries) UpdateUserWallet(ctx context.Context, arg UpdateUserWalletParams) (UserWallets, error) { - row := q.db.QueryRow(ctx, updateUserWallet, arg.ID, arg.IsDefault, arg.UpdatedAt) - var i UserWallets - err := row.Scan( - &i.ID, - &i.UserID, - &i.Address, - &i.Type, - &i.Chain, - &i.IsDefault, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} diff --git a/db/sqlc/users.sql.go b/db/sqlc/users.sql.go index b17f3b5..e7ab2a2 100644 --- a/db/sqlc/users.sql.go +++ b/db/sqlc/users.sql.go @@ -12,285 +12,331 @@ import ( "github.com/jackc/pgx/v5/pgtype" ) -const checkEmailExists = `-- name: CheckEmailExists :one -SELECT EXISTS ( - SELECT 1 - FROM users - WHERE - email = $1 - LIMIT 1 - ) AS exists -` - -func (q *Queries) CheckEmailExists(ctx context.Context, email string) (bool, error) { - row := q.db.QueryRow(ctx, checkEmailExists, email) - var exists bool - err := row.Scan(&exists) - return exists, err -} - -const countSearchUsers = `-- name: CountSearchUsers :one -SELECT COUNT(*) -FROM users -WHERE - ( - first_name ILIKE '%' || $1 || '%' OR - last_name ILIKE '%' || $1 || '%' OR - email ILIKE '%' || $1 || '%' OR - nationality ILIKE '%' || $1 || '%' - ) -` - -// Counts the number of users matching a search query -func (q *Queries) CountSearchUsers(ctx context.Context, dollar_1 pgtype.Text) (int64, error) { - row := q.db.QueryRow(ctx, countSearchUsers, dollar_1) - var count int64 - err := row.Scan(&count) - return count, err -} - -const countUsers = `-- name: CountUsers :one -SELECT COUNT(*) FROM users -` - -// Counts the total number of users (useful for pagination) -func (q *Queries) CountUsers(ctx context.Context) (int64, error) { - row := q.db.QueryRow(ctx, countUsers) - var count int64 - err := row.Scan(&count) - return count, err -} - -const countUsersByAccountType = `-- name: CountUsersByAccountType :one -SELECT COUNT(*) FROM users -WHERE account_type = $1 -` - -// Counts users filtered by account type -func (q *Queries) CountUsersByAccountType(ctx context.Context, accountType string) (int64, error) { - row := q.db.QueryRow(ctx, countUsersByAccountType, accountType) - var count int64 - err := row.Scan(&count) - return count, err -} - -const createUser = `-- name: CreateUser :one -INSERT INTO users ( +const createPersonalUser = `-- name: CreatePersonalUser :one +INSERT INTO personal_users ( id, - email, - password_hash, - profile_picture, - account_type, - gender, - personal_account_type, first_name, last_name, + profile_picture, + phone_number, + phone_number_verified, + phone_number_verified_at, nationality, residential_country, - job_role, - company_name, - company_size, - company_industry, - company_description, - company_headquarters, - auth_provider, - provider_id, - employee_type, - company_website, - employment_type, user_address, user_city, user_postal_code, + gender, + date_of_birth, + job_role, + personal_account_type, + employment_type, + tax_id, + default_payment_currency, + default_payment_method, + hourly_rate, + specialization, + kyc_status, + kyc_verified_at, created_at, updated_at ) VALUES ( - COALESCE($1, uuid_generate_v4()), + $1, $2, $3, - COALESCE($4, ''), + $4, $5, - $6, + COALESCE($6, FALSE), $7, $8, $9, $10, $11, $12, - COALESCE($13, ''), - COALESCE($14, ''), - COALESCE($15, ''), - COALESCE($16, ''), - COALESCE($17, ''), + $13, + $14, + $15, + $16, + $17, $18, $19, $20, - COALESCE($21, ''), - COALESCE($22, ''), - COALESCE($23, ''), - COALESCE($24, ''), - COALESCE($25, ''), - COALESCE($26, now()), - COALESCE($27, now()) -) RETURNING id, email, password_hash, profile_picture, account_type, gender, personal_account_type, phone_number, phone_number_verified, phone_number_verified_at, first_name, last_name, nationality, residential_country, job_role, company_name, company_size, company_industry, company_description, company_headquarters, user_address, user_city, user_postal_code, employee_type, auth_provider, provider_id, company_website, employment_type, created_at, updated_at + $21, + $22, + COALESCE($23, 'pending'), + $24, + COALESCE($25, NOW()), + COALESCE($26, NOW()) +) RETURNING id, first_name, last_name, profile_picture, phone_number, phone_number_verified, phone_number_verified_at, nationality, residential_country, user_address, user_city, user_postal_code, gender, date_of_birth, job_role, personal_account_type, employment_type, tax_id, default_payment_currency, default_payment_method, hourly_rate, specialization, kyc_status, kyc_verified_at, created_at, updated_at ` -type CreateUserParams struct { - ID interface{} `json:"id"` - Email string `json:"email"` - PasswordHash pgtype.Text `json:"password_hash"` - ProfilePicture interface{} `json:"profile_picture"` - AccountType string `json:"account_type"` - Gender pgtype.Text `json:"gender"` - PersonalAccountType string `json:"personal_account_type"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - Nationality string `json:"nationality"` - ResidentialCountry pgtype.Text `json:"residential_country"` - JobRole pgtype.Text `json:"job_role"` - CompanyName interface{} `json:"company_name"` - CompanySize interface{} `json:"company_size"` - CompanyIndustry interface{} `json:"company_industry"` - CompanyDescription interface{} `json:"company_description"` - CompanyHeadquarters interface{} `json:"company_headquarters"` - AuthProvider pgtype.Text `json:"auth_provider"` - ProviderID string `json:"provider_id"` - EmployeeType pgtype.Text `json:"employee_type"` - CompanyWebsite interface{} `json:"company_website"` - EmploymentType interface{} `json:"employment_type"` - UserAddress interface{} `json:"user_address"` - UserCity interface{} `json:"user_city"` - UserPostalCode interface{} `json:"user_postal_code"` - CreatedAt interface{} `json:"created_at"` - UpdatedAt interface{} `json:"updated_at"` +type CreatePersonalUserParams struct { + ID uuid.UUID `json:"id"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` + ProfilePicture pgtype.Text `json:"profile_picture"` + PhoneNumber pgtype.Text `json:"phone_number"` + PhoneNumberVerified interface{} `json:"phone_number_verified"` + PhoneNumberVerifiedAt pgtype.Timestamptz `json:"phone_number_verified_at"` + Nationality pgtype.Text `json:"nationality"` + ResidentialCountry pgtype.Text `json:"residential_country"` + UserAddress pgtype.Text `json:"user_address"` + UserCity pgtype.Text `json:"user_city"` + UserPostalCode pgtype.Text `json:"user_postal_code"` + Gender pgtype.Text `json:"gender"` + DateOfBirth pgtype.Date `json:"date_of_birth"` + JobRole pgtype.Text `json:"job_role"` + PersonalAccountType pgtype.Text `json:"personal_account_type"` + EmploymentType pgtype.Text `json:"employment_type"` + TaxID pgtype.Text `json:"tax_id"` + DefaultPaymentCurrency pgtype.Text `json:"default_payment_currency"` + DefaultPaymentMethod pgtype.Text `json:"default_payment_method"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + Specialization pgtype.Text `json:"specialization"` + KycStatus interface{} `json:"kyc_status"` + KycVerifiedAt pgtype.Timestamptz `json:"kyc_verified_at"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` } -// Creates a new user record and returns the created user -func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (Users, error) { - row := q.db.QueryRow(ctx, createUser, +func (q *Queries) CreatePersonalUser(ctx context.Context, arg CreatePersonalUserParams) (PersonalUsers, error) { + row := q.db.QueryRow(ctx, createPersonalUser, arg.ID, - arg.Email, - arg.PasswordHash, - arg.ProfilePicture, - arg.AccountType, - arg.Gender, - arg.PersonalAccountType, arg.FirstName, arg.LastName, + arg.ProfilePicture, + arg.PhoneNumber, + arg.PhoneNumberVerified, + arg.PhoneNumberVerifiedAt, arg.Nationality, arg.ResidentialCountry, - arg.JobRole, - arg.CompanyName, - arg.CompanySize, - arg.CompanyIndustry, - arg.CompanyDescription, - arg.CompanyHeadquarters, - arg.AuthProvider, - arg.ProviderID, - arg.EmployeeType, - arg.CompanyWebsite, - arg.EmploymentType, arg.UserAddress, arg.UserCity, arg.UserPostalCode, + arg.Gender, + arg.DateOfBirth, + arg.JobRole, + arg.PersonalAccountType, + arg.EmploymentType, + arg.TaxID, + arg.DefaultPaymentCurrency, + arg.DefaultPaymentMethod, + arg.HourlyRate, + arg.Specialization, + arg.KycStatus, + arg.KycVerifiedAt, arg.CreatedAt, arg.UpdatedAt, ) - var i Users + var i PersonalUsers err := row.Scan( &i.ID, - &i.Email, - &i.PasswordHash, + &i.FirstName, + &i.LastName, &i.ProfilePicture, - &i.AccountType, - &i.Gender, - &i.PersonalAccountType, &i.PhoneNumber, &i.PhoneNumberVerified, &i.PhoneNumberVerifiedAt, - &i.FirstName, - &i.LastName, &i.Nationality, &i.ResidentialCountry, - &i.JobRole, - &i.CompanyName, - &i.CompanySize, - &i.CompanyIndustry, - &i.CompanyDescription, - &i.CompanyHeadquarters, &i.UserAddress, &i.UserCity, &i.UserPostalCode, - &i.EmployeeType, - &i.AuthProvider, - &i.ProviderID, - &i.CompanyWebsite, + &i.Gender, + &i.DateOfBirth, + &i.JobRole, + &i.PersonalAccountType, &i.EmploymentType, + &i.TaxID, + &i.DefaultPaymentCurrency, + &i.DefaultPaymentMethod, + &i.HourlyRate, + &i.Specialization, + &i.KycStatus, + &i.KycVerifiedAt, &i.CreatedAt, &i.UpdatedAt, ) return i, err } -const deleteUser = `-- name: DeleteUser :exec -DELETE FROM users -WHERE id = $1 +const createUser = `-- name: CreateUser :one +INSERT INTO users ( + id, + email, + password_hash, + auth_provider, + provider_id, + email_verified, + email_verified_at, + account_type, + account_status, + two_factor_enabled, + two_factor_method, + user_login_type, + created_at, + updated_at, + last_login_at, + deleted_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + COALESCE($6, FALSE), + $7, + $8, + COALESCE($9, 'pending'), + COALESCE($10, FALSE), + $11, + $12, + COALESCE($13, NOW()), + COALESCE($14, NOW()), + $15, + $16 +) RETURNING id, email, password_hash, auth_provider, provider_id, email_verified, email_verified_at, account_type, account_status, two_factor_enabled, two_factor_method, user_login_type, created_at, updated_at, last_login_at, deleted_at ` -// Permanently deletes a user record -func (q *Queries) DeleteUser(ctx context.Context, id uuid.UUID) error { - _, err := q.db.Exec(ctx, deleteUser, id) - return err +type CreateUserParams struct { + ID interface{} `json:"id"` + Email string `json:"email"` + PasswordHash pgtype.Text `json:"password_hash"` + AuthProvider pgtype.Text `json:"auth_provider"` + ProviderID pgtype.Text `json:"provider_id"` + EmailVerified interface{} `json:"email_verified"` + EmailVerifiedAt pgtype.Timestamptz `json:"email_verified_at"` + AccountType string `json:"account_type"` + AccountStatus interface{} `json:"account_status"` + TwoFactorEnabled interface{} `json:"two_factor_enabled"` + TwoFactorMethod pgtype.Text `json:"two_factor_method"` + UserLoginType pgtype.Text `json:"user_login_type"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` + LastLoginAt pgtype.Timestamptz `json:"last_login_at"` + DeletedAt pgtype.Timestamptz `json:"deleted_at"` } -const getUser = `-- name: GetUser :one -SELECT id, email, password_hash, profile_picture, account_type, gender, personal_account_type, phone_number, phone_number_verified, phone_number_verified_at, first_name, last_name, nationality, residential_country, job_role, company_name, company_size, company_industry, company_description, company_headquarters, user_address, user_city, user_postal_code, employee_type, auth_provider, provider_id, company_website, employment_type, created_at, updated_at FROM users WHERE id = $1::uuid LIMIT 1 -` - -func (q *Queries) GetUser(ctx context.Context, dollar_1 uuid.UUID) (Users, error) { - row := q.db.QueryRow(ctx, getUser, dollar_1) +func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (Users, error) { + row := q.db.QueryRow(ctx, createUser, + arg.ID, + arg.Email, + arg.PasswordHash, + arg.AuthProvider, + arg.ProviderID, + arg.EmailVerified, + arg.EmailVerifiedAt, + arg.AccountType, + arg.AccountStatus, + arg.TwoFactorEnabled, + arg.TwoFactorMethod, + arg.UserLoginType, + arg.CreatedAt, + arg.UpdatedAt, + arg.LastLoginAt, + arg.DeletedAt, + ) var i Users err := row.Scan( &i.ID, &i.Email, &i.PasswordHash, - &i.ProfilePicture, + &i.AuthProvider, + &i.ProviderID, + &i.EmailVerified, + &i.EmailVerifiedAt, &i.AccountType, - &i.Gender, - &i.PersonalAccountType, + &i.AccountStatus, + &i.TwoFactorEnabled, + &i.TwoFactorMethod, + &i.UserLoginType, + &i.CreatedAt, + &i.UpdatedAt, + &i.LastLoginAt, + &i.DeletedAt, + ) + return i, err +} + +const getPersonalUserByID = `-- name: GetPersonalUserByID :one +SELECT pu.id, pu.first_name, pu.last_name, pu.profile_picture, pu.phone_number, pu.phone_number_verified, pu.phone_number_verified_at, pu.nationality, pu.residential_country, pu.user_address, pu.user_city, pu.user_postal_code, pu.gender, pu.date_of_birth, pu.job_role, pu.personal_account_type, pu.employment_type, pu.tax_id, pu.default_payment_currency, pu.default_payment_method, pu.hourly_rate, pu.specialization, pu.kyc_status, pu.kyc_verified_at, pu.created_at, pu.updated_at, u.email, u.account_status +FROM personal_users pu +JOIN users u ON pu.id = u.id +WHERE pu.id = $1 AND u.deleted_at IS NULL +` + +type GetPersonalUserByIDRow struct { + ID uuid.UUID `json:"id"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` + ProfilePicture pgtype.Text `json:"profile_picture"` + PhoneNumber pgtype.Text `json:"phone_number"` + PhoneNumberVerified pgtype.Bool `json:"phone_number_verified"` + PhoneNumberVerifiedAt pgtype.Timestamptz `json:"phone_number_verified_at"` + Nationality pgtype.Text `json:"nationality"` + ResidentialCountry pgtype.Text `json:"residential_country"` + UserAddress pgtype.Text `json:"user_address"` + UserCity pgtype.Text `json:"user_city"` + UserPostalCode pgtype.Text `json:"user_postal_code"` + Gender pgtype.Text `json:"gender"` + DateOfBirth pgtype.Date `json:"date_of_birth"` + JobRole pgtype.Text `json:"job_role"` + PersonalAccountType pgtype.Text `json:"personal_account_type"` + EmploymentType pgtype.Text `json:"employment_type"` + TaxID pgtype.Text `json:"tax_id"` + DefaultPaymentCurrency pgtype.Text `json:"default_payment_currency"` + DefaultPaymentMethod pgtype.Text `json:"default_payment_method"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + Specialization pgtype.Text `json:"specialization"` + KycStatus pgtype.Text `json:"kyc_status"` + KycVerifiedAt pgtype.Timestamptz `json:"kyc_verified_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + Email string `json:"email"` + AccountStatus pgtype.Text `json:"account_status"` +} + +func (q *Queries) GetPersonalUserByID(ctx context.Context, id uuid.UUID) (GetPersonalUserByIDRow, error) { + row := q.db.QueryRow(ctx, getPersonalUserByID, id) + var i GetPersonalUserByIDRow + err := row.Scan( + &i.ID, + &i.FirstName, + &i.LastName, + &i.ProfilePicture, &i.PhoneNumber, &i.PhoneNumberVerified, &i.PhoneNumberVerifiedAt, - &i.FirstName, - &i.LastName, &i.Nationality, &i.ResidentialCountry, - &i.JobRole, - &i.CompanyName, - &i.CompanySize, - &i.CompanyIndustry, - &i.CompanyDescription, - &i.CompanyHeadquarters, &i.UserAddress, &i.UserCity, &i.UserPostalCode, - &i.EmployeeType, - &i.AuthProvider, - &i.ProviderID, - &i.CompanyWebsite, + &i.Gender, + &i.DateOfBirth, + &i.JobRole, + &i.PersonalAccountType, &i.EmploymentType, + &i.TaxID, + &i.DefaultPaymentCurrency, + &i.DefaultPaymentMethod, + &i.HourlyRate, + &i.Specialization, + &i.KycStatus, + &i.KycVerifiedAt, &i.CreatedAt, &i.UpdatedAt, + &i.Email, + &i.AccountStatus, ) return i, err } const getUserByEmail = `-- name: GetUserByEmail :one -SELECT id, email, password_hash, profile_picture, account_type, gender, personal_account_type, phone_number, phone_number_verified, phone_number_verified_at, first_name, last_name, nationality, residential_country, job_role, company_name, company_size, company_industry, company_description, company_headquarters, user_address, user_city, user_postal_code, employee_type, auth_provider, provider_id, company_website, employment_type, created_at, updated_at FROM users -WHERE email = $1 -LIMIT 1 +SELECT id, email, password_hash, auth_provider, provider_id, email_verified, email_verified_at, account_type, account_status, two_factor_enabled, two_factor_method, user_login_type, created_at, updated_at, last_login_at, deleted_at FROM users +WHERE email = $1 AND deleted_at IS NULL ` -// Retrieves a single user by their email address func (q *Queries) GetUserByEmail(ctx context.Context, email string) (Users, error) { row := q.db.QueryRow(ctx, getUserByEmail, email) var i Users @@ -298,56 +344,67 @@ func (q *Queries) GetUserByEmail(ctx context.Context, email string) (Users, erro &i.ID, &i.Email, &i.PasswordHash, - &i.ProfilePicture, + &i.AuthProvider, + &i.ProviderID, + &i.EmailVerified, + &i.EmailVerifiedAt, &i.AccountType, - &i.Gender, - &i.PersonalAccountType, - &i.PhoneNumber, - &i.PhoneNumberVerified, - &i.PhoneNumberVerifiedAt, - &i.FirstName, - &i.LastName, - &i.Nationality, - &i.ResidentialCountry, - &i.JobRole, - &i.CompanyName, - &i.CompanySize, - &i.CompanyIndustry, - &i.CompanyDescription, - &i.CompanyHeadquarters, - &i.UserAddress, - &i.UserCity, - &i.UserPostalCode, - &i.EmployeeType, + &i.AccountStatus, + &i.TwoFactorEnabled, + &i.TwoFactorMethod, + &i.UserLoginType, + &i.CreatedAt, + &i.UpdatedAt, + &i.LastLoginAt, + &i.DeletedAt, + ) + return i, err +} + +const getUserByID = `-- name: GetUserByID :one +SELECT id, email, password_hash, auth_provider, provider_id, email_verified, email_verified_at, account_type, account_status, two_factor_enabled, two_factor_method, user_login_type, created_at, updated_at, last_login_at, deleted_at FROM users +WHERE id = $1 AND deleted_at IS NULL +` + +func (q *Queries) GetUserByID(ctx context.Context, id uuid.UUID) (Users, error) { + row := q.db.QueryRow(ctx, getUserByID, id) + var i Users + err := row.Scan( + &i.ID, + &i.Email, + &i.PasswordHash, &i.AuthProvider, &i.ProviderID, - &i.CompanyWebsite, - &i.EmploymentType, + &i.EmailVerified, + &i.EmailVerifiedAt, + &i.AccountType, + &i.AccountStatus, + &i.TwoFactorEnabled, + &i.TwoFactorMethod, + &i.UserLoginType, &i.CreatedAt, &i.UpdatedAt, + &i.LastLoginAt, + &i.DeletedAt, ) return i, err } -const listUsers = `-- name: ListUsers :many -SELECT id, email, password_hash, profile_picture, account_type, gender, personal_account_type, phone_number, phone_number_verified, phone_number_verified_at, first_name, last_name, nationality, residential_country, job_role, company_name, company_size, company_industry, company_description, company_headquarters, user_address, user_city, user_postal_code, employee_type, auth_provider, provider_id, company_website, employment_type, created_at, updated_at -FROM users -ORDER BY - CASE WHEN $3::text = 'ASC' THEN created_at END ASC, - CASE WHEN $3::text = 'DESC' OR $3::text IS NULL THEN created_at END DESC -LIMIT $1 -OFFSET $2 +const getUsersByAccountType = `-- name: GetUsersByAccountType :many +SELECT id, email, password_hash, auth_provider, provider_id, email_verified, email_verified_at, account_type, account_status, two_factor_enabled, two_factor_method, user_login_type, created_at, updated_at, last_login_at, deleted_at FROM users +WHERE account_type = $1 AND deleted_at IS NULL +ORDER BY created_at DESC +LIMIT $3 OFFSET $2 ` -type ListUsersParams struct { - Limit int32 `json:"limit"` - Offset int32 `json:"offset"` - Column3 string `json:"column_3"` +type GetUsersByAccountTypeParams struct { + AccountType string `json:"account_type"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` } -// Lists users with pagination support -func (q *Queries) ListUsers(ctx context.Context, arg ListUsersParams) ([]Users, error) { - rows, err := q.db.Query(ctx, listUsers, arg.Limit, arg.Offset, arg.Column3) +func (q *Queries) GetUsersByAccountType(ctx context.Context, arg GetUsersByAccountTypeParams) ([]Users, error) { + rows, err := q.db.Query(ctx, getUsersByAccountType, arg.AccountType, arg.OffsetVal, arg.LimitVal) if err != nil { return nil, err } @@ -359,33 +416,19 @@ func (q *Queries) ListUsers(ctx context.Context, arg ListUsersParams) ([]Users, &i.ID, &i.Email, &i.PasswordHash, - &i.ProfilePicture, - &i.AccountType, - &i.Gender, - &i.PersonalAccountType, - &i.PhoneNumber, - &i.PhoneNumberVerified, - &i.PhoneNumberVerifiedAt, - &i.FirstName, - &i.LastName, - &i.Nationality, - &i.ResidentialCountry, - &i.JobRole, - &i.CompanyName, - &i.CompanySize, - &i.CompanyIndustry, - &i.CompanyDescription, - &i.CompanyHeadquarters, - &i.UserAddress, - &i.UserCity, - &i.UserPostalCode, - &i.EmployeeType, &i.AuthProvider, &i.ProviderID, - &i.CompanyWebsite, - &i.EmploymentType, + &i.EmailVerified, + &i.EmailVerifiedAt, + &i.AccountType, + &i.AccountStatus, + &i.TwoFactorEnabled, + &i.TwoFactorMethod, + &i.UserLoginType, &i.CreatedAt, &i.UpdatedAt, + &i.LastLoginAt, + &i.DeletedAt, ); err != nil { return nil, err } @@ -397,32 +440,20 @@ func (q *Queries) ListUsers(ctx context.Context, arg ListUsersParams) ([]Users, return items, nil } -const listUsersByAccountType = `-- name: ListUsersByAccountType :many -SELECT id, email, password_hash, profile_picture, account_type, gender, personal_account_type, phone_number, phone_number_verified, phone_number_verified_at, first_name, last_name, nationality, residential_country, job_role, company_name, company_size, company_industry, company_description, company_headquarters, user_address, user_city, user_postal_code, employee_type, auth_provider, provider_id, company_website, employment_type, created_at, updated_at -FROM users -WHERE account_type = $3 -ORDER BY - CASE WHEN $4::text = 'ASC' THEN created_at END ASC, - CASE WHEN $4::text = 'DESC' OR $4::text IS NULL THEN created_at END DESC -LIMIT $1 -OFFSET $2 +const listUsers = `-- name: ListUsers :many +SELECT id, email, password_hash, auth_provider, provider_id, email_verified, email_verified_at, account_type, account_status, two_factor_enabled, two_factor_method, user_login_type, created_at, updated_at, last_login_at, deleted_at FROM users +WHERE deleted_at IS NULL +ORDER BY created_at DESC +LIMIT $2 OFFSET $1 ` -type ListUsersByAccountTypeParams struct { - Limit int32 `json:"limit"` - Offset int32 `json:"offset"` - AccountType string `json:"account_type"` - Column4 string `json:"column_4"` +type ListUsersParams struct { + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` } -// Lists users filtered by account type with pagination -func (q *Queries) ListUsersByAccountType(ctx context.Context, arg ListUsersByAccountTypeParams) ([]Users, error) { - rows, err := q.db.Query(ctx, listUsersByAccountType, - arg.Limit, - arg.Offset, - arg.AccountType, - arg.Column4, - ) +func (q *Queries) ListUsers(ctx context.Context, arg ListUsersParams) ([]Users, error) { + rows, err := q.db.Query(ctx, listUsers, arg.OffsetVal, arg.LimitVal) if err != nil { return nil, err } @@ -434,33 +465,19 @@ func (q *Queries) ListUsersByAccountType(ctx context.Context, arg ListUsersByAcc &i.ID, &i.Email, &i.PasswordHash, - &i.ProfilePicture, - &i.AccountType, - &i.Gender, - &i.PersonalAccountType, - &i.PhoneNumber, - &i.PhoneNumberVerified, - &i.PhoneNumberVerifiedAt, - &i.FirstName, - &i.LastName, - &i.Nationality, - &i.ResidentialCountry, - &i.JobRole, - &i.CompanyName, - &i.CompanySize, - &i.CompanyIndustry, - &i.CompanyDescription, - &i.CompanyHeadquarters, - &i.UserAddress, - &i.UserCity, - &i.UserPostalCode, - &i.EmployeeType, &i.AuthProvider, &i.ProviderID, - &i.CompanyWebsite, - &i.EmploymentType, + &i.EmailVerified, + &i.EmailVerifiedAt, + &i.AccountType, + &i.AccountStatus, + &i.TwoFactorEnabled, + &i.TwoFactorMethod, + &i.UserLoginType, &i.CreatedAt, &i.UpdatedAt, + &i.LastLoginAt, + &i.DeletedAt, ); err != nil { return nil, err } @@ -472,38 +489,22 @@ func (q *Queries) ListUsersByAccountType(ctx context.Context, arg ListUsersByAcc return items, nil } -const searchUsers = `-- name: SearchUsers :many -SELECT id, email, password_hash, profile_picture, account_type, gender, personal_account_type, phone_number, phone_number_verified, phone_number_verified_at, first_name, last_name, nationality, residential_country, job_role, company_name, company_size, company_industry, company_description, company_headquarters, user_address, user_city, user_postal_code, employee_type, auth_provider, provider_id, company_website, employment_type, created_at, updated_at -FROM users -WHERE - ( - first_name ILIKE '%' || $3 || '%' OR - last_name ILIKE '%' || $3 || '%' OR - email ILIKE '%' || $3 || '%' OR - nationality ILIKE '%' || $3 || '%' - ) -ORDER BY - CASE WHEN $4::text = 'ASC' THEN created_at END ASC, - CASE WHEN $4::text = 'DESC' OR $4::text IS NULL THEN created_at END DESC -LIMIT $1 -OFFSET $2 +const searchUsersByEmail = `-- name: SearchUsersByEmail :many +SELECT id, email, password_hash, auth_provider, provider_id, email_verified, email_verified_at, account_type, account_status, two_factor_enabled, two_factor_method, user_login_type, created_at, updated_at, last_login_at, deleted_at FROM users +WHERE email ILIKE '%' || $1 || '%' + AND deleted_at IS NULL +ORDER BY email +LIMIT $3 OFFSET $2 ` -type SearchUsersParams struct { - Limit int32 `json:"limit"` - Offset int32 `json:"offset"` - Column3 pgtype.Text `json:"column_3"` - Column4 string `json:"column_4"` +type SearchUsersByEmailParams struct { + SearchTerm pgtype.Text `json:"search_term"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` } -// Searches for users by name, email, or nationality with pagination -func (q *Queries) SearchUsers(ctx context.Context, arg SearchUsersParams) ([]Users, error) { - rows, err := q.db.Query(ctx, searchUsers, - arg.Limit, - arg.Offset, - arg.Column3, - arg.Column4, - ) +func (q *Queries) SearchUsersByEmail(ctx context.Context, arg SearchUsersByEmailParams) ([]Users, error) { + rows, err := q.db.Query(ctx, searchUsersByEmail, arg.SearchTerm, arg.OffsetVal, arg.LimitVal) if err != nil { return nil, err } @@ -515,33 +516,19 @@ func (q *Queries) SearchUsers(ctx context.Context, arg SearchUsersParams) ([]Use &i.ID, &i.Email, &i.PasswordHash, - &i.ProfilePicture, - &i.AccountType, - &i.Gender, - &i.PersonalAccountType, - &i.PhoneNumber, - &i.PhoneNumberVerified, - &i.PhoneNumberVerifiedAt, - &i.FirstName, - &i.LastName, - &i.Nationality, - &i.ResidentialCountry, - &i.JobRole, - &i.CompanyName, - &i.CompanySize, - &i.CompanyIndustry, - &i.CompanyDescription, - &i.CompanyHeadquarters, - &i.UserAddress, - &i.UserCity, - &i.UserPostalCode, - &i.EmployeeType, &i.AuthProvider, &i.ProviderID, - &i.CompanyWebsite, - &i.EmploymentType, + &i.EmailVerified, + &i.EmailVerifiedAt, + &i.AccountType, + &i.AccountStatus, + &i.TwoFactorEnabled, + &i.TwoFactorMethod, + &i.UserLoginType, &i.CreatedAt, &i.UpdatedAt, + &i.LastLoginAt, + &i.DeletedAt, ); err != nil { return nil, err } @@ -553,511 +540,203 @@ func (q *Queries) SearchUsers(ctx context.Context, arg SearchUsersParams) ([]Use return items, nil } -const updateUser = `-- name: UpdateUser :one -UPDATE users -SET - email = COALESCE($2, email), - profile_picture = $3, - account_type = COALESCE($4, account_type), - gender = $5, - personal_account_type = COALESCE($6, personal_account_type), - first_name = COALESCE($7, first_name), - last_name = COALESCE($8, last_name), - nationality = COALESCE($9, nationality), - residential_country = $10, - job_role = $11, - company_website = $12, - employment_type = $13, - company_name = $14, - company_headquarters = $15, - company_size = $16, - company_description = $17, - company_industry = $18, - auth_provider = COALESCE($19, auth_provider), - provider_id = COALESCE($20, provider_id), - user_address = COALESCE($21, user_address), - user_city = COALESCE($22, user_city), - user_postal_code = COALESCE($23, user_postal_code), - updated_at = now() +const softDeleteUser = `-- name: SoftDeleteUser :exec +UPDATE users SET + deleted_at = NOW(), + updated_at = NOW() WHERE id = $1 -RETURNING id, email, password_hash, profile_picture, account_type, gender, personal_account_type, phone_number, phone_number_verified, phone_number_verified_at, first_name, last_name, nationality, residential_country, job_role, company_name, company_size, company_industry, company_description, company_headquarters, user_address, user_city, user_postal_code, employee_type, auth_provider, provider_id, company_website, employment_type, created_at, updated_at ` -type UpdateUserParams struct { - ID uuid.UUID `json:"id"` - Email string `json:"email"` - ProfilePicture pgtype.Text `json:"profile_picture"` - AccountType string `json:"account_type"` - Gender pgtype.Text `json:"gender"` - PersonalAccountType string `json:"personal_account_type"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - Nationality string `json:"nationality"` - ResidentialCountry pgtype.Text `json:"residential_country"` - JobRole pgtype.Text `json:"job_role"` - CompanyWebsite pgtype.Text `json:"company_website"` - EmploymentType pgtype.Text `json:"employment_type"` - CompanyName pgtype.Text `json:"company_name"` - CompanyHeadquarters pgtype.Text `json:"company_headquarters"` - CompanySize pgtype.Text `json:"company_size"` - CompanyDescription pgtype.Text `json:"company_description"` - CompanyIndustry pgtype.Text `json:"company_industry"` - AuthProvider pgtype.Text `json:"auth_provider"` - ProviderID string `json:"provider_id"` - UserAddress pgtype.Text `json:"user_address"` - UserCity pgtype.Text `json:"user_city"` - UserPostalCode pgtype.Text `json:"user_postal_code"` +func (q *Queries) SoftDeleteUser(ctx context.Context, id uuid.UUID) error { + _, err := q.db.Exec(ctx, softDeleteUser, id) + return err } -// Updates user details and returns the updated user -func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (Users, error) { - row := q.db.QueryRow(ctx, updateUser, - arg.ID, - arg.Email, - arg.ProfilePicture, - arg.AccountType, - arg.Gender, - arg.PersonalAccountType, +const updatePersonalUser = `-- name: UpdatePersonalUser :one +UPDATE personal_users SET + first_name = COALESCE($1, first_name), + last_name = COALESCE($2, last_name), + profile_picture = COALESCE($3, profile_picture), + phone_number = COALESCE($4, phone_number), + phone_number_verified = COALESCE($5, phone_number_verified), + phone_number_verified_at = COALESCE($6, phone_number_verified_at), + nationality = COALESCE($7, nationality), + residential_country = COALESCE($8, residential_country), + user_address = COALESCE($9, user_address), + user_city = COALESCE($10, user_city), + user_postal_code = COALESCE($11, user_postal_code), + gender = COALESCE($12, gender), + date_of_birth = COALESCE($13, date_of_birth), + job_role = COALESCE($14, job_role), + employment_type = COALESCE($15, employment_type), + tax_id = COALESCE($16, tax_id), + default_payment_currency = COALESCE($17, default_payment_currency), + default_payment_method = COALESCE($18, default_payment_method), + hourly_rate = COALESCE($19, hourly_rate), + specialization = COALESCE($20, specialization), + kyc_status = COALESCE($21, kyc_status), + kyc_verified_at = COALESCE($22, kyc_verified_at), + updated_at = NOW() +WHERE id = $23 +RETURNING id, first_name, last_name, profile_picture, phone_number, phone_number_verified, phone_number_verified_at, nationality, residential_country, user_address, user_city, user_postal_code, gender, date_of_birth, job_role, personal_account_type, employment_type, tax_id, default_payment_currency, default_payment_method, hourly_rate, specialization, kyc_status, kyc_verified_at, created_at, updated_at +` + +type UpdatePersonalUserParams struct { + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` + ProfilePicture pgtype.Text `json:"profile_picture"` + PhoneNumber pgtype.Text `json:"phone_number"` + PhoneNumberVerified pgtype.Bool `json:"phone_number_verified"` + PhoneNumberVerifiedAt pgtype.Timestamptz `json:"phone_number_verified_at"` + Nationality pgtype.Text `json:"nationality"` + ResidentialCountry pgtype.Text `json:"residential_country"` + UserAddress pgtype.Text `json:"user_address"` + UserCity pgtype.Text `json:"user_city"` + UserPostalCode pgtype.Text `json:"user_postal_code"` + Gender pgtype.Text `json:"gender"` + DateOfBirth pgtype.Date `json:"date_of_birth"` + JobRole pgtype.Text `json:"job_role"` + EmploymentType pgtype.Text `json:"employment_type"` + TaxID pgtype.Text `json:"tax_id"` + DefaultPaymentCurrency pgtype.Text `json:"default_payment_currency"` + DefaultPaymentMethod pgtype.Text `json:"default_payment_method"` + HourlyRate pgtype.Numeric `json:"hourly_rate"` + Specialization pgtype.Text `json:"specialization"` + KycStatus pgtype.Text `json:"kyc_status"` + KycVerifiedAt pgtype.Timestamptz `json:"kyc_verified_at"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdatePersonalUser(ctx context.Context, arg UpdatePersonalUserParams) (PersonalUsers, error) { + row := q.db.QueryRow(ctx, updatePersonalUser, arg.FirstName, arg.LastName, + arg.ProfilePicture, + arg.PhoneNumber, + arg.PhoneNumberVerified, + arg.PhoneNumberVerifiedAt, arg.Nationality, arg.ResidentialCountry, - arg.JobRole, - arg.CompanyWebsite, - arg.EmploymentType, - arg.CompanyName, - arg.CompanyHeadquarters, - arg.CompanySize, - arg.CompanyDescription, - arg.CompanyIndustry, - arg.AuthProvider, - arg.ProviderID, arg.UserAddress, arg.UserCity, arg.UserPostalCode, - ) - var i Users - err := row.Scan( - &i.ID, - &i.Email, - &i.PasswordHash, - &i.ProfilePicture, - &i.AccountType, - &i.Gender, - &i.PersonalAccountType, - &i.PhoneNumber, - &i.PhoneNumberVerified, - &i.PhoneNumberVerifiedAt, - &i.FirstName, - &i.LastName, - &i.Nationality, - &i.ResidentialCountry, - &i.JobRole, - &i.CompanyName, - &i.CompanySize, - &i.CompanyIndustry, - &i.CompanyDescription, - &i.CompanyHeadquarters, - &i.UserAddress, - &i.UserCity, - &i.UserPostalCode, - &i.EmployeeType, - &i.AuthProvider, - &i.ProviderID, - &i.CompanyWebsite, - &i.EmploymentType, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const updateUserAddress = `-- name: UpdateUserAddress :one -UPDATE users -SET - user_address = COALESCE($2, user_address), - user_city = COALESCE($3, user_city), - user_postal_code = COALESCE($4, user_postal_code), - updated_at = now() -WHERE id = $1 -RETURNING id, email, password_hash, profile_picture, account_type, gender, personal_account_type, phone_number, phone_number_verified, phone_number_verified_at, first_name, last_name, nationality, residential_country, job_role, company_name, company_size, company_industry, company_description, company_headquarters, user_address, user_city, user_postal_code, employee_type, auth_provider, provider_id, company_website, employment_type, created_at, updated_at -` - -type UpdateUserAddressParams struct { - ID uuid.UUID `json:"id"` - UserAddress pgtype.Text `json:"user_address"` - UserCity pgtype.Text `json:"user_city"` - UserPostalCode pgtype.Text `json:"user_postal_code"` -} - -// Updates a user's address -func (q *Queries) UpdateUserAddress(ctx context.Context, arg UpdateUserAddressParams) (Users, error) { - row := q.db.QueryRow(ctx, updateUserAddress, + arg.Gender, + arg.DateOfBirth, + arg.JobRole, + arg.EmploymentType, + arg.TaxID, + arg.DefaultPaymentCurrency, + arg.DefaultPaymentMethod, + arg.HourlyRate, + arg.Specialization, + arg.KycStatus, + arg.KycVerifiedAt, arg.ID, - arg.UserAddress, - arg.UserCity, - arg.UserPostalCode, ) - var i Users + var i PersonalUsers err := row.Scan( &i.ID, - &i.Email, - &i.PasswordHash, - &i.ProfilePicture, - &i.AccountType, - &i.Gender, - &i.PersonalAccountType, - &i.PhoneNumber, - &i.PhoneNumberVerified, - &i.PhoneNumberVerifiedAt, &i.FirstName, &i.LastName, - &i.Nationality, - &i.ResidentialCountry, - &i.JobRole, - &i.CompanyName, - &i.CompanySize, - &i.CompanyIndustry, - &i.CompanyDescription, - &i.CompanyHeadquarters, - &i.UserAddress, - &i.UserCity, - &i.UserPostalCode, - &i.EmployeeType, - &i.AuthProvider, - &i.ProviderID, - &i.CompanyWebsite, - &i.EmploymentType, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const updateUserCompanyDetails = `-- name: UpdateUserCompanyDetails :one -UPDATE users -SET - company_name = COALESCE($2, company_name), - company_headquarters = COALESCE($3, company_headquarters), - company_size = COALESCE($4, company_size), - company_industry = COALESCE($5, company_industry), - company_description = COALESCE($6, company_description), - company_headquarters = COALESCE($7, company_headquarters), - account_type = COALESCE($8, account_type), - updated_at = now() -WHERE id = $1 -RETURNING id, email, password_hash, profile_picture, account_type, gender, personal_account_type, phone_number, phone_number_verified, phone_number_verified_at, first_name, last_name, nationality, residential_country, job_role, company_name, company_size, company_industry, company_description, company_headquarters, user_address, user_city, user_postal_code, employee_type, auth_provider, provider_id, company_website, employment_type, created_at, updated_at -` - -type UpdateUserCompanyDetailsParams struct { - ID uuid.UUID `json:"id"` - CompanyName pgtype.Text `json:"company_name"` - CompanyHeadquarters pgtype.Text `json:"company_headquarters"` - CompanySize pgtype.Text `json:"company_size"` - CompanyIndustry pgtype.Text `json:"company_industry"` - CompanyDescription pgtype.Text `json:"company_description"` - CompanyHeadquarters_2 pgtype.Text `json:"company_headquarters_2"` - AccountType string `json:"account_type"` -} - -// Updates a user's company details -func (q *Queries) UpdateUserCompanyDetails(ctx context.Context, arg UpdateUserCompanyDetailsParams) (Users, error) { - row := q.db.QueryRow(ctx, updateUserCompanyDetails, - arg.ID, - arg.CompanyName, - arg.CompanyHeadquarters, - arg.CompanySize, - arg.CompanyIndustry, - arg.CompanyDescription, - arg.CompanyHeadquarters_2, - arg.AccountType, - ) - var i Users - err := row.Scan( - &i.ID, - &i.Email, - &i.PasswordHash, &i.ProfilePicture, - &i.AccountType, - &i.Gender, - &i.PersonalAccountType, &i.PhoneNumber, &i.PhoneNumberVerified, &i.PhoneNumberVerifiedAt, - &i.FirstName, - &i.LastName, &i.Nationality, &i.ResidentialCountry, - &i.JobRole, - &i.CompanyName, - &i.CompanySize, - &i.CompanyIndustry, - &i.CompanyDescription, - &i.CompanyHeadquarters, &i.UserAddress, &i.UserCity, &i.UserPostalCode, - &i.EmployeeType, - &i.AuthProvider, - &i.ProviderID, - &i.CompanyWebsite, - &i.EmploymentType, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const updateUserEmail = `-- name: UpdateUserEmail :one -UPDATE users -SET - email = $2, - updated_at = now() -WHERE id = $1 -RETURNING id, email, password_hash, profile_picture, account_type, gender, personal_account_type, phone_number, phone_number_verified, phone_number_verified_at, first_name, last_name, nationality, residential_country, job_role, company_name, company_size, company_industry, company_description, company_headquarters, user_address, user_city, user_postal_code, employee_type, auth_provider, provider_id, company_website, employment_type, created_at, updated_at -` - -type UpdateUserEmailParams struct { - ID uuid.UUID `json:"id"` - Email string `json:"email"` -} - -// Updates a user's email address with validation that the new email is unique -func (q *Queries) UpdateUserEmail(ctx context.Context, arg UpdateUserEmailParams) (Users, error) { - row := q.db.QueryRow(ctx, updateUserEmail, arg.ID, arg.Email) - var i Users - err := row.Scan( - &i.ID, - &i.Email, - &i.PasswordHash, - &i.ProfilePicture, - &i.AccountType, &i.Gender, - &i.PersonalAccountType, - &i.PhoneNumber, - &i.PhoneNumberVerified, - &i.PhoneNumberVerifiedAt, - &i.FirstName, - &i.LastName, - &i.Nationality, - &i.ResidentialCountry, + &i.DateOfBirth, &i.JobRole, - &i.CompanyName, - &i.CompanySize, - &i.CompanyIndustry, - &i.CompanyDescription, - &i.CompanyHeadquarters, - &i.UserAddress, - &i.UserCity, - &i.UserPostalCode, - &i.EmployeeType, - &i.AuthProvider, - &i.ProviderID, - &i.CompanyWebsite, - &i.EmploymentType, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err -} - -const updateUserJobRole = `-- name: UpdateUserJobRole :one -UPDATE users -SET - job_role = COALESCE($2, job_role), - updated_at = now() -WHERE id = $1 -RETURNING id, email, password_hash, profile_picture, account_type, gender, personal_account_type, phone_number, phone_number_verified, phone_number_verified_at, first_name, last_name, nationality, residential_country, job_role, company_name, company_size, company_industry, company_description, company_headquarters, user_address, user_city, user_postal_code, employee_type, auth_provider, provider_id, company_website, employment_type, created_at, updated_at -` - -type UpdateUserJobRoleParams struct { - ID uuid.UUID `json:"id"` - JobRole pgtype.Text `json:"job_role"` -} - -// Updates a user's job role -func (q *Queries) UpdateUserJobRole(ctx context.Context, arg UpdateUserJobRoleParams) (Users, error) { - row := q.db.QueryRow(ctx, updateUserJobRole, arg.ID, arg.JobRole) - var i Users - err := row.Scan( - &i.ID, - &i.Email, - &i.PasswordHash, - &i.ProfilePicture, - &i.AccountType, - &i.Gender, &i.PersonalAccountType, - &i.PhoneNumber, - &i.PhoneNumberVerified, - &i.PhoneNumberVerifiedAt, - &i.FirstName, - &i.LastName, - &i.Nationality, - &i.ResidentialCountry, - &i.JobRole, - &i.CompanyName, - &i.CompanySize, - &i.CompanyIndustry, - &i.CompanyDescription, - &i.CompanyHeadquarters, - &i.UserAddress, - &i.UserCity, - &i.UserPostalCode, - &i.EmployeeType, - &i.AuthProvider, - &i.ProviderID, - &i.CompanyWebsite, &i.EmploymentType, + &i.TaxID, + &i.DefaultPaymentCurrency, + &i.DefaultPaymentMethod, + &i.HourlyRate, + &i.Specialization, + &i.KycStatus, + &i.KycVerifiedAt, &i.CreatedAt, &i.UpdatedAt, ) return i, err } -const updateUserPassword = `-- name: UpdateUserPassword :exec -UPDATE users -SET - password_hash = $2, - updated_at = now() -WHERE id = $1 -` - -type UpdateUserPasswordParams struct { - ID uuid.UUID `json:"id"` - PasswordHash pgtype.Text `json:"password_hash"` -} - -// Updates a user's password -func (q *Queries) UpdateUserPassword(ctx context.Context, arg UpdateUserPasswordParams) error { - _, err := q.db.Exec(ctx, updateUserPassword, arg.ID, arg.PasswordHash) - return err -} - -const updateUserPersonalDetails = `-- name: UpdateUserPersonalDetails :one -UPDATE users -SET - nationality = COALESCE($2, nationality), - phone_number = COALESCE($3, phone_number), - residential_country = COALESCE($4, residential_country), - account_type = COALESCE($5, account_type), - personal_account_type = COALESCE($6, personal_account_type), - updated_at = now() - WHERE id = $1 - RETURNING id, email, password_hash, profile_picture, account_type, gender, personal_account_type, phone_number, phone_number_verified, phone_number_verified_at, first_name, last_name, nationality, residential_country, job_role, company_name, company_size, company_industry, company_description, company_headquarters, user_address, user_city, user_postal_code, employee_type, auth_provider, provider_id, company_website, employment_type, created_at, updated_at +const updateUser = `-- name: UpdateUser :one +UPDATE users SET + password_hash = COALESCE($1, password_hash), + auth_provider = COALESCE($2, auth_provider), + provider_id = COALESCE($3, provider_id), + email_verified = COALESCE($4, email_verified), + email_verified_at = COALESCE($5, email_verified_at), + account_status = COALESCE($6, account_status), + two_factor_enabled = COALESCE($7, two_factor_enabled), + two_factor_method = COALESCE($8, two_factor_method), + last_login_at = COALESCE($9, last_login_at), + updated_at = NOW() +WHERE id = $10 AND deleted_at IS NULL +RETURNING id, email, password_hash, auth_provider, provider_id, email_verified, email_verified_at, account_type, account_status, two_factor_enabled, two_factor_method, user_login_type, created_at, updated_at, last_login_at, deleted_at ` -type UpdateUserPersonalDetailsParams struct { - ID uuid.UUID `json:"id"` - Nationality string `json:"nationality"` - PhoneNumber pgtype.Text `json:"phone_number"` - ResidentialCountry pgtype.Text `json:"residential_country"` - AccountType string `json:"account_type"` - PersonalAccountType string `json:"personal_account_type"` +type UpdateUserParams struct { + PasswordHash pgtype.Text `json:"password_hash"` + AuthProvider pgtype.Text `json:"auth_provider"` + ProviderID pgtype.Text `json:"provider_id"` + EmailVerified pgtype.Bool `json:"email_verified"` + EmailVerifiedAt pgtype.Timestamptz `json:"email_verified_at"` + AccountStatus pgtype.Text `json:"account_status"` + TwoFactorEnabled pgtype.Bool `json:"two_factor_enabled"` + TwoFactorMethod pgtype.Text `json:"two_factor_method"` + LastLoginAt pgtype.Timestamptz `json:"last_login_at"` + ID uuid.UUID `json:"id"` } -// Updates a user's personal details -func (q *Queries) UpdateUserPersonalDetails(ctx context.Context, arg UpdateUserPersonalDetailsParams) (Users, error) { - row := q.db.QueryRow(ctx, updateUserPersonalDetails, +func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (Users, error) { + row := q.db.QueryRow(ctx, updateUser, + arg.PasswordHash, + arg.AuthProvider, + arg.ProviderID, + arg.EmailVerified, + arg.EmailVerifiedAt, + arg.AccountStatus, + arg.TwoFactorEnabled, + arg.TwoFactorMethod, + arg.LastLoginAt, arg.ID, - arg.Nationality, - arg.PhoneNumber, - arg.ResidentialCountry, - arg.AccountType, - arg.PersonalAccountType, ) var i Users err := row.Scan( &i.ID, &i.Email, &i.PasswordHash, - &i.ProfilePicture, - &i.AccountType, - &i.Gender, - &i.PersonalAccountType, - &i.PhoneNumber, - &i.PhoneNumberVerified, - &i.PhoneNumberVerifiedAt, - &i.FirstName, - &i.LastName, - &i.Nationality, - &i.ResidentialCountry, - &i.JobRole, - &i.CompanyName, - &i.CompanySize, - &i.CompanyIndustry, - &i.CompanyDescription, - &i.CompanyHeadquarters, - &i.UserAddress, - &i.UserCity, - &i.UserPostalCode, - &i.EmployeeType, &i.AuthProvider, &i.ProviderID, - &i.CompanyWebsite, - &i.EmploymentType, + &i.EmailVerified, + &i.EmailVerifiedAt, + &i.AccountType, + &i.AccountStatus, + &i.TwoFactorEnabled, + &i.TwoFactorMethod, + &i.UserLoginType, &i.CreatedAt, &i.UpdatedAt, + &i.LastLoginAt, + &i.DeletedAt, ) return i, err } -const updateUserProfile = `-- name: UpdateUserProfile :one -UPDATE users -SET - profile_picture = COALESCE($2, profile_picture), - first_name = COALESCE($3, first_name), - last_name = COALESCE($4, last_name) +const updateUserLoginTime = `-- name: UpdateUserLoginTime :exec +UPDATE users SET + last_login_at = NOW(), + updated_at = NOW() WHERE id = $1 -RETURNING id, email, password_hash, profile_picture, account_type, gender, personal_account_type, phone_number, phone_number_verified, phone_number_verified_at, first_name, last_name, nationality, residential_country, job_role, company_name, company_size, company_industry, company_description, company_headquarters, user_address, user_city, user_postal_code, employee_type, auth_provider, provider_id, company_website, employment_type, created_at, updated_at ` -type UpdateUserProfileParams struct { - ID uuid.UUID `json:"id"` - ProfilePicture pgtype.Text `json:"profile_picture"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` -} - -// Updates a user's profile information -func (q *Queries) UpdateUserProfile(ctx context.Context, arg UpdateUserProfileParams) (Users, error) { - row := q.db.QueryRow(ctx, updateUserProfile, - arg.ID, - arg.ProfilePicture, - arg.FirstName, - arg.LastName, - ) - var i Users - err := row.Scan( - &i.ID, - &i.Email, - &i.PasswordHash, - &i.ProfilePicture, - &i.AccountType, - &i.Gender, - &i.PersonalAccountType, - &i.PhoneNumber, - &i.PhoneNumberVerified, - &i.PhoneNumberVerifiedAt, - &i.FirstName, - &i.LastName, - &i.Nationality, - &i.ResidentialCountry, - &i.JobRole, - &i.CompanyName, - &i.CompanySize, - &i.CompanyIndustry, - &i.CompanyDescription, - &i.CompanyHeadquarters, - &i.UserAddress, - &i.UserCity, - &i.UserPostalCode, - &i.EmployeeType, - &i.AuthProvider, - &i.ProviderID, - &i.CompanyWebsite, - &i.EmploymentType, - &i.CreatedAt, - &i.UpdatedAt, - ) - return i, err +func (q *Queries) UpdateUserLoginTime(ctx context.Context, id uuid.UUID) error { + _, err := q.db.Exec(ctx, updateUserLoginTime, id) + return err } diff --git a/db/sqlc/wallet.sql.go b/db/sqlc/wallet.sql.go new file mode 100644 index 0000000..6235686 --- /dev/null +++ b/db/sqlc/wallet.sql.go @@ -0,0 +1,870 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.29.0 +// source: wallet.sql + +package sqlc + +import ( + "context" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" +) + +const createSupportedNetwork = `-- name: CreateSupportedNetwork :one +INSERT INTO supported_networks ( + id, + name, + chain_id, + network_type, + currency_symbol, + block_explorer_url, + rpc_url, + is_evm_compatible, + is_active, + transaction_speed, + average_block_time, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + $6, + $7, + COALESCE($8, FALSE), + COALESCE($9, TRUE), + $10, + $11, + COALESCE($12, NOW()), + COALESCE($13, NOW()) +) RETURNING id, name, chain_id, network_type, currency_symbol, block_explorer_url, rpc_url, is_evm_compatible, is_active, transaction_speed, average_block_time, created_at, updated_at +` + +type CreateSupportedNetworkParams struct { + ID interface{} `json:"id"` + Name string `json:"name"` + ChainID int32 `json:"chain_id"` + NetworkType string `json:"network_type"` + CurrencySymbol string `json:"currency_symbol"` + BlockExplorerUrl pgtype.Text `json:"block_explorer_url"` + RpcUrl pgtype.Text `json:"rpc_url"` + IsEvmCompatible interface{} `json:"is_evm_compatible"` + IsActive interface{} `json:"is_active"` + TransactionSpeed pgtype.Text `json:"transaction_speed"` + AverageBlockTime pgtype.Int4 `json:"average_block_time"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateSupportedNetwork(ctx context.Context, arg CreateSupportedNetworkParams) (SupportedNetworks, error) { + row := q.db.QueryRow(ctx, createSupportedNetwork, + arg.ID, + arg.Name, + arg.ChainID, + arg.NetworkType, + arg.CurrencySymbol, + arg.BlockExplorerUrl, + arg.RpcUrl, + arg.IsEvmCompatible, + arg.IsActive, + arg.TransactionSpeed, + arg.AverageBlockTime, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i SupportedNetworks + err := row.Scan( + &i.ID, + &i.Name, + &i.ChainID, + &i.NetworkType, + &i.CurrencySymbol, + &i.BlockExplorerUrl, + &i.RpcUrl, + &i.IsEvmCompatible, + &i.IsActive, + &i.TransactionSpeed, + &i.AverageBlockTime, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createSupportedToken = `-- name: CreateSupportedToken :one +INSERT INTO supported_tokens ( + id, + network_id, + name, + symbol, + decimals, + contract_address, + token_type, + logo_url, + is_stablecoin, + is_active, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + COALESCE($5, 18), + $6, + $7, + $8, + COALESCE($9, FALSE), + COALESCE($10, TRUE), + COALESCE($11, NOW()), + COALESCE($12, NOW()) +) RETURNING id, network_id, name, symbol, decimals, contract_address, token_type, logo_url, is_stablecoin, is_active, created_at, updated_at +` + +type CreateSupportedTokenParams struct { + ID interface{} `json:"id"` + NetworkID uuid.UUID `json:"network_id"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals interface{} `json:"decimals"` + ContractAddress pgtype.Text `json:"contract_address"` + TokenType string `json:"token_type"` + LogoUrl pgtype.Text `json:"logo_url"` + IsStablecoin interface{} `json:"is_stablecoin"` + IsActive interface{} `json:"is_active"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateSupportedToken(ctx context.Context, arg CreateSupportedTokenParams) (SupportedTokens, error) { + row := q.db.QueryRow(ctx, createSupportedToken, + arg.ID, + arg.NetworkID, + arg.Name, + arg.Symbol, + arg.Decimals, + arg.ContractAddress, + arg.TokenType, + arg.LogoUrl, + arg.IsStablecoin, + arg.IsActive, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i SupportedTokens + err := row.Scan( + &i.ID, + &i.NetworkID, + &i.Name, + &i.Symbol, + &i.Decimals, + &i.ContractAddress, + &i.TokenType, + &i.LogoUrl, + &i.IsStablecoin, + &i.IsActive, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const createUserWallet = `-- name: CreateUserWallet :one +INSERT INTO user_wallets ( + id, + user_id, + wallet_address, + wallet_type, + chain_id, + is_default, + is_verified, + verification_method, + verified_at, + nickname, + created_at, + updated_at +) VALUES ( + COALESCE($1, uuid_generate_v4()), + $2, + $3, + $4, + $5, + COALESCE($6, FALSE), + COALESCE($7, FALSE), + $8, + $9, + $10, + COALESCE($11, NOW()), + COALESCE($12, NOW()) +) RETURNING id, user_id, wallet_address, wallet_type, chain_id, is_default, is_verified, verification_method, verified_at, nickname, created_at, updated_at +` + +type CreateUserWalletParams struct { + ID interface{} `json:"id"` + UserID uuid.UUID `json:"user_id"` + WalletAddress string `json:"wallet_address"` + WalletType string `json:"wallet_type"` + ChainID int32 `json:"chain_id"` + IsDefault interface{} `json:"is_default"` + IsVerified interface{} `json:"is_verified"` + VerificationMethod pgtype.Text `json:"verification_method"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + Nickname pgtype.Text `json:"nickname"` + CreatedAt interface{} `json:"created_at"` + UpdatedAt interface{} `json:"updated_at"` +} + +func (q *Queries) CreateUserWallet(ctx context.Context, arg CreateUserWalletParams) (UserWallets, error) { + row := q.db.QueryRow(ctx, createUserWallet, + arg.ID, + arg.UserID, + arg.WalletAddress, + arg.WalletType, + arg.ChainID, + arg.IsDefault, + arg.IsVerified, + arg.VerificationMethod, + arg.VerifiedAt, + arg.Nickname, + arg.CreatedAt, + arg.UpdatedAt, + ) + var i UserWallets + err := row.Scan( + &i.ID, + &i.UserID, + &i.WalletAddress, + &i.WalletType, + &i.ChainID, + &i.IsDefault, + &i.IsVerified, + &i.VerificationMethod, + &i.VerifiedAt, + &i.Nickname, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const deleteUserWallet = `-- name: DeleteUserWallet :exec +DELETE FROM user_wallets WHERE id = $1 +` + +func (q *Queries) DeleteUserWallet(ctx context.Context, id uuid.UUID) error { + _, err := q.db.Exec(ctx, deleteUserWallet, id) + return err +} + +const getMainnetNetworks = `-- name: GetMainnetNetworks :many +SELECT id, name, chain_id, network_type, currency_symbol, block_explorer_url, rpc_url, is_evm_compatible, is_active, transaction_speed, average_block_time, created_at, updated_at FROM supported_networks +WHERE network_type = 'mainnet' AND is_active = TRUE +ORDER BY chain_id +` + +func (q *Queries) GetMainnetNetworks(ctx context.Context) ([]SupportedNetworks, error) { + rows, err := q.db.Query(ctx, getMainnetNetworks) + if err != nil { + return nil, err + } + defer rows.Close() + items := []SupportedNetworks{} + for rows.Next() { + var i SupportedNetworks + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ChainID, + &i.NetworkType, + &i.CurrencySymbol, + &i.BlockExplorerUrl, + &i.RpcUrl, + &i.IsEvmCompatible, + &i.IsActive, + &i.TransactionSpeed, + &i.AverageBlockTime, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getStablecoinsByNetwork = `-- name: GetStablecoinsByNetwork :many +SELECT st.id, st.network_id, st.name, st.symbol, st.decimals, st.contract_address, st.token_type, st.logo_url, st.is_stablecoin, st.is_active, st.created_at, st.updated_at, sn.name as network_name, sn.chain_id +FROM supported_tokens st +JOIN supported_networks sn ON st.network_id = sn.id +WHERE sn.chain_id = $1 AND st.is_stablecoin = TRUE AND st.is_active = TRUE +ORDER BY st.symbol +` + +type GetStablecoinsByNetworkRow struct { + ID uuid.UUID `json:"id"` + NetworkID uuid.UUID `json:"network_id"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals int32 `json:"decimals"` + ContractAddress pgtype.Text `json:"contract_address"` + TokenType string `json:"token_type"` + LogoUrl pgtype.Text `json:"logo_url"` + IsStablecoin pgtype.Bool `json:"is_stablecoin"` + IsActive pgtype.Bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + NetworkName string `json:"network_name"` + ChainID int32 `json:"chain_id"` +} + +func (q *Queries) GetStablecoinsByNetwork(ctx context.Context, chainID int32) ([]GetStablecoinsByNetworkRow, error) { + rows, err := q.db.Query(ctx, getStablecoinsByNetwork, chainID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetStablecoinsByNetworkRow{} + for rows.Next() { + var i GetStablecoinsByNetworkRow + if err := rows.Scan( + &i.ID, + &i.NetworkID, + &i.Name, + &i.Symbol, + &i.Decimals, + &i.ContractAddress, + &i.TokenType, + &i.LogoUrl, + &i.IsStablecoin, + &i.IsActive, + &i.CreatedAt, + &i.UpdatedAt, + &i.NetworkName, + &i.ChainID, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getSupportedNetworkByChainID = `-- name: GetSupportedNetworkByChainID :one +SELECT id, name, chain_id, network_type, currency_symbol, block_explorer_url, rpc_url, is_evm_compatible, is_active, transaction_speed, average_block_time, created_at, updated_at FROM supported_networks +WHERE chain_id = $1 AND is_active = TRUE +` + +func (q *Queries) GetSupportedNetworkByChainID(ctx context.Context, chainID int32) (SupportedNetworks, error) { + row := q.db.QueryRow(ctx, getSupportedNetworkByChainID, chainID) + var i SupportedNetworks + err := row.Scan( + &i.ID, + &i.Name, + &i.ChainID, + &i.NetworkType, + &i.CurrencySymbol, + &i.BlockExplorerUrl, + &i.RpcUrl, + &i.IsEvmCompatible, + &i.IsActive, + &i.TransactionSpeed, + &i.AverageBlockTime, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const getSupportedNetworks = `-- name: GetSupportedNetworks :many +SELECT id, name, chain_id, network_type, currency_symbol, block_explorer_url, rpc_url, is_evm_compatible, is_active, transaction_speed, average_block_time, created_at, updated_at FROM supported_networks +WHERE is_active = TRUE +ORDER BY chain_id +` + +func (q *Queries) GetSupportedNetworks(ctx context.Context) ([]SupportedNetworks, error) { + rows, err := q.db.Query(ctx, getSupportedNetworks) + if err != nil { + return nil, err + } + defer rows.Close() + items := []SupportedNetworks{} + for rows.Next() { + var i SupportedNetworks + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ChainID, + &i.NetworkType, + &i.CurrencySymbol, + &i.BlockExplorerUrl, + &i.RpcUrl, + &i.IsEvmCompatible, + &i.IsActive, + &i.TransactionSpeed, + &i.AverageBlockTime, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTestnetNetworks = `-- name: GetTestnetNetworks :many +SELECT id, name, chain_id, network_type, currency_symbol, block_explorer_url, rpc_url, is_evm_compatible, is_active, transaction_speed, average_block_time, created_at, updated_at FROM supported_networks +WHERE network_type = 'testnet' AND is_active = TRUE +ORDER BY chain_id +` + +func (q *Queries) GetTestnetNetworks(ctx context.Context) ([]SupportedNetworks, error) { + rows, err := q.db.Query(ctx, getTestnetNetworks) + if err != nil { + return nil, err + } + defer rows.Close() + items := []SupportedNetworks{} + for rows.Next() { + var i SupportedNetworks + if err := rows.Scan( + &i.ID, + &i.Name, + &i.ChainID, + &i.NetworkType, + &i.CurrencySymbol, + &i.BlockExplorerUrl, + &i.RpcUrl, + &i.IsEvmCompatible, + &i.IsActive, + &i.TransactionSpeed, + &i.AverageBlockTime, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getTokenByContract = `-- name: GetTokenByContract :one +SELECT st.id, st.network_id, st.name, st.symbol, st.decimals, st.contract_address, st.token_type, st.logo_url, st.is_stablecoin, st.is_active, st.created_at, st.updated_at, sn.name as network_name, sn.chain_id +FROM supported_tokens st +JOIN supported_networks sn ON st.network_id = sn.id +WHERE st.contract_address = $1 AND sn.chain_id = $2 +` + +type GetTokenByContractParams struct { + ContractAddress pgtype.Text `json:"contract_address"` + ChainID int32 `json:"chain_id"` +} + +type GetTokenByContractRow struct { + ID uuid.UUID `json:"id"` + NetworkID uuid.UUID `json:"network_id"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals int32 `json:"decimals"` + ContractAddress pgtype.Text `json:"contract_address"` + TokenType string `json:"token_type"` + LogoUrl pgtype.Text `json:"logo_url"` + IsStablecoin pgtype.Bool `json:"is_stablecoin"` + IsActive pgtype.Bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + NetworkName string `json:"network_name"` + ChainID int32 `json:"chain_id"` +} + +func (q *Queries) GetTokenByContract(ctx context.Context, arg GetTokenByContractParams) (GetTokenByContractRow, error) { + row := q.db.QueryRow(ctx, getTokenByContract, arg.ContractAddress, arg.ChainID) + var i GetTokenByContractRow + err := row.Scan( + &i.ID, + &i.NetworkID, + &i.Name, + &i.Symbol, + &i.Decimals, + &i.ContractAddress, + &i.TokenType, + &i.LogoUrl, + &i.IsStablecoin, + &i.IsActive, + &i.CreatedAt, + &i.UpdatedAt, + &i.NetworkName, + &i.ChainID, + ) + return i, err +} + +const getTokensByNetwork = `-- name: GetTokensByNetwork :many +SELECT st.id, st.network_id, st.name, st.symbol, st.decimals, st.contract_address, st.token_type, st.logo_url, st.is_stablecoin, st.is_active, st.created_at, st.updated_at, sn.name as network_name, sn.chain_id +FROM supported_tokens st +JOIN supported_networks sn ON st.network_id = sn.id +WHERE sn.chain_id = $1 AND st.is_active = TRUE +ORDER BY st.symbol +` + +type GetTokensByNetworkRow struct { + ID uuid.UUID `json:"id"` + NetworkID uuid.UUID `json:"network_id"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals int32 `json:"decimals"` + ContractAddress pgtype.Text `json:"contract_address"` + TokenType string `json:"token_type"` + LogoUrl pgtype.Text `json:"logo_url"` + IsStablecoin pgtype.Bool `json:"is_stablecoin"` + IsActive pgtype.Bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + NetworkName string `json:"network_name"` + ChainID int32 `json:"chain_id"` +} + +func (q *Queries) GetTokensByNetwork(ctx context.Context, chainID int32) ([]GetTokensByNetworkRow, error) { + rows, err := q.db.Query(ctx, getTokensByNetwork, chainID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetTokensByNetworkRow{} + for rows.Next() { + var i GetTokensByNetworkRow + if err := rows.Scan( + &i.ID, + &i.NetworkID, + &i.Name, + &i.Symbol, + &i.Decimals, + &i.ContractAddress, + &i.TokenType, + &i.LogoUrl, + &i.IsStablecoin, + &i.IsActive, + &i.CreatedAt, + &i.UpdatedAt, + &i.NetworkName, + &i.ChainID, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserWalletsByNetwork = `-- name: GetUserWalletsByNetwork :many +SELECT uw.id, uw.user_id, uw.wallet_address, uw.wallet_type, uw.chain_id, uw.is_default, uw.is_verified, uw.verification_method, uw.verified_at, uw.nickname, uw.created_at, uw.updated_at, sn.name as network_name +FROM user_wallets uw +JOIN supported_networks sn ON uw.chain_id = sn.chain_id +WHERE uw.user_id = $1 AND uw.chain_id = $2 +ORDER BY uw.is_default DESC, uw.created_at DESC +` + +type GetUserWalletsByNetworkParams struct { + UserID uuid.UUID `json:"user_id"` + ChainID int32 `json:"chain_id"` +} + +type GetUserWalletsByNetworkRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + WalletAddress string `json:"wallet_address"` + WalletType string `json:"wallet_type"` + ChainID int32 `json:"chain_id"` + IsDefault pgtype.Bool `json:"is_default"` + IsVerified pgtype.Bool `json:"is_verified"` + VerificationMethod pgtype.Text `json:"verification_method"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + Nickname pgtype.Text `json:"nickname"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + NetworkName string `json:"network_name"` +} + +func (q *Queries) GetUserWalletsByNetwork(ctx context.Context, arg GetUserWalletsByNetworkParams) ([]GetUserWalletsByNetworkRow, error) { + rows, err := q.db.Query(ctx, getUserWalletsByNetwork, arg.UserID, arg.ChainID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetUserWalletsByNetworkRow{} + for rows.Next() { + var i GetUserWalletsByNetworkRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.WalletAddress, + &i.WalletType, + &i.ChainID, + &i.IsDefault, + &i.IsVerified, + &i.VerificationMethod, + &i.VerifiedAt, + &i.Nickname, + &i.CreatedAt, + &i.UpdatedAt, + &i.NetworkName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getUserWalletsByUser = `-- name: GetUserWalletsByUser :many +SELECT uw.id, uw.user_id, uw.wallet_address, uw.wallet_type, uw.chain_id, uw.is_default, uw.is_verified, uw.verification_method, uw.verified_at, uw.nickname, uw.created_at, uw.updated_at, sn.name as network_name +FROM user_wallets uw +JOIN supported_networks sn ON uw.chain_id = sn.chain_id +WHERE uw.user_id = $1 +ORDER BY uw.is_default DESC, uw.created_at DESC +` + +type GetUserWalletsByUserRow struct { + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` + WalletAddress string `json:"wallet_address"` + WalletType string `json:"wallet_type"` + ChainID int32 `json:"chain_id"` + IsDefault pgtype.Bool `json:"is_default"` + IsVerified pgtype.Bool `json:"is_verified"` + VerificationMethod pgtype.Text `json:"verification_method"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + Nickname pgtype.Text `json:"nickname"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + NetworkName string `json:"network_name"` +} + +func (q *Queries) GetUserWalletsByUser(ctx context.Context, userID uuid.UUID) ([]GetUserWalletsByUserRow, error) { + rows, err := q.db.Query(ctx, getUserWalletsByUser, userID) + if err != nil { + return nil, err + } + defer rows.Close() + items := []GetUserWalletsByUserRow{} + for rows.Next() { + var i GetUserWalletsByUserRow + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.WalletAddress, + &i.WalletType, + &i.ChainID, + &i.IsDefault, + &i.IsVerified, + &i.VerificationMethod, + &i.VerifiedAt, + &i.Nickname, + &i.CreatedAt, + &i.UpdatedAt, + &i.NetworkName, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const searchTokens = `-- name: SearchTokens :many +SELECT st.id, st.network_id, st.name, st.symbol, st.decimals, st.contract_address, st.token_type, st.logo_url, st.is_stablecoin, st.is_active, st.created_at, st.updated_at, sn.name as network_name, sn.chain_id +FROM supported_tokens st +JOIN supported_networks sn ON st.network_id = sn.id +WHERE (st.name ILIKE '%' || $1 || '%' OR st.symbol ILIKE '%' || $1 || '%') + AND st.is_active = TRUE +ORDER BY st.symbol +LIMIT $3 OFFSET $2 +` + +type SearchTokensParams struct { + SearchTerm pgtype.Text `json:"search_term"` + OffsetVal int32 `json:"offset_val"` + LimitVal int32 `json:"limit_val"` +} + +type SearchTokensRow struct { + ID uuid.UUID `json:"id"` + NetworkID uuid.UUID `json:"network_id"` + Name string `json:"name"` + Symbol string `json:"symbol"` + Decimals int32 `json:"decimals"` + ContractAddress pgtype.Text `json:"contract_address"` + TokenType string `json:"token_type"` + LogoUrl pgtype.Text `json:"logo_url"` + IsStablecoin pgtype.Bool `json:"is_stablecoin"` + IsActive pgtype.Bool `json:"is_active"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` + NetworkName string `json:"network_name"` + ChainID int32 `json:"chain_id"` +} + +func (q *Queries) SearchTokens(ctx context.Context, arg SearchTokensParams) ([]SearchTokensRow, error) { + rows, err := q.db.Query(ctx, searchTokens, arg.SearchTerm, arg.OffsetVal, arg.LimitVal) + if err != nil { + return nil, err + } + defer rows.Close() + items := []SearchTokensRow{} + for rows.Next() { + var i SearchTokensRow + if err := rows.Scan( + &i.ID, + &i.NetworkID, + &i.Name, + &i.Symbol, + &i.Decimals, + &i.ContractAddress, + &i.TokenType, + &i.LogoUrl, + &i.IsStablecoin, + &i.IsActive, + &i.CreatedAt, + &i.UpdatedAt, + &i.NetworkName, + &i.ChainID, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const setUserWalletAsDefault = `-- name: SetUserWalletAsDefault :exec +UPDATE user_wallets SET + is_default = CASE WHEN id = $1 THEN TRUE ELSE FALSE END, + updated_at = NOW() +WHERE user_id = $2 AND chain_id = $3 +` + +type SetUserWalletAsDefaultParams struct { + WalletID uuid.UUID `json:"wallet_id"` + UserID uuid.UUID `json:"user_id"` + ChainID int32 `json:"chain_id"` +} + +func (q *Queries) SetUserWalletAsDefault(ctx context.Context, arg SetUserWalletAsDefaultParams) error { + _, err := q.db.Exec(ctx, setUserWalletAsDefault, arg.WalletID, arg.UserID, arg.ChainID) + return err +} + +const updateNetworkStatus = `-- name: UpdateNetworkStatus :one +UPDATE supported_networks SET + is_active = $1, + updated_at = NOW() +WHERE chain_id = $2 +RETURNING id, name, chain_id, network_type, currency_symbol, block_explorer_url, rpc_url, is_evm_compatible, is_active, transaction_speed, average_block_time, created_at, updated_at +` + +type UpdateNetworkStatusParams struct { + IsActive pgtype.Bool `json:"is_active"` + ChainID int32 `json:"chain_id"` +} + +func (q *Queries) UpdateNetworkStatus(ctx context.Context, arg UpdateNetworkStatusParams) (SupportedNetworks, error) { + row := q.db.QueryRow(ctx, updateNetworkStatus, arg.IsActive, arg.ChainID) + var i SupportedNetworks + err := row.Scan( + &i.ID, + &i.Name, + &i.ChainID, + &i.NetworkType, + &i.CurrencySymbol, + &i.BlockExplorerUrl, + &i.RpcUrl, + &i.IsEvmCompatible, + &i.IsActive, + &i.TransactionSpeed, + &i.AverageBlockTime, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const updateUserWallet = `-- name: UpdateUserWallet :one +UPDATE user_wallets SET + wallet_type = COALESCE($1, wallet_type), + is_default = COALESCE($2, is_default), + is_verified = COALESCE($3, is_verified), + verification_method = COALESCE($4, verification_method), + verified_at = COALESCE($5, verified_at), + nickname = COALESCE($6, nickname), + updated_at = NOW() +WHERE id = $7 +RETURNING id, user_id, wallet_address, wallet_type, chain_id, is_default, is_verified, verification_method, verified_at, nickname, created_at, updated_at +` + +type UpdateUserWalletParams struct { + WalletType string `json:"wallet_type"` + IsDefault pgtype.Bool `json:"is_default"` + IsVerified pgtype.Bool `json:"is_verified"` + VerificationMethod pgtype.Text `json:"verification_method"` + VerifiedAt pgtype.Timestamptz `json:"verified_at"` + Nickname pgtype.Text `json:"nickname"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdateUserWallet(ctx context.Context, arg UpdateUserWalletParams) (UserWallets, error) { + row := q.db.QueryRow(ctx, updateUserWallet, + arg.WalletType, + arg.IsDefault, + arg.IsVerified, + arg.VerificationMethod, + arg.VerifiedAt, + arg.Nickname, + arg.ID, + ) + var i UserWallets + err := row.Scan( + &i.ID, + &i.UserID, + &i.WalletAddress, + &i.WalletType, + &i.ChainID, + &i.IsDefault, + &i.IsVerified, + &i.VerificationMethod, + &i.VerifiedAt, + &i.Nickname, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/go.mod b/go.mod index 6175680..de2f610 100644 --- a/go.mod +++ b/go.mod @@ -110,7 +110,7 @@ require ( require ( github.com/ethereum/go-ethereum v1.15.11 - github.com/go-redis/redis/v8 v8.11.5 + github.com/shopspring/decimal v1.4.0 ) require ( @@ -123,7 +123,6 @@ require ( github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect - github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.0 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect diff --git a/go.sum b/go.sum index d369506..6c267fd 100644 --- a/go.sum +++ b/go.sum @@ -71,8 +71,6 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/ethereum/c-kzg-4844/v2 v2.1.0 h1:gQropX9YFBhl3g4HYhwE70zq3IHFRgbbNPw0Shwzf5w= github.com/ethereum/c-kzg-4844/v2 v2.1.0/go.mod h1:TC48kOKjJKPbN7C++qIgt0TJzZ70QznYR7Ob+WXl57E= github.com/ethereum/go-ethereum v1.15.11 h1:JK73WKeu0WC0O1eyX+mdQAVHUV+UR1a9VB/domDngBU= @@ -121,8 +119,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= -github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= -github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= @@ -216,16 +212,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/o1egl/paseto v1.0.0 h1:bwpvPu2au176w4IBlhbyUv/S5VPptERIA99Oap5qUd0= github.com/o1egl/paseto v1.0.0/go.mod h1:5HxsZPmw/3RI2pAwGo1HhOOwSdvBpcuVzO7uDkm+CLU= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= @@ -269,6 +259,8 @@ github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFT github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= @@ -429,8 +421,6 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AW gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=