Files
telecom-platform/apps/api-server/internal/services/subscriber_payment.go
T
nutcas3 1889e78db2 feat: Refactor SubscriberService to split monolithic service into modular files with method organization by domain
- Remove all method implementations from subscriber.go (CreateSubscriber/GetSubscriber/GetSubscriberByIMSI/UpdateSubscriber/SuspendSubscriber/TerminateSubscriber/ListSubscribers/terminateSubscriberSessions/GetAccount/ListInvoices/GetInvoice/ListRatingPlans/GetRatingPlan/ListAlerts/SearchSubscribers/ResolveAlert/CreateAlert and all other methods)
- Update SubscriberService struct comment
2026-04-24 08:51:13 +03:00

123 lines
4.2 KiB
Go

package services
import (
"context"
"fmt"
"time"
"github.com/nutcas3/telecom-platform/apps/api-server/internal/models"
)
// AddPaymentMethod creates a new payment method for the given subscriber.
func (s *SubscriberService) AddPaymentMethod(ctx context.Context, subscriberId int, req *models.AddPaymentMethodRequest) (*models.PaymentMethod, error) {
paymentMethodID := fmt.Sprintf("pm_%d_%d", subscriberId, time.Now().Unix())
last4, brand, expiryMonth, expiryYear, err := s.processPaymentToken(ctx, req.Token)
if err != nil {
return nil, fmt.Errorf("failed to process payment token: %w", err)
}
paymentMethod := &models.PaymentMethod{
ID: paymentMethodID,
SubscriberID: uint(subscriberId),
GatewayID: "default_gateway",
Type: req.Type,
CustomerID: fmt.Sprintf("cus_%d", subscriberId),
Last4: last4,
Brand: brand,
ExpiryMonth: expiryMonth,
ExpiryYear: expiryYear,
IsDefault: req.IsDefault,
CreatedAt: time.Now(),
}
if err := s.db.DB.WithContext(ctx).Create(paymentMethod).Error; err != nil {
return nil, fmt.Errorf("failed to add payment method: %w", err)
}
return paymentMethod, nil
}
// processPaymentToken resolves a Stripe token to card details.
func (s *SubscriberService) processPaymentToken(ctx context.Context, token string) (last4, brand string, expiryMonth, expiryYear int, err error) {
details, err := s.stripeGW.RetrievePaymentMethodFromToken(ctx, token)
if err != nil {
return "", "", 0, 0, fmt.Errorf("failed to retrieve payment method from token: %w", err)
}
return details.Last4, details.Brand, details.ExpiryMonth, details.ExpiryYear, nil
}
// RemovePaymentMethod removes a payment method, preventing removal of the only one and
// reassigning the default before deletion.
func (s *SubscriberService) RemovePaymentMethod(ctx context.Context, paymentMethodId string) (bool, error) {
var paymentMethod models.PaymentMethod
if err := s.db.DB.WithContext(ctx).First(&paymentMethod, "id = ?", paymentMethodId).Error; err != nil {
return false, fmt.Errorf("payment method not found: %w", err)
}
var count int64
if err := s.db.DB.WithContext(ctx).
Model(&models.PaymentMethod{}).
Where("subscriber_id = ?", paymentMethod.SubscriberID).
Count(&count).Error; err != nil {
return false, fmt.Errorf("failed to check payment methods: %w", err)
}
if count == 1 {
return false, fmt.Errorf("cannot remove the only payment method")
}
if paymentMethod.IsDefault {
var newDefault models.PaymentMethod
if err := s.db.DB.WithContext(ctx).
Where("subscriber_id = ? AND id != ?", paymentMethod.SubscriberID, paymentMethodId).
First(&newDefault).Error; err != nil {
return false, fmt.Errorf("failed to find alternative payment method: %w", err)
}
if err := s.db.DB.WithContext(ctx).
Model(&newDefault).
Update("is_default", true).Error; err != nil {
return false, fmt.Errorf("failed to set new default payment method: %w", err)
}
}
if err := s.db.DB.WithContext(ctx).Delete(&paymentMethod).Error; err != nil {
return false, fmt.Errorf("failed to delete payment method: %w", err)
}
return true, nil
}
// SetDefaultPaymentMethod marks one payment method as default and unsets others in a transaction.
func (s *SubscriberService) SetDefaultPaymentMethod(ctx context.Context, paymentMethodId string) (*models.PaymentMethod, error) {
var paymentMethod models.PaymentMethod
tx := s.db.DB.WithContext(ctx).Begin()
if err := tx.Model(&models.PaymentMethod{}).
Where("id = ?", paymentMethodId).
First(&paymentMethod).Error; err != nil {
tx.Rollback()
return nil, fmt.Errorf("payment method not found: %w", err)
}
if err := tx.Model(&models.PaymentMethod{}).
Where("subscriber_id = ? AND id != ?", paymentMethod.SubscriberID, paymentMethodId).
Update("is_default", false).Error; err != nil {
tx.Rollback()
return nil, fmt.Errorf("failed to update other payment methods: %w", err)
}
if err := tx.Model(&paymentMethod).
Update("is_default", true).Error; err != nil {
tx.Rollback()
return nil, fmt.Errorf("failed to set default payment method: %w", err)
}
if err := tx.Commit().Error; err != nil {
return nil, fmt.Errorf("failed to commit transaction: %w", err)
}
return &paymentMethod, nil
}