refactor: app (WIP)

This commit is contained in:
Kirill 2023-06-13 13:22:51 +00:00 committed by Mikhail
parent 4c38cc4f5c
commit db80989c81
134 changed files with 8295 additions and 5021 deletions

8
.dockerignore Normal file

@ -0,0 +1,8 @@
.mockery.yaml
.golangci.yaml
.gitlab-ci.yaml
.gitingore
.Makefile
.README.md
deployments
tests

16
.env.test Normal file

@ -0,0 +1,16 @@
HTTP_HOST=0.0.0.0
HTTP_PORT=8080
HTTP_DOMEN=http://localhost:8080
GRPC_HOST=0.0.0.0
GRPC_PORT=8081
YOOMONEY_STORE_ID=storeid
YOOMONEY_SECRET_KEY=secret
MONGO_HOST=mongo
MONGO_PORT=27017
MONGO_USER=admin
MONGO_PASSWORD=admin
MONGO_DB_NAME=admin
MONGO_AUTH=admin

1
.gitignore vendored

@ -48,5 +48,4 @@ Thumbs.db
*.mov *.mov
*.wmv *.wmv
profile profile
treasurer

164
.golangci.yaml Normal file

@ -0,0 +1,164 @@
run:
timeout: 5m
skip-files:
- \.pb\.go$
- \.pb\.validate\.go$
- \.pb\.gw\.go$
- \.gen\.go$
skip-dirs:
- mocks
- proto
linters:
disable-all: true
enable:
- asasalint
- asciicheck
- bidichk
- bodyclose
- containedctx
- depguard
- dogsled
- dupword
- durationcheck
- errcheck
- errchkjson
- exportloopref
- goconst
- gocritic
- godot
- gofmt
- gci
- goprintffuncname
- gosec
- gosimple
- govet
- importas
- ineffassign
- misspell
- nakedret
- nilerr
- noctx
- nolintlint
- nosprintfhostport
- prealloc
- predeclared
- revive
- rowserrcheck
- staticcheck
- stylecheck
- thelper
- typecheck
- unconvert
- unparam
- unused
- usestdlibvars
- whitespace
linters-settings:
errcheck:
exclude-functions:
- (io.Closer).Close
govet:
check-shadowing: true
gci:
custom-order: false
section-separators:
- newLine
sections:
- standard # Standard section: captures all standard packages.
- default # Default section: contains all imports that could not be matched to another section type.
- blank # Blank section: contains all blank imports. This section is not present unless explicitly enabled.
- dot # Dot section: contains all dot imports. This section is not present unless explicitly enabled.
importas:
no-unaliased: true
alias:
# Foundation libraries
- pkg: git.sbercloud.tech/products/paas/shared/foundation/management-server
alias: mgmtserver
maligned:
suggest-new: true
goconst:
min-len: 2
min-occurrences: 2
lll:
line-length: 140
revive:
rules:
# The following rules are recommended https://github.com/mgechev/revive#recommended-configuration
- name: blank-imports
- name: context-as-argument
- name: context-keys-type
- name: dot-imports
- name: error-return
- name: error-strings
- name: error-naming
# - name: exported
- name: if-return
- name: increment-decrement
- name: var-naming
- name: var-declaration
# - name: package-comments
- name: range
- name: receiver-naming
- name: time-naming
- name: unexported-return
- name: indent-error-flow
- name: errorf
- name: empty-block
- name: superfluous-else
- name: unused-parameter
- name: unreachable-code
- name: redefines-builtin-id
#
# Rules in addition to the recommended configuration above.
#
- name: bool-literal-in-expr
- name: constant-logical-expr
gosec:
excludes:
- G307 # Deferring unsafe method "Close" on type "\*os.File"
- G108 # Profiling endpoint is automatically exposed on /debug/pprof
gocritic:
enabled-tags:
- diagnostic
- experimental
- performance
disabled-checks:
- appendAssign
- dupImport # https://github.com/go-critic/go-critic/issues/845
- evalOrder
- ifElseChain
- octalLiteral
- regexpSimplify
- sloppyReassign
- truncateCmp
- typeDefFirst
- unnamedResult
- unnecessaryDefer
- whyNoLint
- wrapperFunc
- rangeValCopy
- hugeParam
issues:
exclude-rules:
- text: "at least one file in a package should have a package comment"
linters:
- stylecheck
- text: "should have a package comment, unless it's in another file for this package"
linters:
- golint
- text: "should have comment or be unexported"
linters:
- golint
- path: _test\.go
linters:
- gosec
- dupl
exclude-use-default: false
output:
# colored-line-number|line-number|json|tab|checkstyle, default is "colored-line-number"
format: colored-line-number
print-linter-name: true

6
.mockery.yaml Normal file

@ -0,0 +1,6 @@
exported: True
inpackage: False
keeptree: True
case: underscore
with-expecter: True
inpackage-suffix: True

@ -1,10 +1,72 @@
FROM alpine # BUILD
ADD treasurer / FROM golang:1.20.3-alpine AS build
COPY prod.crt /
COPY prod.key / # Update depences
ENV APP_ADDR=:3000 RUN apk update && apk add --no-cache curl
ENV DATABASE_URI=mongodb://mongodb,mongodb2 # Create build directory
ENV PAYWAY_DB_URI=mongodb://mongodb,mongodb2 RUN mkdir /app/bin -p
ENV DEVELOPMENT=false RUN mkdir /bin/golang-migrate -p
RUN apk add --no-cache ca-certificates # Download migrate app
CMD ["/treasurer"] RUN GOLANG_MIGRATE_VERSION=v4.15.1 && \
curl -L https://github.com/golang-migrate/migrate/releases/download/${GOLANG_MIGRATE_VERSION}/migrate.linux-amd64.tar.gz |\
tar xvz migrate -C /bin/golang-migrate
# Download health check utility
RUN GRPC_HEALTH_PROBE_VERSION=v0.4.6 && \
wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \
chmod +x /bin/grpc_health_probe
# Set home directory
WORKDIR /app
# Copy go.mod
ADD go.mod go.sum /app/
# Download go depences
RUN go mod download
# Copy all local files
ADD . /app
# Build app
RUN GOOS=linux go build -o bin ./...
# TEST
FROM alpine:latest AS test
# Install packages
RUN apk --no-cache add ca-certificates
ENV GO111MODULE=off
# Create home directory
WORKDIR /app
# Copy build file
COPY --from=build /app/bin/app ./app
# CMD
CMD [ "./app" ]
# MIGRATION
FROM alpine:latest AS migration
# Install packages
RUN apk --no-cache add ca-certificates
# Create home directory
WORKDIR /app
# Copy migration dir
COPY --from=build /app/migrations/test ./migrations
# Install migrate tool
COPY --from=build /bin/golang-migrate /usr/local/bin
# PRODUCTION
FROM alpine:latest AS production
# Install packages
RUN apk --no-cache add ca-certificates
# Create home directory
WORKDIR /app
# Copy build file
COPY --from=build /app/bin/app ./app
# Copy grpc health probe dir
COPY --from=build /bin/grpc_health_probe /bin/grpc_health_probe
# Install migrate tool
COPY --from=build /bin/golang-migrate /usr/local/bin
# CMD
CMD ["./app"]

@ -1,10 +0,0 @@
FROM alpine
ADD treasurer /
COPY prod.crt /
COPY prod.key /
ENV APP_ADDR=:3000
ENV DATABASE_URI=mongodb://mongodb
ENV PAYWAY_DB_URI=mongodb://mongodb
ENV DEVELOPMENT=false
RUN apk add --no-cache ca-certificates
CMD ["/treasurer"]

@ -1,30 +1,50 @@
GOCMD=go
GOBUILD=$(GOCMD) build
GOCLEAN=$(GOCMD) clean
GOTEST=$(GOCMD) test
RELEASE?=$(git tag)
COMMIT?=$(shell git rev-parse --short HEAD)
BUILD_TIME?=$(shell date -u '+%Y-%m-%d_%H:%M:%S')
PROJECT?=bitbucket.org/skeris/treasurer
GOOS?=linux
GOARCH?=amd64
BINARY_NAME=treasurer
PORT?=3000
all: build run help: ## show this help
clean: @echo 'usage: make [target] ...'
$(GOCLEAN) @echo ''
rm -f $(BINARY_NAME) @echo 'targets:'
build: clean @egrep '^(.+)\:\ .*##\ (.+)' ${MAKEFILE_LIST} | sed 's/:.*##/#/' | column -t -c 2 -s '#'
CGO_ENABLED=0 GOOS=${GOOS} GOARCH=${GOARCH} $(GOBUILD) \
-ldflags "-s -w -X ${PROJECT}/version.Release=${RELEASE} \ install: ## install all go dependencies
-X ${PROJECT}/version.Commit=${COMMIT} -X ${PROJECT}/version.BuildTime=${BUILD_TIME}" \ go get \
-o ${BINARY_NAME} github.com/bufbuild/buf/cmd/buf \
container: build github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \
docker build -t $(BINARY_NAME):$(RELEASE) . github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 \
#run: container google.golang.org/grpc/cmd/protoc-gen-go-grpc \
# docker stop $(BINARY_NAME):$(RELEASE) || true && docker rm $(BINARY_NAME):$(RELEASE) google.golang.org/protobuf/cmd/protoc-gen-go
test-build:
CGO_ENABLED=0 $(GOTEST) -c -o ./payway/test ./payway generate: ## generate grpc proto for golang
docker compose up --build --force-recreate --abort-on-container-exit --force-recreate --remove-orphans --exit-code-from test buf generate
docker compose down
test: ## run all layers tests
@make test.unit
@make test.integration
test.unit: ## run unit tests
go test ./internal/...
test.integration: ## run integration tests
@make test.integration.up
@make test.integration.start
@make test.integration.down
test.integration.up: ## build integration test environment
docker-compose -f deployments/test/docker-compose.yaml up -d
test.integration.start: ## run integration test
go test ./tests/integration/...
test.integration.down: ## shutting down integration environment
docker-compose -f deployments/test/docker-compose.yaml down --volumes --rmi local
run: ## run app
go run ./cmd/app/main.go
mock: ## run mock
go run ./cmd/mock/main.go
dev.up: ## run dev environment
docker-compose -f deployments/dev/docker-compose.yaml up -d
dev.down: ## shutting down dev environment
docker-compose -f deployments/dev/docker-compose.yaml down --volumes --rmi local

30
README.md Normal file

@ -0,0 +1,30 @@
# customer
Сервис customer
| Branch | Pipeline | Code coverage |
| ------------- |:-----------------:| --------------:|
| master | [![pipeline status](https://penahub.gitlab.yandexcloud.net/external/treasurer/badges/master/pipeline.svg)](https://penahub.gitlab.yandexcloud.net/external/treasurer/-/pipelines) | [![coverage report](https://penahub.gitlab.yandexcloud.net/external/treasurer/badges/master/coverage.svg?job=test)](https://penahub.gitlab.yandexcloud.net/external/treasurer/-/pipelines) |
| staging | [![pipeline status](https://penahub.gitlab.yandexcloud.net/external/treasurer/badges/staging/pipeline.svg)](https://penahub.gitlab.yandexcloud.net/external/treasurer/-/pipelines) | [![coverage report](https://penahub.gitlab.yandexcloud.net/external/treasurer/badges/staging/coverage.svg?job=test)](https://penahub.gitlab.yandexcloud.net/external/treasurer/-/pipelines) |
| dev | [![pipeline status](https://penahub.gitlab.yandexcloud.net/external/treasurer/badges/dev/pipeline.svg)](https://penahub.gitlab.yandexcloud.net/external/treasurer/-/pipelines) | [![coverage report](https://penahub.gitlab.yandexcloud.net/external/treasurer/badges/dev/coverage.svg?job=test)](https://penahub.gitlab.yandexcloud.net/external/treasurer/-/pipelines) |
## Переменные окружения приложения
```
HTTP_HOST - хост приложения (HTTP)
HTTP_PORT - порт приложения (HTTP)
HTTP_DOMEN - домен приложения (HTTP)
GRPC_HOST - хост приложения (GRPC)
GRPC_PORT - порт приложения (GRPC)
MONGO_HOST - хост MongoDB
MONGO_PORT - порт MongoDB
MONGO_USER - пользователь MongoDB
MONGO_DB_NAME - название базы данных для подключения
MONGO_PASSWORD - пароль пользователя MongoDB
MONGO_AUTH - имя базы данных Mongo, по которой будет производится авторизация
YOOMONEY_STORE_ID - id магазина, зарегистрированного на yoomoney
YOOMONEY_SECRET_KEY - секретный ключ yoomoney
```

@ -1,293 +0,0 @@
package app
import (
"context"
"errors"
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"bitbucket.org/skeris/bbfoundation/middleware"
"bitbucket.org/skeris/bbfoundation/role"
r "bitbucket.org/skeris/bbfoundation/router"
"bitbucket.org/skeris/treasurer/dal"
h "bitbucket.org/skeris/treasurer/handlers"
"bitbucket.org/skeris/treasurer/payway"
v "bitbucket.org/skeris/treasurer/version"
"github.com/danilsolovyov/validator"
"github.com/skeris/appInit"
"github.com/themakers/hlog"
"go.uber.org/zap"
tb "gopkg.in/tucnak/telebot.v2"
)
//#region ======== Application Structs & Functions ========
type Options struct {
IsProduction bool `env:"IS_PRODUCTION" default:"false"`
Development bool `env:"DEVELOPMENT" default:"true"`
AppName string `env:"APP_NAME" default:"treasurer"`
AppAddr string `env:"APP_ADDR" default:"localhost:3001"` //localhost:3000
AllowedOrigins string `env:"ALLOWED_ORIGINS" default:"*"`
AllowedHeaders string `env:"ALLOWED_HEADERS" default:"*"`
ExposeHeaders string `env:"EXPOSE_HEADERS" default:"*"`
MongoDbUri string `env:"DATABASE_URI" default:"mongodb+srv://user_1:cEDxC8ptLMMeoA5m@cluster0.aomle.mongodb.net/test"`
PayWayDbUri string `env:"PAYWAY_DB_URI" default:"mongodb+srv://user_2:vW3WNWViJaXYSraT@cluster0.aomle.mongodb.net/test"`
MongoDbTable string `env:"DATABASE_TABLE" default:"treasurer"`
MongoCollections string `env:"COLLECTION_NAME" default:"payment"`
}
type App struct {
logger *zap.Logger
err chan error
}
func (a App) GetLogger() *zap.Logger {
return a.logger
}
func (a App) GetErr() chan error {
return a.err
}
//#endregion
//#region ======== Hl Info Structs ========
type InfoSvcStarted struct{}
type InfoInterruptSignal struct{}
type InfoTerminateSignal struct{}
type InfoSvcShuttingDown struct{}
type InfoSvcDone struct{}
//#endregion
//#region ======== Hl ErrorTypeApp Structs ========
type ErrorTypeApp struct {
Error error
}
type ErrorCanNotServe ErrorTypeApp
type ErrorSvcShuttingDown ErrorTypeApp
type ErrorZlogSync ErrorTypeApp
type ErrorConnectToMongo ErrorTypeApp
type ErrorDisconnectFromMongo ErrorTypeApp
type ErrorConnectToToRoles ErrorTypeApp
//#endregion
func New(ctx context.Context, options interface{}) (appInit.CommonApp, error) {
opts := options.(Options)
var errCh chan error
// Create logger
zlog, err := zap.NewDevelopment()
if err != nil {
panic(err)
}
zlog = zlog.WithOptions(zap.AddCallerSkip(2))
hlogger := hlog.New(zlog)
hlogger = hlogger.With(v.GetVersion())
defer func() {
err = zlog.Sync()
if err != nil {
hlogger.Emit(ErrorZlogSync{err})
}
}()
// Connect to MongoDb "Treasurer"
connMongo, err := dal.CreateMongo(ctx, hlogger, dal.MongoDbOptions{
DalName: "MongoDB",
URI: opts.MongoDbUri,
DbTable: opts.MongoDbTable,
Collections: opts.MongoCollections,
})
if err != nil {
hlogger.Emit(ErrorConnectToMongo{err})
return App{zlog, errCh}, err
}
ctxL, cancL := context.WithCancel(ctx)
defer cancL()
go connMongo.ListenPayment(ctxL)
// Connect to MongoDb "PayWay"
connPayWay, err := dal.CreateMongo(ctx, hlogger, dal.MongoDbOptions{
DalName: "MongoPayWay",
URI: opts.PayWayDbUri,
DbTable: "payway",
Collections: "payway,paywayPayment",
})
if err != nil {
hlogger.Emit(ErrorConnectToMongo{err})
return App{zlog, errCh}, err
}
payWay, err := payway.NewPayWay(ctx, hlogger, connPayWay, connMongo)
if err != nil {
fmt.Println("PAYWAYERR", err)
//return nil, err
}
go connPayWay.ListenPayWay(ctx, func(data *dal.PayWay) error {
_, ok := payWay.Cache[data.ShortName]
if !ok {
errText := fmt.Sprintf("%v (%v) not found in cache", data.ID, data.ShortName)
return errors.New(errText)
}
payWay.Cache[data.ShortName].UpdateData(data)
return nil
})
// TODO: remove roles logic from project
// Start Roles
roles, err := role.NewRoles(ctx, hlogger, role.MongoDalOptions{
DalName: "MongoRoles",
URI: opts.MongoDbUri,
})
if err != nil {
hlogger.Emit(ErrorConnectToToRoles{err})
return App{zlog, errCh}, err
}
// Set routers
// TODO: remove
validators := h.CreateValidators(
&h.RequestCreatePayment{},
&h.RequestCreatePayout{},
)
chCommon := h.CommonOpts{
AllowedOrigins: opts.AllowedOrigins,
Mongo: connMongo,
Hl: hlogger,
}
// TODO: remove unnecessary with all usages
crucsNotifier, err := tb.NewBot(tb.Settings{
Token: "",
Verbose: false,
ParseMode: tb.ModeHTML,
Poller: &tb.LongPoller{
Timeout: time.Second,
},
})
if err != nil {
return nil, err
}
// TODO: use echo or gofiber. please remove this f*cking strange shit
// TODO: actualise api for invoice and available methods
// invoice используется для получения ссылки на оплату. по сути он выполняет 2 действия: складывает запись запроса в базу, чтобы хранились actions которые надо выполнить в ответ на события, и запросить у соответствующего платёжного сервиса правильную платёжную ссылку
// TODO: для каждого платёжного аггрегатора надо реализовать хендлер типа /listener/{paywayId}, где paywayId - айди аггрегатора
router, svcRouter, allowedRoles := r.NewCombineRouter("", r.Handlers{
"/listener/create/refill": {
Handle: func(w http.ResponseWriter, r *http.Request) {
ch := h.NewHandler(w, r, chCommon, validators["RequestCreatePayment"])
h.CreatePaymentHandler(ch, payWay, crucsNotifier)
},
},
"/listener/create/payout": {
Handle: func(w http.ResponseWriter, r *http.Request) {
ch := h.NewHandler(w, r, chCommon, validators["RequestCreatePayout"])
h.CreatePayoutHandler(ch, payWay)
},
}, // pub 0b922668de7e440f263d36bf91c506d3 sek 82afd8dad1db3785d4a94e539e142a39
"/listener/{payWay}": {
Handle: func(w http.ResponseWriter, r *http.Request) {
ch := h.NewHandler(w, r, chCommon, validator.Validator{})
h.PaymentListenerHandler(ch, payWay)
},
},
"/payoutListener/{payWay}": { //TODO: remove unnecessary
Handle: func(w http.ResponseWriter, r *http.Request) {
ch := h.NewHandler(w, r, chCommon, validator.Validator{})
h.PayoutListenerHandler(ch, payWay)
},
},
"/listener/getPayWays": {
Handle: func(w http.ResponseWriter, r *http.Request) {
ch := h.NewHandler(w, r, chCommon, validator.Validator{})
h.GetPayWays(ch, payWay)
},
},
})
// TODO: remove unnecessary
// Set Middlewares
mw := middleware.NewMiddleware(
opts.IsProduction,
hlogger,
roles,
opts.AllowedOrigins,
opts.AllowedHeaders,
allowedRoles,
opts.ExposeHeaders,
)
//TODO: remove unnecessary
router.Use(
mw.MiddlewareLogger,
mw.MiddlewareOriginAccess,
mw.MiddlewareRecovery,
)
// TODO: remove unnecessary
svcRouter.Use(
//mw.MiddlewareJwtCookie,
//mw.MiddlewareJwt,
//mw.MiddlewareGetJwt,
//mw.MiddlewareRoleAccess,
)
// Startup server
srv := &http.Server{Addr: opts.AppAddr, Handler: router}
go func() {
tmplKey := "%s.key"
tmplCrt := "%s.crt"
//if !options.LoggerDevMode {
tmplCrt = fmt.Sprintf(tmplCrt, "prod")
tmplKey = fmt.Sprintf(tmplKey, "prod")
if err := srv.ListenAndServeTLS(tmplCrt, tmplKey); err != http.ErrServerClosed && err != nil {
hlogger.Emit(ErrorCanNotServe{Error: err})
}
}()
hlogger.Emit(InfoSvcStarted{})
// Graceful Shutdown
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
killSignal := <-interrupt
switch killSignal {
case os.Interrupt:
err = errors.New("interrupted")
hlogger.Emit(InfoInterruptSignal{})
case syscall.SIGTERM:
err = errors.New("terminated")
hlogger.Emit(InfoTerminateSignal{})
}
hlogger.Emit(InfoSvcShuttingDown{})
err = srv.Shutdown(ctx)
if err != nil {
hlogger.Emit(ErrorSvcShuttingDown{err})
}
hlogger.Emit(InfoSvcDone{})
err = errors.New("finished") // Костыль чтобы приложение нормально закрывалось...
return App{zlog, errCh}, err
}

8
buf.gen.yaml Normal file

@ -0,0 +1,8 @@
version: v1
plugins:
- name: go
out: internal/proto
- name: go-grpc
out: internal/proto
opt:
- require_unimplemented_servers=false

3
buf.work.yaml Normal file

@ -0,0 +1,3 @@
version: v1
directories:
- proto

4
buf.yaml Normal file

@ -0,0 +1,4 @@
version: v1
lint:
use:
- DEFAULT

39
cmd/app/main.go Normal file

@ -0,0 +1,39 @@
package main
import (
"context"
"errors"
"log"
"os/signal"
"syscall"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/app"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/initialize"
)
func main() {
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
logger, err := zap.NewProduction(zap.AddStacktrace(zap.DPanicLevel))
if err != nil {
log.Fatalf("failed to init zap logger: %v", err)
}
defer cancel()
defer func() {
if syncErr := logger.Sync(); syncErr != nil {
if !errors.Is(syncErr, syscall.EBADF) && !errors.Is(syncErr, syscall.ENOTTY) {
log.Fatalf("failed to sync zap logger: %v", syncErr)
}
}
}()
config, err := initialize.Configuration(".env.test")
if err != nil {
logger.Fatal("failed to init config: %v", zap.Error(err))
}
if err := app.Run(ctx, config, logger); err != nil {
logger.Fatal("failed to run app: %v", zap.Error(err))
}
}

40
cmd/mock/main.go Normal file

@ -0,0 +1,40 @@
package main
import (
"log"
"github.com/walkerus/go-wiremock"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models/yandex"
)
func main() {
mocklient := wiremock.NewClient("http://localhost:8000")
if err := mocklient.StubFor(wiremock.
Post(wiremock.URLPathEqualTo("/payments")).
WithBodyPattern(wiremock.EqualToJson(`{
"amount": {
"value": "150.00",
"currency": "RUB"
},
"payment_method_data": {
"type": "bank_card"
},
"confirmation": {
"type": "redirect",
"enforce": true,
"locale": "ru_RU",
"return_url": "https://www.example.com/return_url"
},
}`)).
WillReturnJSON(
&yandex.Payment{},
map[string]string{"Content-Type": "application/json"},
200,
).
AtPriority(1),
); err != nil {
log.Fatal("failed to stub <create phone payments>: %w", err)
}
}

@ -0,0 +1,3 @@
package main
func MockWebhooks() {}

@ -1,19 +0,0 @@
services:
test:
build: ./payway
depends_on:
- mongo
- mongosetup
mongo:
image: mongo:6
hostname: mongo
restart: always
entrypoint: ["/usr/bin/mongod", "--logpath", "/dev/null","--bind_ip_all","--replSet","rs0"]
mongosetup:
image: mongo:6
depends_on:
- mongo
restart: "no"
logging:
driver: "none"
entrypoint: [ "bash", "-c", "sleep 2 && mongosh --host mongo:27017 --eval 'rs.initiate()'"]

@ -1,104 +0,0 @@
package dal
// This file contains Hl structs for Data Access Layer
//#region ======== HLOGGER ERRORS ========
//#region ======== Common ========
type ErrorType struct {
Err error
}
type ErrorDalNewClient ErrorType
type ErrorDalUnableToConnect ErrorType
type ErrorDalPingFailed ErrorType
type ErrorDalDisconnectFailure ErrorType
type ErrorDalInit ErrorType
//#endregion
//#region ======== Postgre SQL ========
//#endregion
//#region ======== MongoDB ========
type ErrorInsertPayment ErrorType
type ErrorUpdatePayment ErrorType
type ErrorGetPayment ErrorType
type ErrorListenPayment ErrorType
type ErrorInsertPayWay ErrorType
type ErrorUpdatePayWay ErrorType
type ErrorGetPayWay ErrorType
type ErrorListenPayWay ErrorType
type ErrorInsertPayout ErrorType
type ErrorUpdatePayout ErrorType
type ErrorGetPayout ErrorType
type ErrorListenPayout ErrorType
type ErrorInsertPayWayPayment ErrorType
type ErrorUpdatePayWayPayment ErrorType
type ErrorDeletePayWayPayment ErrorType
type ErrorGetPayWayPayment ErrorType
//#endregion
//#endregion
//#region ======== HLOGGER INFO ========
//#region ======== MongoDB ========
type InfoInsertPayWay InfoType
type InfoUpdatePayWay InfoType
type InfoGetPayWay InfoType
type InfoListenPayWay InfoType
type InfoInsertPayment InfoType
type InfoUpdatePayment InfoType
type InfoGetPayment InfoType
type InfoListenPayment InfoType
type InfoInsertPayout InfoType
type InfoUpdatePayout InfoType
type InfoGetPayout InfoType
type InfoListenPayout InfoType
type InfoInsertPayWayPayment InfoType
type InfoUpdatePayWayPayment InfoType
type InfoDeletePayWayPayment InfoType
type InfoGetPayWayPayment InfoType
type InfoPayWay struct {
CtxPayWay string
CtxName string
CtxEvent string
}
//#endregion
//#region ======== Common ========
type InfoType struct {
Info interface{}
}
type InfoDalConnected InfoType
type InfoDalDisconnected InfoType
type InfoDalInit struct {
Result string
}
type InfoDalPing struct {
Delay int64 // Milliseconds
}
//#endregion
//#region ======== Postgre SQL ========
//#endregion
//#endregion

@ -1,139 +0,0 @@
package dal
import (
//"bitbucket.org/skeris/bbfoundation/sse"
"context"
"strings"
"time"
"github.com/themakers/hlog"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
//#region ======== Data Access Layer structs ========
// MongoConnection - Constructor LayerMongoDb
type MongoConnection struct {
conn *mongo.Client // Mongo connected pairCache
hl hlog.Logger // HLogger for Data Access Layer
opts MongoDbOptions // Database options
db *mongo.Database // Database
coll map[string]*mongo.Collection // Collections map
}
// MongoDbOptions - Connect params
type MongoDbOptions struct {
DalName string // Name of the Data Access Layer
URI string // MongoDB URI
DbTable string // MongoDB name
Collections string // MongoDB list collection names
}
//#endregion
//#region ======== Data Access Layer Constructor ========
// CreateMongo подключается к MongoDB.
//
// Input:
// ctx - Application context
// hlogger - Application logger
// opts - Application options for MongoDB
//
// Return: MongoConnection, error
//
// Logger:
// ErrorDalNewClient - mongo.NewClient return error
// ErrorDalUnableToConnect - Unable to connect to MongoDB
// InfoDalConnected - Successfully connected to MongoDB
func CreateMongo(ctx context.Context, hlogger hlog.Logger, opts MongoDbOptions) (*MongoConnection, error) {
hlogger = hlogger.With(opts)
conn, err := mongo.NewClient(options.Client().ApplyURI(opts.URI))
if err != nil {
hlogger.Emit(ErrorDalNewClient{err})
return nil, err
}
ctxTO, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
err = conn.Connect(ctxTO)
if err != nil {
hlogger.Emit(ErrorDalUnableToConnect{err})
}
collections := map[string]*mongo.Collection{}
for _, name := range strings.Split(opts.Collections, ",") {
collections[name] = conn.Database(opts.DbTable).Collection(name)
}
mongoConn := &MongoConnection{
conn: conn,
hl: hlogger,
opts: opts,
db: conn.Database(opts.DbTable),
coll: collections,
}
_, err = mongoConn.Ping(ctx)
if err == nil {
hlogger.Emit(InfoDalConnected{})
}
return mongoConn, err
}
//#endregion
//#region ======== Data Access Layer functions ========
// DisconnectFromDb разрывает соединение с MongoDB
//
// Return: error
//
// Logger:
// ErrorDalDisconnectFailure - Something is wrong
// InfoDalDisconnected - Successfully disconnected from MongoDB
func (mc *MongoConnection) DisconnectFromDb() error {
err := mc.conn.Disconnect(context.TODO())
if err != nil {
mc.hl.Emit(ErrorDalDisconnectFailure{err})
}
mc.hl.Emit(InfoDalDisconnected{})
return err
}
// Ping пингует соединение MongoDB.
//
// Return:
// int64 - ping delay in milliseconds
// error
//
// Logger:
// ErrorDalPingFailed - Ping received an error
// InfoDalPing - Ping delay in milliseconds
func (mc *MongoConnection) Ping(ctx context.Context) (int64, error) {
start := time.Now()
err := mc.conn.Ping(ctx, readpref.Primary())
delay := time.Since(start).Milliseconds()
if err != nil {
mc.hl.Emit(ErrorDalPingFailed{err})
} else {
mc.hl.Emit(InfoDalPing{delay})
}
return delay, err
}
//#endregion

@ -1,363 +0,0 @@
package dal
import (
"bytes"
"context"
"errors"
"fmt"
"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"
"net/http"
"time"
)
const PaymentTimeout = 15 * time.Minute
type Payment struct {
ID string `json:"id" bson:"_id"`
RequesterID string `json:"requester_id" bson:"requester_id"`
UserIP string `json:"user_ip" bson:"user_ip"`
Email string `json:"email" bson:"email"`
Phone string `json:"phone" bson:"phone"`
Description string `json:"description" bson:"description"`
IsRefill bool `json:"is_refill" bson:"is_refill"` // Флаг описывает ввод/вывод средств
Status string `json:"status" bson:"status"` // Значения: open, wait, pending, in_progress, timeout,
// accepted, declined
PayWayID string `json:"payway_id" bson:"payway_id"` //
PaymentType string `json:"payment_type" bson:"payment_type"` //
ServiceID string `json:"service_id" bson:"service_id"` // ID платежа в платежном сервисе
Destination string `json:"destination" bson:"destination"` // Назначение платежа. Only for payout/withdrawal
Amount float64 `json:"amount" bson:"amount"`
Currency string `json:"currency" bson:"currency"`
IsFake bool `json:"is_fake" bson:"is_fake"`
OnAccept Action `json:"on_accept" bson:"on_accept"`
OnDecline Action `json:"on_decline" bson:"on_decline"`
OnTimeout Action `json:"on_timeout" bson:"on_timeout"`
PendedAt time.Time `json:"pended_at" bson:"pended_at"`
CreatedAt time.Time `json:"created_at" bson:"created_at"`
UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
}
type Action struct {
ActionType string `json:"action_type" bson:"action_type"` // Значения: mail, vk, tg, sms, request
Target string `json:"target" bson:"target"`
Data string `json:"data" bson:"data"`
}
func (mc *MongoConnection) InsertPayment(ctx context.Context, record *Payment) (string, error) {
err := record.Prepare()
if err != nil {
mc.hl.Emit(ErrorInsertPayment{err})
return "", nil
}
result, err := mc.coll["payment"].InsertOne(ctx, record)
if err != nil {
mc.hl.Emit(ErrorInsertPayment{err})
return "", err
}
mc.hl.Emit(InfoInsertPayment{result})
return result.InsertedID.(string), nil
}
func (mc *MongoConnection) GetPayment(ctx context.Context, id string) (*Payment, error) {
filter := bson.M{"_id": id}
var result Payment
err := mc.coll["payment"].FindOne(ctx, filter).Decode(&result)
if err == mongo.ErrNoDocuments {
return nil, nil
} else {
if err != nil {
mc.hl.Emit(ErrorGetPayment{err})
return nil, err
}
}
mc.hl.Emit(InfoGetPayment{id})
return &result, err
}
func (mc *MongoConnection) GetPaymentByServiceID(ctx context.Context, serviceId, isRefill string) (*Payment,
error) {
filter := bson.M{"api_id": serviceId}
switch isRefill {
case "yes", "true":
filter["is_refill"] = true
case "no", "false":
filter["is_refill"] = false
}
var result Payment
err := mc.coll["payment"].FindOne(ctx, filter).Decode(&result)
if err == mongo.ErrNoDocuments {
return nil, nil
} else {
if err != nil {
mc.hl.Emit(ErrorGetPayment{err})
}
}
mc.hl.Emit(InfoGetPayment{fmt.Sprintf("by service_id %v", serviceId)})
return &result, err
}
func (mc *MongoConnection) GetPaymentListByStatus(ctx context.Context, status, isRefill string) ([]Payment,
error) {
err := CheckPaymentStatus(status)
if err != nil {
mc.hl.Emit(ErrorGetPayment{err})
return nil, nil
}
filter := bson.M{"status": status}
switch isRefill {
case "yes", "true":
filter["is_refill"] = true
case "no", "false":
filter["is_refill"] = false
}
cursor, err := mc.coll["payment"].Find(ctx, filter)
if err != nil {
mc.hl.Emit(ErrorGetPayment{err})
return nil, nil
}
var results []Payment
err = cursor.All(ctx, &results)
if err != nil {
mc.hl.Emit(ErrorGetPayment{err})
return nil, nil
}
mc.hl.Emit(InfoGetPayment{fmt.Sprintf("by status %v", status)})
return results, nil
}
func (mc *MongoConnection) UpdatePaymentStatus(ctx context.Context, id, status string) error {
err := CheckPaymentStatus(status)
if err != nil {
mc.hl.Emit(ErrorUpdatePayment{err})
return err
}
update := bson.M{
"updated_at": time.Now(),
"status": status,
}
result, err := mc.coll["payment"].UpdateByID(ctx, id, bson.D{{"$set", update}})
if err != nil {
mc.hl.Emit(ErrorUpdatePayment{err})
return err
}
mc.hl.Emit(InfoUpdatePayment{result})
return nil
}
func (mc *MongoConnection) UpdatePaymentServiceID(ctx context.Context, id, serviceId string) error {
update := bson.M{
"updated_at": time.Now(),
"service_id": serviceId,
}
result, err := mc.coll["payment"].UpdateByID(ctx, id, bson.D{{"$set", update}})
if err != nil {
mc.hl.Emit(ErrorUpdatePayment{err})
return err
}
mc.hl.Emit(InfoUpdatePayment{result})
return nil
}
func (mc *MongoConnection) ListenPayment(ctx context.Context) {
operationTypes := []bson.D{{{"operationType", "update"}}}
matchStage := bson.D{
{"$match", bson.D{{"$or", operationTypes}}},
}
opts := options.ChangeStream().SetFullDocument(options.UpdateLookup)
changeStream, err := mc.coll["payment"].Watch(ctx,
mongo.Pipeline{matchStage}, opts)
if err != nil {
mc.hl.Emit(ErrorListenPayment{err})
return
}
// routine: SetTimeout - каждые 3 минуты проверяет БД на наличие записей с истекшим PaymentTimeout
go func() {
for {
paymentList, err := mc.GetPaymentListByStatus(ctx, "open", "")
if err != nil {
mc.hl.Emit(ErrorListenPayment{err})
} else {
for _, payment := range paymentList {
if time.Since(payment.CreatedAt) >= PaymentTimeout {
err = mc.UpdatePaymentStatus(ctx, payment.ID, "timeout")
}
if err != nil {
mc.hl.Emit(ErrorListenPayment{err})
}
}
}
// Прерывание
select {
case <-ctx.Done():
return
case <-time.After(3 * time.Minute): // Сладкий сон
continue
}
}
}()
// routine: UpdateListener
go func() {
// Перехват паники (см. ниже)
defer func() {
if err := recover(); err != nil {
mc.hl.Emit(ErrorListenPayment{err.(error)})
}
}()
for changeStream.Next(ctx) {
// При закрытии приложения происходит паника (change_stream.go 561). context не важен...'
current := changeStream.Current
if err != nil {
mc.hl.Emit(ErrorListenPayment{err})
return
}
var payment Payment
err = bson.Unmarshal(current.Lookup("fullDocument").Value, &payment)
if err != nil {
mc.hl.Emit(ErrorListenPayment{err})
return
}
var action Action
switch payment.Status {
case "accepted":
action = payment.OnAccept
case "timeout":
action = payment.OnTimeout
case "declined":
action = payment.OnDecline
}
// Some work with action
if payment.Status == "accepted" && payment.IsRefill {
switch action.ActionType {
case "request":
fmt.Println("CYCLE", payment )
buf := bytes.Buffer{}
buf.Write([]byte(action.Data))
if _, err := http.Post("https://fynrods.ru/bet/increase", "application/json", &buf); err != nil {
fmt.Println("ERRINC", err )
}
}
}
mc.hl.Emit(InfoListenPayment{fmt.Sprintf("%v %v done", payment.ID, payment.Status)})
}
if err = changeStream.Err(); err != nil {
mc.hl.Emit(ErrorListenPayment{err})
}
}()
select {
case <-ctx.Done():
err = changeStream.Close(context.TODO())
if err != nil {
mc.hl.Emit(ErrorListenPayment{err})
}
return
}
}
func (p *Payment) Prepare() error {
err := CheckPaymentStatus(p.Status)
if err != nil {
return err
}
err = CheckActionType(p.OnAccept.ActionType)
if err != nil {
return err
}
err = CheckActionType(p.OnDecline.ActionType)
if err != nil {
return err
}
err = CheckActionType(p.OnTimeout.ActionType)
if err != nil {
return err
}
now := time.Now()
if p.ID == "" {
p.ID = primitive.NewObjectIDFromTimestamp(now).Hex()
}
p.CreatedAt = now
p.UpdatedAt = now
return nil
}
func CheckPaymentStatus(status string) error {
allowedStatus := map[string]struct{}{"open": {}, "wait": {}, "pending": {}, "timeout": {}, "accepted": {},
"declined": {}, "in_progress": {}}
if _, ok := allowedStatus[status]; !ok {
return errors.New("got bad status: " + status)
}
return nil
}
func CheckActionType(aType string) error {
allowedType := map[string]struct{}{"mail": {}, "vk": {}, "tg": {}, "sms": {}, "request": {}}
if _, ok := allowedType[aType]; !ok {
return errors.New("got bad type: " + aType)
}
return nil
}

@ -1,359 +0,0 @@
package dal
import (
"context"
"crypto/aes"
"encoding/hex"
"fmt"
"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"
"strings"
"time"
)
const BlockSize = 16
const PrivateKey = "SomePrivateKey1!" //16 byte
type PayWay struct {
ID string `bson:"_id"`
Name string `bson:"name"`
ShortName string `bson:"short_name"`
MerchantID string `bson:"merchant_id"`
WalletID string `bson:"wallet_id"`
Secret1 string `bson:"secret_1"`
Secret2 string `bson:"secret_2"`
Secret3 string `bson:"secret_3"`
PayoutTypeList []PayoutType `bson:"payout_type_list"` // TODO: перенести так же как и payment
CreatedAt time.Time `bson:"created_at"`
UpdatedAt time.Time `bson:"updated_at"`
}
type PayoutType struct {
Name string `bson:"name"`
IsEnabled bool `bson:"is_enabled"`
Currency string `bson:"currency"` // Валюта вывода: RUB, EUR, USD и т.д.
ApiId string `bson:"api_id"`
Commission float64 `bson:"commission"`
Minimum float64 `bson:"minimum"`
Maximum float64 `bson:"maximum"`
}
func (mc *MongoConnection) InsertPayWay(ctx context.Context, record PayWay) (string, error) {
now := time.Now()
if record.ID == "" {
record.ID = primitive.NewObjectIDFromTimestamp(now).Hex()
}
record.CreatedAt = now
record.UpdatedAt = now
if record.Secret1 != "" {
s, err := EncryptAES(PrivateKey, record.Secret1)
if err != nil {
mc.hl.Emit(ErrorInsertPayWay{err})
return "", err
}
record.Secret1 = s
}
if record.Secret2 != "" {
s, err := EncryptAES(PrivateKey, record.Secret2)
if err != nil {
mc.hl.Emit(ErrorInsertPayWay{err})
return "", err
}
record.Secret2 = s
}
if record.Secret3 != "" {
s, err := EncryptAES(PrivateKey, record.Secret3)
if err != nil {
mc.hl.Emit(ErrorInsertPayWay{err})
return "", err
}
record.Secret3 = s
}
result, err := mc.coll["payway"].InsertOne(ctx, record)
if err != nil {
mc.hl.Emit(ErrorInsertPayWay{err})
return "", err
}
mc.hl.Emit(InfoInsertPayWay{result})
return result.InsertedID.(string), nil
}
func (mc *MongoConnection) UpdatePayWay(ctx context.Context, record PayWay) error {
update := bson.M{"updated_at": time.Now()}
if record.Name != "" {
update["name"] = record.Name
}
if record.ShortName != "" {
update["short_name"] = record.ShortName
}
if record.MerchantID != "" {
update["merchant_id"] = record.MerchantID
}
if record.WalletID != "" {
update["wallet_id"] = record.WalletID
}
if record.PayoutTypeList != nil || len(record.PayoutTypeList) != 0 {
update["payout_type_list"] = record.PayoutTypeList
}
if record.Secret1 != "" {
s, err := EncryptAES(PrivateKey, record.Secret1)
if err != nil {
mc.hl.Emit(ErrorUpdatePayWay{err})
return err
}
update["secret_1"] = s
}
if record.Secret2 != "" {
s, err := EncryptAES(PrivateKey, record.Secret2)
if err != nil {
mc.hl.Emit(ErrorUpdatePayWay{err})
return err
}
update["secret_2"] = s
}
if record.Secret3 != "" {
s, err := EncryptAES(PrivateKey, record.Secret3)
if err != nil {
mc.hl.Emit(ErrorUpdatePayWay{err})
return err
}
update["secret_3"] = s
}
result, err := mc.coll["payway"].UpdateByID(ctx, record.ID, bson.D{{"$set", update}})
if err != nil {
mc.hl.Emit(ErrorUpdatePayWay{err})
return err
}
mc.hl.Emit(InfoUpdatePayWay{result})
return nil
}
func (mc *MongoConnection) GetPayWay(ctx context.Context, id string) (*PayWay, error) {
filter := bson.M{"_id": id}
var result PayWay
err := mc.coll["payway"].FindOne(ctx, filter).Decode(&result)
if err == mongo.ErrNoDocuments {
return nil, nil
} else {
if err != nil {
mc.hl.Emit(ErrorGetPayWay{err})
return nil, err
}
}
if result.Secret1 != "" {
s, err := DecryptAES(PrivateKey, result.Secret1)
if err != nil {
mc.hl.Emit(ErrorGetPayWay{err})
return nil, err
}
result.Secret1 = s
}
if result.Secret2 != "" {
s, err := DecryptAES(PrivateKey, result.Secret2)
if err != nil {
mc.hl.Emit(ErrorGetPayWay{err})
return nil, err
}
result.Secret2 = s
}
if result.Secret3 != "" {
s, err := DecryptAES(PrivateKey, result.Secret3)
if err != nil {
mc.hl.Emit(ErrorGetPayWay{err})
return nil, err
}
result.Secret3 = s
}
return &result, err
}
func (mc *MongoConnection) GetPayWayByName(ctx context.Context, name string) (*PayWay, error) {
filter := bson.M{"name": name}
var result PayWay
err := mc.coll["payway"].FindOne(ctx, filter).Decode(&result)
if err == mongo.ErrNoDocuments {
return nil, err
} else {
if err != nil {
mc.hl.Emit(ErrorGetPayWay{err})
return nil, err
}
}
if result.Secret1 != "" {
s, err := DecryptAES(PrivateKey, result.Secret1)
if err != nil {
mc.hl.Emit(ErrorGetPayWay{err})
return nil, err
}
result.Secret1 = s
}
if result.Secret2 != "" {
s, err := DecryptAES(PrivateKey, result.Secret2)
if err != nil {
mc.hl.Emit(ErrorGetPayWay{err})
return nil, err
}
result.Secret2 = s
}
if result.Secret3 != "" {
s, err := DecryptAES(PrivateKey, result.Secret3)
if err != nil {
mc.hl.Emit(ErrorGetPayWay{err})
return nil, err
}
result.Secret3 = s
}
return &result, err
}
//func (mc *MongoConnection) GetPayWayListByPayoutType(ctx context.Context, name string) ([]PayWay, error) {
//
//}
func (mc *MongoConnection) ListenPayWay(ctx context.Context, updateAction func(data *PayWay) error) {
operationTypes := []bson.D{{{"operationType", "update"}}}
matchStage := bson.D{
{"$match", bson.D{{"$or", operationTypes}}},
}
opts := options.ChangeStream().SetFullDocument(options.UpdateLookup)
changeStream, err := mc.coll["payway"].Watch(ctx,
mongo.Pipeline{matchStage}, opts)
if err != nil {
mc.hl.Emit(ErrorListenPayWay{err})
return
}
go func() {
// Перехват паники (см. ниже)
defer func() {
if err := recover(); err != nil {
mc.hl.Emit(ErrorListenPayWay{err.(error)})
}
}()
for changeStream.Next(ctx) {
// При закрытии приложения происходит паника (change_stream.go 561). context не важен...'
current := changeStream.Current
if err != nil {
mc.hl.Emit(ErrorListenPayWay{err})
return
}
var payWay PayWay
err = bson.Unmarshal(current.Lookup("fullDocument").Value, &payWay)
if err != nil {
mc.hl.Emit(ErrorListenPayWay{err})
return
}
err = updateAction(&payWay)
if err != nil {
mc.hl.Emit(ErrorListenPayWay{err})
continue
}
mc.hl.Emit(InfoListenPayWay{fmt.Sprintf("%v (%v) updated", payWay.ID, payWay.ShortName)})
}
if err = changeStream.Err(); err != nil {
mc.hl.Emit(ErrorListenPayWay{err})
}
}()
select {
case <-ctx.Done():
err = changeStream.Close(context.TODO())
if err != nil {
mc.hl.Emit(ErrorListenPayWay{err})
}
return
}
}
func EncryptAES(key, data string) (string, error) {
c, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
// @TODO: Выглядит как костыль, но что поделать?
// Для большей безопасности можно генерировать случайную строку с указателем конца информации. example = "...`randS"
if len(data) < BlockSize {
x := BlockSize - len(data)
data += strings.Repeat("`", x)
}
out := make([]byte, len(data))
c.Encrypt(out, []byte(data))
return hex.EncodeToString(out), nil
}
func DecryptAES(key, data string) (string, error) {
ct, _ := hex.DecodeString(data)
c, err := aes.NewCipher([]byte(key))
if err != nil {
return "", err
}
pt := make([]byte, len(ct))
c.Decrypt(pt, ct)
// @TODO: Выглядит как костыль, но что поделать?
result := strings.ReplaceAll(string(pt[:]), "`", "")
return result, nil
}

@ -1,180 +0,0 @@
package dal
import (
"context"
"errors"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"time"
)
// @TODO: Rename to PayWayRefill
type PayWayPayment struct {
ID string `bson:"_id"` // PayWay-ApiId
ApiId string `bson:"api_id"`
Name string `bson:"name"`
PayWay string `bson:"payWay"`
Currency string `bson:"currency"`
Commission float64 `bson:"commission"`
Minimum float64 `bson:"minimum"`
Maximum float64 `bson:"maximum"`
Status string `bson:"status"` // active, inactive
CreatedAt time.Time `bson:"created_at"`
UpdatedAt time.Time `bson:"updated_at"`
}
func (mc *MongoConnection) InsertPayWayPayment(ctx context.Context, record PayWayPayment) (string, error) {
now := time.Now()
if record.ApiId == "" {
err := errors.New("got empty apiId")
mc.hl.Emit(ErrorInsertPayWayPayment{err})
return "", err
}
if record.PayWay == "" {
err := errors.New("got empty payWay")
mc.hl.Emit(ErrorInsertPayWayPayment{err})
return "", err
}
record.ID = fmt.Sprintf("%v-%v", record.PayWay, record.ApiId)
record.CreatedAt = now
record.UpdatedAt = now
result, err := mc.coll["paywayPayment"].InsertOne(ctx, record)
if err != nil {
mc.hl.Emit(ErrorInsertPayWayPayment{err})
return "", err
}
mc.hl.Emit(InfoInsertPayWayPayment{result})
mc.hl.Emit(InfoPayWay{
CtxPayWay: record.PayWay,
CtxName: record.Name,
CtxEvent: "add",
})
return result.InsertedID.(string), nil
}
func (mc *MongoConnection) UpdatePayWayPayment(ctx context.Context, record PayWayPayment) error {
//update := bson.M{"updated_at": time.Now()}
//if record.ID == "" {
// err := errors.New("got empty id")
// mc.hl.Emit(ErrorUpdatePayWayPayment{err})
// return err
//}
//
//if record.Name != "" {
// update["name"] = record.Name
//}
//
//if record.PayWay != "" {
// update["payway"] = record.Name
//}
//
//if record.Status != "" {
// update["status"] = record.Name
//}
record.UpdatedAt = time.Now()
opts := options.FindOneAndUpdate().SetUpsert(true)
err := mc.coll["paywayPayment"].FindOneAndUpdate(ctx, bson.M{
"_id": record.ID,
}, bson.D{{"$set", record}}, opts).Decode(&PayWayPayment{})
if err != nil {
mc.hl.Emit(ErrorUpdatePayWayPayment{err})
return err
}
//mc.hl.Emit(InfoInsertPayWayPayment{result})
if record.Status != "" {
//update["status"] = record.Name
pw, _ := mc.GetPayWayPayment(ctx, record.ID)
if pw.Status != record.Status {
event := "stop"
if record.Status == "active" {
event = "start"
}
mc.hl.Emit(InfoPayWay{
CtxPayWay: pw.PayWay,
CtxName: pw.Name,
CtxEvent: event,
})
}
}
return nil
}
func (mc *MongoConnection) GetPayWayPayment(ctx context.Context, id string) (*PayWayPayment, error) {
filter := bson.M{"_id": id}
var result PayWayPayment
err := mc.coll["paywayPayment"].FindOne(ctx, filter).Decode(&result)
if err == mongo.ErrNoDocuments {
return nil, nil
} else {
if err != nil {
mc.hl.Emit(ErrorGetPayWayPayment{err})
return nil, err
}
}
mc.hl.Emit(InfoGetPayWayPayment{result.ID})
return &result, err
}
func (mc *MongoConnection) GetPayWayPaymentByPayWay(ctx context.Context, payWay string) ([]PayWayPayment, error) {
filter := bson.M{"payWay": payWay}
var results []PayWayPayment
cursor, err := mc.coll["paywayPayment"].Find(ctx, filter)
if err != nil {
mc.hl.Emit(ErrorGetPayWayPayment{err})
return results, nil
}
err = cursor.All(ctx, &results)
if err != nil {
mc.hl.Emit(ErrorGetPayWayPayment{err})
return nil, nil
}
mc.hl.Emit(InfoGetPayWayPayment{fmt.Sprintf("by status %v", payWay)})
return results, nil
}
func (mc *MongoConnection) DeletePayWayPayment(ctx context.Context, id string) error {
filter := bson.M{"_id": id}
result, err := mc.coll["paywayPayment"].DeleteOne(ctx, filter)
if err != nil {
mc.hl.Emit(ErrorDeletePayWayPayment{err})
return err
}
mc.hl.Emit(InfoDeletePayWayPayment{result})
return nil
}

@ -0,0 +1,70 @@
version: "3.3"
services:
treasurer-app:
build:
context: ../../.
dockerfile: Dockerfile
target: test
environment:
- HTTP_HOST=0.0.0.0
- HTTP_PORT=8080
- HTTP_DOMEN=http://localhost:8080
- GRPC_HOST=0.0.0.0
- GRPC_PORT=8081
- YOOMONEY_STORE_ID = id
- YOOMONEY_SECRET_KEY = secret
- MONGO_HOST=mongo
- MONGO_PORT=27017
- MONGO_USER=admin
- MONGO_PASSWORD=admin
- MONGO_DB_NAME=admin
- MONGO_AUTH=admin
ports:
- 8080:8080
- 8081:8081
depends_on:
- migration
networks:
- dev
migration:
build:
context: ../../.
dockerfile: Dockerfile
target: migration
command:
[
"sh",
"-c",
'migrate -source file://migrations -database "mongodb://admin:admin@localhost:27017/admin?authSource=admin" up',
]
depends_on:
- mongo
networks:
- dev
mongo:
image: 'mongo:6.0.3'
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: admin
ports:
- '27017:27017'
networks:
- dev
mock:
image: 'wiremock/wiremock:2.35.0'
ports:
- 8000:8080
networks:
- dev
depends_on:
- app
networks:
dev:

@ -0,0 +1,54 @@
version: "3.3"
services:
treasurer-app:
build:
context: ../../.
dockerfile: Dockerfile
target: test
environment:
- HTTP_HOST=0.0.0.0
- HTTP_PORT=8080
- HTTP_DOMEN=http://localhost:8080
- GRPC_HOST=0.0.0.0
- GRPC_PORT=8081
- YOOMONEY_STORE_ID=storeid
- YOOMONEY_SECRET_KEY=secret
- MONGO_HOST=mongo
- MONGO_PORT=27017
- MONGO_USER=admin
- MONGO_PASSWORD=admin
- MONGO_DB_NAME=admin
- MONGO_AUTH=admin
ports:
- 8080:8080
- 8081:8081
networks:
- dev
depends_on:
- mongo
mongo:
image: 'mongo:6.0.3'
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: admin
ports:
- '27017:27017'
networks:
- dev
mock:
image: 'wiremock/wiremock:2.35.0'
ports:
- 8000:8080
networks:
- dev
depends_on:
- treasurer-app
networks:
dev:

85
go.mod

@ -1,55 +1,56 @@
module bitbucket.org/skeris/treasurer module penahub.gitlab.yandexcloud.net/external/treasurer
go 1.18 go 1.20
require ( require (
bitbucket.org/skeris/bbfoundation v0.0.0-20210610132656-b53719699505 github.com/getkin/kin-openapi v0.118.0
github.com/danilsolovyov/validator v0.0.9 github.com/go-resty/resty/v2 v2.7.0
github.com/fatih/structs v1.1.0 github.com/google/uuid v1.3.0
github.com/gofiber/fiber/v2 v2.38.1 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/gorilla/mux v1.8.0 github.com/joho/godotenv v1.5.1
github.com/gorilla/schema v1.2.0 github.com/labstack/echo/v4 v4.10.2
github.com/rs/xid v1.3.0 github.com/sethvargo/go-envconfig v0.9.0
github.com/skeris/appInit v0.1.12 github.com/stretchr/testify v1.8.4
github.com/stretchr/testify v1.8.1 github.com/walkerus/go-wiremock v1.5.0
github.com/themakers/bdd v0.0.0-20210316111417-6b1dfe326f33 go.mongodb.org/mongo-driver v1.11.7
github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf go.uber.org/zap v1.24.0
go.mongodb.org/mongo-driver v1.10.1 google.golang.org/grpc v1.55.0
go.uber.org/zap v1.23.0 google.golang.org/protobuf v1.30.0
gopkg.in/tucnak/telebot.v2 v2.5.0
) )
require ( require (
github.com/MarsherSusanin/pena_hub_packages_common v0.0.0-20220912173602-40f15e2b8a39 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/aws/aws-sdk-go v1.34.28 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/fatih/color v1.10.0 // indirect github.com/go-openapi/swag v0.22.4 // indirect
github.com/go-stack/stack v1.8.0 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/gofiber/fiber v1.14.6 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/gofiber/utils v0.0.10 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/golang/snappy v0.0.1 // indirect github.com/invopop/yaml v0.2.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.15.0 // indirect github.com/klauspost/compress v1.16.5 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect github.com/labstack/gommon v0.4.0 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/montanaflynn/stats v0.7.1 // indirect
github.com/perimeterx/marshmallow v1.1.4 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/themakers/identity v0.0.0-20200703212242-9142bb6b35e1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.40.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.1 // indirect github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.3 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
go.uber.org/atomic v1.7.0 // indirect go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect golang.org/x/crypto v0.9.0 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect golang.org/x/sync v0.2.0 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/sys v0.9.0 // indirect
golang.org/x/text v0.10.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

407
go.sum

@ -1,146 +1,110 @@
bitbucket.org/skeris/bbfoundation v0.0.0-20210610132656-b53719699505 h1:fVCLuKNCoXjNjzfz9/evcNcx2EA+WxoTjf27Ek1ANd8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
bitbucket.org/skeris/bbfoundation v0.0.0-20210610132656-b53719699505/go.mod h1:QVOC6t15n9LpOSIgL2UjKzFdpnOsOptuZJfbrg2v0xk=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/MarsherSusanin/pena_hub_packages_common v0.0.0-20220912173602-40f15e2b8a39 h1:8IlSS2NqXq0/fvviP0tr88LJP8+qOIChikFoSeKLhEo= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/MarsherSusanin/pena_hub_packages_common v0.0.0-20220912173602-40f15e2b8a39/go.mod h1:ojl1vRFZav2wB+L603ewTi6nSJRAVSd+w4d/AednibU= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
github.com/danilsolovyov/validator v0.0.9 h1:XlbB/lxrfLw2Gk4QTMrrEW8wM0NzWHQmEvSHEZqScGM=
github.com/danilsolovyov/validator v0.0.9/go.mod h1:2jwh4O+5hyKFNRQQTo395fW+l2gyRKPtv+V+uMzAbGM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/getkin/kin-openapi v0.118.0 h1:z43njxPmJ7TaPpMSCQb7PN0dEYno4tyBPQcrFdHoLuM=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/getkin/kin-openapi v0.118.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
github.com/gofiber/fiber v1.14.6 h1:QRUPvPmr8ijQuGo1MgupHBn8E+wW0IKqiOvIZPtV70o=
github.com/gofiber/fiber v1.14.6/go.mod h1:Yw2ekF1YDPreO9V6TMYjynu94xRxZBdaa8X5HhHsjCM=
github.com/gofiber/fiber/v2 v2.38.1 h1:GEQ/Yt3Wsf2a30iTqtLXlBYJZso0JXPovt/tmj5H9jU=
github.com/gofiber/fiber/v2 v2.38.1/go.mod h1:t0NlbaXzuGH7I+7M4paE848fNWInZ7mfxI/Er1fTth8=
github.com/gofiber/utils v0.0.10 h1:3Mr7X7JdCUo7CWf/i5sajSaDmArEDtti8bM1JUVso2U=
github.com/gofiber/utils v0.0.10/go.mod h1:9J5aHFUIjq0XfknT4+hdSMG6/jzfaAgCu4HEbWDeBlo=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U= github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/onsi/ginkgo v1.16.2 h1:HFB2fbVIlhIfCfOW81bZFbiC/RvnpXSdhbF2/DJr134=
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.12.0 h1:p4oGGk2M2UJc0wWN4lHFvIB71lxsh0T/UiKCCgFADY8=
github.com/onsi/gomega v1.12.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/sethvargo/go-envconfig v0.9.0 h1:Q6FQ6hVEeTECULvkJZakq3dZMeBQ3JUpcKMfPQbKMDE=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/sethvargo/go-envconfig v0.9.0/go.mod h1:Iz1Gy1Sf3T64TQlJSvee81qDhf7YIlt8GMUX6yyNFs0=
github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/skeris/appInit v0.1.12 h1:osGnk4d0vzUVsEV66JOmXcqiHbC2+N9IiOBjOiSCzm0=
github.com/skeris/appInit v0.1.12/go.mod h1:4ElEeXWVGzU3dlYq/eMWJ/U5hd+LKisc1z3+ySh1XmY=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@ -148,172 +112,165 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/themakers/bdd v0.0.0-20210316111417-6b1dfe326f33 h1:N9f/Q+2Ssa+yDcbfaoLTYvXmdeyUUxsJKdPUVsjSmiA= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/themakers/bdd v0.0.0-20210316111417-6b1dfe326f33/go.mod h1:rpcH99JknBh8seZmlOlUg51gasZH6QH34oXNsIwYT6E= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf h1:TJJm6KcBssmbWzplF5lzixXl1RBAi/ViPs1GaSOkhwo=
github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf/go.mod h1:1FsorU3vnXO9xS9SrhUp8fRb/6H/Zfll0rPt1i4GWaA=
github.com/themakers/identity v0.0.0-20200703212242-9142bb6b35e1 h1:DuzLgIqC0AxW3Gy+Mhwn15R9KvFe8nifO6Pbe3j07Ng=
github.com/themakers/identity v0.0.0-20200703212242-9142bb6b35e1/go.mod h1:lHYuLs7VL+KVZpEzfXnrv8YwlGXcuZgUZjV5pSRb+Fc=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/walkerus/go-wiremock v1.5.0 h1:ipaYzaZnnOJRQS4wNFqz4YFphC/sM9GM+EiLEzv3KLc=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/walkerus/go-wiremock v1.5.0/go.mod h1:gMzQpReT5mG5T/PaW8pSFiPhazrcHb1mnf6JHdKwY5w=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.mongodb.org/mongo-driver v1.5.2 h1:AsxOLoJTgP6YNM0fXWw4OjdluYmWzQYp+lFJL7xu9fU= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mongodb.org/mongo-driver v1.5.2/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw= go.mongodb.org/mongo-driver v1.11.7 h1:LIwYxASDLGUg/8wOhgOOZhX8tQa/9tgZPgzZoVqJvcs=
go.mongodb.org/mongo-driver v1.10.1 h1:NujsPveKwHaWuKUer/ceo9DzEe7HIj1SlJ6uvXZG0S4= go.mongodb.org/mongo-driver v1.11.7/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY=
go.mongodb.org/mongo-driver v1.10.1/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/tucnak/telebot.v2 v2.5.0 h1:i+NynLo443Vp+Zn3Gv9JBjh3Z/PaiKAQwcnhNI7y6Po=
gopkg.in/tucnak/telebot.v2 v2.5.0/go.mod h1:BgaIIx50PSRS9pG59JH+geT82cfvoJU/IaI5TJdN3v8=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

@ -1,164 +0,0 @@
package handlers
import (
"bitbucket.org/skeris/bbfoundation/jwt_adapter"
"bitbucket.org/skeris/treasurer/dal"
"encoding/json"
"errors"
"fmt"
"github.com/danilsolovyov/validator"
"github.com/gorilla/schema"
"github.com/themakers/hlog"
"net/http"
)
//#region ======== Handler Struct ========
type Handler struct {
w http.ResponseWriter
r *http.Request
origins string
mongo *dal.MongoConnection
hl hlog.Logger
validator validator.Validator
}
type CommonOpts struct {
AllowedOrigins string
Mongo *dal.MongoConnection
Hl hlog.Logger
}
func NewHandler(
w http.ResponseWriter,
r *http.Request,
common CommonOpts,
validator validator.Validator) *Handler {
return &Handler{
w: w, r: r,
origins: common.AllowedOrigins,
mongo: common.Mongo,
hl: common.Hl,
validator: validator,
}
}
func (h *Handler) Prepare(w http.ResponseWriter, r *http.Request, validator validator.Validator) {
h.w = w
h.r = r
h.validator = validator
}
func (h *Handler) getJwtUserId() (string, error) {
if jwtAdapter, ok := h.r.Context().Value("JWT").(*jwt_adapter.JwtAdapter); ok {
return jwtAdapter.GetUserID(), nil
}
return "", errors.New("no token in context")
}
// report Error - Send false Response with string error
func (h *Handler) reportError(status int, errClient string, errLog error) {
h.w.Header().Set("Access-Control-Allow-Origin", h.origins)
h.w.Header().Set("Content-Type", "application/json; charset=utf-8")
h.w.WriteHeader(status)
errEncode := json.NewEncoder(h.w).Encode(Response{false, errClient})
if errEncode != nil {
h.hl.Emit(ErrorReportCanNotSend{errEncode})
}
h.hl.Emit(ErrorHandler{h.r.URL.String(), errLog})
}
// send Response struct with http status 200
func (h *Handler) sendResponse(response Response) {
h.w.Header().Set("Access-Control-Allow-Origin", h.origins)
h.w.Header().Set("Content-Type", "application/json; charset=utf-8")
h.w.WriteHeader(http.StatusOK)
err := json.NewEncoder(h.w).Encode(response)
if err != nil {
h.reportError(http.StatusInternalServerError, "response failed", err)
}
}
// send response as sse
func (h *Handler) sendSseData(data interface{}, flusher http.Flusher) {
response, err := json.Marshal(data)
if err != nil {
h.reportError(http.StatusInternalServerError, "failed", err)
return
}
_, err = fmt.Fprintf(h.w, "data: %s\n\n", response)
flusher.Flush()
if err != nil {
h.reportError(http.StatusInternalServerError, "failed", err)
}
}
func (h *Handler) handlePostRequest(request interface{}) error {
decoder := validator.Decoder{Decoder: json.NewDecoder(h.r.Body)}
err := decoder.DecodeAndValidate(request, h.validator)
if err != nil {
h.reportError(http.StatusBadRequest, err.Error(), err)
return err
}
return nil
}
func (h *Handler) handleGetRequest(request interface{}) error {
//query := query
err := h.r.ParseForm()
if err != nil {
h.reportError(http.StatusBadRequest, err.Error(), err)
return err
}
fmt.Println("DATAAAA",h.r.Form)
err = schema.NewDecoder().Decode(request, h.r.Form)
if err != nil {
h.reportError(http.StatusBadRequest, err.Error(), err)
return err
}
return nil
}
//#endregion
// MB Size constants
const (
MB = 1 << 20
)
//#region ======== Response Structs ========
type Response struct {
Success bool `json:"success"` // True if OK
Message interface{} `json:"message"` // Message Response body
}
//#endregion
//#region ======== Hl Handlers Errors ========
type ErrorReportCanNotSend struct {
Err error
}
type ErrorHandler struct {
URL string
Err error
}
//#endregion
//#region ======== Other functions ========
//#endregion

@ -1,196 +0,0 @@
package handlers
import (
"errors"
"fmt"
"net/http"
"strconv"
"bitbucket.org/skeris/treasurer/dal"
"bitbucket.org/skeris/treasurer/payway"
"github.com/gorilla/mux"
tb "gopkg.in/tucnak/telebot.v2"
)
type RequestCreatePayment struct {
RequesterID string `json:"requester_id" validate:"required"`
Amount float64 `json:"amount" validate:">0"`
PaymentType string `json:"payment_type" validate:"required"` // Тип пополнения dal.PayWayPayment.ApiId
Currency string `json:"currency"`
PayWayID string `json:"payway_id" validate:"required"` // Присылать именно ID, а не shortName! id: fk1, sn: fk
Email string `json:"email"`
Phone string `json:"phone"`
OnAccept Action `json:"on_accept"`
OnDecline Action `json:"on_decline"`
OnTimeout Action `json:"on_timeout"`
}
type Action struct {
ActionType string `json:"action_type" validate:"required,format=^(mail|vk|tg|sms|request)$"`
Target string `json:"target" validate:"required"`
Data string `json:"data" validate:"required"`
}
func CreatePaymentHandler(h *Handler, pwc *payway.PayWay, crush *tb.Bot) {
var request RequestCreatePayment
err := h.handlePostRequest(&request)
if err != nil {
fmt.Println("handlePostRequest", err)
return
}
fmt.Println("Skeris1")
record := &dal.Payment{
RequesterID: request.RequesterID,
UserIP: h.r.RemoteAddr,
Email: request.Email,
Phone: request.Phone,
Status: "open",
Amount: request.Amount,
PaymentType: request.PaymentType,
Currency: request.Currency,
PayWayID: request.PayWayID,
IsRefill: true,
OnAccept: dal.Action{ActionType: request.OnAccept.ActionType, Data: request.OnAccept.Data},
OnDecline: dal.Action{ActionType: request.OnDecline.ActionType, Data: request.OnDecline.Data},
OnTimeout: dal.Action{ActionType: request.OnTimeout.ActionType, Data: request.OnTimeout.Data},
}
fmt.Println("Skeris2")
id, err := h.mongo.InsertPayment(h.r.Context(), record)
fmt.Println("Skeris3")
if err != nil {
fmt.Println("InsertPayment", err)
h.reportError(http.StatusInternalServerError, "failed", err)
return
}
fmt.Println("Skeris4")
pw := pwc.GetPayWayById(request.PayWayID)
fmt.Println("Skeris5")
if pw == nil {
errs := "got bad pay_way: " + request.PayWayID
h.reportError(http.StatusBadRequest, errs, errors.New(errs))
return
}
if request.Email == "" {
request.Email = "solovyevdanil@yandex.ru"
}
if request.Phone == "" {
request.Phone = "+79885895677"
}
if request.PaymentType == "2" {
request.PaymentType = "Qiwi"
}
fmt.Println("Skeris6")
url, err := pw.CreatePaymentUrl(
fmt.Sprintf("%.2f", request.Amount),
id,
request.PaymentType, // Использовать значение -1 для тестов
request.Currency,
"ru",
request.Email,
request.Phone,
request.RequesterID,
h.r.RemoteAddr,
)
fmt.Println("Skeris7")
if err != nil {
fmt.Println("CreatePaymentUrl", err)
if _, err := crush.Send(tb.ChatID(-1001572699960),
fmt.Sprintf("Платёжка %s не справилась создать ссылку и вот почему: %s", request.PayWayID, err.Error())); err != nil {
fmt.Println("CAN NOT NOTIFY", err)
}
h.reportError(http.StatusInternalServerError, "failed", err)
return
}
fmt.Println("Skeris8")
h.sendResponse(Response{
Success: true,
Message: map[string]string{"id": id, "url": url},
})
}
func PaymentListenerHandler(h *Handler, pwc *payway.PayWay) {
payWay := mux.Vars(h.r)["payWay"]
var err error
switch payWay {
case "fk":
var request payway.ReqPaymentListenerFk
err = h.handleGetRequest(&request)
if err != nil {
h.reportError(http.StatusInternalServerError, "failed", err)
return
}
err = pwc.Cache[payWay].PaymentListener(h.r.Context(), h.r.RemoteAddr, &request, h.mongo)
if err != nil {
h.reportError(http.StatusInternalServerError, "failed", err)
return
}
// уведомляем фрикассу о получении данных
// @TODO: не уверен что надо слать в конце, а не в начале... Может случиться так что фрикасса начнет бесконечно
// долбить сервис даже если имеется ошибка в данных.
_, err = fmt.Fprint(h.w, "YES")
if err != nil {
h.reportError(http.StatusInternalServerError, "failed", err)
return
}
case "bt":
var request payway.ReqPaymentListenerBt
if err := h.r.ParseForm(); err != nil {
return
}
request.Sign = h.r.Form.Get("sign")
request.OrderId = h.r.Form.Get("orderId")
request.UserComment = h.r.Form.Get("user_comment")
amt, err := strconv.ParseFloat(h.r.Form.Get("amount"), 64)
request.Amount = amt
err = pwc.Cache[payWay].PaymentListener(h.r.Context(), h.r.RemoteAddr, &request, h.mongo)
if err != nil {
h.reportError(http.StatusInternalServerError, "failed", err)
return
}
//// уведомляем фрикассу о получении данных
//// @TODO: не уверен что надо слать в конце, а не в начале... Может случиться так что фрикасса начнет бесконечно
//// долбить сервис даже если имеется ошибка в данных.
_, err = fmt.Fprint(h.w, "OK")
//if err != nil {
// h.reportError(http.StatusInternalServerError, "failed", err)
// return
//}
}
}
type GetPayWaysResp struct {
Name string `json:"name"`
ID string `json:"ID"`
}
func GetPayWays(h *Handler, pwc *payway.PayWay) {
paymentList, err := pwc.GetPaymentList()
if err != nil {
h.reportError(http.StatusInternalServerError, fmt.Sprint(err), err)
return
}
h.sendResponse(Response{
Success: true,
Message: paymentList,
})
}

@ -1,90 +0,0 @@
package handlers
import (
"bitbucket.org/skeris/treasurer/dal"
"bitbucket.org/skeris/treasurer/payway"
"github.com/gorilla/mux"
"net/http"
)
type RequestCreatePayout struct {
RequesterID string `json:"requester_id" validate:"required"`
Amount float64 `json:"amount" validate:">0"` // Сумма для вывода
Destination string `json:"destination" validate:"required"` // Счет на который выводим
PayWayID string `json:"payway_id" validate:"required"` // Присылать именно ID, а не shortName! id: fk1, sn: fk
PayoutType string `json:"payout_type" validate:"required"` // Тип вывода: payoutType.CommonID
Currency string `json:"currency"`
Description string `json:"description"` // Пока не придумал что сюда заполнять
Email string `json:"email"`
Phone string `json:"phone"`
IsFake bool `json:"is_fake"`
OnAccept Action `json:"on_accept"`
OnDecline Action `json:"on_decline"`
OnTimeout Action `json:"on_timeout"`
}
func CreatePayoutHandler(h *Handler, pwc *payway.PayWay) {
var request RequestCreatePayout
err := h.handlePostRequest(&request)
if err != nil {
return
}
// Добавить в монгу запись
record := &dal.Payment{
RequesterID: request.RequesterID,
Amount: request.Amount,
Destination: request.Destination,
PayWayID: request.PayWayID,
PaymentType: request.PayoutType,
Currency: request.Currency,
Description: request.Description, // Пока не придумал что сюда заполнять
Email: request.Email,
Phone: request.Phone,
IsFake: request.IsFake,
UserIP: h.r.RemoteAddr,
Status: "open",
OnAccept: dal.Action{ActionType: request.OnAccept.ActionType, Data: request.OnAccept.Data},
OnDecline: dal.Action{ActionType: request.OnDecline.ActionType, Data: request.OnDecline.Data},
OnTimeout: dal.Action{ActionType: request.OnTimeout.ActionType, Data: request.OnTimeout.Data},
IsRefill: false,
}
id, err := h.mongo.InsertPayment(h.r.Context(), record)
if err != nil {
h.reportError(http.StatusInternalServerError, "failed", err)
return
}
// Добавить в очередь запись
pwc.QueuePayout.Enqueue(id)
h.sendResponse(Response{
Success: true,
Message: map[string]string{"id": id},
})
}
func PayoutListenerHandler(h *Handler, pwc *payway.PayWay) {
payWay := mux.Vars(h.r)["payWay"]
var err error
switch payWay {
case "fk":
var request payway.ReqPayoutListenerFk
err = h.handleGetRequest(&request)
if err != nil {
return
}
err = pwc.Cache[payWay].PayoutListener(h.r.Context(), h.r.RemoteAddr, &request, h.mongo)
if err != nil {
h.reportError(http.StatusInternalServerError, "failed", err)
return
}
}
}

@ -1,18 +0,0 @@
package handlers
import (
"github.com/danilsolovyov/validator"
)
type Validators map[string]validator.Validator
func CreateValidators(s ...interface{}) Validators {
validators := Validators{}
for _, val := range s {
v := validator.NewValidator(val)
validators[v.GetName()] = v
}
return validators
}

115
internal/app/app.go Normal file

@ -0,0 +1,115 @@
package app
import (
"context"
"fmt"
"time"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/initialize"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/server"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/swagger"
"penahub.gitlab.yandexcloud.net/external/treasurer/pkg/closer"
"penahub.gitlab.yandexcloud.net/external/treasurer/pkg/mongo"
)
const (
shutdownTimeout = 5 * time.Second
)
func Run(ctx context.Context, config *models.Config, logger *zap.Logger) error {
mongoDB, connectionErr := mongo.Connect(ctx, &mongo.ConnectDeps{
Configuration: &config.Database,
Timeout: 10 * time.Second,
})
if connectionErr != nil {
return fmt.Errorf("failed connection to db: %w", connectionErr)
}
closer := closer.New()
openapi, swaggerErr := swagger.GetSwagger()
if swaggerErr != nil {
return fmt.Errorf("failed to loading openapi spec: %w", swaggerErr)
}
repositories, err := initialize.NewRepositories(initialize.RepositoriesDeps{
Logger: logger,
Database: mongoDB,
})
if err != nil {
return err.Wrap("failed to initialize repositories")
}
clients, err := initialize.NewClients(initialize.ClientsDeps{
Logger: logger,
YoomoneyConfiguration: &config.Service.YoomomeyConfiguration,
})
if err != nil {
return err.Wrap("failed to initialize clients")
}
services, err := initialize.NewServices(initialize.ServicesDeps{
Logger: logger,
Repositories: *repositories,
Clients: *clients,
ConfigurationHTTP: &config.HTTP,
})
if err != nil {
return err.Wrap("failed to initialize services")
}
controllers, err := initialize.NewControllers(initialize.ControllersDeps{
Logger: logger,
Services: *services,
})
if err != nil {
return err.Wrap("failed to initialize controllers")
}
api, err := initialize.NewAPI(controllers)
if err != nil {
return err.Wrap("failed to initialize api")
}
httpServer, err := server.NewHTTP(server.DepsHTTP{
Logger: logger,
Swagger: openapi,
})
if err != nil {
return err.Wrap("failed to initialize http server")
}
httpServer.Register(api)
grpcServer, err := server.NewGRPC(server.DepsGRPC{
Logger: logger,
})
if err != nil {
return err.Wrap("failed to initialize grpc server")
}
grpcServer.Register(controllers.PaymentGRPC)
go httpServer.Run(&config.HTTP)
go grpcServer.Run(&config.GRPC)
closer.Add(mongoDB.Client().Disconnect)
closer.Add(httpServer.Stop)
closer.Add(grpcServer.Stop)
<-ctx.Done()
logger.Info("shutting down app gracefully")
shutdownCtx, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer cancel()
if err := closer.Close(shutdownCtx); err != nil {
return fmt.Errorf("closer: %w", err)
}
return nil
}

64
internal/errors/errors.go Normal file

@ -0,0 +1,64 @@
package errors
import (
"errors"
"fmt"
)
type ErrorType error
var (
ErrInternalError ErrorType = errors.New("internal error")
ErrInvalidArgs ErrorType = errors.New("invalid arguments")
ErrMethodNotImplemented ErrorType = errors.New("method is not implemented")
ErrNotFound ErrorType = errors.New("record not found")
ErrNoAccess ErrorType = errors.New("no access")
ErrConflict ErrorType = errors.New("record already exist")
ErrInsufficientFunds ErrorType = errors.New("insufficient funds")
)
type Error interface {
Error() string
Type() ErrorType
Wrap(message string) Error
SetType(errorType ErrorType) Error
}
type customError struct {
errorType ErrorType
err error
}
func NewWithError(err error, errorType ErrorType) Error {
return &customError{
errorType: errorType,
err: err,
}
}
func NewWithMessage(message string, errorType ErrorType) Error {
return &customError{
errorType: errorType,
err: errors.New(message),
}
}
func (receiver *customError) Error() string {
return receiver.err.Error()
}
func (receiver *customError) Type() ErrorType {
return receiver.errorType
}
func (receiver *customError) Wrap(message string) Error {
receiver.err = fmt.Errorf("%s: %w", message, receiver.err)
return receiver
}
func (receiver *customError) SetType(errorType ErrorType) Error {
receiver.errorType = errorType
return receiver
}

27
internal/errors/grpc.go Normal file

@ -0,0 +1,27 @@
package errors
import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
const defaultGRPCCode = codes.Internal
var grpcCodes = map[error]codes.Code{
ErrInvalidArgs: codes.InvalidArgument,
ErrConflict: codes.AlreadyExists,
ErrInsufficientFunds: codes.Unavailable,
ErrInternalError: codes.Internal,
ErrMethodNotImplemented: codes.Unimplemented,
ErrNoAccess: codes.Unavailable,
ErrNotFound: codes.NotFound,
}
func GRPC(message string, err Error) error {
currentStatus, ok := grpcCodes[err]
if !ok {
return status.Errorf(defaultGRPCCode, message, err)
}
return status.Errorf(currentStatus, message, err)
}

33
internal/errors/http.go Normal file

@ -0,0 +1,33 @@
package errors
import (
"net/http"
"github.com/labstack/echo/v4"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
)
var httpStatuses = map[ErrorType]int{
ErrInternalError: http.StatusInternalServerError,
ErrInvalidArgs: http.StatusBadRequest,
ErrNoAccess: http.StatusForbidden,
ErrNotFound: http.StatusNotFound,
ErrMethodNotImplemented: http.StatusNotImplemented,
ErrConflict: http.StatusConflict,
ErrInsufficientFunds: http.StatusPaymentRequired,
}
func HTTP(ctx echo.Context, err Error) error {
status, ok := httpStatuses[err.Type()]
if !ok {
return ctx.JSON(http.StatusInternalServerError, models.ResponseErrorHTTP{
StatusCode: http.StatusInternalServerError,
Message: err.Error(),
})
}
return ctx.JSON(status, models.ResponseErrorHTTP{
StatusCode: status,
Message: err.Error(),
})
}

@ -0,0 +1,13 @@
package initialize
import (
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/swagger"
)
func NewAPI(controllers *Controllers) (*swagger.API, errors.Error) {
return swagger.New(swagger.Deps{
CommonController: controllers.CommonREST,
YandexStatusController: controllers.YandexStatusREST,
})
}

@ -0,0 +1,38 @@
package initialize
import (
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/interface/client"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
)
type ClientsDeps struct {
Logger *zap.Logger
YoomoneyConfiguration *models.YoomomeyConfiguration
}
type Clients struct {
Callback *client.CallbackClient
Yandex *client.YandexClient
}
func NewClients(deps ClientsDeps) (*Clients, errors.Error) {
callbackClient, err := client.NewCallbackClient(client.CallbackClientDeps{Logger: deps.Logger})
if err != nil {
return nil, err
}
yandexClient, err := client.NewYandexClient(client.YandexClientDeps{
Logger: deps.Logger,
Configuration: deps.YoomoneyConfiguration,
})
if err != nil {
return nil, err
}
return &Clients{
Callback: callbackClient,
Yandex: yandexClient,
}, nil
}

@ -0,0 +1,15 @@
package initialize
import (
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
"penahub.gitlab.yandexcloud.net/external/treasurer/pkg/env"
)
func Configuration(path string) (*models.Config, error) {
config, err := env.Parse[models.Config](path)
if err != nil {
return nil, err
}
return config, nil
}

@ -0,0 +1,52 @@
package initialize
import (
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/interface/controller/grpc"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/interface/controller/rest"
)
type ControllersDeps struct {
Logger *zap.Logger
Services Services
}
type Controllers struct {
CommonREST *rest.CommonController
YandexStatusREST *rest.YandexStatusController
PaymentGRPC *grpc.PaymentController
}
func NewControllers(deps ControllersDeps) (*Controllers, errors.Error) {
commonControllerREST, err := rest.NewCommonController(rest.CommonControllerDeps{
Logger: deps.Logger,
PaymentService: deps.Services.Payment,
})
if err != nil {
return nil, err
}
yandexStatusControllerREST, err := rest.NewYandexStatusController(rest.YandexStatusControllerDeps{
Logger: deps.Logger,
StatusService: deps.Services.Status,
CallbackService: deps.Services.Callback,
})
if err != nil {
return nil, err
}
paymentControllerGRPC, err := grpc.NewPaymentController(grpc.PaymentControllerDeps{
Logger: deps.Logger,
PaymentService: deps.Services.Payment,
})
if err != nil {
return nil, err
}
return &Controllers{
CommonREST: commonControllerREST,
YandexStatusREST: yandexStatusControllerREST,
PaymentGRPC: paymentControllerGRPC,
}, nil
}

@ -0,0 +1,29 @@
package initialize
import (
"go.mongodb.org/mongo-driver/mongo"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/interface/repository"
)
type RepositoriesDeps struct {
Logger *zap.Logger
Database *mongo.Database
}
type Repositories struct {
Payment *repository.PaymentRepository
}
func NewRepositories(deps RepositoriesDeps) (*Repositories, errors.Error) {
paymentRepository, err := repository.NewPaymentRepository(repository.PaymentRepositoryDeps{
Logger: deps.Logger,
Collection: deps.Database.Collection("payments"),
})
if err != nil {
return nil, err
}
return &Repositories{Payment: paymentRepository}, nil
}

@ -0,0 +1,79 @@
package initialize
import (
"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/service/callback"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/service/payment"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/service/status"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/service/webhook"
)
type ServicesDeps struct {
Logger *zap.Logger
Repositories Repositories
Clients Clients
ConfigurationHTTP *models.ConfigurationHTTP
}
type Services struct {
Callback *callback.Service
Payment *payment.Service
YandexPayment *payment.Yandex
Status *status.Service
YandexWebhook *webhook.Yandex
}
func NewServices(deps ServicesDeps) (*Services, errors.Error) {
callbackService, err := callback.New(callback.Deps{
Logger: deps.Logger,
CallbackClient: deps.Clients.Callback,
PaymentRepository: deps.Repositories.Payment,
})
if err != nil {
return nil, err
}
yandexPaymentService, err := payment.NewYandex(payment.YandexPaymentServiceDeps{
Logger: deps.Logger,
YandexPaymentClient: deps.Clients.Yandex,
})
if err != nil {
return nil, err
}
paymentService, err := payment.New(payment.Deps{
Logger: deps.Logger,
PaymentRepository: deps.Repositories.Payment,
PaymentStrategyService: yandexPaymentService,
})
if err != nil {
return nil, err
}
statusService, err := status.New(status.Deps{
Logger: deps.Logger,
PaymentRepository: deps.Repositories.Payment,
})
if err != nil {
return nil, err
}
yandexWebhookService, err := webhook.NewYandex(webhook.YandexDeps{
Logger: deps.Logger,
YandexWebhookClient: deps.Clients.Yandex,
Configuration: deps.ConfigurationHTTP,
})
if err != nil {
return nil, err
}
return &Services{
Callback: callbackService,
Payment: paymentService,
YandexPayment: yandexPaymentService,
Status: statusService,
YandexWebhook: yandexWebhookService,
}, nil
}

@ -0,0 +1,109 @@
package client
import (
"context"
"fmt"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/proto/payment_callback"
)
type CallbackClientDeps struct {
Logger *zap.Logger
}
type CallbackClient struct {
logger *zap.Logger
}
func NewCallbackClient(deps CallbackClientDeps) (*CallbackClient, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("logger is nil on <NewCallbackClient>", errors.ErrInvalidArgs)
}
return &CallbackClient{logger: deps.Logger}, nil
}
func (receiver *CallbackClient) SendOnSuccess(ctx context.Context, host string, event *models.Event) errors.Error {
connection, err := grpc.Dial(host, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
receiver.logger.Error("failed to connect on <SendOnSuccess> of <CallbackClient>", zap.Error(err), zap.String("host", host))
return errors.NewWithError(fmt.Errorf("failed connect to callback service: %w", err), errors.ErrInternalError)
}
defer func() {
if closeErr := connection.Close(); closeErr != nil {
receiver.logger.Error("failed to close connection on <SendOnSuccess> of <CallbackClient>", zap.Error(closeErr))
}
}()
client := payment_callback.NewPaymentCallbackServiceClient(connection)
if _, err := client.OnSuccess(ctx, &payment_callback.Event{
Key: event.Key,
Message: event.Message,
Payment: &payment_callback.Payment{
ID: event.Payment.ID,
UserID: event.Payment.UserID,
PaymentID: event.Payment.PaymentID,
IdempotencePaymentID: event.Payment.IdempotencePaymentID,
Amount: event.Payment.Amount,
Currency: event.Payment.Currency,
Type: string(event.Payment.Type),
Status: string(event.Payment.Status),
Completed: event.Payment.Completed,
},
}); err != nil {
receiver.logger.Error("failed to send success callback on <SendOnSuccess> of <CallbackClient>",
zap.Error(err),
zap.String("host", host),
zap.Any("event", event),
)
return errors.NewWithError(fmt.Errorf("failed to send success callback: %w", err), errors.ErrInternalError)
}
return nil
}
func (receiver *CallbackClient) SendOnFailure(ctx context.Context, host string, event *models.Event) errors.Error {
connection, err := grpc.Dial(host, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
receiver.logger.Error("failed to connect on <SendOnFailure> of <CallbackClient>", zap.Error(err), zap.String("host", host))
return errors.NewWithError(fmt.Errorf("failed connect to callback service: %w", err), errors.ErrInternalError)
}
defer func() {
if closeErr := connection.Close(); closeErr != nil {
receiver.logger.Error("failed to close connection on <SendOnFailure> of <CallbackClient>", zap.Error(closeErr))
}
}()
client := payment_callback.NewPaymentCallbackServiceClient(connection)
if _, err := client.OnFailure(ctx, &payment_callback.Event{
Key: event.Key,
Message: event.Message,
Payment: &payment_callback.Payment{
ID: event.Payment.ID,
UserID: event.Payment.UserID,
PaymentID: event.Payment.PaymentID,
IdempotencePaymentID: event.Payment.IdempotencePaymentID,
Amount: event.Payment.Amount,
Currency: event.Payment.Currency,
Type: string(event.Payment.Type),
Status: string(event.Payment.Status),
Completed: event.Payment.Completed,
},
}); err != nil {
receiver.logger.Error("failed to send failure callback on <SendOnFailure> of <CallbackClient>",
zap.Error(err),
zap.String("host", host),
zap.Any("event", event),
)
return errors.NewWithError(fmt.Errorf("failed to send failure callback: %w", err), errors.ErrInternalError)
}
return nil
}

@ -0,0 +1,253 @@
package client
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/internal/utils"
"penahub.gitlab.yandexcloud.net/external/treasurer/pkg/client"
)
const (
yandexPaymentsMockURL = "http://mock:8080/payments"
yandexPaymentsProdURL = "https://api.yookassa.ru/v3/payments"
yandexWebhooksMockURL = "http://mock:8080/webhooks"
yandexWebhooksProdURL = "https://api.yookassa.ru/v3/webhooks"
)
const (
yandexPaymentsURL = yandexPaymentsMockURL
yandexWebhooksURL = yandexWebhooksMockURL
)
type YandexClientDeps struct {
Logger *zap.Logger
Configuration *models.YoomomeyConfiguration
}
type YandexClient struct {
logger *zap.Logger
configuration *models.YoomomeyConfiguration
}
func NewYandexClient(deps YandexClientDeps) (*YandexClient, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("Logger is nil on <NewYandexClient>", errors.ErrInvalidArgs)
}
if deps.Configuration == nil {
return nil, errors.NewWithMessage("Configuration is nil on <NewYandexClient>", errors.ErrInvalidArgs)
}
return &YandexClient{
logger: deps.Logger,
configuration: deps.Configuration,
}, nil
}
func (receiver *YandexClient) CreatePayment(ctx context.Context, idempotenceKey string, request *yandex.CreatePaymentRequest[yandex.PaymentMethodType]) (*yandex.Payment, errors.Error) {
response, err := client.Post[yandex.Payment, any](ctx, &client.RequestSettings{
URL: yandexPaymentsURL,
Body: request,
Headers: map[string]string{
"Content-Type": "application/json",
"Idempotence-Key": idempotenceKey,
"Authorization": utils.ConvertYoomoneySercetsToAuth("Basic", receiver.configuration.StoreID, receiver.configuration.SecretKey),
},
})
if err != nil {
receiver.logger.Error("failed to make request on <CreatePayment> of <YandexClient>", zap.Error(err))
return nil, errors.NewWithError(fmt.Errorf("failed to make request: %w", err), errors.ErrInternalError)
}
if response.Error != nil {
receiver.logger.Error("failed to create payment on <CreatePayment> of <YandexClient>", zap.Any("response", response.Error))
return nil, errors.NewWithMessage("failed to create payment", errors.ErrInternalError)
}
return response.Body, nil
}
func (receiver *YandexClient) CreatePaymentB2B(ctx context.Context, idempotenceKey string, request *yandex.CreatePaymentRequest[yandex.PaymentMethodB2B]) (*yandex.Payment, errors.Error) {
response, err := client.Post[yandex.Payment, any](ctx, &client.RequestSettings{
URL: yandexPaymentsURL,
Body: request,
Headers: map[string]string{
"Content-Type": "application/json",
"Idempotence-Key": idempotenceKey,
"Authorization": utils.ConvertYoomoneySercetsToAuth("Basic", receiver.configuration.StoreID, receiver.configuration.SecretKey),
},
})
if err != nil {
receiver.logger.Error("failed to make request on <CreatePaymentB2B> of <YandexClient>", zap.Error(err))
return nil, errors.NewWithError(fmt.Errorf("failed to make request: %w", err), errors.ErrInternalError)
}
if response.Error != nil {
receiver.logger.Error("failed to create payment on <CreatePaymentB2B> of <YandexClient>", zap.Any("response", response.Error))
return nil, errors.NewWithMessage("failed to create payment", errors.ErrInternalError)
}
return response.Body, nil
}
func (receiver *YandexClient) CreatePaymentBankCard(ctx context.Context, idempotenceKey string, request *yandex.CreatePaymentRequest[yandex.PaymentMethodBankCard]) (*yandex.Payment, errors.Error) {
response, err := client.Post[yandex.Payment, any](ctx, &client.RequestSettings{
URL: yandexPaymentsURL,
Body: request,
Headers: map[string]string{
"Content-Type": "application/json",
"Idempotence-Key": idempotenceKey,
"Authorization": utils.ConvertYoomoneySercetsToAuth("Basic", receiver.configuration.StoreID, receiver.configuration.SecretKey),
},
})
if err != nil {
receiver.logger.Error("failed to make request on <CreatePaymentBankCard> of <YandexClient>", zap.Error(err))
return nil, errors.NewWithError(fmt.Errorf("failed to make request: %w", err), errors.ErrInternalError)
}
if response.Error != nil {
receiver.logger.Error("failed to create payment on <CreatePaymentBankCard> of <YandexClient>", zap.Any("response", response.Error))
return nil, errors.NewWithMessage("failed to create payment", errors.ErrInternalError)
}
return response.Body, nil
}
func (receiver *YandexClient) CreatePaymentLogin(ctx context.Context, idempotenceKey string, request *yandex.CreatePaymentRequest[yandex.PaymentMethodLogin]) (*yandex.Payment, errors.Error) {
response, err := client.Post[yandex.Payment, any](ctx, &client.RequestSettings{
URL: yandexPaymentsURL,
Body: request,
Headers: map[string]string{
"Content-Type": "application/json",
"Idempotence-Key": idempotenceKey,
"Authorization": utils.ConvertYoomoneySercetsToAuth("Basic", receiver.configuration.StoreID, receiver.configuration.SecretKey),
},
})
if err != nil {
receiver.logger.Error("failed to make request on <CreatePaymentLogin> of <YandexClient>", zap.Error(err))
return nil, errors.NewWithError(fmt.Errorf("failed to make request: %w", err), errors.ErrInternalError)
}
if response.Error != nil {
receiver.logger.Error("failed to create payment on <CreatePaymentLogin> of <YandexClient>", zap.Any("response", response.Error))
return nil, errors.NewWithMessage("failed to create payment", errors.ErrInternalError)
}
return response.Body, nil
}
func (receiver *YandexClient) CreatePaymentPhone(ctx context.Context, idempotenceKey string, request *yandex.CreatePaymentRequest[yandex.PaymentMethodPhone]) (*yandex.Payment, errors.Error) {
response, err := client.Post[yandex.Payment, any](ctx, &client.RequestSettings{
URL: yandexPaymentsURL,
Body: request,
Headers: map[string]string{
"Content-Type": "application/json",
"Idempotence-Key": idempotenceKey,
"Authorization": utils.ConvertYoomoneySercetsToAuth("Basic", receiver.configuration.StoreID, receiver.configuration.SecretKey),
},
})
if err != nil {
receiver.logger.Error("failed to make request on <CreatePaymentPhone> of <YandexClient>", zap.Error(err))
return nil, errors.NewWithError(fmt.Errorf("failed to make request: %w", err), errors.ErrInternalError)
}
if response.Error != nil {
receiver.logger.Error("failed to create payment on <CreatePaymentPhone> of <YandexClient>", zap.Any("response", response.Error))
return nil, errors.NewWithMessage("failed to create payment", errors.ErrInternalError)
}
return response.Body, nil
}
func (receiver *YandexClient) DeleteWebhook(ctx context.Context, webhookID string) errors.Error {
url, err := url.JoinPath(yandexWebhooksURL, webhookID)
if err != nil {
receiver.logger.Error("failed to join path url on <DeleteWebhook> of <YandexClient>",
zap.Error(err),
zap.String("yandex webhook url", yandexWebhooksURL),
zap.String("webhookID", webhookID),
)
return errors.NewWithError(fmt.Errorf("failed to join url path: %w", err), errors.ErrInternalError)
}
response, err := client.Delete[any, any](ctx, &client.RequestSettings{
URL: url,
Headers: map[string]string{
"Content-Type": "application/json",
// TODO: узнать о получении access token
"Authorization": utils.ConvertYoomoneySercetsToAuth("Basic", receiver.configuration.StoreID, receiver.configuration.SecretKey),
},
})
if err != nil {
receiver.logger.Error("failed to make request on <DeleteWebhook> of <YandexClient>", zap.Error(err))
return errors.NewWithError(fmt.Errorf("failed to make request: %w", err), errors.ErrInternalError)
}
if response.Error != nil {
receiver.logger.Error("failed to delete webhook on <DeleteWebhook> of <YandexClient>",
zap.Any("response", response.Error),
zap.String("url", url),
)
return errors.NewWithMessage("failed to create payment", errors.ErrInternalError)
}
return nil
}
func (receiver *YandexClient) GetWebhookEvents(ctx context.Context) ([]yandex.Webhook, errors.Error) {
response, err := client.Delete[[]yandex.Webhook, any](ctx, &client.RequestSettings{
URL: yandexWebhooksURL,
Headers: map[string]string{
"Content-Type": "application/json",
// TODO: узнать о получении access token
"Authorization": utils.ConvertYoomoneySercetsToAuth("Basic", receiver.configuration.StoreID, receiver.configuration.SecretKey),
},
})
if err != nil {
receiver.logger.Error("failed to make request on <DeleteWebhook> of <YandexClient>", zap.Error(err))
return []yandex.Webhook{}, errors.NewWithError(fmt.Errorf("failed to make request: %w", err), errors.ErrInternalError)
}
if response.Error != nil {
receiver.logger.Error("failed to delete webhook on <DeleteWebhook> of <YandexClient>",
zap.Any("response", response.Error),
zap.String("url", yandexWebhooksURL),
)
return []yandex.Webhook{}, errors.NewWithMessage("failed to create payment", errors.ErrInternalError)
}
return *response.Body, nil
}
func (receiver *YandexClient) SetWebhookEvent(ctx context.Context, idempotenceKey string, request *yandex.CreateWebhookRequest) (string, errors.Error) {
response, err := client.Post[yandex.Webhook, any](ctx, &client.RequestSettings{
URL: yandexWebhooksURL,
Body: request,
Headers: map[string]string{
"Content-Type": "application/json",
"Idempotence-Key": idempotenceKey,
// TODO: узнать о получении access token
"Authorization": utils.ConvertYoomoneySercetsToAuth("Basic", receiver.configuration.StoreID, receiver.configuration.SecretKey),
},
})
if err != nil {
receiver.logger.Error("failed to make request on <DeleteWebhook> of <YandexClient>", zap.Error(err))
return "", errors.NewWithError(fmt.Errorf("failed to make request: %w", err), errors.ErrInternalError)
}
if response.Error != nil {
receiver.logger.Error("failed to delete webhook on <DeleteWebhook> of <YandexClient>",
zap.Any("response", response.Error),
zap.String("url", yandexWebhooksURL),
)
return "", errors.NewWithMessage("failed to create payment", errors.ErrInternalError)
}
return response.Body.ID, nil
}

@ -0,0 +1,240 @@
package grpc
import (
"context"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/proto/treasurer"
)
type PaymentService interface {
CreatePaymentPhone(context.Context, *models.CreatePayment[string]) (string, errors.Error)
CreatePaymentBankCard(context.Context, *models.CreatePayment[*models.BankCard]) (string, errors.Error)
CreatePayment(context.Context, *models.CreatePayment[*any]) (string, errors.Error)
CreatePaymentLogin(context.Context, *models.CreatePayment[string]) (string, errors.Error)
}
type PaymentControllerDeps struct {
Logger *zap.Logger
PaymentService PaymentService
}
type PaymentController struct {
logger *zap.Logger
paymentService PaymentService
}
func NewPaymentController(deps PaymentControllerDeps) (*PaymentController, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("Logger in nil on <NewPaymentController>", errors.ErrInvalidArgs)
}
if deps.PaymentService == nil {
return nil, errors.NewWithMessage("PaymentService in nil on <NewPaymentController>", errors.ErrInvalidArgs)
}
return &PaymentController{
logger: deps.Logger,
paymentService: deps.PaymentService,
}, nil
}
func (receiver *PaymentController) GetPaymentLinkBankCard(ctx context.Context, in *treasurer.GetBankCardPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) {
link, err := receiver.paymentService.CreatePaymentBankCard(ctx, &models.CreatePayment[*models.BankCard]{
Type: models.PaymentTypeBankCard,
Currency: in.MainSettings.Currency,
UserID: in.MainSettings.UserID,
ClientIP: in.MainSettings.ClientIP,
Amount: in.MainSettings.Amount,
CallbackHostGRPC: in.MainSettings.CallbackHostGRPC,
ReturnURL: in.MainSettings.ReturnURL,
Requisites: &models.BankCard{
Number: in.BankCard.Number,
ExpiryYear: in.BankCard.ExpiryYear,
ExpiryMonth: in.BankCard.ExpiryMonth,
CSC: in.BankCard.CSC,
CardHolderName: in.BankCard.CardHolderName,
},
})
if err != nil {
receiver.logger.Error("failed to get payment link on <GetPaymentLinkBankCard> of <PaymentController>", zap.Error(err))
return nil, errors.GRPC("failed to get payment link", err)
}
return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil
}
func (receiver *PaymentController) GetPaymentLinkYooMoney(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) {
link, err := receiver.paymentService.CreatePayment(ctx, &models.CreatePayment[*any]{
Type: models.PaymentTypeYoomoney,
Currency: in.MainSettings.Currency,
UserID: in.MainSettings.UserID,
ClientIP: in.MainSettings.ClientIP,
Amount: in.MainSettings.Amount,
CallbackHostGRPC: in.MainSettings.CallbackHostGRPC,
ReturnURL: in.MainSettings.ReturnURL,
})
if err != nil {
receiver.logger.Error("failed to get payment link on <GetPaymentLinkYooMoney> of <PaymentController>", zap.Error(err))
return nil, errors.GRPC("failed to get payment link", err)
}
return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil
}
func (receiver *PaymentController) GetPaymentLinkQIWI(ctx context.Context, in *treasurer.GetPhonePaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) {
link, err := receiver.paymentService.CreatePaymentPhone(ctx, &models.CreatePayment[string]{
Type: models.PaymentTypeQiwi,
Currency: in.MainSettings.Currency,
UserID: in.MainSettings.UserID,
ClientIP: in.MainSettings.ClientIP,
Amount: in.MainSettings.Amount,
CallbackHostGRPC: in.MainSettings.CallbackHostGRPC,
ReturnURL: in.MainSettings.ReturnURL,
Requisites: in.Phone,
})
if err != nil {
receiver.logger.Error("failed to get payment link on <GetPaymentLinkQIWI> of <PaymentController>", zap.Error(err))
return nil, errors.GRPC("failed to get payment link", err)
}
return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil
}
func (receiver *PaymentController) GetPaymentLinkSberPay(ctx context.Context, in *treasurer.GetPhonePaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) {
link, err := receiver.paymentService.CreatePaymentPhone(ctx, &models.CreatePayment[string]{
Type: models.PaymentTypeSberPay,
Currency: in.MainSettings.Currency,
UserID: in.MainSettings.UserID,
ClientIP: in.MainSettings.ClientIP,
Amount: in.MainSettings.Amount,
CallbackHostGRPC: in.MainSettings.CallbackHostGRPC,
ReturnURL: in.MainSettings.ReturnURL,
Requisites: in.Phone,
})
if err != nil {
receiver.logger.Error("failed to get payment link on <GetPaymentLinkSberPay> of <PaymentController>", zap.Error(err))
return nil, errors.GRPC("failed to get payment link", err)
}
return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil
}
func (receiver *PaymentController) GetPaymentLinkAlfaClick(ctx context.Context, in *treasurer.GetLoginPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) {
link, err := receiver.paymentService.CreatePaymentLogin(ctx, &models.CreatePayment[string]{
Type: models.PaymentTypeAlfabank,
Currency: in.MainSettings.Currency,
UserID: in.MainSettings.UserID,
ClientIP: in.MainSettings.ClientIP,
Amount: in.MainSettings.Amount,
CallbackHostGRPC: in.MainSettings.CallbackHostGRPC,
ReturnURL: in.MainSettings.ReturnURL,
Requisites: in.Login,
})
if err != nil {
receiver.logger.Error("failed to get payment link on <GetPaymentLinkAlfaClick> of <PaymentController>", zap.Error(err))
return nil, errors.GRPC("failed to get payment link", err)
}
return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil
}
func (receiver *PaymentController) GetPaymentLinkTinkoff(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) {
link, err := receiver.paymentService.CreatePayment(ctx, &models.CreatePayment[*any]{
Type: models.PaymentTypeTinkoff,
Currency: in.MainSettings.Currency,
UserID: in.MainSettings.UserID,
ClientIP: in.MainSettings.ClientIP,
Amount: in.MainSettings.Amount,
CallbackHostGRPC: in.MainSettings.CallbackHostGRPC,
ReturnURL: in.MainSettings.ReturnURL,
})
if err != nil {
receiver.logger.Error("failed to get payment link on <GetPaymentLinkTinkoff> of <PaymentController>", zap.Error(err))
return nil, errors.GRPC("failed to get payment link", err)
}
return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil
}
func (receiver *PaymentController) GetPaymentLinkSBP(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) {
link, err := receiver.paymentService.CreatePayment(ctx, &models.CreatePayment[*any]{
Type: models.PaymentTypeSBP,
Currency: in.MainSettings.Currency,
UserID: in.MainSettings.UserID,
ClientIP: in.MainSettings.ClientIP,
Amount: in.MainSettings.Amount,
CallbackHostGRPC: in.MainSettings.CallbackHostGRPC,
ReturnURL: in.MainSettings.ReturnURL,
})
if err != nil {
receiver.logger.Error("failed to get payment link on <GetPaymentLinkSBP> of <PaymentController>", zap.Error(err))
return nil, errors.GRPC("failed to get payment link", err)
}
return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil
}
func (receiver *PaymentController) GetPaymentLinkMobile(ctx context.Context, in *treasurer.GetPhonePaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) {
link, err := receiver.paymentService.CreatePaymentPhone(ctx, &models.CreatePayment[string]{
Type: models.PaymentTypeMobile,
Currency: in.MainSettings.Currency,
UserID: in.MainSettings.UserID,
ClientIP: in.MainSettings.ClientIP,
Amount: in.MainSettings.Amount,
CallbackHostGRPC: in.MainSettings.CallbackHostGRPC,
ReturnURL: in.MainSettings.ReturnURL,
Requisites: in.Phone,
})
if err != nil {
receiver.logger.Error("failed to get payment link on <GetPaymentLinkMobile> of <PaymentController>", zap.Error(err))
return nil, errors.GRPC("failed to get payment link", err)
}
return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil
}
func (receiver *PaymentController) GetPaymentLinkCash(ctx context.Context, in *treasurer.GetPhonePaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) {
link, err := receiver.paymentService.CreatePaymentPhone(ctx, &models.CreatePayment[string]{
Type: models.PaymentTypeCash,
Currency: in.MainSettings.Currency,
UserID: in.MainSettings.UserID,
ClientIP: in.MainSettings.ClientIP,
Amount: in.MainSettings.Amount,
CallbackHostGRPC: in.MainSettings.CallbackHostGRPC,
ReturnURL: in.MainSettings.ReturnURL,
Requisites: in.Phone,
})
if err != nil {
receiver.logger.Error("failed to get payment link on <GetPaymentLinkCash> of <PaymentController>", zap.Error(err))
return nil, errors.GRPC("failed to get payment link", err)
}
return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil
}
func (receiver *PaymentController) GetPaymentLinkInstallments(ctx context.Context, in *treasurer.GetPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) {
link, err := receiver.paymentService.CreatePayment(ctx, &models.CreatePayment[*any]{
Type: models.PaymentTypeInstallments,
Currency: in.MainSettings.Currency,
UserID: in.MainSettings.UserID,
ClientIP: in.MainSettings.ClientIP,
Amount: in.MainSettings.Amount,
CallbackHostGRPC: in.MainSettings.CallbackHostGRPC,
ReturnURL: in.MainSettings.ReturnURL,
})
if err != nil {
receiver.logger.Error("failed to get payment link on <GetPaymentLinkInstallments> of <PaymentController>", zap.Error(err))
return nil, errors.GRPC("failed to get payment link", err)
}
return &treasurer.GetPaymentLinkResponse{RedirectURL: link}, nil
}
func (receiver *PaymentController) GetPaymentLinkSberbankB2B(_ context.Context, _ *treasurer.GetB2BPaymentLinkRequest) (*treasurer.GetPaymentLinkResponse, error) {
return nil, status.Error(codes.Unimplemented, "method not implemented")
}

@ -0,0 +1,50 @@
package rest
import (
"context"
"net/http"
"github.com/labstack/echo/v4"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
)
type PaymentService interface {
GetAvailablePaymentMethods(context.Context) ([]models.PaymentType, errors.Error)
}
type CommonControllerDeps struct {
Logger *zap.Logger
PaymentService PaymentService
}
type CommonController struct {
logger *zap.Logger
paymentService PaymentService
}
func NewCommonController(deps CommonControllerDeps) (*CommonController, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("Logger in nil on <NewCommonController>", errors.ErrInvalidArgs)
}
if deps.PaymentService == nil {
return nil, errors.NewWithMessage("PaymentService in nil on <NewCommonController>", errors.ErrInvalidArgs)
}
return &CommonController{
logger: deps.Logger,
paymentService: deps.PaymentService,
}, nil
}
func (receiver *CommonController) GetAvailablePayments(ctx echo.Context) error {
methods, err := receiver.paymentService.GetAvailablePaymentMethods(ctx.Request().Context())
if err != nil {
receiver.logger.Error("failed to get payment link on <GetAvailablePayments> of <CommonController>", zap.Error(err))
return errors.HTTP(ctx, err)
}
return ctx.JSON(http.StatusOK, methods)
}

@ -0,0 +1,137 @@
package rest
import (
"context"
"fmt"
"net/http"
"github.com/labstack/echo/v4"
"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/internal/utils/echotools"
)
type StatusService interface {
SetStatusCanceled(context.Context, string) (*models.Payment, errors.Error)
SetStatusSuccess(context.Context, string) (*models.Payment, errors.Error)
SetStatusWaiting(context.Context, string) (*models.Payment, errors.Error)
SetStatusRefund(context.Context, string) (*models.Payment, errors.Error)
}
type CallbackService interface {
OnSuccess(context.Context, *models.Event) errors.Error
OnFailure(context.Context, *models.Event) errors.Error
}
type YandexStatusControllerDeps struct {
Logger *zap.Logger
StatusService StatusService
CallbackService CallbackService
}
type YandexStatusController struct {
logger *zap.Logger
statusService StatusService
callbackService CallbackService
}
func NewYandexStatusController(deps YandexStatusControllerDeps) (*YandexStatusController, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("logger is nil on <NewYandexStatusController>", errors.ErrInvalidArgs)
}
if deps.StatusService == nil {
return nil, errors.NewWithMessage("StatusService is nil on <NewYandexStatusController>", errors.ErrInvalidArgs)
}
if deps.CallbackService == nil {
return nil, errors.NewWithMessage("CallbackService is nil on <NewYandexStatusController>", errors.ErrInvalidArgs)
}
return &YandexStatusController{
logger: deps.Logger,
statusService: deps.StatusService,
}, nil
}
func (receiver *YandexStatusController) SetPaymentStatusCanceled(ctx echo.Context) error {
request, err := echotools.Bind[yandex.WebhookNotification[yandex.Payment]](ctx)
if err != nil {
receiver.logger.Error("failed to parse body on <SetPaymentStatusCanceled> of <YandexStatusController>", zap.Error(err))
return errors.HTTP(ctx, errors.NewWithError(fmt.Errorf("failed to parse input body: %w", err), errors.ErrInternalError))
}
payment, setStatusErr := receiver.statusService.SetStatusCanceled(ctx.Request().Context(), request.Object.ID)
if setStatusErr != nil {
receiver.logger.Error("failed to set canceled payment status on <SetPaymentStatusCanceled> of <YandexStatusController>", zap.Error(setStatusErr))
return errors.HTTP(ctx, setStatusErr)
}
if err := receiver.callbackService.OnFailure(ctx.Request().Context(), &models.Event{
Key: string(request.Event),
Message: "yandex send event: payment canceled",
Payment: payment,
}); err != nil {
receiver.logger.Error("failed send success callback on <SetPaymentStatusSucceeded> of <YandexStatusController>", zap.Error(err))
return errors.HTTP(ctx, err)
}
return ctx.JSON(http.StatusOK, nil)
}
func (receiver *YandexStatusController) SetPaymentStatusSucceeded(ctx echo.Context) error {
request, err := echotools.Bind[yandex.WebhookNotification[yandex.Payment]](ctx)
if err != nil {
receiver.logger.Error("failed to parse body on <SetPaymentStatusSucceeded> of <YandexStatusController>", zap.Error(err))
return errors.HTTP(ctx, errors.NewWithError(fmt.Errorf("failed to parse input body: %w", err), errors.ErrInternalError))
}
payment, setStatusErr := receiver.statusService.SetStatusSuccess(ctx.Request().Context(), request.Object.ID)
if setStatusErr != nil {
receiver.logger.Error("failed to set success payment status on <SetPaymentStatusSucceeded> of <YandexStatusController>", zap.Error(setStatusErr))
return errors.HTTP(ctx, setStatusErr)
}
if err := receiver.callbackService.OnSuccess(ctx.Request().Context(), &models.Event{
Key: string(request.Event),
Message: "yandex send event: payment succeeded",
Payment: payment,
}); err != nil {
receiver.logger.Error("failed send success callback on <SetPaymentStatusSucceeded> of <YandexStatusController>", zap.Error(err))
return errors.HTTP(ctx, err)
}
return ctx.JSON(http.StatusOK, nil)
}
func (receiver *YandexStatusController) SetPaymentStatusWaiting(ctx echo.Context) error {
request, err := echotools.Bind[yandex.WebhookNotification[yandex.Payment]](ctx)
if err != nil {
receiver.logger.Error("failed to parse body on <SetPaymentStatusWaiting> of <YandexStatusController>", zap.Error(err))
return errors.HTTP(ctx, errors.NewWithError(fmt.Errorf("failed to parse input body: %w", err), errors.ErrInternalError))
}
if _, err := receiver.statusService.SetStatusWaiting(ctx.Request().Context(), request.Object.ID); err != nil {
receiver.logger.Error("failed to set waiting payment status on <SetPaymentStatusWaiting> of <YandexStatusController>", zap.Error(err))
return errors.HTTP(ctx, err)
}
return ctx.JSON(http.StatusOK, nil)
}
func (receiver *YandexStatusController) SetRefundStatusSucceeded(ctx echo.Context) error {
request, err := echotools.Bind[yandex.WebhookNotification[yandex.Payment]](ctx)
if err != nil {
receiver.logger.Error("failed to parse body on <SetRefundStatusSucceeded> of <YandexStatusController>", zap.Error(err))
return errors.HTTP(ctx, errors.NewWithError(fmt.Errorf("failed to parse input body: %w", err), errors.ErrInternalError))
}
if _, err := receiver.statusService.SetStatusRefund(ctx.Request().Context(), request.Object.ID); err != nil {
receiver.logger.Error("failed to set payment status refund on <SetRefundStatusSucceeded> of <YandexStatusController>", zap.Error(err))
return errors.HTTP(ctx, err)
}
return ctx.JSON(http.StatusOK, nil)
}

@ -0,0 +1,158 @@
package repository
import (
"context"
"fmt"
"time"
"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"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
)
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 <NewPaymentRepository>", errors.ErrInvalidArgs)
}
if deps.Collection == nil {
return nil, errors.NewWithMessage("Collection in nil on <NewPaymentRepository>", 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 <SetPaymentComplete> of <PaymentRepository>",
zap.Error(err),
zap.String("paymentID", paymentID),
)
removeErr := errors.NewWithError(
fmt.Errorf("failed to set payment complete with <%s> on <SetPaymentComplete> of <PaymentRepository>: %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 <Insert> of <PaymentRepository>",
zap.Any("payment", sanitizedPayment),
zap.Error(err),
)
return nil, errors.NewWithError(
fmt.Errorf("failed to insert payment on <Insert> of <AccountRepository>: %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 <SetPaymentStatus> of <PaymentRepository>",
zap.Error(err),
zap.String("paymentID", paymentID),
)
removeErr := errors.NewWithError(
fmt.Errorf("failed to set payment status with <%s> on <SetPaymentStatus> of <PaymentRepository>: %w", paymentID, err),
errors.ErrInternalError,
)
if err == mongo.ErrNoDocuments {
return nil, removeErr.SetType(errors.ErrNotFound)
}
return nil, removeErr
}
return &payment, nil
}

@ -0,0 +1,6 @@
package models
type ResponseErrorHTTP struct {
StatusCode int `json:"statusCode"`
Message string `json:"message"`
}

32
internal/models/config.go Normal file

@ -0,0 +1,32 @@
package models
import (
"penahub.gitlab.yandexcloud.net/external/treasurer/pkg/mongo"
)
type Config struct {
HTTP ConfigurationHTTP
GRPC ConfigurationGRPC
Service ServiceConfiguration
Database mongo.Configuration
}
type ConfigurationHTTP struct {
Host string `env:"HTTP_HOST,default=localhost"`
Port string `env:"HTTP_PORT,default=8080"`
Domen string `env:"HTTP_DOMEN,required"`
}
type ConfigurationGRPC struct {
Host string `env:"GRPC_HOST,default=0.0.0.0"`
Port string `env:"GRPC_PORT,default=8081"`
}
type ServiceConfiguration struct {
YoomomeyConfiguration YoomomeyConfiguration
}
type YoomomeyConfiguration struct {
StoreID string `env:"YOOMONEY_STORE_ID,required"`
SecretKey string `env:"YOOMONEY_SECRET_KEY,required"`
}

7
internal/models/event.go Normal file

@ -0,0 +1,7 @@
package models
type Event struct {
Key string
Message string
Payment *Payment
}

101
internal/models/payment.go Normal file

@ -0,0 +1,101 @@
package models
import (
"time"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models/yandex"
)
type Payment struct {
ID string `json:"id" bson:"_id,omitempty"`
UserID string `json:"userId" bson:"userId"`
PaymentID string `json:"paymentId" bson:"paymentId"`
IdempotencePaymentID string `json:"idempotencePaymentId" bson:"idempotencePaymentId"`
ClientIP string `json:"clientIp" bson:"clientIp"`
Currency string `json:"currency" bson:"currency"`
Amount int64 `json:"amount" bson:"amount"`
Type PaymentType `json:"type" bson:"type"`
Status PaymentStatus `json:"status" bson:"status"`
Completed bool `json:"completed" bson:"completed"`
IsDeleted bool `json:"isDeleted" bson:"isDeleted"`
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
DeletedAt *time.Time `json:"deletedAt,omitempty" bson:"deletedAt,omitempty"`
RawPaymentBody any `json:"rawPaymentBody,omitempty" bson:"rawPaymentBody,omitempty"`
/*
Список адресов в формате host:port, куда будет отправляться платёж при успешной операции
Запрос будет отправляться по протоколу GRPC
*/
CallbackHostGRPC []string `json:"callbackHostGrpc" bson:"callbackHostGrpc"`
}
func (receiver *Payment) Sanitize() *Payment {
now := time.Now()
receiver.ID = ""
receiver.CreatedAt = now
receiver.UpdatedAt = now
receiver.DeletedAt = nil
receiver.IsDeleted = false
receiver.Completed = false
return receiver
}
type CreatePaymentResult struct {
RedirectURL string
Payment *Payment
}
type CreatePayment[T any] struct {
Type PaymentType
Currency string
Amount int64
CallbackHostGRPC []string
ReturnURL string
UserID string
ClientIP string
Requisites T
}
type BankCard struct {
Number string
ExpiryYear string
ExpiryMonth string
CSC *string
CardHolderName *string
}
type PaymentType string
const (
PaymentTypeBankCard PaymentType = "bankCard"
PaymentTypeTinkoff PaymentType = "tinkoffBank"
PaymentTypeQiwi PaymentType = "qiwi"
PaymentTypeSberPay PaymentType = "sberbank"
PaymentTypeYoomoney PaymentType = "yoomoney"
PaymentTypeMobile PaymentType = "mobile"
PaymentTypeInstallments PaymentType = "installments"
PaymentTypeCash PaymentType = "cash"
PaymentTypeSBP PaymentType = "sbp"
PaymentTypeSberB2B PaymentType = "b2bSberbank"
PaymentTypeAlfabank PaymentType = "alfabank"
)
var (
YandexPaymentTypeMap = map[PaymentType]yandex.PaymentType{
PaymentTypeBankCard: yandex.PaymentTypeBankCard,
PaymentTypeTinkoff: yandex.PaymentTypeTinkoff,
PaymentTypeQiwi: yandex.PaymentTypeQiwi,
PaymentTypeSberPay: yandex.PaymentTypeSberPay,
PaymentTypeYoomoney: yandex.PaymentTypeYoomoney,
PaymentTypeMobile: yandex.PaymentTypeMobile,
PaymentTypeInstallments: yandex.PaymentTypeInstallments,
PaymentTypeCash: yandex.PaymentTypeCash,
PaymentTypeSBP: yandex.PaymentTypeSBP,
PaymentTypeSberB2B: yandex.PaymentTypeSberB2B,
PaymentTypeAlfabank: yandex.PaymentTypeAlfabank,
}
)

29
internal/models/status.go Normal file

@ -0,0 +1,29 @@
package models
import "penahub.gitlab.yandexcloud.net/external/treasurer/internal/models/yandex"
type PaymentStatus string
const (
PaymentStatusPending PaymentStatus = "pending"
PaymentStatusWaiting PaymentStatus = "waiting"
PaymentStatusSuccessfully PaymentStatus = "success"
PaymentStatusCanceled PaymentStatus = "canceled"
PaymentStatusRefund PaymentStatus = "refund"
)
var (
YandexPaymentStatusMap = map[PaymentStatus]yandex.PaymentStatus{
PaymentStatusPending: yandex.PaymentStatusPending,
PaymentStatusWaiting: yandex.PaymentStatusWaiting,
PaymentStatusSuccessfully: yandex.PaymentStatusSuccessfully,
PaymentStatusCanceled: yandex.PaymentStatusCanceled,
}
PaymentStatusMap = map[string]PaymentStatus{
string(yandex.PaymentStatusPending): PaymentStatusPending,
string(yandex.PaymentStatusWaiting): PaymentStatusWaiting,
string(yandex.PaymentStatusSuccessfully): PaymentStatusSuccessfully,
string(yandex.PaymentStatusCanceled): PaymentStatusCanceled,
}
)

@ -0,0 +1,14 @@
package yandex
type Amount struct {
Value string `json:"value" bson:"value"`
Currency string `json:"currency" bson:"currency"`
}
type BankCardInformation struct {
Number string `json:"number"`
ExpiryYear string `json:"expiry_year"`
ExpiryMonth string `json:"expiry_month"`
CSC string `json:"csc,omitempty"`
CardHolderName string `json:"cardholder,omitempty"`
}

@ -0,0 +1,44 @@
package yandex
// Payment description https://yookassa.ru/developers/api#payment_object
type Payment struct {
ID string `json:"id" bson:"id"`
Status PaymentStatus `json:"status" bson:"status"`
Amount Amount `json:"amount" bson:"amount"`
Confirmation *ConfirmationRedirect `json:"confirmation" bson:"confirmation"`
IncomeAmount *Amount `json:"income_amount,omitempty" bson:"income_amount,omitempty"`
Description string `json:"description,omitempty" bson:"description,omitempty"`
PaymentMethod any `json:"payment_method,omitempty" bson:"payment_method,omitempty"`
Recipient Recipient `json:"recipient" bson:"recipient"`
CapturedAt string `json:"captured_at,omitempty" bson:"captured_at,omitempty"`
ExpiresAt string `json:"expires_at,omitempty" bson:"expires_at,omitempty"`
CreatedAt string `json:"created_at" bson:"created_at"`
IsTest bool `json:"test" bson:"test"`
RefundedAmount *Amount `json:"refunded_amount,omitempty" bson:"refunded_amount,omitempty"`
IsPaid bool `json:"paid" bson:"paid"`
IsRefundable bool `json:"refundable" bson:"refundable"`
ReceiptRegistration string `json:"receipt_registration,omitempty" bson:"receipt_registration,omitempty"`
Metadata any `json:"metadata,omitempty" bson:"metadata,omitempty"`
CancellationDetails any `json:"cancellation_details,omitempty" bson:"cancellation_details,omitempty"`
AuthorizationDetails any `json:"authorization_details,omitempty" bson:"authorization_details,omitempty"`
Transfers []any `json:"transfers,omitempty" bson:"transfers,omitempty"`
Deal any `json:"deal,omitempty" bson:"deal,omitempty"`
MerchantCustomerID string `json:"merchant_customer_id,omitempty" bson:"merchant_customer_id,omitempty"`
}
type Recipient struct {
AccountID string `json:"account_id" bson:"account_id"`
GatewayID string `json:"gateway_id" bson:"gateway_id"`
}
type Confirmation struct {
}
type PaymentStatus string
const (
PaymentStatusPending PaymentStatus = "pending"
PaymentStatusWaiting PaymentStatus = "waiting_for_capture"
PaymentStatusSuccessfully PaymentStatus = "succeeded"
PaymentStatusCanceled PaymentStatus = "canceled"
)

@ -0,0 +1,55 @@
package yandex
type ConfirmationType string
const (
ConfirmationTypeEmbedded ConfirmationType = "embedded"
ConfirmationTypeExternal ConfirmationType = "external"
ConfirmationTypeMobile ConfirmationType = "mobile_application"
ConfirmationTypeQR ConfirmationType = "qr"
ConfirmationTypeRedirect ConfirmationType = "redirect"
)
type ConfirmationEmbedded struct {
Type ConfirmationType `json:"type"`
ConfirmationToken string `json:"confirmation_token"`
}
type ConfirmationExternal struct {
Type ConfirmationType `json:"type"`
}
type ConfirmationMobile struct {
Type ConfirmationType `json:"type"`
ConfirmationURL string `json:"confirmation_url"`
}
type ConfirmationQR struct {
Type ConfirmationType `json:"type"`
ConfirmationData string `json:"confirmation_data"`
}
type ConfirmationRedirect struct {
Type ConfirmationType `json:"type"`
ConfirmationURL string `json:"confirmation_url"`
ReturnURL *string `json:"return_url,omitempty"`
Enforce *bool `json:"enforce,omitempty"`
}
type CreateConfirmationLocale struct {
Type ConfirmationType `json:"type"`
Locale string `json:"locale,omitempty"`
}
type CreateConfirmationMobile struct {
Type ConfirmationType `json:"type"`
Locale string `json:"locale,omitempty"`
ReturnURL string `json:"return_url"`
}
type CreateConfirmationRedirect struct {
Type ConfirmationType `json:"type"`
Locale string `json:"locale,omitempty"`
ReturnURL string `json:"return_url"`
Enforce bool `json:"enforce,omitempty"`
}

@ -0,0 +1,19 @@
package yandex
// CreatePaymentRequest description https://yookassa.ru/developers/api#create_payment
type CreatePaymentRequest[T any] struct {
Amount Amount `json:"amount"`
Description string `json:"description,omitempty"`
PaymentMethodID *string `json:"payment_method_id,omitempty"`
PaymentMethodData *T `json:"payment_method_data,omitempty"`
Confirmation *CreateConfirmationRedirect `json:"confirmation,omitempty"`
SavePaymentMethod bool `json:"save_payment_method,omitempty"`
Capture bool `json:"capture,omitempty"`
ClientIP string `json:"client_ip,omitempty"`
Metadata any `json:"metadata,omitempty"`
Airline any `json:"airline,omitempty"`
Transfers []any `json:"transfers,omitempty"`
Deal any `json:"deal,omitempty"`
FraudData any `json:"fraud_data,omitempty"`
MerchantCustomerID any `json:"merchant_customer_id,omitempty"`
}

@ -0,0 +1,42 @@
package yandex
type PaymentType string
const (
PaymentTypeBankCard PaymentType = "bank_card"
PaymentTypeTinkoff PaymentType = "tinkoff_bank"
PaymentTypeQiwi PaymentType = "qiwi"
PaymentTypeSberPay PaymentType = "sberbank"
PaymentTypeYoomoney PaymentType = "yoo_money"
PaymentTypeMobile PaymentType = "mobile_balance"
PaymentTypeInstallments PaymentType = "installments"
PaymentTypeCash PaymentType = "cash"
PaymentTypeSBP PaymentType = "sbp"
PaymentTypeSberB2B PaymentType = "b2b_sberbank"
PaymentTypeAlfabank PaymentType = "alfabank"
)
type PaymentMethodBankCard struct {
Type PaymentType `json:"type"`
Card *BankCardInformation `json:"card,omitempty"`
}
type PaymentMethodLogin struct {
Type PaymentType `json:"type"`
Login string `json:"login,omitempty"`
}
type PaymentMethodB2B struct {
Type PaymentType `json:"type"`
PaymentPurpose string `json:"payment_purpose"`
VatData any `json:"vat_data"`
}
type PaymentMethodPhone struct {
Type PaymentType `json:"type"`
Phone string `json:"phone,omitempty"`
}
type PaymentMethodType struct {
Type PaymentType `json:"type"`
}

@ -0,0 +1,54 @@
package yandex
type WebhookEventType string
const (
/* Платеж перешел в статус ожидания. */
WebhookEventPaymentWaiting WebhookEventType = "payment.waiting_for_capture"
/* Платеж перешел в статус "Успешно". */
WebhookEventPaymentSucceeded WebhookEventType = "payment.succeeded"
/* Платеж перешел в статус "Отменён". */
WebhookEventPaymentCanceled WebhookEventType = "payment.canceled"
)
const (
/* Возврат перешел в статус "Успешно". */
WebhookEventRefundSucceeded WebhookEventType = "refund.succeeded"
)
const (
/* Сделка перешла в статус "Закрыта". */
WebhookEventDealClosed WebhookEventType = "deal.closed"
)
const (
/* Выплата перешла в статус "Отменено". */
WebhookEventPayoutCanceled WebhookEventType = "payout.canceled"
/* Выплата перешла в статус "Успешно". */
WebhookEventPayoutSucceeded WebhookEventType = "payout.succeeded"
)
type CreateWebhookRequest struct {
Event WebhookEventType `json:"event"`
URL string `json:"url"`
}
type GetWebhooksResponse struct {
Type string `json:"type"`
Webhooks []Webhook `json:"items"`
}
type Webhook struct {
ID string `json:"id"`
Event WebhookEventType `json:"event"`
URL string `json:"url"`
}
type WebhookNotification[T any] struct {
Type string `json:"type"`
Event WebhookEventType `json:"event"`
Object T `json:"object"`
}

@ -0,0 +1,325 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc (unknown)
// source: callback/service.proto
package payment_callback
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
_ "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type Event struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key string `protobuf:"bytes,1,opt,name=Key,proto3" json:"Key,omitempty"`
Message string `protobuf:"bytes,2,opt,name=Message,proto3" json:"Message,omitempty"`
Payment *Payment `protobuf:"bytes,3,opt,name=Payment,proto3" json:"Payment,omitempty"`
}
func (x *Event) Reset() {
*x = Event{}
if protoimpl.UnsafeEnabled {
mi := &file_callback_service_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Event) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Event) ProtoMessage() {}
func (x *Event) ProtoReflect() protoreflect.Message {
mi := &file_callback_service_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Event.ProtoReflect.Descriptor instead.
func (*Event) Descriptor() ([]byte, []int) {
return file_callback_service_proto_rawDescGZIP(), []int{0}
}
func (x *Event) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (x *Event) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *Event) GetPayment() *Payment {
if x != nil {
return x.Payment
}
return nil
}
type Payment struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
UserID string `protobuf:"bytes,2,opt,name=UserID,proto3" json:"UserID,omitempty"`
PaymentID string `protobuf:"bytes,3,opt,name=PaymentID,proto3" json:"PaymentID,omitempty"`
IdempotencePaymentID string `protobuf:"bytes,4,opt,name=IdempotencePaymentID,proto3" json:"IdempotencePaymentID,omitempty"`
Amount int64 `protobuf:"varint,5,opt,name=Amount,proto3" json:"Amount,omitempty"`
Currency string `protobuf:"bytes,6,opt,name=Currency,proto3" json:"Currency,omitempty"`
Type string `protobuf:"bytes,7,opt,name=Type,proto3" json:"Type,omitempty"`
Status string `protobuf:"bytes,8,opt,name=Status,proto3" json:"Status,omitempty"`
Completed bool `protobuf:"varint,9,opt,name=Completed,proto3" json:"Completed,omitempty"`
}
func (x *Payment) Reset() {
*x = Payment{}
if protoimpl.UnsafeEnabled {
mi := &file_callback_service_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Payment) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Payment) ProtoMessage() {}
func (x *Payment) ProtoReflect() protoreflect.Message {
mi := &file_callback_service_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Payment.ProtoReflect.Descriptor instead.
func (*Payment) Descriptor() ([]byte, []int) {
return file_callback_service_proto_rawDescGZIP(), []int{1}
}
func (x *Payment) GetID() string {
if x != nil {
return x.ID
}
return ""
}
func (x *Payment) GetUserID() string {
if x != nil {
return x.UserID
}
return ""
}
func (x *Payment) GetPaymentID() string {
if x != nil {
return x.PaymentID
}
return ""
}
func (x *Payment) GetIdempotencePaymentID() string {
if x != nil {
return x.IdempotencePaymentID
}
return ""
}
func (x *Payment) GetAmount() int64 {
if x != nil {
return x.Amount
}
return 0
}
func (x *Payment) GetCurrency() string {
if x != nil {
return x.Currency
}
return ""
}
func (x *Payment) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *Payment) GetStatus() string {
if x != nil {
return x.Status
}
return ""
}
func (x *Payment) GetCompleted() bool {
if x != nil {
return x.Completed
}
return false
}
var File_callback_service_proto protoreflect.FileDescriptor
var file_callback_service_proto_rawDesc = []byte{
0x0a, 0x16, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x10, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e,
0x74, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74,
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x68, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e,
0x74, 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x33, 0x0a,
0x07, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19,
0x2e, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
0x6b, 0x2e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x07, 0x50, 0x61, 0x79, 0x6d, 0x65,
0x6e, 0x74, 0x22, 0x81, 0x02, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x0e,
0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x16,
0x0a, 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e,
0x74, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x79, 0x6d, 0x65,
0x6e, 0x74, 0x49, 0x44, 0x12, 0x32, 0x0a, 0x14, 0x49, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65,
0x6e, 0x63, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x52, 0x14, 0x49, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x50,
0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75,
0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
0x12, 0x1a, 0x0a, 0x08, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x06, 0x20, 0x01,
0x28, 0x09, 0x52, 0x08, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x12, 0x0a, 0x04,
0x54, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65,
0x12, 0x16, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
0x52, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x43, 0x6f, 0x6d, 0x70,
0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x43, 0x6f, 0x6d,
0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x32, 0x98, 0x01, 0x0a, 0x16, 0x50, 0x61, 0x79, 0x6d, 0x65,
0x6e, 0x74, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x12, 0x3e, 0x0a, 0x09, 0x4f, 0x6e, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x17,
0x2e, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
0x6b, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
0x00, 0x12, 0x3e, 0x0a, 0x09, 0x4f, 0x6e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x17,
0x2e, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
0x6b, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
0x00, 0x42, 0x14, 0x5a, 0x12, 0x2e, 0x2f, 0x70, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x63,
0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_callback_service_proto_rawDescOnce sync.Once
file_callback_service_proto_rawDescData = file_callback_service_proto_rawDesc
)
func file_callback_service_proto_rawDescGZIP() []byte {
file_callback_service_proto_rawDescOnce.Do(func() {
file_callback_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_callback_service_proto_rawDescData)
})
return file_callback_service_proto_rawDescData
}
var file_callback_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_callback_service_proto_goTypes = []interface{}{
(*Event)(nil), // 0: payment_callback.Event
(*Payment)(nil), // 1: payment_callback.Payment
(*emptypb.Empty)(nil), // 2: google.protobuf.Empty
}
var file_callback_service_proto_depIdxs = []int32{
1, // 0: payment_callback.Event.Payment:type_name -> payment_callback.Payment
0, // 1: payment_callback.PaymentCallbackService.OnSuccess:input_type -> payment_callback.Event
0, // 2: payment_callback.PaymentCallbackService.OnFailure:input_type -> payment_callback.Event
2, // 3: payment_callback.PaymentCallbackService.OnSuccess:output_type -> google.protobuf.Empty
2, // 4: payment_callback.PaymentCallbackService.OnFailure:output_type -> google.protobuf.Empty
3, // [3:5] is the sub-list for method output_type
1, // [1:3] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_callback_service_proto_init() }
func file_callback_service_proto_init() {
if File_callback_service_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_callback_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Event); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_callback_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Payment); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_callback_service_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_callback_service_proto_goTypes,
DependencyIndexes: file_callback_service_proto_depIdxs,
MessageInfos: file_callback_service_proto_msgTypes,
}.Build()
File_callback_service_proto = out.File
file_callback_service_proto_rawDesc = nil
file_callback_service_proto_goTypes = nil
file_callback_service_proto_depIdxs = nil
}

@ -0,0 +1,136 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package payment_callback
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// PaymentCallbackServiceClient is the client API for PaymentCallbackService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type PaymentCallbackServiceClient interface {
OnSuccess(ctx context.Context, in *Event, opts ...grpc.CallOption) (*emptypb.Empty, error)
OnFailure(ctx context.Context, in *Event, opts ...grpc.CallOption) (*emptypb.Empty, error)
}
type paymentCallbackServiceClient struct {
cc grpc.ClientConnInterface
}
func NewPaymentCallbackServiceClient(cc grpc.ClientConnInterface) PaymentCallbackServiceClient {
return &paymentCallbackServiceClient{cc}
}
func (c *paymentCallbackServiceClient) OnSuccess(ctx context.Context, in *Event, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/payment_callback.PaymentCallbackService/OnSuccess", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *paymentCallbackServiceClient) OnFailure(ctx context.Context, in *Event, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/payment_callback.PaymentCallbackService/OnFailure", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// PaymentCallbackServiceServer is the server API for PaymentCallbackService service.
// All implementations should embed UnimplementedPaymentCallbackServiceServer
// for forward compatibility
type PaymentCallbackServiceServer interface {
OnSuccess(context.Context, *Event) (*emptypb.Empty, error)
OnFailure(context.Context, *Event) (*emptypb.Empty, error)
}
// UnimplementedPaymentCallbackServiceServer should be embedded to have forward compatible implementations.
type UnimplementedPaymentCallbackServiceServer struct {
}
func (UnimplementedPaymentCallbackServiceServer) OnSuccess(context.Context, *Event) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method OnSuccess not implemented")
}
func (UnimplementedPaymentCallbackServiceServer) OnFailure(context.Context, *Event) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method OnFailure not implemented")
}
// UnsafePaymentCallbackServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to PaymentCallbackServiceServer will
// result in compilation errors.
type UnsafePaymentCallbackServiceServer interface {
mustEmbedUnimplementedPaymentCallbackServiceServer()
}
func RegisterPaymentCallbackServiceServer(s grpc.ServiceRegistrar, srv PaymentCallbackServiceServer) {
s.RegisterService(&PaymentCallbackService_ServiceDesc, srv)
}
func _PaymentCallbackService_OnSuccess_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Event)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PaymentCallbackServiceServer).OnSuccess(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/payment_callback.PaymentCallbackService/OnSuccess",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PaymentCallbackServiceServer).OnSuccess(ctx, req.(*Event))
}
return interceptor(ctx, in, info, handler)
}
func _PaymentCallbackService_OnFailure_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Event)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(PaymentCallbackServiceServer).OnFailure(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/payment_callback.PaymentCallbackService/OnFailure",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(PaymentCallbackServiceServer).OnFailure(ctx, req.(*Event))
}
return interceptor(ctx, in, info, handler)
}
// PaymentCallbackService_ServiceDesc is the grpc.ServiceDesc for PaymentCallbackService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var PaymentCallbackService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "payment_callback.PaymentCallbackService",
HandlerType: (*PaymentCallbackServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "OnSuccess",
Handler: _PaymentCallbackService_OnSuccess_Handler,
},
{
MethodName: "OnFailure",
Handler: _PaymentCallbackService_OnFailure_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "callback/service.proto",
}

@ -0,0 +1,531 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc (unknown)
// source: treasurer/payment.model.proto
package treasurer
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
anypb "google.golang.org/protobuf/types/known/anypb"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type MainPaymentSettings struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Currency string `protobuf:"bytes,1,opt,name=Currency,proto3" json:"Currency,omitempty"`
Amount int64 `protobuf:"varint,2,opt,name=Amount,proto3" json:"Amount,omitempty"`
CallbackHostGRPC []string `protobuf:"bytes,3,rep,name=CallbackHostGRPC,proto3" json:"CallbackHostGRPC,omitempty"`
ReturnURL string `protobuf:"bytes,4,opt,name=ReturnURL,proto3" json:"ReturnURL,omitempty"`
UserID string `protobuf:"bytes,5,opt,name=UserID,proto3" json:"UserID,omitempty"`
ClientIP string `protobuf:"bytes,6,opt,name=ClientIP,proto3" json:"ClientIP,omitempty"`
}
func (x *MainPaymentSettings) Reset() {
*x = MainPaymentSettings{}
if protoimpl.UnsafeEnabled {
mi := &file_treasurer_payment_model_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *MainPaymentSettings) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MainPaymentSettings) ProtoMessage() {}
func (x *MainPaymentSettings) ProtoReflect() protoreflect.Message {
mi := &file_treasurer_payment_model_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use MainPaymentSettings.ProtoReflect.Descriptor instead.
func (*MainPaymentSettings) Descriptor() ([]byte, []int) {
return file_treasurer_payment_model_proto_rawDescGZIP(), []int{0}
}
func (x *MainPaymentSettings) GetCurrency() string {
if x != nil {
return x.Currency
}
return ""
}
func (x *MainPaymentSettings) GetAmount() int64 {
if x != nil {
return x.Amount
}
return 0
}
func (x *MainPaymentSettings) GetCallbackHostGRPC() []string {
if x != nil {
return x.CallbackHostGRPC
}
return nil
}
func (x *MainPaymentSettings) GetReturnURL() string {
if x != nil {
return x.ReturnURL
}
return ""
}
func (x *MainPaymentSettings) GetUserID() string {
if x != nil {
return x.UserID
}
return ""
}
func (x *MainPaymentSettings) GetClientIP() string {
if x != nil {
return x.ClientIP
}
return ""
}
type BankCardInformation struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Number string `protobuf:"bytes,1,opt,name=Number,proto3" json:"Number,omitempty"`
ExpiryYear string `protobuf:"bytes,2,opt,name=ExpiryYear,proto3" json:"ExpiryYear,omitempty"`
ExpiryMonth string `protobuf:"bytes,3,opt,name=ExpiryMonth,proto3" json:"ExpiryMonth,omitempty"`
CSC *string `protobuf:"bytes,4,opt,name=CSC,proto3,oneof" json:"CSC,omitempty"`
CardHolderName *string `protobuf:"bytes,5,opt,name=CardHolderName,proto3,oneof" json:"CardHolderName,omitempty"`
}
func (x *BankCardInformation) Reset() {
*x = BankCardInformation{}
if protoimpl.UnsafeEnabled {
mi := &file_treasurer_payment_model_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BankCardInformation) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BankCardInformation) ProtoMessage() {}
func (x *BankCardInformation) ProtoReflect() protoreflect.Message {
mi := &file_treasurer_payment_model_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BankCardInformation.ProtoReflect.Descriptor instead.
func (*BankCardInformation) Descriptor() ([]byte, []int) {
return file_treasurer_payment_model_proto_rawDescGZIP(), []int{1}
}
func (x *BankCardInformation) GetNumber() string {
if x != nil {
return x.Number
}
return ""
}
func (x *BankCardInformation) GetExpiryYear() string {
if x != nil {
return x.ExpiryYear
}
return ""
}
func (x *BankCardInformation) GetExpiryMonth() string {
if x != nil {
return x.ExpiryMonth
}
return ""
}
func (x *BankCardInformation) GetCSC() string {
if x != nil && x.CSC != nil {
return *x.CSC
}
return ""
}
func (x *BankCardInformation) GetCardHolderName() string {
if x != nil && x.CardHolderName != nil {
return *x.CardHolderName
}
return ""
}
type Payment struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
UserID string `protobuf:"bytes,2,opt,name=UserID,proto3" json:"UserID,omitempty"`
PaymentID string `protobuf:"bytes,3,opt,name=PaymentID,proto3" json:"PaymentID,omitempty"`
IdempotencePaymentID string `protobuf:"bytes,4,opt,name=IdempotencePaymentID,proto3" json:"IdempotencePaymentID,omitempty"`
ClientIP string `protobuf:"bytes,5,opt,name=ClientIP,proto3" json:"ClientIP,omitempty"`
Currency string `protobuf:"bytes,6,opt,name=Currency,proto3" json:"Currency,omitempty"`
Amount int64 `protobuf:"varint,7,opt,name=Amount,proto3" json:"Amount,omitempty"`
Type string `protobuf:"bytes,8,opt,name=Type,proto3" json:"Type,omitempty"`
Status string `protobuf:"bytes,9,opt,name=Status,proto3" json:"Status,omitempty"`
RawPaymentBody *anypb.Any `protobuf:"bytes,10,opt,name=RawPaymentBody,proto3" json:"RawPaymentBody,omitempty"`
CallbackHostGRPC []string `protobuf:"bytes,11,rep,name=CallbackHostGRPC,proto3" json:"CallbackHostGRPC,omitempty"`
Completed bool `protobuf:"varint,12,opt,name=Completed,proto3" json:"Completed,omitempty"`
IsDeleted bool `protobuf:"varint,13,opt,name=IsDeleted,proto3" json:"IsDeleted,omitempty"`
UpdatedAt *timestamppb.Timestamp `protobuf:"bytes,14,opt,name=UpdatedAt,proto3" json:"UpdatedAt,omitempty"`
CreatedAt *timestamppb.Timestamp `protobuf:"bytes,15,opt,name=CreatedAt,proto3" json:"CreatedAt,omitempty"`
DeletedAt *timestamppb.Timestamp `protobuf:"bytes,16,opt,name=DeletedAt,proto3,oneof" json:"DeletedAt,omitempty"`
}
func (x *Payment) Reset() {
*x = Payment{}
if protoimpl.UnsafeEnabled {
mi := &file_treasurer_payment_model_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Payment) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Payment) ProtoMessage() {}
func (x *Payment) ProtoReflect() protoreflect.Message {
mi := &file_treasurer_payment_model_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Payment.ProtoReflect.Descriptor instead.
func (*Payment) Descriptor() ([]byte, []int) {
return file_treasurer_payment_model_proto_rawDescGZIP(), []int{2}
}
func (x *Payment) GetID() string {
if x != nil {
return x.ID
}
return ""
}
func (x *Payment) GetUserID() string {
if x != nil {
return x.UserID
}
return ""
}
func (x *Payment) GetPaymentID() string {
if x != nil {
return x.PaymentID
}
return ""
}
func (x *Payment) GetIdempotencePaymentID() string {
if x != nil {
return x.IdempotencePaymentID
}
return ""
}
func (x *Payment) GetClientIP() string {
if x != nil {
return x.ClientIP
}
return ""
}
func (x *Payment) GetCurrency() string {
if x != nil {
return x.Currency
}
return ""
}
func (x *Payment) GetAmount() int64 {
if x != nil {
return x.Amount
}
return 0
}
func (x *Payment) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *Payment) GetStatus() string {
if x != nil {
return x.Status
}
return ""
}
func (x *Payment) GetRawPaymentBody() *anypb.Any {
if x != nil {
return x.RawPaymentBody
}
return nil
}
func (x *Payment) GetCallbackHostGRPC() []string {
if x != nil {
return x.CallbackHostGRPC
}
return nil
}
func (x *Payment) GetCompleted() bool {
if x != nil {
return x.Completed
}
return false
}
func (x *Payment) GetIsDeleted() bool {
if x != nil {
return x.IsDeleted
}
return false
}
func (x *Payment) GetUpdatedAt() *timestamppb.Timestamp {
if x != nil {
return x.UpdatedAt
}
return nil
}
func (x *Payment) GetCreatedAt() *timestamppb.Timestamp {
if x != nil {
return x.CreatedAt
}
return nil
}
func (x *Payment) GetDeletedAt() *timestamppb.Timestamp {
if x != nil {
return x.DeletedAt
}
return nil
}
var File_treasurer_payment_model_proto protoreflect.FileDescriptor
var file_treasurer_payment_model_proto_rawDesc = []byte{
0x0a, 0x1d, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2f, 0x70, 0x61, 0x79, 0x6d,
0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x09, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc7, 0x01, 0x0a, 0x13, 0x4d, 0x61, 0x69, 0x6e, 0x50,
0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x1a,
0x0a, 0x08, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x41, 0x6d,
0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x41, 0x6d, 0x6f, 0x75,
0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x10, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x48, 0x6f,
0x73, 0x74, 0x47, 0x52, 0x50, 0x43, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x43, 0x61,
0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x48, 0x6f, 0x73, 0x74, 0x47, 0x52, 0x50, 0x43, 0x12, 0x1c,
0x0a, 0x09, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x55, 0x52, 0x4c, 0x18, 0x04, 0x20, 0x01, 0x28,
0x09, 0x52, 0x09, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x55, 0x52, 0x4c, 0x12, 0x16, 0x0a, 0x06,
0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x55, 0x73,
0x65, 0x72, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x50,
0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x50,
0x22, 0xce, 0x01, 0x0a, 0x13, 0x42, 0x61, 0x6e, 0x6b, 0x43, 0x61, 0x72, 0x64, 0x49, 0x6e, 0x66,
0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x4e, 0x75, 0x6d, 0x62,
0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72,
0x12, 0x1e, 0x0a, 0x0a, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x59, 0x65, 0x61, 0x72, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x59, 0x65, 0x61, 0x72,
0x12, 0x20, 0x0a, 0x0b, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x4d, 0x6f, 0x6e,
0x74, 0x68, 0x12, 0x15, 0x0a, 0x03, 0x43, 0x53, 0x43, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48,
0x00, 0x52, 0x03, 0x43, 0x53, 0x43, 0x88, 0x01, 0x01, 0x12, 0x2b, 0x0a, 0x0e, 0x43, 0x61, 0x72,
0x64, 0x48, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28,
0x09, 0x48, 0x01, 0x52, 0x0e, 0x43, 0x61, 0x72, 0x64, 0x48, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x4e,
0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x43, 0x53, 0x43, 0x42, 0x11,
0x0a, 0x0f, 0x5f, 0x43, 0x61, 0x72, 0x64, 0x48, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x4e, 0x61, 0x6d,
0x65, 0x22, 0xe6, 0x04, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a,
0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x16, 0x0a,
0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x55,
0x73, 0x65, 0x72, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74,
0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e,
0x74, 0x49, 0x44, 0x12, 0x32, 0x0a, 0x14, 0x49, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65, 0x6e,
0x63, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x04, 0x20, 0x01, 0x28,
0x09, 0x52, 0x14, 0x49, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x50, 0x61,
0x79, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x49, 0x50, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e,
0x74, 0x49, 0x50, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18,
0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12,
0x16, 0x0a, 0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52,
0x06, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18,
0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x53,
0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x53, 0x74, 0x61,
0x74, 0x75, 0x73, 0x12, 0x3c, 0x0a, 0x0e, 0x52, 0x61, 0x77, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e,
0x74, 0x42, 0x6f, 0x64, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e,
0x79, 0x52, 0x0e, 0x52, 0x61, 0x77, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x6f, 0x64,
0x79, 0x12, 0x2a, 0x0a, 0x10, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x48, 0x6f, 0x73,
0x74, 0x47, 0x52, 0x50, 0x43, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x43, 0x61, 0x6c,
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x48, 0x6f, 0x73, 0x74, 0x47, 0x52, 0x50, 0x43, 0x12, 0x1c, 0x0a,
0x09, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08,
0x52, 0x09, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x49,
0x73, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09,
0x49, 0x73, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x09, 0x55, 0x70, 0x64,
0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
0x64, 0x41, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74,
0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x52, 0x09, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x3d, 0x0a,
0x09, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x48, 0x00, 0x52, 0x09,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x88, 0x01, 0x01, 0x42, 0x0c, 0x0a, 0x0a,
0x5f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x41, 0x74, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x2f,
0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
file_treasurer_payment_model_proto_rawDescOnce sync.Once
file_treasurer_payment_model_proto_rawDescData = file_treasurer_payment_model_proto_rawDesc
)
func file_treasurer_payment_model_proto_rawDescGZIP() []byte {
file_treasurer_payment_model_proto_rawDescOnce.Do(func() {
file_treasurer_payment_model_proto_rawDescData = protoimpl.X.CompressGZIP(file_treasurer_payment_model_proto_rawDescData)
})
return file_treasurer_payment_model_proto_rawDescData
}
var file_treasurer_payment_model_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_treasurer_payment_model_proto_goTypes = []interface{}{
(*MainPaymentSettings)(nil), // 0: treasurer.MainPaymentSettings
(*BankCardInformation)(nil), // 1: treasurer.BankCardInformation
(*Payment)(nil), // 2: treasurer.Payment
(*anypb.Any)(nil), // 3: google.protobuf.Any
(*timestamppb.Timestamp)(nil), // 4: google.protobuf.Timestamp
}
var file_treasurer_payment_model_proto_depIdxs = []int32{
3, // 0: treasurer.Payment.RawPaymentBody:type_name -> google.protobuf.Any
4, // 1: treasurer.Payment.UpdatedAt:type_name -> google.protobuf.Timestamp
4, // 2: treasurer.Payment.CreatedAt:type_name -> google.protobuf.Timestamp
4, // 3: treasurer.Payment.DeletedAt:type_name -> google.protobuf.Timestamp
4, // [4:4] is the sub-list for method output_type
4, // [4:4] is the sub-list for method input_type
4, // [4:4] is the sub-list for extension type_name
4, // [4:4] is the sub-list for extension extendee
0, // [0:4] is the sub-list for field type_name
}
func init() { file_treasurer_payment_model_proto_init() }
func file_treasurer_payment_model_proto_init() {
if File_treasurer_payment_model_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_treasurer_payment_model_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MainPaymentSettings); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_treasurer_payment_model_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BankCardInformation); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_treasurer_payment_model_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Payment); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
file_treasurer_payment_model_proto_msgTypes[1].OneofWrappers = []interface{}{}
file_treasurer_payment_model_proto_msgTypes[2].OneofWrappers = []interface{}{}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_treasurer_payment_model_proto_rawDesc,
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_treasurer_payment_model_proto_goTypes,
DependencyIndexes: file_treasurer_payment_model_proto_depIdxs,
MessageInfos: file_treasurer_payment_model_proto_msgTypes,
}.Build()
File_treasurer_payment_model_proto = out.File
file_treasurer_payment_model_proto_rawDesc = nil
file_treasurer_payment_model_proto_goTypes = nil
file_treasurer_payment_model_proto_depIdxs = nil
}

@ -0,0 +1,634 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc (unknown)
// source: treasurer/service.proto
package treasurer
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type GetBankCardPaymentLinkRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
MainSettings *MainPaymentSettings `protobuf:"bytes,1,opt,name=MainSettings,proto3" json:"MainSettings,omitempty"`
BankCard *BankCardInformation `protobuf:"bytes,2,opt,name=BankCard,proto3" json:"BankCard,omitempty"`
}
func (x *GetBankCardPaymentLinkRequest) Reset() {
*x = GetBankCardPaymentLinkRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_treasurer_service_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetBankCardPaymentLinkRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetBankCardPaymentLinkRequest) ProtoMessage() {}
func (x *GetBankCardPaymentLinkRequest) ProtoReflect() protoreflect.Message {
mi := &file_treasurer_service_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetBankCardPaymentLinkRequest.ProtoReflect.Descriptor instead.
func (*GetBankCardPaymentLinkRequest) Descriptor() ([]byte, []int) {
return file_treasurer_service_proto_rawDescGZIP(), []int{0}
}
func (x *GetBankCardPaymentLinkRequest) GetMainSettings() *MainPaymentSettings {
if x != nil {
return x.MainSettings
}
return nil
}
func (x *GetBankCardPaymentLinkRequest) GetBankCard() *BankCardInformation {
if x != nil {
return x.BankCard
}
return nil
}
type GetPaymentLinkRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
MainSettings *MainPaymentSettings `protobuf:"bytes,1,opt,name=MainSettings,proto3" json:"MainSettings,omitempty"`
}
func (x *GetPaymentLinkRequest) Reset() {
*x = GetPaymentLinkRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_treasurer_service_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetPaymentLinkRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetPaymentLinkRequest) ProtoMessage() {}
func (x *GetPaymentLinkRequest) ProtoReflect() protoreflect.Message {
mi := &file_treasurer_service_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetPaymentLinkRequest.ProtoReflect.Descriptor instead.
func (*GetPaymentLinkRequest) Descriptor() ([]byte, []int) {
return file_treasurer_service_proto_rawDescGZIP(), []int{1}
}
func (x *GetPaymentLinkRequest) GetMainSettings() *MainPaymentSettings {
if x != nil {
return x.MainSettings
}
return nil
}
type GetPhonePaymentLinkRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
MainSettings *MainPaymentSettings `protobuf:"bytes,1,opt,name=MainSettings,proto3" json:"MainSettings,omitempty"`
Phone string `protobuf:"bytes,2,opt,name=Phone,proto3" json:"Phone,omitempty"`
}
func (x *GetPhonePaymentLinkRequest) Reset() {
*x = GetPhonePaymentLinkRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_treasurer_service_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetPhonePaymentLinkRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetPhonePaymentLinkRequest) ProtoMessage() {}
func (x *GetPhonePaymentLinkRequest) ProtoReflect() protoreflect.Message {
mi := &file_treasurer_service_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetPhonePaymentLinkRequest.ProtoReflect.Descriptor instead.
func (*GetPhonePaymentLinkRequest) Descriptor() ([]byte, []int) {
return file_treasurer_service_proto_rawDescGZIP(), []int{2}
}
func (x *GetPhonePaymentLinkRequest) GetMainSettings() *MainPaymentSettings {
if x != nil {
return x.MainSettings
}
return nil
}
func (x *GetPhonePaymentLinkRequest) GetPhone() string {
if x != nil {
return x.Phone
}
return ""
}
type GetLoginPaymentLinkRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
MainSettings *MainPaymentSettings `protobuf:"bytes,1,opt,name=MainSettings,proto3" json:"MainSettings,omitempty"`
Login string `protobuf:"bytes,2,opt,name=Login,proto3" json:"Login,omitempty"`
}
func (x *GetLoginPaymentLinkRequest) Reset() {
*x = GetLoginPaymentLinkRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_treasurer_service_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetLoginPaymentLinkRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetLoginPaymentLinkRequest) ProtoMessage() {}
func (x *GetLoginPaymentLinkRequest) ProtoReflect() protoreflect.Message {
mi := &file_treasurer_service_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetLoginPaymentLinkRequest.ProtoReflect.Descriptor instead.
func (*GetLoginPaymentLinkRequest) Descriptor() ([]byte, []int) {
return file_treasurer_service_proto_rawDescGZIP(), []int{3}
}
func (x *GetLoginPaymentLinkRequest) GetMainSettings() *MainPaymentSettings {
if x != nil {
return x.MainSettings
}
return nil
}
func (x *GetLoginPaymentLinkRequest) GetLogin() string {
if x != nil {
return x.Login
}
return ""
}
type GetB2BPaymentLinkRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
MainSettings *MainPaymentSettings `protobuf:"bytes,1,opt,name=MainSettings,proto3" json:"MainSettings,omitempty"`
PaymentPurpose string `protobuf:"bytes,2,opt,name=PaymentPurpose,proto3" json:"PaymentPurpose,omitempty"`
VatData *emptypb.Empty `protobuf:"bytes,3,opt,name=VatData,proto3" json:"VatData,omitempty"`
}
func (x *GetB2BPaymentLinkRequest) Reset() {
*x = GetB2BPaymentLinkRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_treasurer_service_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetB2BPaymentLinkRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetB2BPaymentLinkRequest) ProtoMessage() {}
func (x *GetB2BPaymentLinkRequest) ProtoReflect() protoreflect.Message {
mi := &file_treasurer_service_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetB2BPaymentLinkRequest.ProtoReflect.Descriptor instead.
func (*GetB2BPaymentLinkRequest) Descriptor() ([]byte, []int) {
return file_treasurer_service_proto_rawDescGZIP(), []int{4}
}
func (x *GetB2BPaymentLinkRequest) GetMainSettings() *MainPaymentSettings {
if x != nil {
return x.MainSettings
}
return nil
}
func (x *GetB2BPaymentLinkRequest) GetPaymentPurpose() string {
if x != nil {
return x.PaymentPurpose
}
return ""
}
func (x *GetB2BPaymentLinkRequest) GetVatData() *emptypb.Empty {
if x != nil {
return x.VatData
}
return nil
}
type GetPaymentLinkResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
RedirectURL string `protobuf:"bytes,1,opt,name=RedirectURL,proto3" json:"RedirectURL,omitempty"`
}
func (x *GetPaymentLinkResponse) Reset() {
*x = GetPaymentLinkResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_treasurer_service_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GetPaymentLinkResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetPaymentLinkResponse) ProtoMessage() {}
func (x *GetPaymentLinkResponse) ProtoReflect() protoreflect.Message {
mi := &file_treasurer_service_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetPaymentLinkResponse.ProtoReflect.Descriptor instead.
func (*GetPaymentLinkResponse) Descriptor() ([]byte, []int) {
return file_treasurer_service_proto_rawDescGZIP(), []int{5}
}
func (x *GetPaymentLinkResponse) GetRedirectURL() string {
if x != nil {
return x.RedirectURL
}
return ""
}
var File_treasurer_service_proto protoreflect.FileDescriptor
var file_treasurer_service_proto_rawDesc = []byte{
0x0a, 0x17, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2f, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x74, 0x72, 0x65, 0x61, 0x73,
0x75, 0x72, 0x65, 0x72, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x1a, 0x1d, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2f, 0x70, 0x61, 0x79,
0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x22, 0x9f, 0x01, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6e, 0x6b, 0x43, 0x61, 0x72, 0x64,
0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x12, 0x42, 0x0a, 0x0c, 0x4d, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73,
0x75, 0x72, 0x65, 0x72, 0x2e, 0x4d, 0x61, 0x69, 0x6e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74,
0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0c, 0x4d, 0x61, 0x69, 0x6e, 0x53, 0x65,
0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x3a, 0x0a, 0x08, 0x42, 0x61, 0x6e, 0x6b, 0x43, 0x61,
0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73,
0x75, 0x72, 0x65, 0x72, 0x2e, 0x42, 0x61, 0x6e, 0x6b, 0x43, 0x61, 0x72, 0x64, 0x49, 0x6e, 0x66,
0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x42, 0x61, 0x6e, 0x6b, 0x43, 0x61,
0x72, 0x64, 0x22, 0x5b, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74,
0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0c, 0x4d,
0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x4d, 0x61,
0x69, 0x6e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x73, 0x52, 0x0c, 0x4d, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22,
0x76, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65,
0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a,
0x0c, 0x4d, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e,
0x4d, 0x61, 0x69, 0x6e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69,
0x6e, 0x67, 0x73, 0x52, 0x0c, 0x4d, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67,
0x73, 0x12, 0x14, 0x0a, 0x05, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x05, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x22, 0x76, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x4c, 0x6f,
0x67, 0x69, 0x6e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0c, 0x4d, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74,
0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x72,
0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x4d, 0x61, 0x69, 0x6e, 0x50, 0x61, 0x79, 0x6d,
0x65, 0x6e, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x52, 0x0c, 0x4d, 0x61, 0x69,
0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x4c, 0x6f, 0x67,
0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x22,
0xb8, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x42, 0x32, 0x42, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e,
0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x0c,
0x4d, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x4d,
0x61, 0x69, 0x6e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
0x67, 0x73, 0x52, 0x0c, 0x4d, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73,
0x12, 0x26, 0x0a, 0x0e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x50, 0x75, 0x72, 0x70, 0x6f,
0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e,
0x74, 0x50, 0x75, 0x72, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x07, 0x56, 0x61, 0x74, 0x44,
0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
0x79, 0x52, 0x07, 0x56, 0x61, 0x74, 0x44, 0x61, 0x74, 0x61, 0x22, 0x3a, 0x0a, 0x16, 0x47, 0x65,
0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74,
0x55, 0x52, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x52, 0x65, 0x64, 0x69, 0x72,
0x65, 0x63, 0x74, 0x55, 0x52, 0x4c, 0x32, 0xd8, 0x08, 0x0a, 0x10, 0x54, 0x72, 0x65, 0x61, 0x73,
0x75, 0x72, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x67, 0x0a, 0x16, 0x47,
0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x42, 0x61, 0x6e,
0x6b, 0x43, 0x61, 0x72, 0x64, 0x12, 0x28, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65,
0x72, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6e, 0x6b, 0x43, 0x61, 0x72, 0x64, 0x50, 0x61, 0x79,
0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x21, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50,
0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x00, 0x12, 0x5f, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65,
0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x59, 0x6f, 0x6f, 0x4d, 0x6f, 0x6e, 0x65, 0x79, 0x12, 0x20,
0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61,
0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x21, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74,
0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x60, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d,
0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x51, 0x49, 0x57, 0x49, 0x12, 0x25, 0x2e, 0x74, 0x72,
0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x68, 0x6f, 0x6e, 0x65,
0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47,
0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x63, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x50, 0x61,
0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x53, 0x62, 0x65, 0x72, 0x50, 0x61, 0x79,
0x12, 0x25, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74,
0x50, 0x68, 0x6f, 0x6e, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75,
0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69,
0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x65, 0x0a, 0x17,
0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x41, 0x6c,
0x66, 0x61, 0x43, 0x6c, 0x69, 0x63, 0x6b, 0x12, 0x25, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75,
0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x79, 0x6d,
0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21,
0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61,
0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x12, 0x5e, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e,
0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x54, 0x69, 0x6e, 0x6b, 0x6f, 0x66, 0x66, 0x12, 0x20, 0x2e, 0x74,
0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d,
0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21,
0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61,
0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x12, 0x65, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e,
0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x53, 0x62, 0x65, 0x72, 0x62, 0x61, 0x6e, 0x6b, 0x42, 0x32, 0x42,
0x12, 0x23, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74,
0x42, 0x32, 0x42, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65,
0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x11, 0x47, 0x65,
0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x53, 0x42, 0x50, 0x12,
0x20, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50,
0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x21, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65,
0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x62, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79,
0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x6f, 0x62, 0x69, 0x6c, 0x65, 0x12, 0x25,
0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x68,
0x6f, 0x6e, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65,
0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x60, 0x0a, 0x12, 0x47, 0x65,
0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x43, 0x61, 0x73, 0x68,
0x12, 0x25, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74,
0x50, 0x68, 0x6f, 0x6e, 0x65, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75,
0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69,
0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x63, 0x0a, 0x1a,
0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x49, 0x6e,
0x73, 0x74, 0x61, 0x6c, 0x6c, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x20, 0x2e, 0x74, 0x72, 0x65,
0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d, 0x65, 0x6e,
0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x74,
0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x79, 0x6d,
0x65, 0x6e, 0x74, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x00, 0x42, 0x0d, 0x5a, 0x0b, 0x2e, 0x2f, 0x74, 0x72, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x72,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_treasurer_service_proto_rawDescOnce sync.Once
file_treasurer_service_proto_rawDescData = file_treasurer_service_proto_rawDesc
)
func file_treasurer_service_proto_rawDescGZIP() []byte {
file_treasurer_service_proto_rawDescOnce.Do(func() {
file_treasurer_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_treasurer_service_proto_rawDescData)
})
return file_treasurer_service_proto_rawDescData
}
var file_treasurer_service_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_treasurer_service_proto_goTypes = []interface{}{
(*GetBankCardPaymentLinkRequest)(nil), // 0: treasurer.GetBankCardPaymentLinkRequest
(*GetPaymentLinkRequest)(nil), // 1: treasurer.GetPaymentLinkRequest
(*GetPhonePaymentLinkRequest)(nil), // 2: treasurer.GetPhonePaymentLinkRequest
(*GetLoginPaymentLinkRequest)(nil), // 3: treasurer.GetLoginPaymentLinkRequest
(*GetB2BPaymentLinkRequest)(nil), // 4: treasurer.GetB2BPaymentLinkRequest
(*GetPaymentLinkResponse)(nil), // 5: treasurer.GetPaymentLinkResponse
(*MainPaymentSettings)(nil), // 6: treasurer.MainPaymentSettings
(*BankCardInformation)(nil), // 7: treasurer.BankCardInformation
(*emptypb.Empty)(nil), // 8: google.protobuf.Empty
}
var file_treasurer_service_proto_depIdxs = []int32{
6, // 0: treasurer.GetBankCardPaymentLinkRequest.MainSettings:type_name -> treasurer.MainPaymentSettings
7, // 1: treasurer.GetBankCardPaymentLinkRequest.BankCard:type_name -> treasurer.BankCardInformation
6, // 2: treasurer.GetPaymentLinkRequest.MainSettings:type_name -> treasurer.MainPaymentSettings
6, // 3: treasurer.GetPhonePaymentLinkRequest.MainSettings:type_name -> treasurer.MainPaymentSettings
6, // 4: treasurer.GetLoginPaymentLinkRequest.MainSettings:type_name -> treasurer.MainPaymentSettings
6, // 5: treasurer.GetB2BPaymentLinkRequest.MainSettings:type_name -> treasurer.MainPaymentSettings
8, // 6: treasurer.GetB2BPaymentLinkRequest.VatData:type_name -> google.protobuf.Empty
0, // 7: treasurer.TreasurerService.GetPaymentLinkBankCard:input_type -> treasurer.GetBankCardPaymentLinkRequest
1, // 8: treasurer.TreasurerService.GetPaymentLinkYooMoney:input_type -> treasurer.GetPaymentLinkRequest
2, // 9: treasurer.TreasurerService.GetPaymentLinkQIWI:input_type -> treasurer.GetPhonePaymentLinkRequest
2, // 10: treasurer.TreasurerService.GetPaymentLinkSberPay:input_type -> treasurer.GetPhonePaymentLinkRequest
3, // 11: treasurer.TreasurerService.GetPaymentLinkAlfaClick:input_type -> treasurer.GetLoginPaymentLinkRequest
1, // 12: treasurer.TreasurerService.GetPaymentLinkTinkoff:input_type -> treasurer.GetPaymentLinkRequest
4, // 13: treasurer.TreasurerService.GetPaymentLinkSberbankB2B:input_type -> treasurer.GetB2BPaymentLinkRequest
1, // 14: treasurer.TreasurerService.GetPaymentLinkSBP:input_type -> treasurer.GetPaymentLinkRequest
2, // 15: treasurer.TreasurerService.GetPaymentLinkMobile:input_type -> treasurer.GetPhonePaymentLinkRequest
2, // 16: treasurer.TreasurerService.GetPaymentLinkCash:input_type -> treasurer.GetPhonePaymentLinkRequest
1, // 17: treasurer.TreasurerService.GetPaymentLinkInstallments:input_type -> treasurer.GetPaymentLinkRequest
5, // 18: treasurer.TreasurerService.GetPaymentLinkBankCard:output_type -> treasurer.GetPaymentLinkResponse
5, // 19: treasurer.TreasurerService.GetPaymentLinkYooMoney:output_type -> treasurer.GetPaymentLinkResponse
5, // 20: treasurer.TreasurerService.GetPaymentLinkQIWI:output_type -> treasurer.GetPaymentLinkResponse
5, // 21: treasurer.TreasurerService.GetPaymentLinkSberPay:output_type -> treasurer.GetPaymentLinkResponse
5, // 22: treasurer.TreasurerService.GetPaymentLinkAlfaClick:output_type -> treasurer.GetPaymentLinkResponse
5, // 23: treasurer.TreasurerService.GetPaymentLinkTinkoff:output_type -> treasurer.GetPaymentLinkResponse
5, // 24: treasurer.TreasurerService.GetPaymentLinkSberbankB2B:output_type -> treasurer.GetPaymentLinkResponse
5, // 25: treasurer.TreasurerService.GetPaymentLinkSBP:output_type -> treasurer.GetPaymentLinkResponse
5, // 26: treasurer.TreasurerService.GetPaymentLinkMobile:output_type -> treasurer.GetPaymentLinkResponse
5, // 27: treasurer.TreasurerService.GetPaymentLinkCash:output_type -> treasurer.GetPaymentLinkResponse
5, // 28: treasurer.TreasurerService.GetPaymentLinkInstallments:output_type -> treasurer.GetPaymentLinkResponse
18, // [18:29] is the sub-list for method output_type
7, // [7:18] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
}
func init() { file_treasurer_service_proto_init() }
func file_treasurer_service_proto_init() {
if File_treasurer_service_proto != nil {
return
}
file_treasurer_payment_model_proto_init()
if !protoimpl.UnsafeEnabled {
file_treasurer_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetBankCardPaymentLinkRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_treasurer_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetPaymentLinkRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_treasurer_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetPhonePaymentLinkRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_treasurer_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetLoginPaymentLinkRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_treasurer_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetB2BPaymentLinkRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_treasurer_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GetPaymentLinkResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_treasurer_service_proto_rawDesc,
NumEnums: 0,
NumMessages: 6,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_treasurer_service_proto_goTypes,
DependencyIndexes: file_treasurer_service_proto_depIdxs,
MessageInfos: file_treasurer_service_proto_msgTypes,
}.Build()
File_treasurer_service_proto = out.File
file_treasurer_service_proto_rawDesc = nil
file_treasurer_service_proto_goTypes = nil
file_treasurer_service_proto_depIdxs = nil
}

@ -0,0 +1,459 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package treasurer
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// TreasurerServiceClient is the client API for TreasurerService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type TreasurerServiceClient interface {
GetPaymentLinkBankCard(ctx context.Context, in *GetBankCardPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error)
GetPaymentLinkYooMoney(ctx context.Context, in *GetPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error)
GetPaymentLinkQIWI(ctx context.Context, in *GetPhonePaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error)
GetPaymentLinkSberPay(ctx context.Context, in *GetPhonePaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error)
GetPaymentLinkAlfaClick(ctx context.Context, in *GetLoginPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error)
GetPaymentLinkTinkoff(ctx context.Context, in *GetPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error)
GetPaymentLinkSberbankB2B(ctx context.Context, in *GetB2BPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error)
GetPaymentLinkSBP(ctx context.Context, in *GetPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error)
GetPaymentLinkMobile(ctx context.Context, in *GetPhonePaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error)
GetPaymentLinkCash(ctx context.Context, in *GetPhonePaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error)
GetPaymentLinkInstallments(ctx context.Context, in *GetPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error)
}
type treasurerServiceClient struct {
cc grpc.ClientConnInterface
}
func NewTreasurerServiceClient(cc grpc.ClientConnInterface) TreasurerServiceClient {
return &treasurerServiceClient{cc}
}
func (c *treasurerServiceClient) GetPaymentLinkBankCard(ctx context.Context, in *GetBankCardPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error) {
out := new(GetPaymentLinkResponse)
err := c.cc.Invoke(ctx, "/treasurer.TreasurerService/GetPaymentLinkBankCard", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *treasurerServiceClient) GetPaymentLinkYooMoney(ctx context.Context, in *GetPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error) {
out := new(GetPaymentLinkResponse)
err := c.cc.Invoke(ctx, "/treasurer.TreasurerService/GetPaymentLinkYooMoney", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *treasurerServiceClient) GetPaymentLinkQIWI(ctx context.Context, in *GetPhonePaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error) {
out := new(GetPaymentLinkResponse)
err := c.cc.Invoke(ctx, "/treasurer.TreasurerService/GetPaymentLinkQIWI", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *treasurerServiceClient) GetPaymentLinkSberPay(ctx context.Context, in *GetPhonePaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error) {
out := new(GetPaymentLinkResponse)
err := c.cc.Invoke(ctx, "/treasurer.TreasurerService/GetPaymentLinkSberPay", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *treasurerServiceClient) GetPaymentLinkAlfaClick(ctx context.Context, in *GetLoginPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error) {
out := new(GetPaymentLinkResponse)
err := c.cc.Invoke(ctx, "/treasurer.TreasurerService/GetPaymentLinkAlfaClick", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *treasurerServiceClient) GetPaymentLinkTinkoff(ctx context.Context, in *GetPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error) {
out := new(GetPaymentLinkResponse)
err := c.cc.Invoke(ctx, "/treasurer.TreasurerService/GetPaymentLinkTinkoff", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *treasurerServiceClient) GetPaymentLinkSberbankB2B(ctx context.Context, in *GetB2BPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error) {
out := new(GetPaymentLinkResponse)
err := c.cc.Invoke(ctx, "/treasurer.TreasurerService/GetPaymentLinkSberbankB2B", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *treasurerServiceClient) GetPaymentLinkSBP(ctx context.Context, in *GetPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error) {
out := new(GetPaymentLinkResponse)
err := c.cc.Invoke(ctx, "/treasurer.TreasurerService/GetPaymentLinkSBP", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *treasurerServiceClient) GetPaymentLinkMobile(ctx context.Context, in *GetPhonePaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error) {
out := new(GetPaymentLinkResponse)
err := c.cc.Invoke(ctx, "/treasurer.TreasurerService/GetPaymentLinkMobile", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *treasurerServiceClient) GetPaymentLinkCash(ctx context.Context, in *GetPhonePaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error) {
out := new(GetPaymentLinkResponse)
err := c.cc.Invoke(ctx, "/treasurer.TreasurerService/GetPaymentLinkCash", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *treasurerServiceClient) GetPaymentLinkInstallments(ctx context.Context, in *GetPaymentLinkRequest, opts ...grpc.CallOption) (*GetPaymentLinkResponse, error) {
out := new(GetPaymentLinkResponse)
err := c.cc.Invoke(ctx, "/treasurer.TreasurerService/GetPaymentLinkInstallments", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// TreasurerServiceServer is the server API for TreasurerService service.
// All implementations should embed UnimplementedTreasurerServiceServer
// for forward compatibility
type TreasurerServiceServer interface {
GetPaymentLinkBankCard(context.Context, *GetBankCardPaymentLinkRequest) (*GetPaymentLinkResponse, error)
GetPaymentLinkYooMoney(context.Context, *GetPaymentLinkRequest) (*GetPaymentLinkResponse, error)
GetPaymentLinkQIWI(context.Context, *GetPhonePaymentLinkRequest) (*GetPaymentLinkResponse, error)
GetPaymentLinkSberPay(context.Context, *GetPhonePaymentLinkRequest) (*GetPaymentLinkResponse, error)
GetPaymentLinkAlfaClick(context.Context, *GetLoginPaymentLinkRequest) (*GetPaymentLinkResponse, error)
GetPaymentLinkTinkoff(context.Context, *GetPaymentLinkRequest) (*GetPaymentLinkResponse, error)
GetPaymentLinkSberbankB2B(context.Context, *GetB2BPaymentLinkRequest) (*GetPaymentLinkResponse, error)
GetPaymentLinkSBP(context.Context, *GetPaymentLinkRequest) (*GetPaymentLinkResponse, error)
GetPaymentLinkMobile(context.Context, *GetPhonePaymentLinkRequest) (*GetPaymentLinkResponse, error)
GetPaymentLinkCash(context.Context, *GetPhonePaymentLinkRequest) (*GetPaymentLinkResponse, error)
GetPaymentLinkInstallments(context.Context, *GetPaymentLinkRequest) (*GetPaymentLinkResponse, error)
}
// UnimplementedTreasurerServiceServer should be embedded to have forward compatible implementations.
type UnimplementedTreasurerServiceServer struct {
}
func (UnimplementedTreasurerServiceServer) GetPaymentLinkBankCard(context.Context, *GetBankCardPaymentLinkRequest) (*GetPaymentLinkResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPaymentLinkBankCard not implemented")
}
func (UnimplementedTreasurerServiceServer) GetPaymentLinkYooMoney(context.Context, *GetPaymentLinkRequest) (*GetPaymentLinkResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPaymentLinkYooMoney not implemented")
}
func (UnimplementedTreasurerServiceServer) GetPaymentLinkQIWI(context.Context, *GetPhonePaymentLinkRequest) (*GetPaymentLinkResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPaymentLinkQIWI not implemented")
}
func (UnimplementedTreasurerServiceServer) GetPaymentLinkSberPay(context.Context, *GetPhonePaymentLinkRequest) (*GetPaymentLinkResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPaymentLinkSberPay not implemented")
}
func (UnimplementedTreasurerServiceServer) GetPaymentLinkAlfaClick(context.Context, *GetLoginPaymentLinkRequest) (*GetPaymentLinkResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPaymentLinkAlfaClick not implemented")
}
func (UnimplementedTreasurerServiceServer) GetPaymentLinkTinkoff(context.Context, *GetPaymentLinkRequest) (*GetPaymentLinkResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPaymentLinkTinkoff not implemented")
}
func (UnimplementedTreasurerServiceServer) GetPaymentLinkSberbankB2B(context.Context, *GetB2BPaymentLinkRequest) (*GetPaymentLinkResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPaymentLinkSberbankB2B not implemented")
}
func (UnimplementedTreasurerServiceServer) GetPaymentLinkSBP(context.Context, *GetPaymentLinkRequest) (*GetPaymentLinkResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPaymentLinkSBP not implemented")
}
func (UnimplementedTreasurerServiceServer) GetPaymentLinkMobile(context.Context, *GetPhonePaymentLinkRequest) (*GetPaymentLinkResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPaymentLinkMobile not implemented")
}
func (UnimplementedTreasurerServiceServer) GetPaymentLinkCash(context.Context, *GetPhonePaymentLinkRequest) (*GetPaymentLinkResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPaymentLinkCash not implemented")
}
func (UnimplementedTreasurerServiceServer) GetPaymentLinkInstallments(context.Context, *GetPaymentLinkRequest) (*GetPaymentLinkResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetPaymentLinkInstallments not implemented")
}
// UnsafeTreasurerServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to TreasurerServiceServer will
// result in compilation errors.
type UnsafeTreasurerServiceServer interface {
mustEmbedUnimplementedTreasurerServiceServer()
}
func RegisterTreasurerServiceServer(s grpc.ServiceRegistrar, srv TreasurerServiceServer) {
s.RegisterService(&TreasurerService_ServiceDesc, srv)
}
func _TreasurerService_GetPaymentLinkBankCard_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetBankCardPaymentLinkRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TreasurerServiceServer).GetPaymentLinkBankCard(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/treasurer.TreasurerService/GetPaymentLinkBankCard",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TreasurerServiceServer).GetPaymentLinkBankCard(ctx, req.(*GetBankCardPaymentLinkRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TreasurerService_GetPaymentLinkYooMoney_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetPaymentLinkRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TreasurerServiceServer).GetPaymentLinkYooMoney(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/treasurer.TreasurerService/GetPaymentLinkYooMoney",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TreasurerServiceServer).GetPaymentLinkYooMoney(ctx, req.(*GetPaymentLinkRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TreasurerService_GetPaymentLinkQIWI_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetPhonePaymentLinkRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TreasurerServiceServer).GetPaymentLinkQIWI(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/treasurer.TreasurerService/GetPaymentLinkQIWI",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TreasurerServiceServer).GetPaymentLinkQIWI(ctx, req.(*GetPhonePaymentLinkRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TreasurerService_GetPaymentLinkSberPay_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetPhonePaymentLinkRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TreasurerServiceServer).GetPaymentLinkSberPay(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/treasurer.TreasurerService/GetPaymentLinkSberPay",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TreasurerServiceServer).GetPaymentLinkSberPay(ctx, req.(*GetPhonePaymentLinkRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TreasurerService_GetPaymentLinkAlfaClick_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetLoginPaymentLinkRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TreasurerServiceServer).GetPaymentLinkAlfaClick(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/treasurer.TreasurerService/GetPaymentLinkAlfaClick",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TreasurerServiceServer).GetPaymentLinkAlfaClick(ctx, req.(*GetLoginPaymentLinkRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TreasurerService_GetPaymentLinkTinkoff_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetPaymentLinkRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TreasurerServiceServer).GetPaymentLinkTinkoff(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/treasurer.TreasurerService/GetPaymentLinkTinkoff",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TreasurerServiceServer).GetPaymentLinkTinkoff(ctx, req.(*GetPaymentLinkRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TreasurerService_GetPaymentLinkSberbankB2B_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetB2BPaymentLinkRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TreasurerServiceServer).GetPaymentLinkSberbankB2B(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/treasurer.TreasurerService/GetPaymentLinkSberbankB2B",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TreasurerServiceServer).GetPaymentLinkSberbankB2B(ctx, req.(*GetB2BPaymentLinkRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TreasurerService_GetPaymentLinkSBP_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetPaymentLinkRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TreasurerServiceServer).GetPaymentLinkSBP(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/treasurer.TreasurerService/GetPaymentLinkSBP",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TreasurerServiceServer).GetPaymentLinkSBP(ctx, req.(*GetPaymentLinkRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TreasurerService_GetPaymentLinkMobile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetPhonePaymentLinkRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TreasurerServiceServer).GetPaymentLinkMobile(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/treasurer.TreasurerService/GetPaymentLinkMobile",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TreasurerServiceServer).GetPaymentLinkMobile(ctx, req.(*GetPhonePaymentLinkRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TreasurerService_GetPaymentLinkCash_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetPhonePaymentLinkRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TreasurerServiceServer).GetPaymentLinkCash(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/treasurer.TreasurerService/GetPaymentLinkCash",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TreasurerServiceServer).GetPaymentLinkCash(ctx, req.(*GetPhonePaymentLinkRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TreasurerService_GetPaymentLinkInstallments_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetPaymentLinkRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TreasurerServiceServer).GetPaymentLinkInstallments(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/treasurer.TreasurerService/GetPaymentLinkInstallments",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TreasurerServiceServer).GetPaymentLinkInstallments(ctx, req.(*GetPaymentLinkRequest))
}
return interceptor(ctx, in, info, handler)
}
// TreasurerService_ServiceDesc is the grpc.ServiceDesc for TreasurerService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var TreasurerService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "treasurer.TreasurerService",
HandlerType: (*TreasurerServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetPaymentLinkBankCard",
Handler: _TreasurerService_GetPaymentLinkBankCard_Handler,
},
{
MethodName: "GetPaymentLinkYooMoney",
Handler: _TreasurerService_GetPaymentLinkYooMoney_Handler,
},
{
MethodName: "GetPaymentLinkQIWI",
Handler: _TreasurerService_GetPaymentLinkQIWI_Handler,
},
{
MethodName: "GetPaymentLinkSberPay",
Handler: _TreasurerService_GetPaymentLinkSberPay_Handler,
},
{
MethodName: "GetPaymentLinkAlfaClick",
Handler: _TreasurerService_GetPaymentLinkAlfaClick_Handler,
},
{
MethodName: "GetPaymentLinkTinkoff",
Handler: _TreasurerService_GetPaymentLinkTinkoff_Handler,
},
{
MethodName: "GetPaymentLinkSberbankB2B",
Handler: _TreasurerService_GetPaymentLinkSberbankB2B_Handler,
},
{
MethodName: "GetPaymentLinkSBP",
Handler: _TreasurerService_GetPaymentLinkSBP_Handler,
},
{
MethodName: "GetPaymentLinkMobile",
Handler: _TreasurerService_GetPaymentLinkMobile_Handler,
},
{
MethodName: "GetPaymentLinkCash",
Handler: _TreasurerService_GetPaymentLinkCash_Handler,
},
{
MethodName: "GetPaymentLinkInstallments",
Handler: _TreasurerService_GetPaymentLinkInstallments_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "treasurer/service.proto",
}

78
internal/server/grpc.go Normal file

@ -0,0 +1,78 @@
package server
import (
"context"
"fmt"
"net"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap"
grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
"go.uber.org/zap"
"google.golang.org/grpc"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/proto/treasurer"
)
type DepsGRPC struct {
Logger *zap.Logger
}
type GRPC struct {
logger *zap.Logger
grpc *grpc.Server
}
func NewGRPC(deps DepsGRPC) (*GRPC, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("Logger is nil on <NewGRPC>", errors.ErrInvalidArgs)
}
grpcStreamInterceptor := grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
grpc_zap.StreamServerInterceptor(deps.Logger),
grpc_recovery.StreamServerInterceptor(),
))
grpcUnaryInterceptor := grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
grpc_zap.UnaryServerInterceptor(deps.Logger),
grpc_recovery.UnaryServerInterceptor(),
))
return &GRPC{
grpc: grpc.NewServer(grpcStreamInterceptor, grpcUnaryInterceptor),
logger: deps.Logger,
}, nil
}
func (receiver *GRPC) Run(config *models.ConfigurationGRPC) {
connectionString := fmt.Sprintf("%s:%s", config.Host, config.Port)
receiver.logger.Info("Starting GRPC Server", zap.String("host", connectionString))
if err := receiver.listen(connectionString); err != nil && err != grpc.ErrServerStopped {
receiver.logger.Error("GRPC Listen error", zap.Error(err))
}
}
func (receiver *GRPC) Stop(_ context.Context) error {
receiver.grpc.GracefulStop()
receiver.logger.Info("Shutting down GRPC server...")
return nil
}
func (receiver *GRPC) Register(server treasurer.TreasurerServiceServer) *GRPC {
treasurer.RegisterTreasurerServiceServer(receiver.grpc, server)
return receiver
}
func (receiver *GRPC) listen(address string) error {
listener, err := net.Listen("tcp", address)
if err != nil {
return err
}
return receiver.grpc.Serve(listener)
}

85
internal/server/http.go Normal file

@ -0,0 +1,85 @@
package server
import (
"context"
"fmt"
"net/http"
"time"
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"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/swagger"
)
type DepsHTTP struct {
Logger *zap.Logger
Swagger *openapi3.T
}
type HTTP struct {
logger *zap.Logger
server *http.Server
echo *echo.Echo
}
func NewHTTP(deps DepsHTTP) (*HTTP, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("Logger is nil on <NewHTTP>", errors.ErrInvalidArgs)
}
if deps.Swagger == nil {
return nil, errors.NewWithMessage("Swagger is nil on <NewHTTP>", errors.ErrInvalidArgs)
}
echo := echo.New()
echo.Use(middleware.Recover())
return &HTTP{
echo: echo,
logger: deps.Logger,
server: &http.Server{
Handler: echo,
MaxHeaderBytes: 1 << 20,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
},
}, nil
}
func (receiver *HTTP) Listen(address string) error {
receiver.server.Addr = address
return receiver.server.ListenAndServe()
}
func (receiver *HTTP) Run(config *models.ConfigurationHTTP) {
connectionString := fmt.Sprintf("%s:%s", config.Host, config.Port)
startServerMessage := fmt.Sprintf("starting http server on %s", connectionString)
receiver.logger.Info(startServerMessage)
if err := receiver.Listen(connectionString); err != nil && err != http.ErrServerClosed {
receiver.logger.Error("http listen error: ", zap.Error(err))
}
}
func (receiver *HTTP) Stop(ctx context.Context) error {
receiver.logger.Info("shutting down server...")
if err := receiver.server.Shutdown(ctx); err != nil {
return fmt.Errorf("failed to shutdown server: %w", err)
}
return nil
}
func (receiver *HTTP) Register(api *swagger.API) *HTTP {
swagger.RegisterHandlers(receiver.echo, api)
return receiver
}

@ -0,0 +1,127 @@
package callback
import (
"context"
"sync"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
)
type CallbackClient interface {
SendOnSuccess(ctx context.Context, host string, event *models.Event) errors.Error
SendOnFailure(ctx context.Context, host string, event *models.Event) errors.Error
}
type PaymentRepository interface {
SetPaymentComplete(ctx context.Context, paymentID string) (*models.Payment, errors.Error)
}
type Deps struct {
Logger *zap.Logger
CallbackClient CallbackClient
PaymentRepository PaymentRepository
}
type Service struct {
logger *zap.Logger
callbackClient CallbackClient
paymentRepository PaymentRepository
}
func New(deps Deps) (*Service, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("logger is nil on <NewCallbackService>", errors.ErrInvalidArgs)
}
if deps.CallbackClient == nil {
return nil, errors.NewWithMessage("CallbackClient is nil on <NewCallbackService>", errors.ErrInvalidArgs)
}
if deps.PaymentRepository == nil {
return nil, errors.NewWithMessage("PaymentRepository is nil on <NewCallbackService>", errors.ErrInvalidArgs)
}
return &Service{
logger: deps.Logger,
callbackClient: deps.CallbackClient,
paymentRepository: deps.PaymentRepository,
}, nil
}
func (receiver *Service) OnSuccess(ctx context.Context, event *models.Event) errors.Error {
waitGroup := sync.WaitGroup{}
mutex := sync.Mutex{}
executeErrors := make([]error, 0)
for _, callbackURL := range event.Payment.CallbackHostGRPC {
waitGroup.Add(1)
go func(url string) {
defer waitGroup.Done()
if err := receiver.callbackClient.SendOnSuccess(ctx, url, event); err != nil {
receiver.logger.Error("failid to send callback on <OnSuccess> of <CallbackService>")
mutex.Lock()
executeErrors = append(executeErrors, err)
mutex.Unlock()
return
}
if _, err := receiver.paymentRepository.SetPaymentComplete(ctx, event.Payment.PaymentID); err != nil {
receiver.logger.Error("failid to set payment complete on <OnSuccess> of <CallbackService>")
mutex.Lock()
executeErrors = append(executeErrors, err)
mutex.Unlock()
return
}
}(callbackURL)
}
waitGroup.Wait()
if len(executeErrors) >= len(event.Payment.CallbackHostGRPC) {
receiver.logger.Error("failid to success payment on <OnSuccess> of <CallbackService>", zap.Errors("errors", executeErrors))
return errors.NewWithMessage("failed to success payment: all operations failed", errors.ErrInternalError)
}
return nil
}
func (receiver *Service) OnFailure(ctx context.Context, event *models.Event) errors.Error {
waitGroup := sync.WaitGroup{}
mutex := sync.Mutex{}
executeErrors := make([]error, 0)
for _, callbackURL := range event.Payment.CallbackHostGRPC {
waitGroup.Add(1)
go func(url string) {
defer waitGroup.Done()
if err := receiver.callbackClient.SendOnFailure(ctx, url, event); err != nil {
receiver.logger.Error("failid to send callback on <OnFailure> of <CallbackService>")
mutex.Lock()
executeErrors = append(executeErrors, err)
mutex.Unlock()
return
}
}(callbackURL)
}
waitGroup.Wait()
if len(executeErrors) >= len(event.Payment.CallbackHostGRPC) {
receiver.logger.Error("failid to success payment on <OnFailure> of <CallbackService>", zap.Errors("errors", executeErrors))
return errors.NewWithMessage("failed to success payment: all operations failed", errors.ErrInternalError)
}
return nil
}

@ -0,0 +1,153 @@
package payment
import (
"context"
"fmt"
"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/utils"
)
type PaymentStrategyService interface {
CreatePaymentPhone(ctx context.Context, uuid string, payment *models.CreatePayment[string]) (*models.CreatePaymentResult, errors.Error)
CreatePaymentBankCard(ctx context.Context, uuid string, payment *models.CreatePayment[*models.BankCard]) (*models.CreatePaymentResult, errors.Error)
CreatePayment(ctx context.Context, uuid string, payment *models.CreatePayment[*any]) (*models.CreatePaymentResult, errors.Error)
CreatePaymentLogin(ctx context.Context, uuid string, payment *models.CreatePayment[string]) (*models.CreatePaymentResult, errors.Error)
}
type PaymentRepository interface {
Insert(context.Context, *models.Payment) (*models.Payment, errors.Error)
}
type Deps struct {
Logger *zap.Logger
PaymentStrategyService PaymentStrategyService
PaymentRepository PaymentRepository
}
type Service struct {
logger *zap.Logger
paymentStrategyService PaymentStrategyService
paymentRepository PaymentRepository
}
func New(deps Deps) (*Service, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("logger is nil on <NewCallbackClient>", errors.ErrInvalidArgs)
}
if deps.PaymentStrategyService == nil {
return nil, errors.NewWithMessage("PaymentStrategyService is nil on <NewCallbackClient>", errors.ErrInvalidArgs)
}
if deps.PaymentRepository == nil {
return nil, errors.NewWithMessage("PaymentRepository is nil on <NewCallbackClient>", errors.ErrInvalidArgs)
}
return &Service{
logger: deps.Logger,
paymentStrategyService: deps.PaymentStrategyService,
paymentRepository: deps.PaymentRepository,
}, nil
}
func (receiver *Service) CreatePaymentPhone(ctx context.Context, request *models.CreatePayment[string]) (string, errors.Error) {
paymentUUID, generateErr := utils.GenerateUUID()
if generateErr != nil {
receiver.logger.Error("failed to generate uuid on <CreatePaymentPhone> of <PaymentService>", zap.Error(generateErr))
return "", errors.NewWithError(fmt.Errorf("failed to generate uuid: %w", generateErr), errors.ErrInternalError)
}
response, err := receiver.paymentStrategyService.CreatePaymentPhone(ctx, paymentUUID, request)
if err != nil {
receiver.logger.Error("failed to create payment on <CreatePaymentPhone> of <PaymentService>", zap.Error(err))
return "", err
}
if _, err := receiver.paymentRepository.Insert(ctx, response.Payment); err != nil {
receiver.logger.Error("failed to insert payment on <CreatePaymentPhone> of <PaymentService>", zap.Error(err))
return "", err
}
return response.RedirectURL, nil
}
func (receiver *Service) CreatePaymentBankCard(ctx context.Context, request *models.CreatePayment[*models.BankCard]) (string, errors.Error) {
paymentUUID, generateErr := utils.GenerateUUID()
if generateErr != nil {
receiver.logger.Error("failed to generate uuid on <CreatePaymentBankCard> of <PaymentService>", zap.Error(generateErr))
return "", errors.NewWithError(fmt.Errorf("failed to generate uuid: %w", generateErr), errors.ErrInternalError)
}
response, err := receiver.paymentStrategyService.CreatePaymentBankCard(ctx, paymentUUID, request)
if err != nil {
receiver.logger.Error("failed to create payment on <CreatePaymentBankCard> of <PaymentService>", zap.Error(err))
return "", err
}
if _, err := receiver.paymentRepository.Insert(ctx, response.Payment); err != nil {
receiver.logger.Error("failed to insert payment on <CreatePaymentBankCard> of <PaymentService>", zap.Error(err))
return "", err
}
return response.RedirectURL, nil
}
func (receiver *Service) CreatePayment(ctx context.Context, request *models.CreatePayment[*any]) (string, errors.Error) {
paymentUUID, generateErr := utils.GenerateUUID()
if generateErr != nil {
receiver.logger.Error("failed to generate uuid on <CreatePayment> of <PaymentService>", zap.Error(generateErr))
return "", errors.NewWithError(fmt.Errorf("failed to generate uuid: %w", generateErr), errors.ErrInternalError)
}
response, err := receiver.paymentStrategyService.CreatePayment(ctx, paymentUUID, request)
if err != nil {
receiver.logger.Error("failed to create payment on <CreatePayment> of <PaymentService>", zap.Error(err))
return "", err
}
if _, err := receiver.paymentRepository.Insert(ctx, response.Payment); err != nil {
receiver.logger.Error("failed to insert payment on <CreatePayment> of <PaymentService>", zap.Error(err))
return "", err
}
return response.RedirectURL, nil
}
func (receiver *Service) CreatePaymentLogin(ctx context.Context, request *models.CreatePayment[string]) (string, errors.Error) {
paymentUUID, generateErr := utils.GenerateUUID()
if generateErr != nil {
receiver.logger.Error("failed to generate uuid on <CreatePaymentLogin> of <PaymentService>", zap.Error(generateErr))
return "", errors.NewWithError(fmt.Errorf("failed to generate uuid: %w", generateErr), errors.ErrInternalError)
}
response, err := receiver.paymentStrategyService.CreatePaymentLogin(ctx, paymentUUID, request)
if err != nil {
receiver.logger.Error("failed to create payment on <CreatePaymentLogin> of <PaymentService>", zap.Error(err))
return "", err
}
if _, err := receiver.paymentRepository.Insert(ctx, response.Payment); err != nil {
receiver.logger.Error("failed to insert payment on <CreatePaymentLogin> of <PaymentService>", zap.Error(err))
return "", err
}
return response.RedirectURL, nil
}
func (receiver *Service) GetAvailablePaymentMethods(_ context.Context) ([]models.PaymentType, errors.Error) {
return []models.PaymentType{
models.PaymentTypeBankCard,
models.PaymentTypeTinkoff,
models.PaymentTypeQiwi,
models.PaymentTypeSberPay,
models.PaymentTypeYoomoney,
models.PaymentTypeMobile,
models.PaymentTypeInstallments,
models.PaymentTypeCash,
models.PaymentTypeSBP,
models.PaymentTypeSberB2B,
}, nil
}

@ -0,0 +1,213 @@
package payment
import (
"context"
"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/internal/utils"
)
type YandexPaymentClient interface {
CreatePaymentPhone(ctx context.Context, idempotenceKey string, request *yandex.CreatePaymentRequest[yandex.PaymentMethodPhone]) (*yandex.Payment, errors.Error)
CreatePayment(ctx context.Context, idempotenceKey string, request *yandex.CreatePaymentRequest[yandex.PaymentMethodType]) (*yandex.Payment, errors.Error)
CreatePaymentBankCard(ctx context.Context, idempotenceKey string, request *yandex.CreatePaymentRequest[yandex.PaymentMethodBankCard]) (*yandex.Payment, errors.Error)
CreatePaymentB2B(ctx context.Context, idempotenceKey string, request *yandex.CreatePaymentRequest[yandex.PaymentMethodB2B]) (*yandex.Payment, errors.Error)
CreatePaymentLogin(ctx context.Context, idempotenceKey string, request *yandex.CreatePaymentRequest[yandex.PaymentMethodLogin]) (*yandex.Payment, errors.Error)
}
type YandexPaymentServiceDeps struct {
Logger *zap.Logger
YandexPaymentClient YandexPaymentClient
}
type Yandex struct {
logger *zap.Logger
yandexPaymentClient YandexPaymentClient
}
func NewYandex(deps YandexPaymentServiceDeps) (*Yandex, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("logger is nil on <NewCallbackClient>", errors.ErrInvalidArgs)
}
if deps.YandexPaymentClient == nil {
return nil, errors.NewWithMessage("YandexPaymentClient is nil on <NewCallbackClient>", errors.ErrInvalidArgs)
}
return &Yandex{
logger: deps.Logger,
yandexPaymentClient: deps.YandexPaymentClient,
}, nil
}
func (receiver *Yandex) CreatePaymentPhone(ctx context.Context, uuid string, request *models.CreatePayment[string]) (*models.CreatePaymentResult, errors.Error) {
yandexPayment, err := receiver.yandexPaymentClient.CreatePaymentPhone(ctx, uuid, &yandex.CreatePaymentRequest[yandex.PaymentMethodPhone]{
Amount: yandex.Amount{
Value: utils.ConvertAmountToStringFloat(request.Amount),
Currency: request.Currency,
},
PaymentMethodData: &yandex.PaymentMethodPhone{
Type: models.YandexPaymentTypeMap[request.Type],
Phone: request.Requisites,
},
Confirmation: &yandex.CreateConfirmationRedirect{
Type: yandex.ConfirmationTypeRedirect,
Locale: "ru_RU",
ReturnURL: request.ReturnURL,
Enforce: true,
},
Capture: true,
ClientIP: request.ClientIP,
})
if err != nil {
receiver.logger.Error("failed to create payment on <CreatePaymentPhone> of <YandexPaymentService>", zap.Error(err))
return nil, err
}
return &models.CreatePaymentResult{
Payment: &models.Payment{
UserID: request.UserID,
PaymentID: yandexPayment.ID,
ClientIP: request.ClientIP,
Currency: request.Currency,
IdempotencePaymentID: uuid,
Amount: request.Amount,
Type: request.Type,
Status: models.PaymentStatusMap[string(yandexPayment.Status)],
Completed: false,
RawPaymentBody: yandexPayment,
CallbackHostGRPC: request.CallbackHostGRPC,
},
RedirectURL: yandexPayment.Confirmation.ConfirmationURL,
}, nil
}
func (receiver *Yandex) CreatePaymentBankCard(ctx context.Context, uuid string, request *models.CreatePayment[*models.BankCard]) (*models.CreatePaymentResult, errors.Error) {
yandexPayment, err := receiver.yandexPaymentClient.CreatePaymentBankCard(ctx, uuid, &yandex.CreatePaymentRequest[yandex.PaymentMethodBankCard]{
Amount: yandex.Amount{
Value: utils.ConvertAmountToStringFloat(request.Amount),
Currency: request.Currency,
},
PaymentMethodData: &yandex.PaymentMethodBankCard{
Type: models.YandexPaymentTypeMap[request.Type],
Card: &yandex.BankCardInformation{
Number: request.Requisites.Number,
ExpiryYear: request.Requisites.ExpiryYear,
ExpiryMonth: request.Requisites.ExpiryMonth,
},
},
Confirmation: &yandex.CreateConfirmationRedirect{
Type: yandex.ConfirmationTypeRedirect,
Locale: "ru_RU",
ReturnURL: request.ReturnURL,
Enforce: true,
},
Capture: true,
ClientIP: request.ClientIP,
})
if err != nil {
receiver.logger.Error("failed to create payment on <CreatePaymentBankCard> of <YandexPaymentService>", zap.Error(err))
return nil, err
}
return &models.CreatePaymentResult{
Payment: &models.Payment{
UserID: request.UserID,
PaymentID: yandexPayment.ID,
IdempotencePaymentID: uuid,
ClientIP: request.ClientIP,
Currency: request.Currency,
Amount: request.Amount,
Type: request.Type,
Status: models.PaymentStatusMap[string(yandexPayment.Status)],
Completed: false,
RawPaymentBody: yandexPayment,
CallbackHostGRPC: request.CallbackHostGRPC,
},
RedirectURL: yandexPayment.Confirmation.ConfirmationURL,
}, nil
}
func (receiver *Yandex) CreatePayment(ctx context.Context, uuid string, request *models.CreatePayment[*any]) (*models.CreatePaymentResult, errors.Error) {
yandexPayment, err := receiver.yandexPaymentClient.CreatePayment(ctx, uuid, &yandex.CreatePaymentRequest[yandex.PaymentMethodType]{
Amount: yandex.Amount{
Value: utils.ConvertAmountToStringFloat(request.Amount),
Currency: request.Currency,
},
PaymentMethodData: &yandex.PaymentMethodType{Type: models.YandexPaymentTypeMap[request.Type]},
Confirmation: &yandex.CreateConfirmationRedirect{
Type: yandex.ConfirmationTypeRedirect,
Locale: "ru_RU",
ReturnURL: request.ReturnURL,
Enforce: true,
},
Capture: true,
ClientIP: request.ClientIP,
})
if err != nil {
receiver.logger.Error("failed to create payment on <CreatePayment> of <YandexPaymentService>", zap.Error(err))
return nil, err
}
return &models.CreatePaymentResult{
Payment: &models.Payment{
UserID: request.UserID,
PaymentID: yandexPayment.ID,
IdempotencePaymentID: uuid,
ClientIP: request.ClientIP,
Currency: request.Currency,
Amount: request.Amount,
Type: request.Type,
Status: models.PaymentStatusMap[string(yandexPayment.Status)],
Completed: false,
RawPaymentBody: yandexPayment,
CallbackHostGRPC: request.CallbackHostGRPC,
},
RedirectURL: yandexPayment.Confirmation.ConfirmationURL,
}, nil
}
func (receiver *Yandex) CreatePaymentLogin(ctx context.Context, uuid string, request *models.CreatePayment[string]) (*models.CreatePaymentResult, errors.Error) {
yandexPayment, err := receiver.yandexPaymentClient.CreatePaymentLogin(ctx, uuid, &yandex.CreatePaymentRequest[yandex.PaymentMethodLogin]{
Amount: yandex.Amount{
Value: utils.ConvertAmountToStringFloat(request.Amount),
Currency: request.Currency,
},
PaymentMethodData: &yandex.PaymentMethodLogin{
Type: models.YandexPaymentTypeMap[request.Type],
Login: request.Requisites,
},
Confirmation: &yandex.CreateConfirmationRedirect{
Type: yandex.ConfirmationTypeRedirect,
Locale: "ru_RU",
ReturnURL: request.ReturnURL,
Enforce: true,
},
Capture: true,
ClientIP: request.ClientIP,
})
if err != nil {
receiver.logger.Error("failed to create payment on <CreatePaymentLogin> of <YandexPaymentService>", zap.Error(err))
return nil, err
}
return &models.CreatePaymentResult{
Payment: &models.Payment{
UserID: request.UserID,
PaymentID: yandexPayment.ID,
IdempotencePaymentID: uuid,
ClientIP: request.ClientIP,
Currency: request.Currency,
Amount: request.Amount,
Type: request.Type,
Status: models.PaymentStatusMap[string(yandexPayment.Status)],
Completed: false,
RawPaymentBody: yandexPayment,
CallbackHostGRPC: request.CallbackHostGRPC,
},
RedirectURL: yandexPayment.Confirmation.ConfirmationURL,
}, nil
}

@ -0,0 +1,78 @@
package status
import (
"context"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/models"
)
type PaymentRepository interface {
SetPaymentStatus(ctx context.Context, paymentID string, status models.PaymentStatus) (*models.Payment, errors.Error)
}
type Deps struct {
Logger *zap.Logger
PaymentRepository PaymentRepository
}
type Service struct {
logger *zap.Logger
paymentRepository PaymentRepository
}
func New(deps Deps) (*Service, errors.Error) {
if deps.Logger == nil {
return nil, errors.NewWithMessage("logger is nil on <NewStatusService>", errors.ErrInvalidArgs)
}
if deps.PaymentRepository == nil {
return nil, errors.NewWithMessage("PaymentRepository is nil on <NewStatusService>", errors.ErrInvalidArgs)
}
return &Service{
logger: deps.Logger,
paymentRepository: deps.PaymentRepository,
}, nil
}
func (receiver *Service) SetStatusCanceled(ctx context.Context, paymentID string) (*models.Payment, errors.Error) {
payment, err := receiver.paymentRepository.SetPaymentStatus(ctx, paymentID, models.PaymentStatusCanceled)
if err != nil {
receiver.logger.Error("failed to set payment status on <SetStatusCanceled> of <StatusService>", zap.Error(err))
return nil, err
}
return payment, nil
}
func (receiver *Service) SetStatusSuccess(ctx context.Context, paymentID string) (*models.Payment, errors.Error) {
payment, err := receiver.paymentRepository.SetPaymentStatus(ctx, paymentID, models.PaymentStatusSuccessfully)
if err != nil {
receiver.logger.Error("failed to set payment status on <SetStatusSuccess> of <StatusService>", zap.Error(err))
return nil, err
}
return payment, nil
}
func (receiver *Service) SetStatusWaiting(ctx context.Context, paymentID string) (*models.Payment, errors.Error) {
payment, err := receiver.paymentRepository.SetPaymentStatus(ctx, paymentID, models.PaymentStatusWaiting)
if err != nil {
receiver.logger.Error("failed to set payment status on <SetStatusWaiting> of <StatusService>", zap.Error(err))
return nil, err
}
return payment, nil
}
func (receiver *Service) SetStatusRefund(ctx context.Context, paymentID string) (*models.Payment, errors.Error) {
payment, err := receiver.paymentRepository.SetPaymentStatus(ctx, paymentID, models.PaymentStatusRefund)
if err != nil {
receiver.logger.Error("failed to set payment status on <SetStatusRefund> of <StatusService>", zap.Error(err))
return nil, err
}
return payment, nil
}

@ -0,0 +1,191 @@
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
}

224
internal/swagger/api.gen.go Normal file

@ -0,0 +1,224 @@
// Package swagger provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen version v1.12.4 DO NOT EDIT.
package swagger
import (
"bytes"
"compress/gzip"
"encoding/base64"
"fmt"
"net/url"
"path"
"strings"
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
)
// ServerInterface represents all server handlers.
type ServerInterface interface {
// (GET /available)
GetAvailablePayments(ctx echo.Context) error
// (POST /yandex/payment/status/canceled)
SetYandexPaymentStatusCanceled(ctx echo.Context) error
// (POST /yandex/payment/status/succeeded)
SetYandexPaymentStatusSucceeded(ctx echo.Context) error
// (POST /yandex/payment/status/waiting)
SetYandexPaymentStatusWaiting(ctx echo.Context) error
// (POST /yandex/refund/status/succeeded)
SetYandexRefundStatusSucceeded(ctx echo.Context) error
}
// ServerInterfaceWrapper converts echo contexts to parameters.
type ServerInterfaceWrapper struct {
Handler ServerInterface
}
// GetAvailablePayments converts echo context to params.
func (w *ServerInterfaceWrapper) GetAvailablePayments(ctx echo.Context) error {
var err error
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.GetAvailablePayments(ctx)
return err
}
// SetYandexPaymentStatusCanceled converts echo context to params.
func (w *ServerInterfaceWrapper) SetYandexPaymentStatusCanceled(ctx echo.Context) error {
var err error
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.SetYandexPaymentStatusCanceled(ctx)
return err
}
// SetYandexPaymentStatusSucceeded converts echo context to params.
func (w *ServerInterfaceWrapper) SetYandexPaymentStatusSucceeded(ctx echo.Context) error {
var err error
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.SetYandexPaymentStatusSucceeded(ctx)
return err
}
// SetYandexPaymentStatusWaiting converts echo context to params.
func (w *ServerInterfaceWrapper) SetYandexPaymentStatusWaiting(ctx echo.Context) error {
var err error
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.SetYandexPaymentStatusWaiting(ctx)
return err
}
// SetYandexRefundStatusSucceeded converts echo context to params.
func (w *ServerInterfaceWrapper) SetYandexRefundStatusSucceeded(ctx echo.Context) error {
var err error
// Invoke the callback with all the unmarshalled arguments
err = w.Handler.SetYandexRefundStatusSucceeded(ctx)
return err
}
// This is a simple interface which specifies echo.Route addition functions which
// are present on both echo.Echo and echo.Group, since we want to allow using
// either of them for path registration
type EchoRouter interface {
CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
RegisterHandlersWithBaseURL(router, si, "")
}
// Registers handlers, and prepends BaseURL to the paths, so that the paths
// can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
router.GET(baseURL+"/available", wrapper.GetAvailablePayments)
router.POST(baseURL+"/yandex/payment/status/canceled", wrapper.SetYandexPaymentStatusCanceled)
router.POST(baseURL+"/yandex/payment/status/succeeded", wrapper.SetYandexPaymentStatusSucceeded)
router.POST(baseURL+"/yandex/payment/status/waiting", wrapper.SetYandexPaymentStatusWaiting)
router.POST(baseURL+"/yandex/refund/status/succeeded", wrapper.SetYandexRefundStatusSucceeded)
}
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
"H4sIAAAAAAAC/+xYzW7bRhB+FWLbQwIwlpw2DaBb0kMR9NDARlEUSWBsyJXD1CIZknIiGAL0kzRBHTRI",
"0EMPRYq0PReybNm0fuhXmH2FPkkxs0tJlLaOVSC3XBKJImdnvm++b4beY05QCwNf+EnMKnssdh6IGqeP",
"N2pB3U/wUxgFoYgST9B1px5Fwnca+NkVsRN5YeIFPqsw+EO2YCCfwYHswhD6MIAJTOQ+nFowhAyOLOhD",
"D0byZ9mR+xb0LfkUMtmCMfRkBwbWrc1vrnx+df06s5l4wmvhjmAVtvHtTWazpBHilziJPH+bNW22y3fq",
"wpDDO9mFMUbE+NCX+3AgW9DDTCDDTKYpwKBwznp5rVxePqlps0g8qnuRcFnljj7WnqFwb/pEcP+hcBLM",
"7TZv1ISfbCY8qRNmwq/X8OnH3Es8f3urGkRbDg+TeoSxQuG7eJbN4rrjCOEKF0/gviN2hDt3wqz6DeF4",
"oSdM/HDHQeK2PNeAzq9whKzIDqTyKaQwJOQz2bIQMjiEHpxAChMN399f8zjmJvi3eSIe88aqp8i27MIB",
"9GBIF7t0U++9qM/VVDjaBP6mSAr4b4hHdREbgBK7Gr/FDoIMDuQ+Zg8D24KMulcVABmMLdml3j7CLzCS",
"r2AgO3NYzVrKDxKv6jmcIhtA1ElX9tinkaiyCvukNJNjSWux9D33XfFE14SPqTjL6oMUzixK/icYwBCR",
"XbPgLyRAtiGl7PtTKQwsOEGi5XPSaQoD65/WL9Z8ztalYqn5jZdXqHKBSfrV1thPETDxWCx7uc2n9nQe",
"dtrEmignkpu7xU2cv0HngrF8ZcEZOpXsYN2yBceqlSFVP42UU8GxqWlt5gR+1YtqCgrTKXNuRL4o23ie",
"bCNr/+foGVxOJHjy/vLoqBM4ohwo8gmpEXVvLKkQaSnwWziDVLZVtAVDNfy4FF08Cb1IxO/J2rawA4sy",
"PMQLfRwjY8jgGDWILX0AA8JUoTXBm/CZsUayI19akMII0kW0j/Jf55A2ZbyqrRaIK5rqDCoeu9XrPP4C",
"/71WvYZfjWf7TlATW6u2fsiNSf8uW5AqD4Ah+oZOFTE1NsX9INgR3FchSZZbNZE8CFzjGO7IFq4BsiO7",
"2PLIE3KUYe8twnJpRqLiawSpfE7JvJRt7NJMdgpiWYpx2SSKaH5MngfWbJ7SU9W67/L7OyaXfUP6UelO",
"MBvdNdpdB3gBu6tP9/WxdCzqDDLrxu1bRjDVeajdFYmNpwvGefcXtxGcH3ocntsPiCvVklEpp6pBBlTP",
"j5BCaihlwetpWusc7dyw50kpuJbOS7drgYXl8dAkNVQDoyUdUF9oYjKt8Lb6Xw0/TZJsU0F95VLWFeUJ",
"I9mVz3M3UJuQfEbrK20vYxjLrj1nRrjR0I3KpFA61A00czvypW2po5QZZqg1dItTnVIKp4VotC5Po+EC",
"S0nl9mWTh+AhKu0UezFvOq2S6f5CypnpGjH2EmXO72alX6HN75Dc9nDJueRr7HS5L59ZtN6/0FvAKbPZ",
"rohiBfv6WnmtTDtNKHweeqzCPlsrr60Tn8kDatIS3+XeTq6rbWFqwqlJIEijfB4rSvJhOMVyiOQcaRF2",
"4UyniUsO9XKPLDlDwHSwIhi4T9CsvuWyCvtKJDfyBLVmYurDOAz8WG0dV8tlegcK/ES7Cg/DHb38lB7G",
"akgq5dGOmVv8HfbIe+whZJ5aqD3/h6Baxdb2ElGj4Et+ry/wKOIN1fNFtBab6iJAzCOAERO+HWN6IW+w",
"e3ih1KDFq6QtvqQEXJq+juAmFhgN5LdF7mSXGrNH+2YfhqQDvEBDob08B+4yeJtPa/kaJnfZEkubIils",
"hsrWvsyzUw4k4uRm4DZWouo8C/2vd4pmU3necocsQPMnUYXiwY3bgExvARmk/5ox1BuYyC5OV/16/UqN",
"xxeQwgEGWonV2QvnB6Z1HoDswrRuzr0Pf+R1BV71Hxo+uFjhGNL8ZQIGF+b1O53eR1bPZ1XtQB9arIVV",
"dUW5blCGH9V6EV5nV/aYz2s42vGX5r3mvwEAAP//ghXolIcVAAA=",
}
// GetSwagger returns the content of the embedded swagger specification file
// or error if failed to decode
func decodeSpec() ([]byte, error) {
zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %s", err)
}
zr, err := gzip.NewReader(bytes.NewReader(zipped))
if err != nil {
return nil, fmt.Errorf("error decompressing spec: %s", err)
}
var buf bytes.Buffer
_, err = buf.ReadFrom(zr)
if err != nil {
return nil, fmt.Errorf("error decompressing spec: %s", err)
}
return buf.Bytes(), nil
}
var rawSpec = decodeSpecCached()
// a naive cached of a decoded swagger spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
return data, err
}
}
// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
var res = make(map[string]func() ([]byte, error))
if len(pathToFile) > 0 {
res[pathToFile] = rawSpec
}
return res
}
// GetSwagger returns the Swagger specification corresponding to the generated code
// in this file. The external references of Swagger specification are resolved.
// The logic of resolving external references is tightly connected to "import-mapping" feature.
// Externally referenced files must be embedded in the corresponding golang packages.
// Urls can be supported but this task was out of the scope.
func GetSwagger() (swagger *openapi3.T, err error) {
var resolvePath = PathToRawSpec("")
loader := openapi3.NewLoader()
loader.IsExternalRefsAllowed = true
loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
var pathToFile = url.String()
pathToFile = path.Clean(pathToFile)
getSpec, ok := resolvePath[pathToFile]
if !ok {
err1 := fmt.Errorf("path not found: %s", pathToFile)
return nil, err1
}
return getSpec()
}
var specData []byte
specData, err = rawSpec()
if err != nil {
return
}
swagger, err = loader.LoadFromData(specData)
if err != nil {
return
}
return
}

77
internal/swagger/api.go Normal file

@ -0,0 +1,77 @@
package swagger
import (
"github.com/labstack/echo/v4"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/errors"
)
//go:generate oapi-codegen --config api.yaml ../../openapi.yaml
//go:generate oapi-codegen --config models.yaml ../../openapi.yaml
type commonController interface {
// (GET /available)
GetAvailablePayments(ctx echo.Context) error
}
type yandexStatusController interface {
// (POST /yandex/payment/status/canceled)
SetPaymentStatusCanceled(ctx echo.Context) error
// (POST /yandex/payment/status/succeeded)
SetPaymentStatusSucceeded(ctx echo.Context) error
// (POST /yandex/payment/status/waiting)
SetPaymentStatusWaiting(ctx echo.Context) error
// (POST /yandex/refund/status/succeeded)
SetRefundStatusSucceeded(ctx echo.Context) error
}
type Deps struct {
CommonController commonController
YandexStatusController yandexStatusController
}
type API struct {
commonController commonController
yandexStatusController yandexStatusController
}
func New(deps Deps) (*API, errors.Error) {
if deps.CommonController == nil {
return nil, errors.NewWithMessage("CommonController in nil on <NewSwaggerAPI>", errors.ErrInvalidArgs)
}
if deps.YandexStatusController == nil {
return nil, errors.NewWithMessage("YandexStatusController in nil on <NewSwaggerAPI>", errors.ErrInvalidArgs)
}
return &API{
commonController: deps.CommonController,
yandexStatusController: deps.YandexStatusController,
}, nil
}
// Common
func (receiver *API) GetAvailablePayments(ctx echo.Context) error {
return receiver.commonController.GetAvailablePayments(ctx)
}
// Status (Yandex)
func (receiver *API) SetYandexPaymentStatusCanceled(ctx echo.Context) error {
return receiver.yandexStatusController.SetPaymentStatusCanceled(ctx)
}
func (receiver *API) SetYandexPaymentStatusSucceeded(ctx echo.Context) error {
return receiver.yandexStatusController.SetPaymentStatusSucceeded(ctx)
}
func (receiver *API) SetYandexPaymentStatusWaiting(ctx echo.Context) error {
return receiver.yandexStatusController.SetPaymentStatusWaiting(ctx)
}
func (receiver *API) SetYandexRefundStatusSucceeded(ctx echo.Context) error {
return receiver.yandexStatusController.SetRefundStatusSucceeded(ctx)
}

@ -0,0 +1,6 @@
output: api.gen.go
package: swagger
generate:
echo-server: true
models: false
embedded-spec: true

@ -0,0 +1,94 @@
// Package swagger provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen version v1.12.4 DO NOT EDIT.
package swagger
// Defines values for PaymentStatus.
const (
Canceled PaymentStatus = "canceled"
Pending PaymentStatus = "pending"
Succeeded PaymentStatus = "succeeded"
WaitingForCapture PaymentStatus = "waiting_for_capture"
)
// Amount defines model for Amount.
type Amount struct {
// Currency Трехбуквенный код валюты в формате ISO-4217
Currency string `json:"currency"`
// Value Сумма в выбранной валюте
Value string `json:"value"`
}
// PaymentStatus defines model for PaymentStatus.
type PaymentStatus string
// Recipient defines model for Recipient.
type Recipient struct {
// AccountId Идентификатор магазина в ЮKassa
AccountId string `json:"account_id"`
// GatewayId Идентификатор субаккаунта
GatewayId string `json:"gateway_id"`
}
// SetPaymentStatusRequest defines model for SetPaymentStatusRequest.
type SetPaymentStatusRequest struct {
// Event Событие, о котором уведомляет ЮKassa
Event string `json:"event"`
Object YandexPayment `json:"object"`
// Type Тип объекта. Фиксированное значение — notification (уведомление)
Type string `json:"type"`
}
// YandexPayment defines model for YandexPayment.
type YandexPayment struct {
Amount Amount `json:"amount"`
// CapturedAt Время подтверждения платежа
CapturedAt *string `json:"captured_at,omitempty"`
// Confirmation Выбранный способ подтверждения платежа
Confirmation *map[string]interface{} `json:"confirmation,omitempty"`
// CreatedAt Время создания заказа
CreatedAt string `json:"created_at"`
// Description Описание
Description *string `json:"description,omitempty"`
// ExpiresAt Время, до которого вы можете бесплатно отменить или подтвердить платеж
ExpiresAt *string `json:"expires_at,omitempty"`
// Id Идентификатор платежа в ЮKassa
Id string `json:"id"`
IncomeAmount *Amount `json:"income_amount,omitempty"`
// Paid Признак оплаты заказа
Paid bool `json:"paid"`
// PaymentMethod Структура метода платежа (может отличаться от способа платежа)
PaymentMethod *map[string]interface{} `json:"payment_method,omitempty"`
Recipient Recipient `json:"recipient"`
// Refundable Возможность провести возврат по API
Refundable bool `json:"refundable"`
RefundedAmount *Amount `json:"refunded_amount,omitempty"`
Status PaymentStatus `json:"status"`
// Test Признак тестовой операции
Test bool `json:"test"`
}
// SetYandexPaymentStatusCanceledJSONRequestBody defines body for SetYandexPaymentStatusCanceled for application/json ContentType.
type SetYandexPaymentStatusCanceledJSONRequestBody = SetPaymentStatusRequest
// SetYandexPaymentStatusSucceededJSONRequestBody defines body for SetYandexPaymentStatusSucceeded for application/json ContentType.
type SetYandexPaymentStatusSucceededJSONRequestBody = SetPaymentStatusRequest
// SetYandexPaymentStatusWaitingJSONRequestBody defines body for SetYandexPaymentStatusWaiting for application/json ContentType.
type SetYandexPaymentStatusWaitingJSONRequestBody = SetPaymentStatusRequest
// SetYandexRefundStatusSucceededJSONRequestBody defines body for SetYandexRefundStatusSucceeded for application/json ContentType.
type SetYandexRefundStatusSucceededJSONRequestBody = SetPaymentStatusRequest

@ -0,0 +1,4 @@
output: models.gen.go
package: swagger
generate:
models: true

7
internal/utils/amount.go Normal file

@ -0,0 +1,7 @@
package utils
import "strconv"
func ConvertAmountToStringFloat(amount int64) string {
return strconv.FormatFloat(float64(amount)/100, 'f', 2, 64)
}

@ -0,0 +1,43 @@
package utils_test
import (
"testing"
"github.com/stretchr/testify/assert"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/utils"
)
func TestConvertAmountToStringFloat(t *testing.T) {
testCases := []struct {
name string
amount int64
expected string
}{
{
name: "Успешная конвертация числа 10020 в 100.20",
amount: 10020,
expected: "100.20",
},
{
name: "Успешная конвертация числа 10002 в 100.02",
amount: 10002,
expected: "100.02",
},
{
name: "Успешная конвертация числа 12054 в 120.54",
amount: 12054,
expected: "120.54",
},
{
name: "Успешная конвертация числа 198531 в 1985.31",
amount: 198531,
expected: "1985.31",
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
assert.Equal(t, testCase.expected, utils.ConvertAmountToStringFloat(testCase.amount))
})
}
}

@ -0,0 +1,13 @@
package echotools
import "github.com/labstack/echo/v4"
func Bind[T any](ctx echo.Context) (*T, error) {
item := new(T)
if err := ctx.Bind(item); err != nil {
return nil, err
}
return item, nil
}

19
internal/utils/uuid.go Normal file

@ -0,0 +1,19 @@
package utils
import (
"fmt"
"github.com/google/uuid"
)
func GenerateUUID() (result string, err error) {
defer func() {
if recovered := recover(); recovered != nil {
err = fmt.Errorf("recovered generateUUID error: %v", recovered)
}
}()
generatedUUID := uuid.New()
return generatedUUID.String(), nil
}

@ -0,0 +1,15 @@
package utils
import (
"encoding/base64"
"fmt"
"strings"
)
func ConvertYoomoneySercetsToAuth(authType, storeID, secretKey string) string {
credentials := fmt.Sprintf("%s:%s", storeID, secretKey)
encoded := base64.StdEncoding.EncodeToString([]byte(credentials))
trimedAuthType := strings.TrimSpace(authType)
return fmt.Sprintf("%s %s", trimedAuthType, encoded)
}

@ -0,0 +1,22 @@
package utils_test
import (
"testing"
"github.com/stretchr/testify/assert"
"penahub.gitlab.yandexcloud.net/external/treasurer/internal/utils"
)
func TestConvertYoomoneySercetsToAuth(t *testing.T) {
t.Run("Успешная конвертация секретов в base64 используя метод Basic", func(t *testing.T) {
assert.Equal(t, "Basic aWQ6c2VjcmV0", utils.ConvertYoomoneySercetsToAuth("Basic", "id", "secret"))
})
t.Run("Успешная конвертация секретов в base64 используя метод Bearer", func(t *testing.T) {
assert.Equal(t, "Bearer aWQ6c2VjcmV0", utils.ConvertYoomoneySercetsToAuth("Bearer", "id", "secret"))
})
t.Run("Успешная конвертация секретов в base64 используя метод Basic, в котором лишние пробелы", func(t *testing.T) {
assert.Equal(t, "Basic aWQ6c2VjcmV0", utils.ConvertYoomoneySercetsToAuth("Basic ", "id", "secret"))
})
}

@ -1,30 +0,0 @@
kind: Deployment
apiVersion: apps/v1
metadata:
name: treasurer
spec:
replicas: 1
selector:
matchLabels:
app: treasurer
template:
metadata:
labels:
app: treasurer
tier: backend
spec:
imagePullSecrets:
- name: regcred
containers:
- name: treasurer
image: 192.168.193.230:31320/treasurer
imagePullPolicy: Always
resources:
requests:
memory: 50Mi
limits:
memory: 1Gi
ports:
- containerPort: 3000
name: http
restartPolicy: Always

@ -1,11 +0,0 @@
kind: Service
apiVersion: v1
metadata:
name: treasurer
spec:
ports:
- port: 3000
targetPort: 3000
protocol: TCP
selector:
app: treasurer

10
main.go

@ -1,10 +0,0 @@
package main
import (
"bitbucket.org/skeris/treasurer/app"
"github.com/skeris/appInit"
)
func main() {
appInit.Initialize(app.New, app.Options{})
}

@ -0,0 +1 @@
[{ "delete": "amocrm", "deletes": [{ "q": {} }] }]

@ -0,0 +1,85 @@
[
{
"insert": "amocrm",
"ordered": true,
"documents": [
{
"amocrmId": "1",
"userId": "1",
"information": {
"id": 30228997,
"name": "ООО ПЕНА",
"subdomain": "penadigital",
"created_at": 1683680509,
"created_by": 0,
"updated_at": 1683680509,
"updated_by": 0,
"current_user_id": 8110726,
"country": "RU",
"customers_mode": "disabled",
"is_unsorted_on": true,
"is_loss_reason_enabled": true,
"is_helpbot_enabled": false,
"is_technical_account": true,
"contact_name_display_order": 1,
"amojo_id": "",
"uuid": "",
"version": 0,
"_links": { "self": { "href": "https://penadigital.amocrm.ru/api/v4/account" } },
"_embedded": {
"amojo_rights": { "can_direct": false, "can_create_groups": false },
"users_groups": null,
"task_types": null,
"entity_names": {
"leads": {
"ru": {
"gender": "",
"plural_form": {
"dative": "",
"default": "",
"genitive": "",
"accusative": "",
"instrumental": "",
"prepositional": ""
},
"singular_form": {
"dative": "",
"default": "",
"genitive": "",
"accusative": "",
"instrumental": "",
"prepositional": ""
}
},
"en": {
"singular_form": { "default": "" },
"plural_form": { "default": "" },
"gender": ""
},
"es": {
"singular_form": { "default": "" },
"plural_form": { "default": "" },
"gender": ""
}
}
},
"datetime_settings": {
"date_pattern": "",
"short_date_pattern": "",
"short_time_pattern": "",
"date_formant": "",
"time_format": "",
"timezone": "",
"timezone_offset": ""
}
}
},
"audit": {
"createdAt": "2022-12-31T00:00:00.000Z",
"updatedAt": "2022-12-31T00:00:00.000Z",
"deleted": false
}
}
]
}
]

@ -4,11 +4,15 @@ info:
description: |- description: |-
Область отвественности сервиса - получить на вход сумму, которуб надо запросить, и список действий, который надо выполнить, в зависимости от события оплаты Область отвественности сервиса - получить на вход сумму, которуб надо запросить, и список действий, который надо выполнить, в зависимости от события оплаты
version: 1.0.0 version: 1.0.0
tags: tags:
- name: pay - name: pay
paths: paths:
/available
/available:
get: get:
operationId: getAvailablePayments
description: метод для получения списка доступных вариантов для оплаты description: метод для получения списка доступных вариантов для оплаты
tags: tags:
- pay - pay
@ -22,82 +26,166 @@ paths:
example: ["qiwi", "visa", "tinkoff"] example: ["qiwi", "visa", "tinkoff"]
items: items:
type: string type: string
/invoice:
/yandex/payment/status/waiting:
post: post:
description: метод для создания запроса на оплату operationId: setYandexPaymentStatusWaiting
description: Метод для установки статуса платежа "Ожидание"
tags: tags:
- pay - pay
requestBody: requestBody:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/Request' $ref: '#/components/schemas/SetPaymentStatusRequest'
responses: responses:
'200': '200':
description: успешное создание платёжной ссылки description: Успешная установка статуса
content:
application/json:
schema:
type: object
properties:
link:
type: string
example: "google.ru"
'400':
description: недостаточно данных
'500': '500':
description: порой бывает что платёжные решения глючат все сразу, поэтому приходится оповещать о том, что получится запрос только потом description: Внутренняя ошибка
/yandex/payment/status/succeeded:
post:
operationId: setYandexPaymentStatusSucceeded
description: Метод для установки статуса платежа "Успешно"
tags:
- pay
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SetPaymentStatusRequest'
responses:
'200':
description: Успешная установка статуса
'500':
description: Внутренняя ошибка
/yandex/payment/status/canceled:
post:
operationId: setYandexPaymentStatusCanceled
description: Метод для установки статуса платежа "Отменён"
tags:
- pay
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SetPaymentStatusRequest'
responses:
'200':
description: Успешная установка статуса
'500':
description: Внутренняя ошибка
/yandex/refund/status/succeeded:
post:
operationId: setYandexRefundStatusSucceeded
description: Метод для установки статуса возврата "Успешно"
tags:
- pay
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/SetPaymentStatusRequest'
responses:
'200':
description: Успешная установка статуса
'500':
description: Внутренняя ошибка
components: components:
schemas: schemas:
Request:
type: object SetPaymentStatusRequest:
properties:
requester:
type: string
example: "asdf7as6df7a5f5asdf"
description: айдишник юзера, создавшего запрос
amount:
type: integer
format: int64
example: 10000
description: количество денег в сотых долях валюты
currency:
type: string
example: "rub"
description: валюта, в которой юзер хочет запросить деньги. Если для такой валюты нет платёжного решения, через переменные окружения должна передаваться дефолтная валюта, которая будет использоваться в таком случае
payway:
type: string
example: "qiwi"
description: платёжный метод, который хочет использовать пользователь для пополнения баланса
additional:
type: string
example: "+79885895677"
description: некоторым платёжным решениям необходимы дополнительные данные, типа номера телефона или почты. Я пока не знаю, как сделать это красиво, пусть будет так
on_accept:
type: array
items:
$ref: '#/components/schemas/Action'
on_decline:
type: array
items:
$ref: '#/components/schemas/Action'
on_timeout:
type: array
items:
$ref: '#/components/schemas/Action'
Action:
type: object type: object
required: [type, event, object]
properties: properties:
type: type:
type: string type: string
enum: ["post", "get", "put", "delete", "patch"] description: Тип объекта. Фиксированное значение — notification (уведомление)
description: это варианты запросов по сети. В последствии тут ещё появятся всякие варианты с отправкой смс, почты, оповещений в телегу и прочих методов доставки результата оплаты example: "notification"
example: post event:
target: $ref: '#/components/schemas/Event'
object:
$ref: '#/components/schemas/YandexPayment'
YandexPayment:
type: object
required: [id, status, amount, recipient, created_at, test, paid, refundable]
properties:
id:
type: string type: string
description: в случае с http запросами, это url на который надо сделать запрос description: Идентификатор платежа в ЮKassa
example: "google.ru" example: "asdf7as6df7a5f5asdf"
data: status:
$ref: '#/components/schemas/PaymentStatus'
amount:
$ref: '#/components/schemas/Amount'
income_amount:
$ref: '#/components/schemas/Amount'
recipient:
$ref: '#/components/schemas/Recipient'
description:
type: string type: string
description: данные, которые надо передать. в условиях https запросов это json или query string description: Описание
example: "{\"some\":\"shit\"}" example: "Описание"
payment_method:
type: object
description: Структура метода платежа (может отличаться от способа платежа)
captured_at:
type: string
description: Время подтверждения платежа
expires_at:
type: string
description: Время, до которого вы можете бесплатно отменить или подтвердить платеж
created_at:
type: string
description: Время создания заказа
confirmation:
type: object
description: Выбранный способ подтверждения платежа
test:
type: boolean
description: Признак тестовой операции
refunded_amount:
$ref: '#/components/schemas/Amount'
paid:
type: boolean
description: Признак оплаты заказа
refundable:
type: boolean
description: Возможность провести возврат по API
Amount:
type: object
required: [value, currency]
properties:
value:
type: string
description: Сумма в выбранной валюте
example: "10.00"
currency:
type: string
description: Трехбуквенный код валюты в формате ISO-4217
example: "RUB"
Recipient:
type: object
required: [account_id, gateway_id]
properties:
account_id:
type: string
description: Идентификатор магазина в ЮKassa
gateway_id:
type: string
description: Идентификатор субаккаунта
PaymentStatus:
type: string
enum: ["waiting_for_capture", "pending", "succeeded", "canceled"]
Event:
type: string
enum: ["payment.waiting_for_capture", "payment.succeeded", "payment.canceled", "refund.succeeded"]

@ -1,46 +0,0 @@
#!/bin/sh -e
cd ..
echo ""
echo ""
echo "################################################################"
echo "#### BUILDING APP"
echo "################################################################"
echo ""
echo ""
make build
echo ""
echo ""
echo "################################################################"
echo "#### BUILDING DOCKER IMAGE"
echo "################################################################"
echo ""
echo ""
sudo docker build -t 192.168.193.230:31320/treasurer:latest .
echo ""
echo ""
echo "################################################################"
echo "#### BUILDING PUSH IMAGE"
echo "################################################################"
echo ""
echo ""
sudo docker push 192.168.193.230:31320/treasurer
echo ""
echo ""
echo "################################################################"
echo "#### RELOAD PODS"
echo "################################################################"
echo ""
echo ""
# TODO: rolling-update
cd ./k8s; kubectl apply -f ./deployment.yml; kubectl apply -f service.yml
kubectl rollout restart deployment treasurer

@ -1,33 +0,0 @@
#!/bin/sh -e
cd ..
git checkout dev
echo ""
echo ""
echo "################################################################"
echo "#### BUILDING APP"
echo "################################################################"
echo ""
echo ""
make build
echo ""
echo ""
echo "################################################################"
echo "#### BUILDING DOCKER IMAGE"
echo "################################################################"
echo ""
echo ""
sudo docker build -t 192.168.193.154:31320/treasurer:latest . -f ./DockerfileStaging
echo ""
echo ""
echo "################################################################"
echo "#### BUILDING PUSH IMAGE"
echo "################################################################"
echo ""
echo ""
sudo docker push 192.168.193.154:31320/treasurer

@ -1,3 +0,0 @@
FROM scratch
ADD test /
CMD ["/test"]

@ -1,168 +0,0 @@
package payway
import (
"bitbucket.org/skeris/treasurer/dal"
"context"
"crypto/md5"
"encoding/json"
"fmt"
"github.com/fatih/structs"
"sort"
)
const UrlBt = "https://merchant.betatransfer.io/api"
type BetaTransfer struct {
MongoID string
Name string
MerchantID string
WalletID string
Secret1 string // Request key
Secret2 string // Response key
Secret3 string // Wallet API Key
PayoutTypeList []dal.PayoutType
PaymentTypeList []dal.PayWayPayment
}
func NewBt(ctx context.Context, conn *dal.MongoConnection) (*BetaTransfer, error) {
bt, err := conn.GetPayWayByName(ctx, "BetaTransfer")
if err != nil {
return nil, err
}
paymentList, err := conn.GetPayWayPaymentByPayWay(ctx, bt.ShortName)
if err != nil {
return nil, err
}
return &BetaTransfer{
MongoID: bt.ID,
Name: bt.Name,
MerchantID: bt.MerchantID,
WalletID: bt.WalletID,
Secret1: bt.Secret1,
Secret2: bt.Secret2,
PayoutTypeList: bt.PayoutTypeList,
PaymentTypeList: paymentList,
}, nil
}
func (bt *BetaTransfer) GetMongoID() string {
return bt.MongoID
}
func (bt *BetaTransfer) GetName() string {
return bt.Name
}
func (bt *BetaTransfer) UpdateData(data *dal.PayWay) {
bt.MongoID = data.ID
bt.Name = data.MerchantID
bt.MerchantID = data.MerchantID
bt.Secret1 = data.Secret1
bt.Secret2 = data.Secret2
bt.Secret3 = data.Secret3
}
func (bt *BetaTransfer) UpdatePayment(data []dal.PayWayPayment) {
bt.PaymentTypeList = data
}
func (bt *BetaTransfer) UpdatePayout(data []dal.PayoutType) {
bt.PayoutTypeList = data
}
type ReqPaymentListenerBt struct {
Sign string
Amount float64
OrderId string
UserComment string
}
// GetPayoutTypeList - возвращает локальные способы вывода средств из кошелька
func (bt *BetaTransfer) GetPayoutTypeList() []dal.PayoutType {
return bt.PayoutTypeList
}
// GetPayoutType - возвращает локальный указанный способ вывода средств, либо nil если не найдено
func (bt *BetaTransfer) GetPayoutType(payoutType string) *dal.PayoutType {
for _, v := range bt.PayoutTypeList {
if v.ApiId == payoutType {
return &v
}
}
return nil
}
// GetPaymentTypeList - возвращает локальные способы пополнения
func (bt *BetaTransfer) GetPaymentTypeList() []dal.PayWayPayment {
return bt.PaymentTypeList
}
// GetPaymentType - возвращает локальный указанный способ пополнения, либо nil если не найдено
func (bt *BetaTransfer) GetPaymentType(paymentType string) *dal.PayWayPayment {
for _, v := range bt.PaymentTypeList {
if v.ApiId == paymentType {
return &v
}
}
return nil
}
// FindPayoutType - возвращает локальный указанный способ вывода средств учитывая amount.
// Возвращает nil если ничего не найдено
func (bt *BetaTransfer) FindPayoutType(payoutType string, amount float64) *dal.PayoutType {
for _, v := range bt.PayoutTypeList {
if v.ApiId == payoutType && amount > v.Minimum && amount < v.Maximum {
return &v
}
}
return nil
}
// prepareData - сортирует структуру по имени поля, добавляет подпись и переводит в байты
func (bt *BetaTransfer) prepareData(data interface{}) ([]byte, error) {
s := structs.New(data)
structMap := s.Map() // Преобразуем структуру в map
// Сортируем по ключу
keys := make([]string, 0, len(structMap))
for k := range structMap {
keys = append(keys, k)
}
sort.Strings(keys)
sorted := map[string]interface{}{}
var str string
for _, k := range keys {
if structMap[k] != "" {
sorted[s.Field(k).Tag("json")] = structMap[k]
str += fmt.Sprintf("%v", structMap[k])
}
}
// Добавляем подпись
sorted["sign"] = bt.createSign([]string{str})
// Переводим в байты
return json.Marshal(sorted)
}
// createSign - создает md5-подпись из указанного массива строк. В конец строки добавляет Secret2
func (bt *BetaTransfer) createSign(s []string) string {
var str string
for _, v := range s {
str += v
}
str += bt.Secret2
h := md5.Sum([]byte(str))
return fmt.Sprintf("%x", h)
}

@ -1,322 +0,0 @@
package payway
import (
"bitbucket.org/skeris/treasurer/dal"
"bytes"
"context"
"crypto/md5"
"encoding/json"
"errors"
"fmt"
"github.com/rs/xid"
"io/ioutil"
"log"
"net/http"
"net/url"
"strconv"
)
//#region ========= Payment =========
type ReqCreatePaymentUrlBt struct {
Amount string `json:"amount"` // Required
Currency string `json:"currency"` // Required
OrderId string `json:"orderId"` // Required
PaymentSystem string `json:"paymentSystem,omitempty"`
UrlResult string `json:"urlResult,omitempty"`
UrlSuccess string `json:"urlSuccess,omitempty"`
UrlFail string `json:"urlFail,omitempty"`
Locale string `json:"locale,omitempty"`
PayerPhone string `json:"payerPhone,omitempty"`
PayerName string `json:"payerName,omitempty"`
PayerEmail string `json:"payerEmail,omitempty"`
PayerFirstName string `json:"payer_firstname,omitempty"`
PayerLastName string `json:"payer_lastname,omitempty"`
PayerPostCode string `json:"payer_postcode,omitempty"`
PayerAddress string `json:"payer_address,omitempty"`
Ip string `json:"ip,omitempty"`
UserComment string `json:"user_comment"` // Returned in Callback
Sign string `json:"sign"` // Required
}
type RespCreatePaymentUrlBt struct {
Status interface{} `json:"status"`
Id int64 `json:"id"`
Url string `json:"url"`
UrlPayment string `json:"urlPayment"`
}
// CreatePaymentUrl - создает ссылку для перевода средств на кошелек (пополнение счета клиента)
func (bt *BetaTransfer) CreatePaymentUrl(amount, orderID, paymentType, currency, lang, email, phone, requesterID,
userIP string) (string, error) {
action := UrlBt + "/payment?token=" + bt.Secret1
data := ReqCreatePaymentUrlBt{
Amount: amount,
Currency: currency,
OrderId: orderID,
PaymentSystem: paymentType,
UrlResult: "",
UrlSuccess: "",
UrlFail: "",
Locale: lang,
PayerPhone: phone,
PayerName: "",
PayerEmail: email,
PayerFirstName: "",
PayerLastName: "",
PayerPostCode: "",
PayerAddress: "",
Ip: "",
UserComment: requesterID,
Sign: "",
}
body, err := bt.prepareData(data)
fmt.Println("Request:", string(body))
if err != nil {
fmt.Println("MarshalErr:", err)
}
params := url.Values{}
params.Add("amount", data.Amount)
params.Add("currency", data.Currency)
params.Add("orderId", xid.New().String())
params.Add("paymentSystem", data.PaymentSystem)
params.Add("locale", lang)
params.Add("user_comment", orderID)
json.Unmarshal(body, &data)
params.Add("sign", data.Sign)
resp, err := http.PostForm(action, params)
fmt.Println("Status:", resp.Status)
var result RespCreatePaymentUrlBt
bodyr, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(" ioutil: ", err)
}
if resp.StatusCode != 200 {
return "", errors.New("bad response: " + string(bodyr))
}
err = json.Unmarshal(bodyr,&result)
if err != nil {
log.Println(" json: ", err)
}
fmt.Println(result)
return result.Url, nil
}
// PaymentListener - Обрабатывает результат перевода
func (bt *BetaTransfer) PaymentListener(ctx context.Context,ip string, request interface{}, mc *dal.MongoConnection) error {
data := request.(*ReqPaymentListenerBt)
if data.Sign != fmt.Sprintf("%x",
md5.Sum([]byte(fmt.Sprint(data.Amount)+data.OrderId+bt.Secret2))) {
return errors.New(fmt.Sprintf("wrong sign: %v, %s, %s", data.Sign, data.OrderId, bt.Secret2))
}
// Проверка существования платежа в БД
payment, err := mc.GetPayment(ctx, data.UserComment)
if err != nil {
return err
}
if payment == nil {
return errors.New("payment not found")
}
// Проверка статуса платежа (должен быть open)
//if payment.Status != "open" || {
// return errors.New(fmt.Sprintf("payment have status: %v", payment.Status))
//}
// Проверка суммы платежа
//if data.Amount != payment.Amount {
// return errors.New(fmt.Sprintf("wrong amount: %v", data.Amount))
//}
//
//// Проверка RequesterID
//if data.RequesterID != payment.RequesterID {
// return errors.New(fmt.Sprintf("wrong us_requesterID: %v", data.RequesterID))
//}
// Обновление статуса платежа в БД
if payment.Status != "accepted" {
err = mc.UpdatePaymentStatus(ctx, data.UserComment, "accepted")
if err != nil {
return err
}
}
return nil
}
func (bt *BetaTransfer) GetPaymentList() ([]dal.PayWayPayment, error) {
//TODO: implement me
return bt.GetPaymentTypeList(), nil
}
//#endregion
//#region ========= Payout =========
type ReqCreatePayoutBt struct {
Amount string `json:"amount,omitempty"` // Required
Currency string `json:"currency"` // Required
OrderId string `json:"orderId"` // Required
PaymentSystem string `json:"paymentSystem"` // Required
UrlResult string `json:"urlResult,omitempty"`
Address string `json:"address"` // Required. Purse
Sign string `json:"sign"` // Required
}
type RespCreatePayoutBt struct {
Status string `json:"status"`
Id int `json:"id"`
PaymentSystem string `json:"paymentSystem"`
OrderId string `json:"orderId"`
OrderAmount string `json:"orderAmount"`
OrderCurrency string `json:"orderCurrency"`
PaymentAmount string `json:"paymentAmount"`
PaymentCurrency string `json:"paymentCurrency"`
Commission string `json:"commission"`
CommissionCurrency string `json:"commissionCurrency"`
}
// CreatePayout - выполняет запрос для вывода средств из кошелька (вывод средств со счета клиента).
// В ответ получает RespCreatePayoutBt
// purse - кошелек для вывода
// amount - сумма для вывода
// desc - описание/комментарий (OrderId)
// exchange = 1 - отключить автообмен
// currency - валюта для вывода
func (bt *BetaTransfer) CreatePayout(amount, orderID, payoutType, currency, address string) (string, error) {
action := UrlBt + "//withdrawal-payment?token=" + bt.Secret1
payout := bt.GetPayoutType(payoutType)
if currency == "" {
currency = payout.Currency
}
data := ReqCreatePayoutBt{
Amount: amount,
Currency: currency,
OrderId: orderID,
PaymentSystem: payoutType,
UrlResult: "",
Address: address,
Sign: "",
}
body, err := bt.prepareData(data)
if err != nil {
fmt.Println("MarshalErr:", err)
}
resp, err := http.Post(action, "application/json", bytes.NewReader(body))
defer func() {
resp.Body.Close()
}()
fmt.Println("Status:", resp.Status)
var result RespCreatePayoutBt
err = json.NewDecoder(resp.Body).Decode(&result)
if resp.StatusCode != 200 {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(" ioutil: ", err)
}
return "", errors.New("bad response: " + string(body))
}
fmt.Println(result)
return strconv.Itoa(result.Id), nil
}
// PayoutListener - обрабатывает результат вывода
func (bt *BetaTransfer) PayoutListener(ctx context.Context, ip string, request interface{}, mc *dal.MongoConnection) error {
fmt.Println("bt.PayoutListener:", request)
return nil
}
func (bt *BetaTransfer) GetPayoutList() ([]dal.PayoutType, error) {
//TODO: implement me
return bt.GetPayoutTypeList(), nil
}
//#endregion
//#region ========= Wallet =========
type RespGetWalletBalanceBt struct {
Account struct {
LockWithdrawal bool `json:"lockWithdrawal"`
LockAccount bool `json:"lockAccount"`
AuthAt int `json:"authAt"`
} `json:"account"`
Balance map[string]string `json:"balance"`
BalanceOnHold map[string]string `json:"balance_on_hold"`
}
// GetWalletBalance - выполняет запрос чтобы узнать баланс кошелька
func (bt *BetaTransfer) GetWalletBalance() (map[string]float64, error) {
action := UrlBt + "/account-info"
params := url.Values{
"token": {bt.Secret1},
"sign": {bt.createSign([]string{bt.Secret1})},
}
action += fmt.Sprintf("?%v", params.Encode())
client := &http.Client{}
resp, err := client.Get(action)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, errors.New(fmt.Sprintf("got bad status: %v", resp.Status))
}
var response RespGetWalletBalanceBt
err = json.NewDecoder(resp.Body).Decode(&response)
if err != nil {
return nil, err
}
var result map[string]float64
for key, val := range response.Balance {
if val == "" {
val = "0.0"
}
toFloat, err := strconv.ParseFloat(val, 64)
if err != nil {
return nil, err
}
result[key] = toFloat
}
return result, nil
}
//#endregion

@ -1,191 +0,0 @@
package payway
import (
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/json"
"fmt"
"sort"
"strings"
"time"
"bitbucket.org/skeris/treasurer/dal"
"github.com/fatih/structs"
"go.mongodb.org/mongo-driver/mongo"
)
//const AllowedIPs = "136.243.38.147 136.243.38.149 136.243.38.150 136.243.38.151 136.243.38.189"
type FreeKassa struct {
MongoID string
Name string
ShortName string
MerchantID string
WalletID string
Secret1 string // Request key
Secret2 string // Response key
Secret3 string // Wallet API Key
PayoutTypeList []dal.PayoutType
PaymentTypeList []dal.PayWayPayment
}
func NewFk(ctx context.Context, conn *dal.MongoConnection) (*FreeKassa, error) {
fmt.Println("NewFK0")
fk, err := conn.GetPayWayByName(ctx, "FreeKassa")
if err != nil {
if err == mongo.ErrNoDocuments {
fk = &dal.PayWay{
ID: "fk1",
Name: "FreeKassa",
ShortName: "fk",
MerchantID: "20397",
WalletID: "20397",
Secret1: "+%H$+Jb$gNw<PbE",
Secret2: "*}/^bkOCGq[C*Ss",
Secret3: "db9f770bf1b400445fb9c7d82e59ba81",
PayoutTypeList: []dal.PayoutType{},
CreatedAt: time.Time{},
UpdatedAt: time.Time{},
}
fk.ID, err = conn.InsertPayWay(ctx, *fk)
if err != nil {
return nil, err
}
} else {
return nil, err
}
}
paymentList, err := conn.GetPayWayPaymentByPayWay(ctx, fk.ShortName)
if err != nil {
return nil, err
}
return &FreeKassa{
MongoID: fk.ID,
Name: fk.Name,
ShortName: fk.ShortName,
MerchantID: fk.MerchantID,
WalletID: fk.WalletID,
Secret1: fk.Secret1,
Secret2: fk.Secret2,
Secret3: fk.Secret3,
PayoutTypeList: fk.PayoutTypeList,
PaymentTypeList: paymentList,
}, nil
}
func (fk *FreeKassa) GetMongoID() string {
return fk.MongoID
}
func (fk *FreeKassa) GetName() string {
return fk.Name
}
func (fk *FreeKassa) UpdateData(data *dal.PayWay) {
fk.MongoID = data.ID
fk.Name = data.MerchantID
fk.MerchantID = data.MerchantID
fk.Secret1 = data.Secret1
fk.Secret2 = data.Secret2
fk.Secret3 = data.Secret3
}
func (fk *FreeKassa) UpdatePayment(data []dal.PayWayPayment) {
fk.PaymentTypeList = data
}
func (fk *FreeKassa) UpdatePayout(data []dal.PayoutType) {
fk.PayoutTypeList = data
}
// GetPayoutTypeList - возвращает локальные способы вывода средств из кошелька
func (fk *FreeKassa) GetPayoutTypeList() []dal.PayoutType {
return fk.PayoutTypeList
}
// GetPayoutType - возвращает локальный указанный способ вывода средств, либо nil если не найдено
func (fk *FreeKassa) GetPayoutType(payoutType string) *dal.PayoutType {
for _, v := range fk.PayoutTypeList {
if v.ApiId == payoutType {
return &v
}
}
return nil
}
// GetPaymentTypeList - возвращает локальные способы пополнения
func (fk *FreeKassa) GetPaymentTypeList() []dal.PayWayPayment {
return fk.PaymentTypeList
}
// GetPaymentType - возвращает локальный указанный способ пополнения, либо nil если не найдено
func (fk *FreeKassa) GetPaymentType(paymentType string) *dal.PayWayPayment {
for _, v := range fk.PaymentTypeList {
if v.ApiId == paymentType {
return &v
}
}
return nil
}
// FindPayoutType - возвращает локальный указанный способ вывода средств учитывая amount.
// Возвращает nil если ничего не найдено
func (fk *FreeKassa) FindPayoutType(payoutType string, amount float64) *dal.PayoutType {
for _, v := range fk.PayoutTypeList {
if v.ApiId == payoutType && amount > v.Minimum && amount < v.Maximum {
return &v
}
}
return nil
}
// prepareData - сортирует структуру по имени поля, добавляет подпись и переводит в байты
func (fk *FreeKassa) prepareData(data interface{}) ([]byte, error) {
s := structs.New(data)
structMap := s.Map() // Преобразуем структуру в map
// Сортируем по ключу
keys := make([]string, 0, len(structMap))
for k := range structMap {
keys = append(keys, k)
}
sort.Strings(keys)
sorted := map[string]interface{}{}
var arr []string
for _, k := range keys {
if structMap[k] != "" {
sorted[s.Field(k).Tag("json")] = structMap[k]
arr = append(arr, fmt.Sprintf("%v", structMap[k]))
}
}
// Добавляем подпись
sorted["signature"] = fk.createSign(arr)
// Переводим в байты
return json.Marshal(sorted)
}
// createSign - создает hmac_sha256 подпись по Secret1
func (fk *FreeKassa) createSign(data []string) string {
str := strings.Join(data, "|")
sign := hmac.New(sha256.New, []byte("45fb9c7d82e59ba81"))
sign.Write([]byte(str))
h := sign.Sum(nil)
return fmt.Sprintf("%x", h)
}

@ -1,620 +0,0 @@
package payway
import (
"bytes"
"context"
"crypto/md5"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"strconv"
"time"
"bitbucket.org/skeris/treasurer/dal"
)
const UrlFk = "https://api.freekassa.ru/v1"
const PrivateKey = "SomePrivateKey1!" //16 byte
//#region ========= Payment =========
type ReqCreatePaymentUrlFk struct {
ShopId int64 `json:"shopId"` // Required
Nonce int64 `json:"nonce"` // Required Уникальный ID запроса, должен всегда быть больше предыдущего значения
Signature string `json:"signature"` // Required
PaymentId string `json:"paymentId"`
I int64 `json:"i"` // Required. ID платежной системы. dal.PaymentType.ApiId
Email string `json:"email"` // Required
IP string `json:"ip"` // Required
Amount float64 `json:"amount"` // Required
Currency string `json:"currency"` // Required
Tel string `json:"tel"`
SuccessUrl string `json:"successUrl,omitempty"`
FailureUrl string `json:"failureUrl,omitempty"`
NotificationUrl string `json:"notificationUrl,omitempty"`
}
type RespCreatePaymentUrlFk struct {
Type string `json:"type"`
OrderId int `json:"order_id"`
OrderHash string `json:"order_hash"`
Location string `json:"location"`
}
// CreatePaymentUrl - создает ссылку для перевода средств на кошелек (пополнение счета клиента)
func (fk *FreeKassa) CreatePaymentUrl(amount, orderID, paymentType, currency, lang, email, phone, requesterID,
userIP string) (string,
error) {
action := UrlFk + "/orders/create"
shopID, err := strconv.ParseInt(fk.MerchantID, 10, 64)
if err != nil {
return "", err
}
apiId, err := strconv.ParseInt(paymentType, 10, 64)
if err != nil {
return "", err
}
amountFloat, err := strconv.ParseFloat(amount, 64)
if err != nil {
return "", err
}
data := ReqCreatePaymentUrlFk{
ShopId: shopID,
Nonce: time.Now().Unix(),
Signature: "",
PaymentId: orderID,
I: apiId,
Email: email,
IP: userIP,
Amount: amountFloat,
Currency: currency,
Tel: phone,
SuccessUrl: "",
FailureUrl: "",
NotificationUrl: "",
}
body, err := fk.prepareData(data)
if err != nil {
return "", err
}
resp, err := http.Post(action, "application/json", bytes.NewReader(body))
defer func() {
resp.Body.Close()
}()
fmt.Println("Status:", resp.Status)
var result RespCreatePaymentUrlFk
bodyR, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(" ioutil: ", err)
}
fmt.Println("ERSPONSE", string(bodyR))
err = json.Unmarshal(bodyR, &result)
if err != nil {
log.Println(" JSONNNNNioutil: ", err)
}
if resp.StatusCode != 200 || err != nil {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(" ioutil: ", err)
}
return "", errors.New("bad response: " + string(body))
}
if result.Type != "success" {
return "", errors.New(fmt.Sprintf("bad response: %v", result))
}
fmt.Println(result)
return result.Location, nil
}
type ReqPaymentListenerFk struct {
MerchantID string `schema:"MERCHANT_ID"`
Amount float64 `schema:"AMOUNT"`
IntId string `schema:"intid"`
PaymentID string `schema:"MERCHANT_ORDER_ID"`
PEmail string `schema:"P_EMAIL"`
PPhone string `schema:"P_PHONE"`
CurID string `schema:"CUR_ID"`
Sign string `schema:"SIGN"`
Comission string `schema:"commission"`
PayerAccount string `schema:"payer_account"`
RequesterID string `schema:"us_requesterID"`
}
// PaymentListener - Обрабатывает результат перевода
func (fk *FreeKassa) PaymentListener(ctx context.Context, ip string, request interface{}, mc *dal.MongoConnection) error {
data := request.(*ReqPaymentListenerFk)
// Проверка IP - временно отключен, т.к. получает айпи из зиротира
//if !strings.Contains(ip, AllowedIPs) {
//return errors.New(fmt.Sprintf("this ip not allowed: %v", ip))
//}
// Проверка подписи
//fmt.Println("ORAAAA", fk.MerchantID+":"+fmt.Sprint(int64(data.Amount))+":"+fk.Secret2+":"+data.PaymentID)
//fmt.Println("ORAAAA", md5.Sum([]byte(fk.MerchantID+":"+fmt.Sprint(int64(data.Amount))+":"+fk.Secret2+":"+data.PaymentID)))
//fmt.Println("ORAAAA", fmt.Sprintf("%x",
// md5.Sum([]byte(fk.MerchantID+":"+fmt.Sprint(int64(data.Amount))+":"+fk.Secret2+":"+data.PaymentID))))
if data.Sign != fmt.Sprintf("%x",
md5.Sum([]byte(fk.MerchantID+":"+fmt.Sprint(int64(data.Amount))+":*}/^bkOCGq[C*Ss:"+data.PaymentID))) {
return errors.New(fmt.Sprintf("wrong sign: %v", data))
}
// Проверка существования платежа в БД
payment, err := mc.GetPayment(ctx, data.PaymentID)
if err != nil {
return err
}
if payment == nil {
return errors.New("payment not found")
}
// Проверка статуса платежа (должен быть open)
if payment.Status != "open" {
return errors.New(fmt.Sprintf("payment have status: %v", payment.Status))
}
// Проверка суммы платежа
//if data.Amount != payment.Amount {
// return errors.New(fmt.Sprintf("wrong amount: %v", data.Amount))
//}
//
//// Проверка RequesterID
//if data.RequesterID != payment.RequesterID {
// return errors.New(fmt.Sprintf("wrong us_requesterID: %v", data.RequesterID))
//}
// Обновление статуса платежа в БД
err = mc.UpdatePaymentStatus(ctx, data.PaymentID, "accepted")
if err != nil {
return err
}
return nil
}
type ReqGetPaymentListFk struct {
ShopId int64 `json:"shopId"` // Required
Nonce int64 `json:"nonce"` // Required
Signature string `json:"signature"` // Required
}
type RespGetPaymentListFk struct {
Type string `json:"type"`
Currencies []struct {
Id int `json:"id"`
Name string `json:"name"`
Currency string `json:"currency"`
IsEnabled int `json:"is_enabled"`
IsFavorite int `json:"is_favorite"`
} `json:"currencies"`
}
// GetPaymentList - возвращает из API актуальный список доступных платежных систем
func (fk *FreeKassa) GetPaymentList() ([]dal.PayWayPayment, error) {
action := UrlFk + "/currencies"
shopID, err := strconv.ParseInt(fk.MerchantID, 10, 64)
if err != nil {
return nil, err
}
nonce := time.Now().Unix()
data := ReqGetPaymentListFk{
ShopId: shopID,
Nonce: nonce,
}
body, err := fk.prepareData(data)
if err != nil {
return nil, err
}
resp, err := http.Post(action, "application/json", bytes.NewReader(body))
if err != nil {
fmt.Println("FKAPIERR", err)
return nil, err
}
defer func() {
resp.Body.Close()
}()
fmt.Println("Status:", resp.Status, data)
var result RespGetPaymentListFk
err = json.NewDecoder(resp.Body).Decode(&result)
if resp.StatusCode != 200 || err != nil {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(" ioutil: ", err)
}
return nil, errors.New("bad response: " + string(body))
}
if result.Type != "success" {
return nil, errors.New(fmt.Sprintf("bad response: %v", result))
}
fmt.Println(result)
var formatted []dal.PayWayPayment
for _, item := range result.Currencies {
status := "active"
if item.IsEnabled == 0 {
status = "inactive"
}
formatted = append(formatted, dal.PayWayPayment{
ID: fmt.Sprintf("%v-%v", fk.ShortName, item.Id),
Name: item.Name,
Status: status,
Currency: item.Currency,
ApiId: strconv.Itoa(item.Id),
Commission: 0,
Minimum: 0,
Maximum: 0,
})
}
return formatted, nil
}
//#endregion
//#region ========= Payout =========
type ReqCreatePayoutFk struct {
ShopId int64 `json:"shopId"` // Required
Nonce int64 `json:"nonce"` // Required Уникальный ID запроса, должен всегда быть больше предыдущего значения
Signature string `json:"signature"` // Required
PaymentId string `json:"paymentId"`
I int64 `json:"i"` // Required. ID платежной системы. dal.PayoutType.ApiId
Account string `json:"account"` // Required. Кошелек для зачисления средств
Amount float64 `json:"amount"` // Required
Currency string `json:"currency"` // Required
}
type RespCreatePayoutFk struct {
Type string `json:"type"`
Data struct {
Id int `json:"id"`
} `json:"data"`
}
// CreatePayout - выполняет запрос для вывода средств из кошелька (вывод средств со счета клиента).
// В ответ получает RespCreatePayoutFk
func (fk *FreeKassa) CreatePayout(amount, orderID, payoutType, currency, address string) (string, error) {
action := UrlFk + "/withdrawals/create"
payout := fk.GetPayoutType(payoutType)
if currency == "" {
currency = payout.Currency
}
shopID, err := strconv.ParseInt(fk.MerchantID, 10, 64)
if err != nil {
return "", err
}
apiId, err := strconv.ParseInt(payoutType, 10, 64)
if err != nil {
return "", err
}
amountFloat, err := strconv.ParseFloat(amount, 64)
if err != nil {
return "", err
}
data := ReqCreatePayoutFk{
ShopId: shopID,
Nonce: time.Now().Unix(),
Signature: "",
PaymentId: orderID,
I: apiId,
Account: address,
Amount: amountFloat,
Currency: currency,
}
body, err := fk.prepareData(data)
if err != nil {
return "", err
}
resp, err := http.Post(action, "application/json", bytes.NewReader(body))
defer func() {
resp.Body.Close()
}()
fmt.Println("Status:", resp.Status)
var result RespCreatePayoutFk
err = json.NewDecoder(resp.Body).Decode(&result)
if resp.StatusCode != 200 || err != nil {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(" ioutil: ", err)
}
return "", errors.New("bad response: " + string(body))
}
if result.Type != "success" {
return "", errors.New(fmt.Sprintf("bad response: %v", result))
}
fmt.Println(result)
return strconv.Itoa(result.Data.Id), nil
}
type ReqPayoutListenerFk struct {
WalletID string `json:"wallet_id" schema:"wallet_id"`
OrderID string `json:"order_id" schema:"order_id"`
Status string `json:"status" schema:"status"`
Amount float64 `json:"amount" schema:"amount"`
UserOrderID string `json:"user_order_id" schema:"user_order_id"`
Sign string `json:"sign" schema:"sign"`
}
// PayoutListener - обрабатывает результат вывода
func (fk *FreeKassa) PayoutListener(ctx context.Context, ip string, request interface{}, mc *dal.MongoConnection) error {
data := request.(*ReqPayoutListenerFk)
// Проверка IP - временно отключен, т.к. получает айпи из зиротира
//if !strings.Contains(ip, AllowedIPs) {
//return errors.New(fmt.Sprintf("this ip not allowed: %v", ip))
//}
// Проверка подписи
if data.Sign != fk.createSign([]string{
fk.WalletID,
data.OrderID,
data.UserOrderID,
data.Status,
fmt.Sprint(data.Amount),
}) {
return errors.New(fmt.Sprintf("wrong sign: %v", data.Sign))
}
// Проверка существования платежа в БД
payout, err := mc.GetPaymentByServiceID(ctx, data.OrderID, "false")
if err != nil {
return err
}
if payout == nil {
return errors.New("payment not found")
}
// Проверка статуса платежа (должен быть open)
if payout.Status != "open" {
return errors.New(fmt.Sprintf("payment have status: %v", payout.Status))
}
// Проверка суммы платежа
if data.Amount != payout.Amount {
return errors.New(fmt.Sprintf("wrong amount: %v", data.Amount))
}
// Обновление статуса платежа в БД
var newStatus string
switch data.Status {
case "1":
newStatus = "accepted"
case "9":
newStatus = "declined"
default:
newStatus = ""
}
err = mc.UpdatePaymentStatus(ctx, payout.ID, newStatus)
if err != nil {
return err
}
return nil
}
type ReqGetPayoutListFk struct {
ShopId int64 `json:"shopId"` // Required
Nonce int64 `json:"nonce"` // Required
Signature string `json:"signature"` // Required
}
type RespGetPayoutListFk struct {
Type string `json:"type"`
Currencies []struct {
Id int `json:"id"`
Name string `json:"name"`
Min float64 `json:"min"`
Max float64 `json:"max"`
Currency string `json:"currency"`
CanExchange int `json:"can_exchange"`
} `json:"currencies"`
}
// GetPayoutList - возвращает из API актуальный список доступных платежных систем
func (fk *FreeKassa) GetPayoutList() ([]dal.PayoutType, error) {
action := UrlFk + "/withdrawals/currencies"
shopID, err := strconv.ParseInt(fk.MerchantID, 10, 64)
if err != nil {
return nil, err
}
data := ReqGetPaymentListFk{
ShopId: shopID,
Nonce: time.Now().Unix(),
Signature: "",
}
body, err := fk.prepareData(data)
if err != nil {
return nil, err
}
resp, err := http.Post(action, "application/json", bytes.NewReader(body))
defer func() {
resp.Body.Close()
}()
fmt.Println("Status:", resp.Status)
var result RespGetPayoutListFk
err = json.NewDecoder(resp.Body).Decode(&result)
fmt.Println("StatuRR:", result, resp.StatusCode, err)
if resp.StatusCode != 200 || err != nil {
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(body)
if err != nil {
log.Println(" ioutil: ", err)
}
return nil, errors.New("bad response: " + string(body))
}
fmt.Println(result)
if result.Type != "success" {
return nil, errors.New(fmt.Sprintf("bad response: %v", result))
}
var formatted []dal.PayoutType
for _, item := range result.Currencies {
formatted = append(formatted, dal.PayoutType{
Name: item.Name,
IsEnabled: true,
Currency: item.Currency,
ApiId: strconv.Itoa(item.Id),
Commission: 0,
Minimum: item.Min,
Maximum: item.Max,
})
}
return formatted, nil
}
//#endregionn
//#region ========= Wallet =========
type ReqGetWalletBalanceFk struct {
ShopId int64 `json:"shopId"` // Required
Nonce int64 `json:"nonce"` // Required
Signature string `json:"signature"` // Required
}
type RespGetWalletBalanceFk struct {
Type string `json:"type"`
Balance []struct {
Currency string `json:"currency"`
Value float64 `json:"value"`
} `json:"balance"`
}
// GetWalletBalance - выполняет запрос чтобы узнать баланс кошелька
// В ответ получает RespGetWalletBalanceFk
func (fk *FreeKassa) GetWalletBalance() (map[string]float64, error) {
action := UrlFk + "/balance"
shopID, err := strconv.ParseInt(fk.MerchantID, 10, 64)
if err != nil {
return nil, err
}
data := ReqGetWalletBalanceFk{
ShopId: shopID,
Nonce: time.Now().Unix(),
Signature: "",
}
body, err := fk.prepareData(data)
if err != nil {
return nil, err
}
resp, err := http.Post(action, "application/json", bytes.NewReader(body))
defer func() {
resp.Body.Close()
}()
fmt.Println("Status:", resp.Status)
var result RespGetWalletBalanceFk
err = json.NewDecoder(resp.Body).Decode(&result)
if resp.StatusCode != 200 || err != nil {
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(" ioutil: ", err)
}
return nil, errors.New("bad response: " + string(body))
}
if result.Type != "success" {
return nil, errors.New(fmt.Sprintf("bad response: %v", result))
}
fmt.Println(result)
var formatted map[string]float64
for _, item := range result.Balance {
formatted[item.Currency] = item.Value
}
return formatted, nil
}
//#endregion

@ -1,18 +0,0 @@
package payway
type ErrorType struct {
Err error
}
type InfoType struct {
Info interface{}
}
type ErrorQueueWorker ErrorType
type ErrorCreatePayout struct {
ErrorType
Url string
}
type InfoQueueWorkerDone InfoType

@ -1,393 +0,0 @@
package payway
import (
"context"
"encoding/json"
"fmt"
"time"
"bitbucket.org/skeris/treasurer/dal"
pw "bitbucket.org/skeris/treasurer/payway/payways"
"bitbucket.org/skeris/treasurer/payway/payways/fk"
"github.com/MarsherSusanin/pena_hub_packages_common/fastconfig"
"github.com/gofiber/fiber/v2"
"github.com/themakers/hlog"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type Payways struct {
pws []*pw.Payway
conn *mongo.Client
db *mongo.Database
collSvcs *mongo.Collection
available map[string]createPW
templates map[string]string
errChan chan error
}
const collServices = "services"
type createPW func() *pw.Payway
func New(
ctx context.Context,
conn *mongo.Client,
db string,
errChan chan error,
available ...pw.PayWayI,
) (*Payways, error) {
a := map[string]createPW{}
t := map[string]string{}
for _, p := range available {
name := p.Type()
a[name] = p.Copy
bts, err := json.Marshal(p)
if err != nil {
return nil, err
}
t[name] = string(bts)
}
d := conn.Database(db)
return &Payways{
available: a,
templates: t,
conn: conn,
db: d,
errChan: errChan,
collSvcs: d.Collection(collServices),
}, nil
}
func (p *Payways) Init(ctx context.Context) error {
if err := p.YieldPayways(ctx, p.ProcessPayways); err != nil {
return err
}
go func() {
if err := p.WatchPayways(ctx, p.ProcessPayways); err != nil {
p.errChan <- err
}
}()
return nil
}
func (p *Payways) Register(api *fiber.App) *fiber.App {
api.Get("/services", p.getServices)
return api
}
func (p *Payways) getServices(c *fiber.Ctx) error {
fmt.Println("getServices")
return c.JSON(p.templates)
}
func (p *Payways) ProcessPayways(d *pw.Payway) error {
switch d.Svc {
case "fk":
way := fk.FreeKassa{}
if err := bson.Unmarshal(d.RawCredentials, &way); err != nil {
return err
}
d.Credentials = way
p.pws = append(p.pws, d)
}
return nil
}
func (p *Payways) WatchPayways(ctx context.Context, yield func(d *pw.Payway) error) error {
cs, err := p.collSvcs.Watch(ctx, mongo.Pipeline{}, options.ChangeStream().SetFullDocument(options.UpdateLookup))
if err != nil {
return err
}
for cs.Next(ctx) {
var change fastconfig.Change
if err := cs.Decode(&change); err != nil {
return err
}
var piece pw.Payway
if err := bson.Unmarshal(change.FullDocument, &piece); err != nil {
return err
}
if err := yield(&piece); err != nil {
return err
}
}
return nil
}
func (p *Payways) YieldPayways(ctx context.Context, yield func(d *pw.Payway) error) error {
cur, err := p.collSvcs.Find(ctx, bson.M{})
if err != nil {
return err
}
for cur.Next(ctx) {
var piece pw.Payway
if err := cur.Decode(&piece); err != nil {
return err
}
if err := yield(&piece); err != nil {
return err
}
}
return nil
}
type PaywayAPI interface {
GetWallet() error
CreateInvoice() error
CreatePayout() error
InvoiceListener() error
PayoutListener() error
GetInvoiceCurrencies() error
GetPayoutCurrencies() error
}
type LayerPayWay interface {
GetMongoID() string
GetName() string
UpdateData(data *dal.PayWay)
UpdatePayment(data []dal.PayWayPayment)
UpdatePayout(data []dal.PayoutType)
// Payment
CreatePaymentUrl(amount, orderID, paymentType, currency, lang, email, phone, requesterID, userIP string) (string, error)
PaymentListener(ctx context.Context, ip string, request interface{}, mc *dal.MongoConnection) error
GetPaymentList() ([]dal.PayWayPayment, error)
GetPaymentTypeList() []dal.PayWayPayment
GetPaymentType(paymentType string) *dal.PayWayPayment
// Payout
CreatePayout(amount, orderID, payoutType, currency, address string) (string, error)
PayoutListener(ctx context.Context, ip string, request interface{}, mc *dal.MongoConnection) error
GetPayoutList() ([]dal.PayoutType, error)
GetPayoutType(payoutType string) *dal.PayoutType
FindPayoutType(payType string, amount float64) *dal.PayoutType
GetWalletBalance() (map[string]float64, error)
}
type PayWay struct {
mongo *dal.MongoConnection
Cache
*QueuePayout
}
func NewPayWay(
ctx context.Context,
logger hlog.Logger,
mongoPayWay, mongoTreasurer *dal.MongoConnection) (*PayWay, error) {
fk, err := NewFk(ctx, mongoPayWay)
if err != nil {
return nil, err
}
bt, err := NewBt(ctx, mongoPayWay)
if err != nil {
return nil, err
}
// TODO: пока заполняем всё это вручную, стоит ли автоматизировать?
cache := Cache{
"fk": fk,
"bt": bt,
}
queue := NewQueuePayout()
// Заполняем очередь значениями из бд
ptList, err := mongoTreasurer.GetPaymentListByStatus(ctx, "open", "false")
if err != nil {
return nil, err
}
for _, payout := range ptList {
queue.Enqueue(payout.ID)
}
payWay := &PayWay{
Cache: cache,
QueuePayout: queue,
mongo: mongoPayWay,
}
worker := newQueueWorker(ctx, payWay, logger, mongoTreasurer)
// update workers
go payWay.WorkerUpdatePayment(ctx)
go payWay.WorkerUpdatePayout(ctx)
go worker.routine()
return payWay, nil
}
type Cache map[string]LayerPayWay
func (c Cache) GetPayWayById(id string) LayerPayWay {
for _, way := range c {
fmt.Println("way:", way.GetMongoID())
if id == way.GetMongoID() {
return way
}
}
return nil
}
func (c Cache) GetPayWayListByPayoutType(payoutType string, amount float64) map[string]LayerPayWay {
result := map[string]LayerPayWay{}
for name, pw := range c {
pt := pw.FindPayoutType(payoutType, amount)
if pt != nil {
result[name] = pw
}
}
return result
}
func (c Cache) GetPaymentList() (map[string][]dal.PayWayPayment, error) {
result := map[string][]dal.PayWayPayment{}
for k, v := range c {
arr, err := v.GetPaymentList()
if err != nil {
fmt.Printf("%v.GetPaymentListErr: %v \r\n", k, err)
return nil, err
}
result[k] = arr
}
return result, nil
}
func (p PayWay) WorkerUpdatePayment(ctx context.Context) {
for {
for name, pw := range p.Cache {
data, err := pw.GetPaymentList()
if err != nil {
fmt.Printf("worker.%v.GetPaymentListErr: %v \r\n", name, err)
}
for k, item := range data {
id := fmt.Sprintf("%v-%v", name, item.ApiId)
data[k].ID = id
payment, err := p.mongo.GetPayWayPayment(ctx, id)
if err != nil {
fmt.Printf("worker.%v.GetPayWayPaymentByApiIdAndPayWay: %v \r\n", name, err)
//payment.ID = xid.New().String()
}
if payment == nil {
payment = &dal.PayWayPayment{ID: id}
}
//if payment != nil {
err = p.mongo.UpdatePayWayPayment(ctx, dal.PayWayPayment{
ID: payment.ID,
ApiId: item.ApiId,
Name: item.Name,
PayWay: name,
Currency: item.Currency,
Commission: item.Commission,
Minimum: item.Minimum,
Maximum: item.Maximum,
Status: item.Status,
})
if err != nil {
fmt.Printf("worker.%v.GetPayWayPaymentByApiIdAndPayWay: %v \r\n", name, err)
}
//} else {
// if err != nil {
// fmt.Printf("worker.%v.GetPayWayPaymentByApiIdAndPayWay: %v \r\n", name, err)
// }
//}
}
pw.UpdatePayment(data)
}
// Прерывание
select {
case <-ctx.Done():
return
case <-time.After(10 * time.Minute): // Сладкий сон
continue
}
}
}
func (p PayWay) WorkerUpdatePayout(ctx context.Context) {
for {
for name, pw := range p.Cache {
data, err := pw.GetPayoutList()
if err != nil {
fmt.Printf("worker.%v.GetPaymentListErr: %v \r\n", name, pw)
}
fmt.Println("OTTO", name, err, data)
pw.UpdatePayout(data)
if err := p.mongo.UpdatePayWay(ctx, dal.PayWay{
ID: pw.GetMongoID(),
PayoutTypeList: data,
}); err != nil {
fmt.Println("UpdatePayoutErr", err)
}
}
// Прерывание
select {
case <-ctx.Done():
return
case <-time.After(10 * time.Minute): // Сладкий сон
continue
}
}
}

@ -1,329 +0,0 @@
package fk
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"reflect"
"sort"
"strings"
"time"
)
const UrlFk = "https://api.freekassa.ru/v1"
type ReqCreateInvoice struct {
ShopId int64 `json:"shopId"`
Nonce int64 `json:"none"`
Signature string `json:"signature"`
PaymentId string `json:"paymentId"`
I int64 `json:"i"`
Email string `json:"email"`
IP string `json:"ip"`
Amount float64 `json:"amount"`
Currency string `json:"currency"`
Tel string `json:"tel"`
SuccessUrl string `json:"successUrl,omitempty"`
FailureUrl string `json:"failureUrl,omitempty"`
NotificationUrl string `json:"motificationUrl,omitempty"`
}
type RespCreateInvoice struct {
Type string `json:"type"`
OrderId int `json:"order_id"`
OrderHash string `json:"order_hash"`
Location string `json:"location"`
}
func (pw *FreeKassa) CreatePaymentUrl(paymentType int64, amount float64, orderId, email, ip, currency, phone string) (string, error) {
body, err := pw.create(&ReqCreateInvoice{
ShopId: pw.ShopId,
Nonce: time.Now().Unix(),
PaymentId: orderId,
I: paymentType,
Email: email,
IP: ip,
Amount: amount,
Currency: currency,
Tel: phone,
})
if err != nil {
return "", err
}
resp, err := http.Post(UrlFk+"/orders/create", "application/json", bytes.NewReader(body))
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", err
}
var result RespCreateInvoice
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return "", err
}
if result.Type != "success" {
return "", fmt.Errorf("create link bad response: %v", result)
}
return result.Location, nil
}
type ReqOrdersHistory struct {
ShopId int64 `json:"id"`
Nonce int64 `json:"nonce"`
Signature string `json:"signature"`
DateFrom string `json:"dateFrom"`
DateTo string `json:"dateTo"`
}
type RespOrdersHistory struct {
Type string `json:"type"`
Pages int64 `json:"pages"`
Orders []Order `json:"orders"`
}
type Order struct {
MerchantOrderId string `json:"merchant_order_id"`
FkOrderId int64 `json:"fk_order_id"`
Amount float64 `json:"amount"`
Currency string `json:"currency"`
Email string `json:"email"`
Account string `json:"account"`
Date string `json:"date"`
Status int `json:"status"`
}
func (pw *FreeKassa) GetOrdersHistory() ([]Order, error) {
var resp RespOrdersHistory
if err := pw.apiRequest("https://api.freekassa.ru/v1/orders", &pw.getOrders, &ReqOrdersHistory{
ShopId: pw.ShopId,
Nonce: time.Now().Unix(),
}, &resp); err != nil {
return nil, err
}
return resp.Orders, nil
}
type ReqGetWallet struct {
ShopId int64 `json:"shopId"`
Nonce int64 `json:"nonce"`
Signature string `json:"signature"`
}
type WalletResp struct {
Type string `json:"type"`
Balance []Wallet `json:"balance"`
}
type Wallet struct {
Currency string `json:"currency" bson:"cur"`
Value string `json:"value" bson:"val"`
}
func (pw *FreeKassa) GetWallet() ([]Wallet, error) {
var resp WalletResp
if err := pw.apiRequest("https://api.freekassa.ru/v1/balance", &pw.wallet, &ReqGetWallet{
ShopId: pw.ShopId,
Nonce: time.Now().Unix(),
}, &resp); err != nil {
return nil, err
}
fmt.Println("wallet", resp)
return resp.Balance, nil
}
type CurreciesResp struct {
Type string `json:"type"`
Currencies []Currency `json:"currencies"`
}
type Currency struct {
Id int `json:"id" bson:"id"`
Name string `json:"name" bson:"name"`
Currency string `json:"currency" bson:"cur"`
IsEnabled uint8 `json:"is_enabled" bson:"is_enabled"`
IsFavourite uint8 `json:"is_favourite" bson:"is_fav"`
}
func (pw *FreeKassa) GetCurrencies() ([]Currency, error) {
var resp CurreciesResp
if err := pw.apiRequest("https://api.freekassa.ru/v1/currencies", &pw.wallet, &ReqGetWallet{
ShopId: pw.ShopId,
Nonce: time.Now().Unix(),
}, &resp); err != nil {
return nil, err
}
fmt.Println("currencies", resp)
return resp.Currencies, nil
}
type ShopResp struct {
Type string `json:"type"`
Shops []Shop `json:"shops"`
}
type Shop struct {
Id int `json:"id" bson:"id"`
Name string `json:"name" bson:"name"`
Url string `json:"url" bson:"url"`
}
func (pw *FreeKassa) GetShops() ([]Shop, error) {
var resp ShopResp
if err := pw.apiRequest("https://api.freekassa.ru/v1/shops", &pw.wallet, &ReqGetWallet{
ShopId: pw.ShopId,
Nonce: time.Now().Unix(),
}, &resp); err != nil {
return nil, err
}
fmt.Println("shops", resp)
return resp.Shops, nil
}
type WithdrawalCurrenciesResp struct {
Type string `json:"type"`
Currencies []WithdrawalCurrencie `json:"currencies"`
}
type WithdrawalCurrencie struct {
Id int `json:"id" bson:"id"`
Name string `json:"name" bson:"name"`
Min float64 `json:"min" bson:"min"`
Max float64 `json:"max" bson:"max"`
Currency string `json:"currency" bson:"cur"`
CanExcahnge uint8 `json:"can_exchange" bson:"can_exch"`
}
func (pw *FreeKassa) GetWithdrawalCurrencies() ([]WithdrawalCurrencie, error) {
var resp WithdrawalCurrenciesResp
if err := pw.apiRequest("https://api.freekassa.ru/v1/withdrawals/currencies", &pw.wallet, &ReqGetWallet{
ShopId: pw.ShopId,
Nonce: time.Now().Unix(),
}, &resp); err != nil {
return nil, err
}
fmt.Println("withdrawals cur", resp)
return resp.Currencies, nil
}
type Access struct {
Type string `json:"type"`
}
func (pw *FreeKassa) Accesable(id int) (bool, error) {
var resp Access
if err := pw.apiRequest(fmt.Sprintf("https://api.freekassa.ru/currencies/%d/status", id), &pw.wallet, &ReqGetWallet{
ShopId: pw.ShopId,
Nonce: time.Now().Unix(),
}, &resp); err != nil {
return false, nil
}
if resp.Type != "success" {
return false, nil
}
return true, nil
}
func (pw *FreeKassa) apiRequest(url string, p *preparer, r, dest any) error {
body, err := (*p)(r)
if err != nil {
return err
}
resp, err := http.Post(url, "application/json", bytes.NewBuffer(body))
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
return fmt.Errorf("status code: %d\nbad response: %s", resp.StatusCode, string(b))
}
if err := json.NewDecoder(resp.Body).Decode(dest); err != nil {
return err
}
return nil
}
func (pw *FreeKassa) prepareData(shape any) func(data any) ([]byte, error) {
var (
sind []int
indexes [][]int
)
func() {
var (
fieldNames []string
ind = map[string][]int{}
)
for _, f := range reflect.VisibleFields(reflect.Indirect(reflect.ValueOf(shape)).Type()) {
name := strings.Split(f.Tag.Get("json"), ",")[0]
if name != "signature" {
fieldNames = append(fieldNames, name)
ind[name] = f.Index
} else {
sind = f.Index
}
}
sort.Strings(fieldNames)
for _, i := range fieldNames {
indexes = append(indexes, ind[i])
}
}()
return func(data any) ([]byte, error) {
val := reflect.Indirect(reflect.ValueOf(data))
var forsign []string
for _, fn := range indexes {
forsign = append(forsign, fmt.Sprint(val.FieldByIndex(fn)))
}
val.FieldByIndex(sind).Set(reflect.ValueOf(pw.createSign([]byte(strings.Join(forsign, "|")))))
return json.Marshal(data)
}
}
func (pw *FreeKassa) createSign(data []byte) string {
sign := hmac.New(sha256.New, pw.byteKey)
sign.Write(data)
return fmt.Sprintf("%x", sign.Sum(nil))
}

@ -1,35 +0,0 @@
package fk
import (
"fmt"
"testing"
"github.com/themakers/bdd"
)
func TestFk(t *testing.T) {
fk := New("db9f770bf1b400445fb9c7d82e59ba81", 20397)
bdd.Scenario(t, "sign creating and data preparing", func(t *testing.T, runid string) {
bdd.Test(t, "prepare data", func() {
fk.create(&ReqCreateInvoice{
ShopId: 1,
Nonce: 2,
Signature: "q",
PaymentId: "w",
I: 3,
Email: "e",
IP: "r",
Amount: 4.5,
Currency: "t",
Tel: "y",
SuccessUrl: "u",
FailureUrl: "i",
NotificationUrl: "o",
})
fmt.Println(fk.GetWallet())
fmt.Println(fk.GetCurrencies())
fmt.Println(fk.GetShops())
fmt.Println(fk.GetWithdrawalCurrencies())
})
})
}

@ -1,43 +0,0 @@
package fk
import (
p "bitbucket.org/skeris/treasurer/payway/payways"
)
type FreeKassa struct {
Key string `json:"key"`
ShopId int64 `json:"shopId"`
byteKey []byte
create, wallet, getOrders preparer
}
type preparer func(any) ([]byte, error)
func New(sk string, shid int64) *FreeKassa {
fk := &FreeKassa{
Key: sk,
ShopId: shid,
byteKey: []byte(sk),
}
fk.create = fk.prepareData(&ReqCreateInvoice{})
fk.wallet = fk.prepareData(&ReqGetWallet{})
fk.getOrders = fk.prepareData(&ReqOrdersHistory{})
return fk
}
func (pw *FreeKassa) Type() string {
return "fk"
}
func (pw *FreeKassa) Copy() *p.Payway {
return &p.Payway{
Credentials: &FreeKassa{},
}
}
//func (pw *FreeKassa) MarshalJSON() ([]byte, error) {
// return json.Marshal(&FreeKassa{})
//}

@ -1,26 +0,0 @@
package pw
import (
"time"
"go.mongodb.org/mongo-driver/bson"
)
type PayWayI interface {
Type() string
Copy() *Payway
//MarshalJSON() ([]byte, error)
}
type Payway struct {
PayWayI
ID string `json:"id" bson:"_id"`
Name string `json:"name" bson:"name"`
Description string `json:"desc" bson:"desc"`
Svc string `json:"svc" bson:"svc"`
RawCredentials bson.Raw `json:"-" bson:"credentials"`
Credentials any `json:"cred" bson:"-"`
CreatedAt time.Time `json:"created_at" bson:"created_at"`
}

@ -1,19 +0,0 @@
package payway
import (
"fmt"
"testing"
"github.com/themakers/bdd"
)
func TestPWs(t *testing.T) {
//ctx := context.Background()
bdd.Scenario(t, "add payways", func(t *testing.T, runid string) {
bdd.Test(t, "create pwmanager", func() {
//pm, err := New(ctx, &fk.FreeKassa{})
//assert.NoError(t, err)
fmt.Println("pws0")
})
})
}

Some files were not shown because too many files have changed in this diff Show More