package store import ( "context" "strings" "time" "github.com/tech/sendico/gateway/tgsettle/storage" "github.com/tech/sendico/gateway/tgsettle/storage/model" "github.com/tech/sendico/pkg/merrors" "github.com/tech/sendico/pkg/mlogger" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.uber.org/zap" ) const ( paymentsCollection = "payments" fieldIdempotencyKey = "idempotencyKey" ) type Payments struct { logger mlogger.Logger coll *mongo.Collection } func NewPayments(logger mlogger.Logger, db *mongo.Database) (*Payments, error) { if db == nil { return nil, merrors.InvalidArgument("mongo database is nil") } p := &Payments{ logger: logger.Named("payments"), coll: db.Collection(paymentsCollection), } _, err := p.coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{ Keys: bson.D{{Key: fieldIdempotencyKey, Value: 1}}, Options: options.Index().SetUnique(true), }) if err != nil { p.logger.Error("Failed to create payments idempotency index", zap.Error(err)) return nil, err } return p, nil } func (p *Payments) FindByIdempotencyKey(ctx context.Context, key string) (*model.PaymentExecution, error) { key = strings.TrimSpace(key) if key == "" { return nil, merrors.InvalidArgument("idempotency key is required", "idempotency_key") } var result model.PaymentExecution err := p.coll.FindOne(ctx, bson.M{fieldIdempotencyKey: key}).Decode(&result) if err == mongo.ErrNoDocuments { return nil, nil } if err != nil { return nil, err } return &result, nil } func (p *Payments) InsertExecution(ctx context.Context, exec *model.PaymentExecution) error { if exec == nil { return merrors.InvalidArgument("payment execution is nil", "execution") } exec.IdempotencyKey = strings.TrimSpace(exec.IdempotencyKey) exec.PaymentIntentID = strings.TrimSpace(exec.PaymentIntentID) exec.QuoteRef = strings.TrimSpace(exec.QuoteRef) if exec.ExecutedAt.IsZero() { exec.ExecutedAt = time.Now() } if _, err := p.coll.InsertOne(ctx, exec); err != nil { if mongo.IsDuplicateKeyError(err) { return storage.ErrDuplicate } return err } return nil } var _ storage.PaymentsStore = (*Payments)(nil)