package model import ( "errors" "time" "github.com/openaccounting/oa-server/core/model/types" "github.com/openaccounting/oa-server/core/repository" "github.com/openaccounting/oa-server/core/util" "github.com/openaccounting/oa-server/database" "gorm.io/gorm" ) // GormModel is the GORM-based implementation of the Model type GormModel struct { repository *repository.GormRepository bcrypt util.Bcrypt config types.Config } // NewGormModel creates a new GORM-based model func NewGormModel(gormDB *gorm.DB, bcrypt util.Bcrypt, config types.Config) *GormModel { repo := repository.NewGormRepository(gormDB) return &GormModel{ repository: repo, bcrypt: bcrypt, config: config, } } // CreateModel creates a new model using the existing database connection func CreateGormModel(bcrypt util.Bcrypt, config types.Config) (*GormModel, error) { // Use the existing database connection if database.DB == nil { return nil, errors.New("database connection not initialized") } return NewGormModel(database.DB, bcrypt, config), nil } // Implement the Interface by delegating to the business logic layer // The business logic layer (existing model methods) will call the repository // UserInterface methods - delegate to existing business logic func (m *GormModel) CreateUser(user *types.User) error { // The existing business logic in user.go will be updated to use the repository // For now, delegate directly to repository for basic operations return m.repository.InsertUser(user) } func (m *GormModel) VerifyUser(code string) error { return m.repository.VerifyUser(code) } func (m *GormModel) UpdateUser(user *types.User) error { return m.repository.UpdateUser(user) } func (m *GormModel) ResetPassword(email string) error { // This would need the full business logic from the original model // For now, simplified implementation user, err := m.repository.GetVerifiedUserByEmail(email) if err != nil { return err } user.PasswordReset, err = util.NewGuid() if err != nil { return err } return m.repository.UpdateUserResetPassword(user) } func (m *GormModel) ConfirmResetPassword(password string, code string) (*types.User, error) { user, err := m.repository.GetUserByResetCode(code) if err != nil { return nil, err } passwordHash, err := m.bcrypt.GenerateFromPassword([]byte(password), m.bcrypt.GetDefaultCost()) if err != nil { return nil, err } user.PasswordHash = string(passwordHash) user.Password = "" err = m.repository.UpdateUser(user) if err != nil { return nil, err } return user, nil } // AccountInterface methods - delegate to repository func (m *GormModel) CreateAccount(account *types.Account, userId string) error { return m.repository.InsertAccount(account) } func (m *GormModel) UpdateAccount(account *types.Account, userId string) error { return m.repository.UpdateAccount(account) } func (m *GormModel) DeleteAccount(id string, userId string, orgId string) error { return m.repository.DeleteAccount(id) } func (m *GormModel) GetAccounts(orgId string, userId string, tokenId string) ([]*types.Account, error) { return m.repository.GetAccountsByOrgId(orgId) } func (m *GormModel) GetAccountsWithBalances(orgId string, userId string, tokenId string, date time.Time) ([]*types.Account, error) { accounts, err := m.repository.GetAccountsByOrgId(orgId) if err != nil { return nil, err } // Add balance calculations err = m.repository.AddBalances(accounts, date) if err != nil { return nil, err } return accounts, nil } func (m *GormModel) GetAccount(orgId, accId, userId, tokenId string) (*types.Account, error) { return m.repository.GetAccount(accId) } func (m *GormModel) GetAccountWithBalance(orgId, accId, userId, tokenId string, date time.Time) (*types.Account, error) { account, err := m.repository.GetAccount(accId) if err != nil { return nil, err } // Add balance calculation err = m.repository.AddBalance(account, date) if err != nil { return nil, err } return account, nil } // Complete OrgInterface implementation func (m *GormModel) CreateOrg(org *types.Org, userId string) error { // Get default accounts - this needs to be implemented properly accounts := []*types.Account{} // Empty for now, should create default chart of accounts return m.repository.CreateOrg(org, userId, accounts) } func (m *GormModel) GetOrg(orgId, userId string) (*types.Org, error) { return m.repository.GetOrg(orgId, userId) } func (m *GormModel) GetOrgs(userId string) ([]*types.Org, error) { return m.repository.GetOrgs(userId) } func (m *GormModel) UpdateOrg(org *types.Org, userId string) error { return m.repository.UpdateOrg(org) } func (m *GormModel) CreateInvite(invite *types.Invite, userId string) error { return m.repository.InsertInvite(invite) } func (m *GormModel) AcceptInvite(invite *types.Invite, userId string) error { return m.repository.AcceptInvite(invite, userId) } func (m *GormModel) GetInvites(orgId, userId string) ([]*types.Invite, error) { return m.repository.GetInvites(orgId) } func (m *GormModel) DeleteInvite(inviteId, userId string) error { return m.repository.DeleteInvite(inviteId) } // SessionInterface implementation func (m *GormModel) CreateSession(session *types.Session) error { return m.repository.InsertSession(session) } func (m *GormModel) InsertSession(session *types.Session) error { return m.repository.InsertSession(session) } func (m *GormModel) DeleteSession(sessionId, userId string) error { return m.repository.DeleteSession(sessionId, userId) } func (m *GormModel) UpdateSessionActivity(sessionId string) error { return m.repository.UpdateSessionActivity(sessionId) } // ApiKeyInterface implementation func (m *GormModel) CreateApiKey(apiKey *types.ApiKey) error { return m.repository.InsertApiKey(apiKey) } func (m *GormModel) InsertApiKey(apiKey *types.ApiKey) error { return m.repository.InsertApiKey(apiKey) } func (m *GormModel) UpdateApiKey(apiKey *types.ApiKey) error { return m.repository.UpdateApiKey(apiKey) } func (m *GormModel) DeleteApiKey(keyId, userId string) error { return m.repository.DeleteApiKey(keyId, userId) } func (m *GormModel) GetApiKeys(userId string) ([]*types.ApiKey, error) { return m.repository.GetApiKeys(userId) } func (m *GormModel) UpdateApiKeyActivity(keyId string) error { return m.repository.UpdateApiKeyActivity(keyId) } // TransactionInterface implementation func (m *GormModel) CreateTransaction(transaction *types.Transaction) error { return m.repository.InsertTransaction(transaction) } func (m *GormModel) UpdateTransaction(transactionId string, transaction *types.Transaction) error { return m.repository.DeleteAndInsertTransaction(transactionId, transaction) } func (m *GormModel) GetTransactionsByAccount(accountId, orgId, userId string, options *types.QueryOptions) ([]*types.Transaction, error) { return m.repository.GetTransactionsByAccount(accountId, options) } func (m *GormModel) GetTransactionsByOrg(orgId, userId string, options *types.QueryOptions) ([]*types.Transaction, error) { return m.repository.GetTransactionsByOrg(orgId, options, []string{}) } func (m *GormModel) DeleteTransaction(transactionId, orgId, userId string) error { return m.repository.DeleteTransaction(transactionId) } func (m *GormModel) InsertTransaction(transaction *types.Transaction) error { return m.repository.InsertTransaction(transaction) } func (m *GormModel) GetTransactionById(id string) (*types.Transaction, error) { return m.repository.GetTransactionById(id) } func (m *GormModel) DeleteAndInsertTransaction(id string, transaction *types.Transaction) error { return m.repository.DeleteAndInsertTransaction(id, transaction) } // PriceInterface implementation func (m *GormModel) CreatePrice(price *types.Price, userId string) error { return m.repository.InsertPrice(price) } func (m *GormModel) DeletePrice(priceId, userId string) error { // Stub implementation - would need proper implementation return nil } func (m *GormModel) GetPricesNearestInTime(orgId string, date time.Time, currency string) ([]*types.Price, error) { // Stub implementation - would need proper implementation based on specific logic return m.repository.GetPrices(orgId, date) } func (m *GormModel) GetPricesByCurrency(orgId, currency, userId string) ([]*types.Price, error) { // Stub implementation - would need proper implementation based on specific logic return m.repository.GetPrices(orgId, time.Now()) } func (m *GormModel) GetPrices(orgId string, date time.Time) ([]*types.Price, error) { return m.repository.GetPrices(orgId, date) } func (m *GormModel) InsertPrice(price *types.Price) error { return m.repository.InsertPrice(price) } // SystemHealthInteface implementation func (m *GormModel) PingDatabase() error { return m.repository.Ping() } func (m *GormModel) Ping() error { return m.repository.Ping() } // BudgetInterface implementation func (m *GormModel) GetBudget(orgId, userId string) (*types.Budget, error) { // Stub implementation - would need proper implementation return &types.Budget{}, nil } func (m *GormModel) CreateBudget(budget *types.Budget, userId string) error { return m.repository.InsertBudget(budget) } func (m *GormModel) DeleteBudget(budgetId, userId string) error { // Stub implementation - would need proper implementation return nil } func (m *GormModel) InsertBudget(budget *types.Budget) error { return m.repository.InsertBudget(budget) } func (m *GormModel) GetBudgets(orgId string) ([]*types.Budget, error) { return m.repository.GetBudgets(orgId) } // Helper methods func (m *GormModel) GetOrgUserIds(orgId string) ([]string, error) { return m.repository.GetOrgUserIds(orgId) }