package repository import ( dbgen "Yimaru-Backend/gen/db" "Yimaru-Backend/internal/domain" "context" "github.com/jackc/pgx/v5/pgtype" ) func (s *Store) CreatePayment(ctx context.Context, input domain.CreatePaymentInput) (*domain.Payment, error) { payment, err := s.queries.CreatePayment(ctx, dbgen.CreatePaymentParams{ UserID: input.UserID, PlanID: int64PtrToPgInt8(input.PlanID), SubscriptionID: pgtype.Int8{Valid: false}, SessionID: pgtype.Text{Valid: false}, TransactionID: pgtype.Text{Valid: false}, Nonce: input.Nonce, Amount: toPgNumeric(input.Amount), Currency: input.Currency, PaymentMethod: toPgText(input.PaymentMethod), Column10: string(domain.PaymentStatusPending), // status with COALESCE PaymentUrl: pgtype.Text{Valid: false}, ExpiresAt: toPgTimestamptzPtr(input.ExpiresAt), }) if err != nil { return nil, err } return paymentToDomain(payment), nil } func (s *Store) GetPaymentByID(ctx context.Context, id int64) (*domain.Payment, error) { payment, err := s.queries.GetPaymentByID(ctx, id) if err != nil { return nil, err } return paymentToDomain(payment), nil } func (s *Store) GetPaymentBySessionID(ctx context.Context, sessionID string) (*domain.Payment, error) { payment, err := s.queries.GetPaymentBySessionID(ctx, toPgText(&sessionID)) if err != nil { return nil, err } return paymentToDomain(payment), nil } func (s *Store) GetPaymentByNonce(ctx context.Context, nonce string) (*domain.Payment, error) { payment, err := s.queries.GetPaymentByNonce(ctx, nonce) if err != nil { return nil, err } return paymentToDomain(payment), nil } func (s *Store) GetPaymentByTransactionID(ctx context.Context, transactionID string) (*domain.Payment, error) { payment, err := s.queries.GetPaymentByTransactionID(ctx, toPgText(&transactionID)) if err != nil { return nil, err } return paymentToDomain(payment), nil } func (s *Store) GetPaymentsByUserID(ctx context.Context, userID int64, limit, offset int32) ([]domain.Payment, error) { payments, err := s.queries.GetPaymentsByUserID(ctx, dbgen.GetPaymentsByUserIDParams{ UserID: userID, Limit: pgtype.Int4{Int32: limit, Valid: true}, Offset: pgtype.Int4{Int32: offset, Valid: true}, }) if err != nil { return nil, err } result := make([]domain.Payment, len(payments)) for i, p := range payments { result[i] = domain.Payment{ ID: p.ID, UserID: p.UserID, PlanID: int8PtrToInt64Ptr(p.PlanID), SubscriptionID: int8PtrToInt64Ptr(p.SubscriptionID), SessionID: fromPgTextPtr(p.SessionID), TransactionID: fromPgTextPtr(p.TransactionID), Nonce: p.Nonce, Amount: fromPgNumeric(p.Amount), Currency: p.Currency, PaymentMethod: fromPgTextPtr(p.PaymentMethod), Status: p.Status, PaymentURL: fromPgTextPtr(p.PaymentUrl), PaidAt: timePtr(p.PaidAt), ExpiresAt: timePtr(p.ExpiresAt), CreatedAt: p.CreatedAt.Time, UpdatedAt: timePtr(p.UpdatedAt), PlanName: fromPgTextPtr(p.PlanName), } } return result, nil } func (s *Store) GetPendingPaymentsByUserID(ctx context.Context, userID int64) ([]domain.Payment, error) { payments, err := s.queries.GetPendingPaymentsByUserID(ctx, userID) if err != nil { return nil, err } result := make([]domain.Payment, len(payments)) for i, p := range payments { result[i] = *paymentToDomain(p) } return result, nil } func (s *Store) UpdatePaymentStatus(ctx context.Context, id int64, status string) error { return s.queries.UpdatePaymentStatus(ctx, dbgen.UpdatePaymentStatusParams{ Status: status, ID: id, }) } func (s *Store) UpdatePaymentStatusBySessionID(ctx context.Context, sessionID, status, transactionID, paymentMethod string) error { return s.queries.UpdatePaymentStatusBySessionID(ctx, dbgen.UpdatePaymentStatusBySessionIDParams{ Status: status, TransactionID: transactionID, PaymentMethod: paymentMethod, SessionID: sessionID, }) } func (s *Store) UpdatePaymentStatusByNonce(ctx context.Context, nonce, status, transactionID, paymentMethod string) error { return s.queries.UpdatePaymentStatusByNonce(ctx, dbgen.UpdatePaymentStatusByNonceParams{ Status: status, TransactionID: transactionID, PaymentMethod: paymentMethod, Nonce: nonce, }) } func (s *Store) UpdatePaymentSessionID(ctx context.Context, id int64, sessionID, paymentURL string) error { return s.queries.UpdatePaymentSessionID(ctx, dbgen.UpdatePaymentSessionIDParams{ SessionID: toPgText(&sessionID), PaymentUrl: toPgText(&paymentURL), ID: id, }) } func (s *Store) LinkPaymentToSubscription(ctx context.Context, paymentID, subscriptionID int64) error { return s.queries.LinkPaymentToSubscription(ctx, dbgen.LinkPaymentToSubscriptionParams{ SubscriptionID: pgtype.Int8{Int64: subscriptionID, Valid: true}, ID: paymentID, }) } func (s *Store) GetExpiredPendingPayments(ctx context.Context) ([]domain.Payment, error) { payments, err := s.queries.GetExpiredPendingPayments(ctx) if err != nil { return nil, err } result := make([]domain.Payment, len(payments)) for i, p := range payments { result[i] = *paymentToDomain(p) } return result, nil } func (s *Store) ExpirePayment(ctx context.Context, id int64) error { return s.queries.ExpirePayment(ctx, id) } func (s *Store) ListPaymentsAdmin(ctx context.Context, filter domain.PaymentListFilter) (domain.PaymentListPage, error) { params := buildPaymentsAdminFilterParams(filter) total, err := s.queries.CountPaymentsAdmin(ctx, dbgen.CountPaymentsAdminParams(params)) if err != nil { return domain.PaymentListPage{}, err } rows, err := s.queries.ListPaymentsAdmin(ctx, dbgen.ListPaymentsAdminParams{ PaymentID: int64PtrToPgInt8(filter.PaymentID), UserID: params.UserID, PlanID: params.PlanID, SubscriptionID: params.SubscriptionID, Status: params.Status, PaymentMethod: params.PaymentMethod, Currency: params.Currency, PlanCategory: params.PlanCategory, CreatedFrom: params.CreatedFrom, CreatedTo: params.CreatedTo, PaidFrom: params.PaidFrom, PaidTo: params.PaidTo, MinAmount: params.MinAmount, MaxAmount: params.MaxAmount, Reference: params.Reference, Limit: filter.Limit, Offset: filter.Offset, }) if err != nil { return domain.PaymentListPage{}, err } items := make([]domain.Payment, len(rows)) for i, row := range rows { items[i] = paymentAdminRowToDomain(row) } return domain.PaymentListPage{ Items: items, Total: total, Limit: filter.Limit, Offset: filter.Offset, }, nil } func buildPaymentsAdminFilterParams(filter domain.PaymentListFilter) dbgen.CountPaymentsAdminParams { return dbgen.CountPaymentsAdminParams{ PaymentID: int64PtrToPgInt8(filter.PaymentID), UserID: int64PtrToPgInt8(filter.UserID), PlanID: int64PtrToPgInt8(filter.PlanID), SubscriptionID: int64PtrToPgInt8(filter.SubscriptionID), Status: toPgText(filter.Status), PaymentMethod: toPgText(filter.PaymentMethod), Currency: toPgText(filter.Currency), PlanCategory: toPgText(filter.PlanCategory), CreatedFrom: toPgTimestamptzPtr(filter.CreatedFrom), CreatedTo: toPgTimestamptzPtr(filter.CreatedTo), PaidFrom: toPgTimestamptzPtr(filter.PaidFrom), PaidTo: toPgTimestamptzPtr(filter.PaidTo), MinAmount: toPgNumericPtr(filter.MinAmount), MaxAmount: toPgNumericPtr(filter.MaxAmount), Reference: toPgText(filter.Reference), } } func paymentAdminRowToDomain(row dbgen.ListPaymentsAdminRow) domain.Payment { return domain.Payment{ ID: row.ID, UserID: row.UserID, PlanID: int8PtrToInt64Ptr(row.PlanID), SubscriptionID: int8PtrToInt64Ptr(row.SubscriptionID), SessionID: fromPgTextPtr(row.SessionID), TransactionID: fromPgTextPtr(row.TransactionID), Nonce: row.Nonce, Amount: fromPgNumeric(row.Amount), Currency: row.Currency, PaymentMethod: fromPgTextPtr(row.PaymentMethod), Status: row.Status, PaymentURL: fromPgTextPtr(row.PaymentUrl), PaidAt: timePtr(row.PaidAt), ExpiresAt: timePtr(row.ExpiresAt), CreatedAt: row.CreatedAt.Time, UpdatedAt: timePtr(row.UpdatedAt), PlanName: fromPgTextPtr(row.PlanName), PlanCategory: fromPgTextPtr(row.PlanCategory), UserEmail: fromPgTextPtr(row.UserEmail), UserFirstName: fromPgTextPtr(row.UserFirstName), UserLastName: fromPgTextPtr(row.UserLastName), } } func toPgNumericPtr(val *float64) pgtype.Numeric { if val == nil { return pgtype.Numeric{Valid: false} } return toPgNumeric(*val) } // Helper functions func paymentToDomain(p dbgen.Payment) *domain.Payment { return &domain.Payment{ ID: p.ID, UserID: p.UserID, PlanID: int8PtrToInt64Ptr(p.PlanID), SubscriptionID: int8PtrToInt64Ptr(p.SubscriptionID), SessionID: fromPgTextPtr(p.SessionID), TransactionID: fromPgTextPtr(p.TransactionID), Nonce: p.Nonce, Amount: fromPgNumeric(p.Amount), Currency: p.Currency, PaymentMethod: fromPgTextPtr(p.PaymentMethod), Status: p.Status, PaymentURL: fromPgTextPtr(p.PaymentUrl), PaidAt: timePtr(p.PaidAt), ExpiresAt: timePtr(p.ExpiresAt), CreatedAt: p.CreatedAt.Time, UpdatedAt: timePtr(p.UpdatedAt), } } func int64PtrToPgInt8(val *int64) pgtype.Int8 { if val == nil { return pgtype.Int8{Valid: false} } return pgtype.Int8{Int64: *val, Valid: true} } func int8PtrToInt64Ptr(val pgtype.Int8) *int64 { if !val.Valid { return nil } return &val.Int64 } func fromPgTextPtr(t pgtype.Text) *string { if !t.Valid { return nil } return &t.String } func strPtr(s string) *string { return &s }