treasurer/internal/service/webhook/yandex.go
2023-06-13 13:22:51 +00:00

192 lines
7.2 KiB
Go

package webhook
import (
"context"
"fmt"
"net/url"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models/yandex"
"penahub.gitlab.yandexcloud.net/external/treasurer/pkg/array"
)
const (
onYandexSuccessWebhookEventKey = "e242352d-5921-44b1-99f9-d022734fe514-success"
onYandexCanceledWebhookEventKey = "e242352d-5921-44b1-99f9-d022734fe514-canceled"
onYandexWaitingWebhookEventKey = "e242352d-5921-44b1-99f9-d022734fe514-waiting"
onYandexRefundWebhookEventKey = "e242352d-5921-44b1-99f9-d022734fe514-refund"
)
type YandexWebhookClient interface {
SetWebhookEvent(ctx context.Context, idempotenceKey string, request *yandex.CreateWebhookRequest) (id string, err errors.Error)
GetWebhookEvents(ctx context.Context) ([]yandex.Webhook, errors.Error)
DeleteWebhook(ctx context.Context, webhookID string) errors.Error
}
type YandexDeps struct {
Logger *zap.Logger
Configuration *models.ConfigurationHTTP
YandexWebhookClient YandexWebhookClient
}
type Yandex struct {
logger *zap.Logger
configuration *models.ConfigurationHTTP
yandexWebhookClient YandexWebhookClient
}
func NewYandex(deps YandexDeps) (*Yandex, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("logger is nil on <NewYandexWebhookService>", errors.ErrInvalidArgs)
}
if deps.Configuration == nil {
return nil, errors.NewWithMessage("Configuration is nil on <NewYandexWebhookService>", errors.ErrInvalidArgs)
}
if deps.YandexWebhookClient == nil {
return nil, errors.NewWithMessage("PaymentRepository is nil on <NewYandexWebhookService>", errors.ErrInvalidArgs)
}
return &Yandex{
logger: deps.Logger,
configuration: deps.Configuration,
yandexWebhookClient: deps.YandexWebhookClient,
}, nil
}
func (receiver *Yandex) SetOnPaymentSuccess(ctx context.Context) errors.Error {
url, urlErr := url.JoinPath(receiver.configuration.Domen, "yandex", "payment", "status", "succeeded")
if urlErr != nil {
receiver.logger.Error("failed to join url path on <SetOnPaymentSuccess> of <WebhookService>", zap.Error(urlErr))
return errors.NewWithError(fmt.Errorf("failed to join url path: %w", urlErr), errors.ErrInternalError)
}
if err := receiver.SetWebhook(ctx, onYandexSuccessWebhookEventKey, &yandex.CreateWebhookRequest{
Event: yandex.WebhookEventPaymentSucceeded,
URL: url,
}); err != nil {
receiver.logger.Error("failed to set webhook on <SetOnPaymentSuccess> of <WebhookService>", zap.Error(err))
return err
}
return nil
}
func (receiver *Yandex) SetOnPaymentCanceled(ctx context.Context) errors.Error {
url, urlErr := url.JoinPath(receiver.configuration.Domen, "yandex", "payment", "status", "canceled")
if urlErr != nil {
receiver.logger.Error("failed to join url path on <SetOnPaymentCanceled> of <WebhookService>", zap.Error(urlErr))
return errors.NewWithError(fmt.Errorf("failed to join url path: %w", urlErr), errors.ErrInternalError)
}
if err := receiver.SetWebhook(ctx, onYandexCanceledWebhookEventKey, &yandex.CreateWebhookRequest{
Event: yandex.WebhookEventPaymentCanceled,
URL: url,
}); err != nil {
receiver.logger.Error("failed to set webhook on <SetOnPaymentCanceled> of <WebhookService>", zap.Error(err))
return err
}
return nil
}
func (receiver *Yandex) SetOnPaymentWaiting(ctx context.Context) errors.Error {
url, urlErr := url.JoinPath(receiver.configuration.Domen, "yandex", "payment", "status", "waiting")
if urlErr != nil {
receiver.logger.Error("failed to join url path on <SetOnPaymentWaiting> of <WebhookService>", zap.Error(urlErr))
return errors.NewWithError(fmt.Errorf("failed to join url path: %w", urlErr), errors.ErrInternalError)
}
if err := receiver.SetWebhook(ctx, onYandexWaitingWebhookEventKey, &yandex.CreateWebhookRequest{
Event: yandex.WebhookEventPaymentWaiting,
URL: url,
}); err != nil {
receiver.logger.Error("failed to set webhook on <SetOnPaymentWaiting> of <WebhookService>", zap.Error(err))
return err
}
return nil
}
func (receiver *Yandex) SetOnPaymentRefund(ctx context.Context) errors.Error {
url, urlErr := url.JoinPath(receiver.configuration.Domen, "yandex", "refund", "status", "canceled")
if urlErr != nil {
receiver.logger.Error("failed to join url path on <SetOnPaymentRefund> of <WebhookService>", zap.Error(urlErr))
return errors.NewWithError(fmt.Errorf("failed to join url path: %w", urlErr), errors.ErrInternalError)
}
if err := receiver.SetWebhook(ctx, onYandexRefundWebhookEventKey, &yandex.CreateWebhookRequest{
Event: yandex.WebhookEventRefundSucceeded,
URL: url,
}); err != nil {
receiver.logger.Error("failed to set webhook on <SetOnPaymentRefund> of <WebhookService>", zap.Error(err))
return err
}
return nil
}
func (receiver *Yandex) SetWebhook(ctx context.Context, idempotenceKey string, request *yandex.CreateWebhookRequest) errors.Error {
webhook, err := receiver.GetWebhookByType(ctx, request.Event)
if err != nil && err.Type() != errors.ErrNotFound {
receiver.logger.Error("failed to get webhook on <SetWebhook> of <WebhookService>", zap.Error(err))
return err
}
if webhook != nil {
receiver.logger.Error("webhook already exist on <SetWebhook> of <WebhookService>")
return errors.NewWithError(
fmt.Errorf("yandex webhook with type <%s> already exist", request.Event),
errors.ErrConflict,
)
}
if _, err := receiver.yandexWebhookClient.SetWebhookEvent(ctx, idempotenceKey, request); err != nil {
receiver.logger.Error("failed to set webhook on <SetWebhook> of <WebhookService>", zap.Error(err))
return err
}
return nil
}
func (receiver *Yandex) GetWebhookByType(ctx context.Context, event yandex.WebhookEventType) (*yandex.Webhook, errors.Error) {
webhooks, err := receiver.yandexWebhookClient.GetWebhookEvents(ctx)
if err != nil {
receiver.logger.Error("failed to get webhooks list on <GetWebhookByKey> of <WebhookService>", zap.Error(err))
return nil, err
}
if len(webhooks) < 1 {
receiver.logger.Error("empty webhooks on <GetWebhookByKey> of <WebhookService>")
return nil, errors.NewWithMessage("webhooks empty in yandex server", errors.ErrNotFound)
}
webhook := array.Find(webhooks, func(webhook yandex.Webhook, _ int, _ []yandex.Webhook) bool {
return webhook.Event == event
})
if webhook == nil {
receiver.logger.Error("webhook not found on <GetWebhookByKey> of <WebhookService>", zap.Error(err), zap.String("event", string(event)))
return nil, errors.NewWithError(fmt.Errorf("yandex webhook not found with <%s> event", event), errors.ErrNotFound)
}
return webhook, nil
}
func (receiver *Yandex) UnsetWebhook(ctx context.Context, event yandex.WebhookEventType) errors.Error {
webhook, err := receiver.GetWebhookByType(ctx, event)
if err != nil {
receiver.logger.Error("failed to get webhook on <UnsetWebhook> of <WebhookService>", zap.Error(err), zap.String("event", string(event)))
return err
}
if err := receiver.yandexWebhookClient.DeleteWebhook(ctx, webhook.ID); err != nil {
receiver.logger.Error("failed to delete webhook on <UnsetWebhook> of <WebhookService>", zap.Error(err), zap.String("id", webhook.ID))
return err
}
return nil
}