package repository import ( "enaklo-pos-be/internal/common/mycontext" "enaklo-pos-be/internal/entity" "enaklo-pos-be/internal/repository/models" "github.com/pkg/errors" "gorm.io/gorm" "time" ) type PartnerSettingsRepository interface { GetByPartnerID(ctx mycontext.Context, partnerID int64) (*entity.PartnerSettings, error) Upsert(ctx mycontext.Context, settings *entity.PartnerSettings) error GetPaymentMethods(ctx mycontext.Context, partnerID int64) ([]entity.PartnerPaymentMethod, error) UpsertPaymentMethod(ctx mycontext.Context, method *entity.PartnerPaymentMethod) error DeletePaymentMethod(ctx mycontext.Context, id int64, partnerID int64) error UpdatePaymentMethodOrder(ctx mycontext.Context, partnerID int64, methodIDs []int64) error } type partnerSettingsRepository struct { db *gorm.DB } func NewPartnerSettingsRepository(db *gorm.DB) PartnerSettingsRepository { return &partnerSettingsRepository{db: db} } func (r *partnerSettingsRepository) GetByPartnerID(ctx mycontext.Context, partnerID int64) (*entity.PartnerSettings, error) { var settingsDB models.PartnerSettingsDB err := r.db.Where("partner_id = ?", partnerID).First(&settingsDB).Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return &entity.PartnerSettings{ PartnerID: partnerID, TaxEnabled: true, TaxPercentage: 10.0, }, nil } return nil, errors.Wrap(err, "failed to get partner settings") } return r.toDomainModel(&settingsDB), nil } func (r *partnerSettingsRepository) Upsert(ctx mycontext.Context, settings *entity.PartnerSettings) error { settingsDB := r.toDBModel(settings) settingsDB.UpdatedAt = time.Now() // Check if record exists var count int64 if err := r.db.Model(&models.PartnerSettingsDB{}).Where("partner_id = ?", settings.PartnerID).Count(&count).Error; err != nil { return errors.Wrap(err, "failed to check partner settings existence") } if count > 0 { // Update existing record if err := r.db.Model(&models.PartnerSettingsDB{}).Where("partner_id = ?", settings.PartnerID).Updates(settingsDB).Error; err != nil { return errors.Wrap(err, "failed to update partner settings") } } else { // Create new record settingsDB.CreatedAt = time.Now() if err := r.db.Create(&settingsDB).Error; err != nil { return errors.Wrap(err, "failed to create partner settings") } } return nil } func (r *partnerSettingsRepository) GetPaymentMethods(ctx mycontext.Context, partnerID int64) ([]entity.PartnerPaymentMethod, error) { var methodsDB []models.PartnerPaymentMethodDB if err := r.db.Where("partner_id = ?", partnerID).Order("display_order").Find(&methodsDB).Error; err != nil { return nil, errors.Wrap(err, "failed to get partner payment methods") } methods := make([]entity.PartnerPaymentMethod, len(methodsDB)) for i, methodDB := range methodsDB { methods[i] = *r.toDomainPaymentMethodModel(&methodDB) } return methods, nil } func (r *partnerSettingsRepository) UpsertPaymentMethod(ctx mycontext.Context, method *entity.PartnerPaymentMethod) error { methodDB := r.toDBPaymentMethodModel(method) methodDB.UpdatedAt = time.Now() tx := r.db.Begin() if tx.Error != nil { return errors.Wrap(tx.Error, "failed to begin transaction") } defer func() { if r := recover(); r != nil { tx.Rollback() } }() if method.ID > 0 { // Update existing record if err := tx.Model(&models.PartnerPaymentMethodDB{}).Where("id = ? AND partner_id = ?", method.ID, method.PartnerID).Updates(methodDB).Error; err != nil { tx.Rollback() return errors.Wrap(err, "failed to update payment method") } } else { // Get the next display order if not specified if method.DisplayOrder == 0 { var maxOrder int if err := tx.Model(&models.PartnerPaymentMethodDB{}).Where("partner_id = ?", method.PartnerID).Select("COALESCE(MAX(display_order), 0)").Row().Scan(&maxOrder); err != nil { tx.Rollback() return errors.Wrap(err, "failed to get max display order") } methodDB.DisplayOrder = maxOrder + 1 } // Create new record methodDB.CreatedAt = time.Now() if err := tx.Create(&methodDB).Error; err != nil { tx.Rollback() return errors.Wrap(err, "failed to create payment method") } method.ID = methodDB.ID } return tx.Commit().Error } func (r *partnerSettingsRepository) DeletePaymentMethod(ctx mycontext.Context, id int64, partnerID int64) error { result := r.db.Where("id = ? AND partner_id = ?", id, partnerID).Delete(&models.PartnerPaymentMethodDB{}) if result.Error != nil { return errors.Wrap(result.Error, "failed to delete payment method") } if result.RowsAffected == 0 { return errors.New("payment method not found or not authorized") } return nil } func (r *partnerSettingsRepository) UpdatePaymentMethodOrder(ctx mycontext.Context, partnerID int64, methodIDs []int64) error { tx := r.db.Begin() if tx.Error != nil { return errors.Wrap(tx.Error, "failed to begin transaction") } defer func() { if r := recover(); r != nil { tx.Rollback() } }() for i, id := range methodIDs { if err := tx.Model(&models.PartnerPaymentMethodDB{}). Where("id = ? AND partner_id = ?", id, partnerID). Update("display_order", i+1).Error; err != nil { tx.Rollback() return errors.Wrap(err, "failed to update payment method order") } } return tx.Commit().Error } func (r *partnerSettingsRepository) toDomainModel(dbModel *models.PartnerSettingsDB) *entity.PartnerSettings { return &entity.PartnerSettings{ PartnerID: dbModel.PartnerID, TaxEnabled: dbModel.TaxEnabled, TaxPercentage: dbModel.TaxPercentage, InvoicePrefix: dbModel.InvoicePrefix, BusinessHours: dbModel.BusinessHours, LogoURL: dbModel.LogoURL, ThemeColor: dbModel.ThemeColor, ReceiptFooterText: dbModel.ReceiptFooterText, ReceiptHeaderText: dbModel.ReceiptHeaderText, CreatedAt: dbModel.CreatedAt, UpdatedAt: dbModel.UpdatedAt, } } func (r *partnerSettingsRepository) toDBModel(domainModel *entity.PartnerSettings) models.PartnerSettingsDB { return models.PartnerSettingsDB{ PartnerID: domainModel.PartnerID, TaxEnabled: domainModel.TaxEnabled, TaxPercentage: domainModel.TaxPercentage, InvoicePrefix: domainModel.InvoicePrefix, BusinessHours: domainModel.BusinessHours, LogoURL: domainModel.LogoURL, ThemeColor: domainModel.ThemeColor, ReceiptFooterText: domainModel.ReceiptFooterText, ReceiptHeaderText: domainModel.ReceiptHeaderText, } } func (r *partnerSettingsRepository) toDomainPaymentMethodModel(dbModel *models.PartnerPaymentMethodDB) *entity.PartnerPaymentMethod { return &entity.PartnerPaymentMethod{ ID: dbModel.ID, PartnerID: dbModel.PartnerID, PaymentMethod: dbModel.PaymentMethod, IsEnabled: dbModel.IsEnabled, DisplayName: dbModel.DisplayName, DisplayOrder: dbModel.DisplayOrder, AdditionalInfo: dbModel.AdditionalInfo, CreatedAt: dbModel.CreatedAt, UpdatedAt: dbModel.UpdatedAt, } } func (r *partnerSettingsRepository) toDBPaymentMethodModel(domainModel *entity.PartnerPaymentMethod) models.PartnerPaymentMethodDB { return models.PartnerPaymentMethodDB{ ID: domainModel.ID, PartnerID: domainModel.PartnerID, PaymentMethod: domainModel.PaymentMethod, IsEnabled: domainModel.IsEnabled, DisplayName: domainModel.DisplayName, DisplayOrder: domainModel.DisplayOrder, AdditionalInfo: domainModel.AdditionalInfo, } }