package repository import ( "context" "fmt" "time" "gitea.pena/PenaSide/treasurer/internal/errors" "gitea.pena/PenaSide/treasurer/internal/models" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" ) var PaymentFields = struct { ID string UserID string PaymentID string IdempotencePaymentID string ClientIP string Currency string Amount string Type string Status string Completed string IsDeleted string CreatedAt string UpdatedAt string DeletedAt string RawPaymentBody string CallbackHostGRPC string }{ ID: "_id", UserID: "userId", PaymentID: "paymentId", IdempotencePaymentID: "idempotencePaymentId", ClientIP: "clientIp", Currency: "currency", Amount: "amount", Type: "type", Status: "status", Completed: "completed", IsDeleted: "isDeleted", CreatedAt: "createdAt", UpdatedAt: "updatedAt", DeletedAt: "deletedAt", RawPaymentBody: "rawPaymentBody", CallbackHostGRPC: "callbackHostGrpc", } type PaymentRepositoryDeps struct { Logger *zap.Logger Collection *mongo.Collection } type PaymentRepository struct { logger *zap.Logger collection *mongo.Collection } func NewPaymentRepository(deps PaymentRepositoryDeps) (*PaymentRepository, errors.Error) { if deps.Logger == nil { return nil, errors.NewWithMessage("Logger in nil on ", errors.ErrInvalidArgs) } if deps.Collection == nil { return nil, errors.NewWithMessage("Collection in nil on ", errors.ErrInvalidArgs) } return &PaymentRepository{ logger: deps.Logger, collection: deps.Collection, }, nil } func (receiver *PaymentRepository) SetPaymentComplete(ctx context.Context, paymentID string) (*models.Payment, errors.Error) { payment := models.Payment{} options := options.FindOneAndUpdate().SetReturnDocument(options.After) filter := bson.M{PaymentFields.PaymentID: paymentID} update := bson.M{"$set": bson.M{ PaymentFields.Completed: true, PaymentFields.UpdatedAt: time.Now(), }} if err := receiver.collection.FindOneAndUpdate(ctx, filter, update, options).Decode(&payment); err != nil { receiver.logger.Error("failed to set payment complete on of ", zap.Error(err), zap.String("paymentID", paymentID), ) removeErr := errors.NewWithError( fmt.Errorf("failed to set payment complete with <%s> on of : %w", paymentID, err), errors.ErrInternalError, ) if err == mongo.ErrNoDocuments { return nil, removeErr.SetType(errors.ErrNotFound) } return nil, removeErr } return &payment, nil } func (receiver *PaymentRepository) Insert(ctx context.Context, payment *models.Payment) (*models.Payment, errors.Error) { sanitizedPayment := payment.Sanitize() result, err := receiver.collection.InsertOne(ctx, sanitizedPayment) if err != nil { receiver.logger.Error("failed to insert payment on of ", zap.Any("payment", sanitizedPayment), zap.Error(err), ) return nil, errors.NewWithError( fmt.Errorf("failed to insert payment on of : %w", err), errors.ErrInternalError, ) } insertedID := result.InsertedID.(primitive.ObjectID).Hex() sanitizedPayment.ID = insertedID return sanitizedPayment, nil } func (receiver *PaymentRepository) SetPaymentStatus(ctx context.Context, paymentID string, status models.PaymentStatus) (*models.Payment, errors.Error) { payment := models.Payment{} options := options.FindOneAndUpdate().SetReturnDocument(options.After) filter := bson.M{PaymentFields.PaymentID: paymentID} update := bson.M{"$set": bson.M{ PaymentFields.Status: status, PaymentFields.UpdatedAt: time.Now(), }} if err := receiver.collection.FindOneAndUpdate(ctx, filter, update, options).Decode(&payment); err != nil { receiver.logger.Error("failed to set payment status on of ", zap.Error(err), zap.String("paymentID", paymentID), ) removeErr := errors.NewWithError( fmt.Errorf("failed to set payment status with <%s> on of : %w", paymentID, err), errors.ErrInternalError, ) if err == mongo.ErrNoDocuments { return nil, removeErr.SetType(errors.ErrNotFound) } return nil, removeErr } return &payment, nil }