feat: overhelm
This commit is contained in:
parent
e15242a2b8
commit
01dce42f5c
20
.env.test
20
.env.test
@ -1,11 +1,11 @@
|
|||||||
GRPC_HOST=0.0.0.0
|
GRPC_HOST=0.0.0.0
|
||||||
GPRC_PORT=9001
|
GPRC_PORT=9001
|
||||||
|
|
||||||
HTTP_PORT=8001
|
HTTP_PORT=8001
|
||||||
|
|
||||||
MONGO_HOST=mongo
|
MONGO_HOST=mongo
|
||||||
MONGO_PORT=27017
|
MONGO_PORT=27017
|
||||||
MONGO_USER=test
|
MONGO_USER=test
|
||||||
MONGO_PASSWORD=test
|
MONGO_PASSWORD=test
|
||||||
MONGO_AUTH=admin
|
MONGO_AUTH=admin
|
||||||
MONGO_DB_NAME=admin
|
MONGO_DB_NAME=admin
|
@ -1,8 +1,31 @@
|
|||||||
stages:
|
stages:
|
||||||
|
- lint
|
||||||
|
- test
|
||||||
- clean
|
- clean
|
||||||
- build
|
- build
|
||||||
- deploy
|
- deploy
|
||||||
|
|
||||||
|
lint:
|
||||||
|
image: golangci/golangci-lint:v1.51-alpine
|
||||||
|
stage: lint
|
||||||
|
script:
|
||||||
|
- go generate ./internal/...
|
||||||
|
- golangci-lint version
|
||||||
|
- golangci-lint run --disable-all --enable=vet --enable=golint ./...
|
||||||
|
|
||||||
|
test:
|
||||||
|
image: golang:1.20-alpine
|
||||||
|
stage: test
|
||||||
|
coverage: /\(statements\)(?:\s+)?(\d+(?:\.\d+)?%)/
|
||||||
|
script:
|
||||||
|
- CGO_ENABLED=0 go test ./internal/... -coverprofile=coverage.out
|
||||||
|
- go tool cover -html=coverage.out -o coverage.html
|
||||||
|
- go tool cover -func coverage.out
|
||||||
|
artifacts:
|
||||||
|
expire_in: "3 days"
|
||||||
|
paths:
|
||||||
|
- coverage.html
|
||||||
|
|
||||||
clean-old:
|
clean-old:
|
||||||
stage: clean
|
stage: clean
|
||||||
image:
|
image:
|
||||||
|
164
.golangci.yaml
Normal file
164
.golangci.yaml
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
run:
|
||||||
|
timeout: 5m
|
||||||
|
skip-files:
|
||||||
|
- \.pb\.go$
|
||||||
|
- .pb.go
|
||||||
|
- \.pb\.validate\.go$
|
||||||
|
- \.pb\.gw\.go$
|
||||||
|
- .pb.gw.go
|
||||||
|
- \.gen\.go$
|
||||||
|
skip-dirs:
|
||||||
|
- mocks
|
||||||
|
|
||||||
|
linters:
|
||||||
|
disable-all: true
|
||||||
|
enable:
|
||||||
|
- asasalint
|
||||||
|
- asciicheck
|
||||||
|
- bidichk
|
||||||
|
- bodyclose
|
||||||
|
- containedctx
|
||||||
|
- 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
6
.mockery.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
exported: True
|
||||||
|
inpackage: False
|
||||||
|
keeptree: True
|
||||||
|
case: underscore
|
||||||
|
with-expecter: True
|
||||||
|
inpackage-suffix: True
|
144
Dockerfile
144
Dockerfile
@ -1,72 +1,72 @@
|
|||||||
# BUILD
|
# BUILD
|
||||||
FROM golang:1.19.5-alpine AS build
|
FROM golang:1.19.5-alpine AS build
|
||||||
|
|
||||||
# Update depences
|
# Update depences
|
||||||
RUN apk update && apk add --no-cache curl
|
RUN apk update && apk add --no-cache curl
|
||||||
# Create build directory
|
# Create build directory
|
||||||
RUN mkdir /app/bin -p
|
RUN mkdir /app/bin -p
|
||||||
RUN mkdir /bin/golang-migrate -p
|
RUN mkdir /bin/golang-migrate -p
|
||||||
# Download migrate app
|
# Download migrate app
|
||||||
RUN GOLANG_MIGRATE_VERSION=v4.15.1 && \
|
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 |\
|
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
|
tar xvz migrate -C /bin/golang-migrate
|
||||||
# Download health check utility
|
# Download health check utility
|
||||||
RUN GRPC_HEALTH_PROBE_VERSION=v0.4.6 && \
|
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 && \
|
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
|
chmod +x /bin/grpc_health_probe
|
||||||
# Set home directory
|
# Set home directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
# Copy go.mod
|
# Copy go.mod
|
||||||
ADD go.mod go.sum /app/
|
ADD go.mod go.sum /app/
|
||||||
# Download go depences
|
# Download go depences
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
# Copy all local files
|
# Copy all local files
|
||||||
ADD . /app
|
ADD . /app
|
||||||
# Build app
|
# Build app
|
||||||
RUN GOOS=linux go build -o bin ./...
|
RUN GOOS=linux go build -o bin ./...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# TEST
|
# TEST
|
||||||
FROM alpine:latest AS test
|
FROM alpine:latest AS test
|
||||||
|
|
||||||
# Install packages
|
# Install packages
|
||||||
RUN apk --no-cache add ca-certificates
|
RUN apk --no-cache add ca-certificates
|
||||||
# Create home directory
|
# Create home directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
# Copy build file
|
# Copy build file
|
||||||
COPY --from=build /app/bin/app ./app
|
COPY --from=build /app/bin/app ./app
|
||||||
# CMD
|
# CMD
|
||||||
CMD ["./app"]
|
CMD ["./app"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# MIGRATION
|
# MIGRATION
|
||||||
FROM alpine:latest AS migration
|
FROM alpine:latest AS migration
|
||||||
|
|
||||||
# Install packages
|
# Install packages
|
||||||
RUN apk --no-cache add ca-certificates
|
RUN apk --no-cache add ca-certificates
|
||||||
# Create home directory
|
# Create home directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
# Copy migration dir
|
# Copy migration dir
|
||||||
COPY --from=build /app/migrations/tests ./migrations
|
COPY --from=build /app/migrations/tests ./migrations
|
||||||
# Install migrate tool
|
# Install migrate tool
|
||||||
COPY --from=build /bin/golang-migrate /usr/local/bin
|
COPY --from=build /bin/golang-migrate /usr/local/bin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# PRODUCTION
|
# PRODUCTION
|
||||||
FROM alpine:latest AS production
|
FROM alpine:latest AS production
|
||||||
|
|
||||||
# Install packages
|
# Install packages
|
||||||
RUN apk --no-cache add ca-certificates
|
RUN apk --no-cache add ca-certificates
|
||||||
# Create home directory
|
# Create home directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
# Copy build file
|
# Copy build file
|
||||||
COPY --from=build /app/bin/app ./app
|
COPY --from=build /app/bin/app ./app
|
||||||
# Copy grpc health probe dir
|
# Copy grpc health probe dir
|
||||||
COPY --from=build /bin/grpc_health_probe /bin/grpc_health_probe
|
COPY --from=build /bin/grpc_health_probe /bin/grpc_health_probe
|
||||||
# Install migrate tool
|
# Install migrate tool
|
||||||
COPY --from=build /bin/golang-migrate /usr/local/bin
|
COPY --from=build /bin/golang-migrate /usr/local/bin
|
||||||
# CMD
|
# CMD
|
||||||
CMD ["./app"]
|
CMD ["./app"]
|
||||||
|
82
Makefile
82
Makefile
@ -1,42 +1,42 @@
|
|||||||
SERVICE_NAME = discount
|
SERVICE_NAME = discount
|
||||||
|
|
||||||
help: ## show this help
|
help: ## show this help
|
||||||
@echo 'usage: make [target] ...'
|
@echo 'usage: make [target] ...'
|
||||||
@echo ''
|
@echo ''
|
||||||
@echo 'targets:'
|
@echo 'targets:'
|
||||||
@egrep '^(.+)\:\ .*##\ (.+)' ${MAKEFILE_LIST} | sed 's/:.*##/#/' | column -t -c 2 -s '#'
|
@egrep '^(.+)\:\ .*##\ (.+)' ${MAKEFILE_LIST} | sed 's/:.*##/#/' | column -t -c 2 -s '#'
|
||||||
|
|
||||||
install: ## install all go dependencies
|
install: ## install all go dependencies
|
||||||
go install \
|
go install \
|
||||||
github.com/bufbuild/buf/cmd/buf \
|
github.com/bufbuild/buf/cmd/buf@v1.23.1 \
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \
|
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest \
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 \
|
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest \
|
||||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc \
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest \
|
||||||
google.golang.org/protobuf/cmd/protoc-gen-go
|
google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||||
|
|
||||||
generate: ## generate grpc proto for golang
|
generate: ## generate grpc proto for golang
|
||||||
buf generate --path ./proto/${SERVICE_NAME}
|
buf generate --path ./proto/${SERVICE_NAME}
|
||||||
|
|
||||||
test: ## run all layers tests
|
test: ## run all layers tests
|
||||||
@make test.unit
|
@make test.unit
|
||||||
@make test.integration
|
@make test.integration
|
||||||
|
|
||||||
test.unit: ## run unit tests
|
test.unit: ## run unit tests
|
||||||
go test ./...
|
go test ./...
|
||||||
|
|
||||||
test.integration: ## run integration tests
|
test.integration: ## run integration tests
|
||||||
@make test.integration.up
|
@make test.integration.up
|
||||||
@make test.integration.start
|
@make test.integration.start
|
||||||
@make test.integration.down
|
@make test.integration.down
|
||||||
|
|
||||||
test.integration.up: ## build integration test environment
|
test.integration.up: ## build integration test environment
|
||||||
docker-compose -f deployments/test/docker-compose.yaml --env-file ./.env.test up -d
|
docker-compose -f deployments/test/docker-compose.yaml --env-file ./.env.test up -d
|
||||||
|
|
||||||
test.integration.start: ## run integration test
|
test.integration.start: ## run integration test
|
||||||
go test -tags integration ./tests/integration/...
|
go test -tags integration ./tests/integration/...
|
||||||
|
|
||||||
test.integration.down: ## shutting down integration environment
|
test.integration.down: ## shutting down integration environment
|
||||||
docker-compose -f deployments/test/docker-compose.yaml --env-file ./.env.test down --volumes --rmi local
|
docker-compose -f deployments/test/docker-compose.yaml --env-file ./.env.test down --volumes --rmi local
|
||||||
|
|
||||||
run: ## run app
|
run: ## run app
|
||||||
go run ./cmd/app/main.go
|
go run ./cmd/app/main.go
|
106
README.md
106
README.md
@ -1,53 +1,53 @@
|
|||||||
# accruals-service
|
# accruals-service
|
||||||
|
|
||||||
Микросервис для создания скидок и формирования цен из реализованных скидок
|
Микросервис для создания скидок и формирования цен из реализованных скидок
|
||||||
|
|
||||||
| Branch | Pipeline | Code coverage |
|
| Branch | Pipeline | Code coverage |
|
||||||
| ------------- |:-----------------:| --------------:|
|
| ------------- |:-----------------:| --------------:|
|
||||||
| main | [](https://penahub.gitlab.yandexcloud.net/pena-services/discount-service/-/pipelines) | [](https://penahub.gitlab.yandexcloud.net/pena-services/discount-service/-/pipelines) |
|
| main | [](https://penahub.gitlab.yandexcloud.net/pena-services/discount-service/-/pipelines) | [](https://penahub.gitlab.yandexcloud.net/pena-services/discount-service/-/pipelines) |
|
||||||
| staging | [](https://penahub.gitlab.yandexcloud.net/pena-services/discount-service/-/pipelines) | [](https://penahub.gitlab.yandexcloud.net/pena-services/discount-service/-/pipelines) |
|
| staging | [](https://penahub.gitlab.yandexcloud.net/pena-services/discount-service/-/pipelines) | [](https://penahub.gitlab.yandexcloud.net/pena-services/discount-service/-/pipelines) |
|
||||||
| dev | [](https://penahub.gitlab.yandexcloud.net/pena-services/discount-service/-/pipelines) | [](https://penahub.gitlab.yandexcloud.net/pena-services/discount-service/-/pipelines) |
|
| dev | [](https://penahub.gitlab.yandexcloud.net/pena-services/discount-service/-/pipelines) | [](https://penahub.gitlab.yandexcloud.net/pena-services/discount-service/-/pipelines) |
|
||||||
|
|
||||||
## Переменные окружения приложения
|
## Переменные окружения приложения
|
||||||
|
|
||||||
```
|
```
|
||||||
GRPC_HOST - хост прослушивания приложения (gRPC)
|
GRPC_HOST - хост прослушивания приложения (gRPC)
|
||||||
GPRC_PORT - порт прослушивания приложения (gRPC)
|
GPRC_PORT - порт прослушивания приложения (gRPC)
|
||||||
HTTP_PORT - порт прослушивания приложения (HTTP)
|
HTTP_PORT - порт прослушивания приложения (HTTP)
|
||||||
|
|
||||||
MONGO_HOST - хост базы данных
|
MONGO_HOST - хост базы данных
|
||||||
MONGO_PORT - порт базы данных
|
MONGO_PORT - порт базы данных
|
||||||
MONGO_USER - имя пользователя базы данных для авторизации
|
MONGO_USER - имя пользователя базы данных для авторизации
|
||||||
MONGO_PASSWORD - пароль пользователя базы данных для авторизации
|
MONGO_PASSWORD - пароль пользователя базы данных для авторизации
|
||||||
MONGO_AUTH - название базы данных для авторизации
|
MONGO_AUTH - название базы данных для авторизации
|
||||||
MONGO_DATABASE_NAME - название базы данных, к которой будет идти подключение
|
MONGO_DATABASE_NAME - название базы данных, к которой будет идти подключение
|
||||||
```
|
```
|
||||||
|
|
||||||
## Пример переменных окружения:
|
## Пример переменных окружения:
|
||||||
|
|
||||||
```
|
```
|
||||||
GRPC_HOST=0.0.0.0
|
GRPC_HOST=0.0.0.0
|
||||||
GPRC_PORT=9001
|
GPRC_PORT=9001
|
||||||
HTTP_PORT=8001
|
HTTP_PORT=8001
|
||||||
|
|
||||||
MONGO_HOST=localhost
|
MONGO_HOST=localhost
|
||||||
MONGO_PORT=27017
|
MONGO_PORT=27017
|
||||||
MONGO_USER=test
|
MONGO_USER=test
|
||||||
MONGO_PASSWORD=test
|
MONGO_PASSWORD=test
|
||||||
MONGO_AUTH=admin
|
MONGO_AUTH=admin
|
||||||
```
|
```
|
||||||
|
|
||||||
## Команды для работы с приложением:
|
## Команды для работы с приложением:
|
||||||
|
|
||||||
```
|
```
|
||||||
make help - вывести список доступных команд с описанием
|
make help - вывести список доступных команд с описанием
|
||||||
make install - устанавливает все необходимые зависимости и инструменты
|
make install - устанавливает все необходимые зависимости и инструменты
|
||||||
make generate - генерирует proto файлы gRPC сервиса
|
make generate - генерирует proto файлы gRPC сервиса
|
||||||
make test - запускает unit и интеграционные тесты
|
make test - запускает unit и интеграционные тесты
|
||||||
make test.unit - запуск unit тестов
|
make test.unit - запуск unit тестов
|
||||||
make test.integration - запуск интеграционных тестов (поднятие и завершение окружения)
|
make test.integration - запуск интеграционных тестов (поднятие и завершение окружения)
|
||||||
make test.integration.up - поднятие тестового окружения
|
make test.integration.up - поднятие тестового окружения
|
||||||
make test.integration.start - запуск интеграционных тестов
|
make test.integration.start - запуск интеграционных тестов
|
||||||
make test.integration.down - завершение тестового окружения
|
make test.integration.down - завершение тестового окружения
|
||||||
make run - запуск приложения
|
make run - запуск приложения
|
||||||
```
|
```
|
||||||
|
@ -1,12 +1,8 @@
|
|||||||
version: v1beta1
|
version: v1
|
||||||
plugins:
|
plugins:
|
||||||
- name: go
|
- name: go
|
||||||
out: internal/proto
|
out: internal/proto
|
||||||
- name: go-grpc
|
- name: go-grpc
|
||||||
out: internal/proto
|
out: internal/proto
|
||||||
opt:
|
opt:
|
||||||
- require_unimplemented_servers=false
|
- require_unimplemented_servers=false
|
||||||
- name: grpc-gateway
|
|
||||||
out: internal/proto
|
|
||||||
- name: openapiv2
|
|
||||||
out: internal/proto
|
|
3
buf.work.yaml
Normal file
3
buf.work.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
version: v1
|
||||||
|
directories:
|
||||||
|
- proto
|
5
buf.yaml
5
buf.yaml
@ -1,7 +1,4 @@
|
|||||||
version: v1beta1
|
version: v1
|
||||||
build:
|
|
||||||
roots:
|
|
||||||
- proto
|
|
||||||
lint:
|
lint:
|
||||||
use:
|
use:
|
||||||
- DEFAULT
|
- DEFAULT
|
@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
formatter "github.com/antonfisher/nested-logrus-formatter"
|
formatter "github.com/antonfisher/nested-logrus-formatter"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/app"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/app"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/env"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/env"
|
||||||
|
@ -1,46 +1,46 @@
|
|||||||
version: "3"
|
version: "3"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
build:
|
build:
|
||||||
context: ../../.
|
context: ../../.
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
target: test
|
target: test
|
||||||
env_file:
|
env_file:
|
||||||
- ../../.env.test
|
- ../../.env.test
|
||||||
ports:
|
ports:
|
||||||
- 9001:9001
|
- 9001:9001
|
||||||
- 8001:8001
|
- 8001:8001
|
||||||
depends_on:
|
depends_on:
|
||||||
- migration
|
- migration
|
||||||
networks:
|
networks:
|
||||||
- integration_test
|
- integration_test
|
||||||
|
|
||||||
migration:
|
migration:
|
||||||
build:
|
build:
|
||||||
context: ../../.
|
context: ../../.
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
target: migration
|
target: migration
|
||||||
command:
|
command:
|
||||||
[
|
[
|
||||||
"sh",
|
"sh",
|
||||||
"-c",
|
"-c",
|
||||||
'migrate -source file://migrations -database "mongodb://$MONGO_USER:$MONGO_PASSWORD@$MONGO_HOST:$MONGO_PORT/$MONGO_AUTH?authSource=$MONGO_AUTH" up',
|
'migrate -source file://migrations -database "mongodb://$MONGO_USER:$MONGO_PASSWORD@$MONGO_HOST:$MONGO_PORT/$MONGO_AUTH?authSource=$MONGO_AUTH" up',
|
||||||
]
|
]
|
||||||
depends_on:
|
depends_on:
|
||||||
- mongo
|
- mongo
|
||||||
networks:
|
networks:
|
||||||
- integration_test
|
- integration_test
|
||||||
|
|
||||||
mongo:
|
mongo:
|
||||||
image: 'mongo:6.0.3'
|
image: 'mongo:6.0.3'
|
||||||
environment:
|
environment:
|
||||||
MONGO_INITDB_ROOT_USERNAME: test
|
MONGO_INITDB_ROOT_USERNAME: test
|
||||||
MONGO_INITDB_ROOT_PASSWORD: test
|
MONGO_INITDB_ROOT_PASSWORD: test
|
||||||
ports:
|
ports:
|
||||||
- '27017:27017'
|
- '27017:27017'
|
||||||
networks:
|
networks:
|
||||||
- integration_test
|
- integration_test
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
integration_test:
|
integration_test:
|
82
go.mod
82
go.mod
@ -5,37 +5,89 @@ go 1.20
|
|||||||
require (
|
require (
|
||||||
github.com/antonfisher/nested-logrus-formatter v1.3.1
|
github.com/antonfisher/nested-logrus-formatter v1.3.1
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0
|
||||||
github.com/joho/godotenv v1.4.0
|
github.com/joho/godotenv v1.4.0
|
||||||
github.com/sethvargo/go-envconfig v0.8.3
|
github.com/sethvargo/go-envconfig v0.8.3
|
||||||
github.com/sirupsen/logrus v1.9.0
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/stretchr/testify v1.8.4
|
||||||
go.mongodb.org/mongo-driver v1.11.1
|
go.mongodb.org/mongo-driver v1.11.1
|
||||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
|
||||||
google.golang.org/genproto v0.0.0-20230119192704-9d59e20e5cd1
|
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e
|
||||||
google.golang.org/grpc v1.52.0
|
google.golang.org/grpc v1.55.0
|
||||||
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8
|
google.golang.org/protobuf v1.31.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
|
||||||
|
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||||
|
github.com/bufbuild/buf v1.23.1 // indirect
|
||||||
|
github.com/bufbuild/connect-go v1.8.0 // indirect
|
||||||
|
github.com/bufbuild/connect-opentelemetry-go v0.3.0 // indirect
|
||||||
|
github.com/bufbuild/protocompile v0.5.1 // indirect
|
||||||
|
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/docker/cli v24.0.2+incompatible // indirect
|
||||||
|
github.com/docker/distribution v2.8.2+incompatible // indirect
|
||||||
|
github.com/docker/docker v24.0.2+incompatible // indirect
|
||||||
|
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||||
|
github.com/docker/go-connections v0.4.0 // indirect
|
||||||
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
|
github.com/felixge/fgprof v0.9.3 // indirect
|
||||||
|
github.com/go-chi/chi/v5 v5.0.8 // indirect
|
||||||
|
github.com/go-logr/logr v1.2.4 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
github.com/gofrs/uuid/v5 v5.0.0 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang/glog v1.1.0 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/klauspost/compress v1.13.6 // indirect
|
github.com/google/go-containerregistry v0.15.2 // indirect
|
||||||
github.com/kr/pretty v0.2.1 // indirect
|
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
|
github.com/jdxcode/netrc v0.0.0-20221124155335-4616370d1a84 // indirect
|
||||||
|
github.com/klauspost/compress v1.16.6 // indirect
|
||||||
|
github.com/klauspost/pgzip v1.2.6 // indirect
|
||||||
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||||
|
github.com/moby/term v0.5.0 // indirect
|
||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||||
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/image-spec v1.1.0-rc3 // indirect
|
||||||
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/pkg/profile v1.7.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/rs/cors v1.9.0 // indirect
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
github.com/spf13/cobra v1.7.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/tetratelabs/wazero v1.2.1 // indirect
|
||||||
|
github.com/vbatts/tar-split v0.11.3 // 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.1 // indirect
|
||||||
github.com/xdg-go/stringprep v1.0.3 // indirect
|
github.com/xdg-go/stringprep v1.0.3 // indirect
|
||||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
|
go.opentelemetry.io/otel v1.16.0 // indirect
|
||||||
golang.org/x/net v0.4.0 // indirect
|
go.opentelemetry.io/otel/metric v1.16.0 // indirect
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
|
go.opentelemetry.io/otel/sdk v1.16.0 // indirect
|
||||||
golang.org/x/sys v0.4.0 // indirect
|
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
||||||
golang.org/x/text v0.5.0 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
go.uber.org/zap v1.24.0 // indirect
|
||||||
|
golang.org/x/crypto v0.10.0 // indirect
|
||||||
|
golang.org/x/mod v0.11.0 // indirect
|
||||||
|
golang.org/x/net v0.11.0 // indirect
|
||||||
|
golang.org/x/sync v0.3.0 // indirect
|
||||||
|
golang.org/x/sys v0.9.0 // indirect
|
||||||
|
golang.org/x/term v0.9.0 // indirect
|
||||||
|
golang.org/x/text v0.10.0 // indirect
|
||||||
|
golang.org/x/tools v0.10.0 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
|
||||||
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
149
go.sum
149
go.sum
@ -1,25 +1,70 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
|
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||||
|
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||||
github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ=
|
github.com/antonfisher/nested-logrus-formatter v1.3.1 h1:NFJIr+pzwv5QLHTPyKz9UMEoHck02Q9L0FP13b/xSbQ=
|
||||||
github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA=
|
github.com/antonfisher/nested-logrus-formatter v1.3.1/go.mod h1:6WTfyWFkBc9+zyBaKIqRrg/KwMqBbodBjgbHjDz7zjA=
|
||||||
|
github.com/bufbuild/buf v1.23.1 h1:BeMkA3+e9XTFEZPDlAI7cydFKlq24wwYiOHp8CvsRzc=
|
||||||
|
github.com/bufbuild/buf v1.23.1/go.mod h1:ERFRzJiIjAOzUSJ3vz1zoI7XfxlBnCwZEyL+NJm4pko=
|
||||||
|
github.com/bufbuild/connect-go v1.8.0 h1:srluNkFkZBfSfg9Qb6DrO+5nMaxix//h2ctrHZhMGKc=
|
||||||
|
github.com/bufbuild/connect-go v1.8.0/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrIQMm1/a6LnHk=
|
||||||
|
github.com/bufbuild/connect-opentelemetry-go v0.3.0 h1:AuZi3asTDKmjGtd2aqpyP4p5QvBFG/YEaHopViLatnk=
|
||||||
|
github.com/bufbuild/connect-opentelemetry-go v0.3.0/go.mod h1:r1ppyTtu1EWeRodk4Q/JbyQhIWtO7eR3GoRDzjeEcNU=
|
||||||
|
github.com/bufbuild/protocompile v0.5.1 h1:mixz5lJX4Hiz4FpqFREJHIXLfaLBntfaJv1h+/jS+Qg=
|
||||||
|
github.com/bufbuild/protocompile v0.5.1/go.mod h1:G5iLmavmF4NsYtpZFvE3B/zFch2GIY8+wjsYLR/lc40=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
|
github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k=
|
||||||
|
github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
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/docker/cli v24.0.2+incompatible h1:QdqR7znue1mtkXIJ+ruQMGQhpw2JzMJLRXp6zpzF6tM=
|
||||||
|
github.com/docker/cli v24.0.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
|
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
|
||||||
|
github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
|
github.com/docker/docker v24.0.2+incompatible h1:eATx+oLz9WdNVkQrr0qjQ8HvRJ4bOOxfzEo8R+dA3cg=
|
||||||
|
github.com/docker/docker v24.0.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
|
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
|
||||||
|
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
|
||||||
|
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||||
|
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
|
||||||
|
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
||||||
|
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
|
||||||
|
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
|
||||||
|
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
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/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
|
||||||
|
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
|
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
|
||||||
|
github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
|
||||||
|
github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
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.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
@ -27,6 +72,8 @@ github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaW
|
|||||||
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 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
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/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/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
@ -34,39 +81,84 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
|
|||||||
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/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/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-containerregistry v0.15.2 h1:MMkSh+tjSdnmJZO7ljvEqV1DjfekB6VUEAZgy3a+TQE=
|
||||||
|
github.com/google/go-containerregistry v0.15.2/go.mod h1:wWK+LnOv4jXMM23IT/F1wdYftGWGr47Is8CG+pmHK1Q=
|
||||||
|
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||||
|
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 h1:hR7/MlvK23p6+lIw9SN1TigNLn9ZnF3W4SYRKq2gAHs=
|
||||||
|
github.com/google/pprof v0.0.0-20230602150820-91b7bce49751/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 h1:1JYBfzqrWPcCclBwxFCPAou9n+q86mfnu7NAeHfte7A=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0 h1:1JYBfzqrWPcCclBwxFCPAou9n+q86mfnu7NAeHfte7A=
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0/go.mod h1:YDZoGHuwE+ov0c8smSH49WLF3F2LaWnYYuDVd+EWrc0=
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.15.0/go.mod h1:YDZoGHuwE+ov0c8smSH49WLF3F2LaWnYYuDVd+EWrc0=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg=
|
||||||
|
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/jdxcode/netrc v0.0.0-20221124155335-4616370d1a84 h1:2uT3aivO7NVpUPGcQX7RbHijHMyWix/yCnIrCWc+5co=
|
||||||
|
github.com/jdxcode/netrc v0.0.0-20221124155335-4616370d1a84/go.mod h1:Zi/ZFkEqFHTm7qkjyNJjaWH4LQA9LQhGJyF0lTYGpxw=
|
||||||
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
|
||||||
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
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.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||||
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.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk=
|
||||||
|
github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
|
github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
|
||||||
|
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
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/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
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 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
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/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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||||
|
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
|
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
|
||||||
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/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
|
github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8=
|
||||||
|
github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||||
|
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
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/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
|
||||||
|
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
|
||||||
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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE=
|
||||||
|
github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sethvargo/go-envconfig v0.8.3 h1:dXyUrDCJvCm3ybP7yNpiux93qoSORvuH23bdsgFfiJ0=
|
github.com/sethvargo/go-envconfig v0.8.3 h1:dXyUrDCJvCm3ybP7yNpiux93qoSORvuH23bdsgFfiJ0=
|
||||||
github.com/sethvargo/go-envconfig v0.8.3/go.mod h1:Iz1Gy1Sf3T64TQlJSvee81qDhf7YIlt8GMUX6yyNFs0=
|
github.com/sethvargo/go-envconfig v0.8.3/go.mod h1:Iz1Gy1Sf3T64TQlJSvee81qDhf7YIlt8GMUX6yyNFs0=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||||
|
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
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=
|
||||||
@ -79,8 +171,15 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
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 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/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/tetratelabs/wazero v1.2.1 h1:J4X2hrGzJvt+wqltuvcSjHQ7ujQxA9gb6PeMs4qlUWs=
|
||||||
|
github.com/tetratelabs/wazero v1.2.1/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ=
|
||||||
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/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8=
|
||||||
|
github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck=
|
||||||
|
github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY=
|
||||||
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.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
|
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
|
||||||
@ -93,22 +192,42 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||||||
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.11.1 h1:QP0znIRTuL0jf1oBQoAoM0C6ZJfBK4kx0Uumtv1A7w8=
|
go.mongodb.org/mongo-driver v1.11.1 h1:QP0znIRTuL0jf1oBQoAoM0C6ZJfBK4kx0Uumtv1A7w8=
|
||||||
go.mongodb.org/mongo-driver v1.11.1/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
|
go.mongodb.org/mongo-driver v1.11.1/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
|
||||||
|
go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s=
|
||||||
|
go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4=
|
||||||
|
go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo=
|
||||||
|
go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4=
|
||||||
|
go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs=
|
||||||
|
go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
|
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||||
|
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||||
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-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-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-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
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/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||||
|
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
||||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||||
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
|
||||||
|
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
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-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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
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/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
|
||||||
|
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
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-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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@ -120,6 +239,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
|||||||
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.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
|
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
|
||||||
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||||
|
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||||
|
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
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-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@ -129,6 +250,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
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/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -137,16 +260,26 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
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-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-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.4.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.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
|
||||||
|
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||||
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.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/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.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
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/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-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-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
@ -155,6 +288,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
|
|||||||
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-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
|
||||||
|
golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
|
||||||
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=
|
||||||
@ -166,6 +301,12 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
|
|||||||
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20230119192704-9d59e20e5cd1 h1:wSjSSQW7LuPdv3m1IrSN33nVxH/kID6OIKy+FMwGB2k=
|
google.golang.org/genproto v0.0.0-20230119192704-9d59e20e5cd1 h1:wSjSSQW7LuPdv3m1IrSN33nVxH/kID6OIKy+FMwGB2k=
|
||||||
google.golang.org/genproto v0.0.0-20230119192704-9d59e20e5cd1/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
google.golang.org/genproto v0.0.0-20230119192704-9d59e20e5cd1/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
|
||||||
|
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e h1:Ao9GzfUMPH3zjVfzXG5rlWlk+Q8MXWKwWpwVQE1MXfw=
|
||||||
|
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
|
||||||
|
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.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
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.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
@ -173,15 +314,23 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
|||||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||||
google.golang.org/grpc v1.52.0 h1:kd48UiU7EHsV4rnLyOJRuP/Il/UHE7gdDAQ+SZI7nZk=
|
google.golang.org/grpc v1.52.0 h1:kd48UiU7EHsV4rnLyOJRuP/Il/UHE7gdDAQ+SZI7nZk=
|
||||||
google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
|
google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
|
||||||
|
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/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA=
|
||||||
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y=
|
||||||
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.28.2-0.20220831092852-f930b1dc76e8 h1:KR8+MyP7/qOlV+8Af01LtjL04bu7on42eVsxT4EyBQk=
|
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8 h1:KR8+MyP7/qOlV+8Af01LtjL04bu7on42eVsxT4EyBQk=
|
||||||
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.2-0.20220831092852-f930b1dc76e8/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||||
|
google.golang.org/protobuf v1.31.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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
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.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
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.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=
|
||||||
|
@ -1,53 +1,71 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
"github.com/sirupsen/logrus"
|
"time"
|
||||||
|
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"github.com/sirupsen/logrus"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/initialize"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/server"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/initialize"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/mongo"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/server"
|
||||||
)
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/closer"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/mongo"
|
||||||
func Run(config *core.Config, logger *logrus.Logger) {
|
)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
|
const (
|
||||||
database, err := mongo.Connect(ctx, &mongo.ConnectDeps{
|
shutdownTimeout = 5 * time.Second
|
||||||
Configuration: &config.Database.Connection,
|
)
|
||||||
Timeout: 10 * time.Second,
|
|
||||||
})
|
func Run(config *core.Config, logger *logrus.Logger) {
|
||||||
if err != nil {
|
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
logger.Fatalln("failed connection to db: ", err)
|
defer cancel()
|
||||||
panic(err)
|
|
||||||
}
|
closer := closer.New()
|
||||||
|
|
||||||
repositories := initialize.NewRepositories(&initialize.RepositoriesDeps{
|
database, err := mongo.Connect(ctx, &mongo.ConnectDeps{
|
||||||
Logger: logger,
|
Configuration: &config.Database.Connection,
|
||||||
Database: database,
|
Timeout: 10 * time.Second,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
services := initialize.NewServices(&initialize.ServicesDeps{
|
logger.Fatalln("failed connection to db: ", err)
|
||||||
Logger: logger,
|
panic(err)
|
||||||
Respositories: repositories,
|
}
|
||||||
})
|
|
||||||
|
repositories := initialize.NewRepositories(&initialize.RepositoriesDeps{
|
||||||
controllers := initialize.NewControllers(&initialize.ControllersDeps{
|
Logger: logger,
|
||||||
Logger: logger,
|
Database: database,
|
||||||
Services: services,
|
})
|
||||||
})
|
|
||||||
|
services := initialize.NewServices(&initialize.ServicesDeps{
|
||||||
serverGRPC := server.NewGRPC(logger).Register(controllers.DiscountController)
|
Logger: logger,
|
||||||
serverHTTP := server.NewHTTP(logger).Register(ctx, &config.GRPC)
|
Repositories: repositories,
|
||||||
|
})
|
||||||
go serverGRPC.Run(&config.GRPC)
|
|
||||||
go serverHTTP.Run(&config.HTTP)
|
controllers := initialize.NewControllers(&initialize.ControllersDeps{
|
||||||
|
Logger: logger,
|
||||||
gracefulShutdown(ctx, &gracefulShutdownDeps{
|
Services: services,
|
||||||
serverGRPC: serverGRPC,
|
})
|
||||||
database: database.Client(),
|
|
||||||
cancel: cancel,
|
serverGRPC := server.NewGRPC(logger).Register(controllers.DiscountController)
|
||||||
})
|
serverHTTP := server.NewHTTP(logger).Register(ctx, &config.GRPC)
|
||||||
}
|
|
||||||
|
go serverGRPC.Run(&config.GRPC)
|
||||||
|
go serverHTTP.Run(&config.HTTP)
|
||||||
|
|
||||||
|
closer.Add(database.Client().Disconnect)
|
||||||
|
closer.Add(serverGRPC.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 {
|
||||||
|
logger.Errorf("failed to close with graceful shutdown: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/server"
|
|
||||||
)
|
|
||||||
|
|
||||||
type gracefulShutdownDeps struct {
|
|
||||||
serverGRPC *server.GRPC
|
|
||||||
database *mongo.Client
|
|
||||||
cancel context.CancelFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
func gracefulShutdown(ctx context.Context, deps *gracefulShutdownDeps) {
|
|
||||||
defer deps.serverGRPC.Stop()
|
|
||||||
defer deps.database.Disconnect(ctx)
|
|
||||||
defer deps.cancel()
|
|
||||||
|
|
||||||
quit := make(chan os.Signal, 1)
|
|
||||||
|
|
||||||
signal.Notify(quit, syscall.SIGTERM, syscall.SIGINT)
|
|
||||||
|
|
||||||
<-quit
|
|
||||||
}
|
|
@ -1,31 +1,31 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/repository"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/repository"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/service"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
var GRPCStatuses = map[error]codes.Code{
|
var GRPCStatuses = map[error]codes.Code{
|
||||||
repository.ErrEmptyArgs: codes.InvalidArgument,
|
repository.ErrEmptyArgs: codes.InvalidArgument,
|
||||||
repository.ErrFindRecord: codes.Internal,
|
repository.ErrFindRecord: codes.Internal,
|
||||||
repository.ErrInsertRecord: codes.Internal,
|
repository.ErrInsertRecord: codes.Internal,
|
||||||
repository.ErrInvalidID: codes.InvalidArgument,
|
repository.ErrInvalidID: codes.InvalidArgument,
|
||||||
repository.ErrMethodNotImplemented: codes.Unimplemented,
|
repository.ErrMethodNotImplemented: codes.Unimplemented,
|
||||||
repository.ErrNoRecord: codes.NotFound,
|
repository.ErrNoRecord: codes.NotFound,
|
||||||
repository.ErrTransaction: codes.Internal,
|
repository.ErrTransaction: codes.Internal,
|
||||||
repository.ErrTransactionSessionStart: codes.Internal,
|
repository.ErrTransactionSessionStart: codes.Internal,
|
||||||
repository.ErrUpdateRecord: codes.Internal,
|
repository.ErrUpdateRecord: codes.Internal,
|
||||||
service.ErrInvalidInputValue: codes.InvalidArgument,
|
service.ErrInvalidInputValue: codes.InvalidArgument,
|
||||||
service.ErrInvalidReturnValue: codes.Internal,
|
service.ErrInvalidReturnValue: codes.Internal,
|
||||||
}
|
}
|
||||||
|
|
||||||
func determineError(message string, err error) error {
|
func determineError(message string, err error) error {
|
||||||
currentStatus, ok := GRPCStatuses[err]
|
currentStatus, ok := GRPCStatuses[err]
|
||||||
if !ok {
|
if !ok {
|
||||||
return status.Errorf(codes.Internal, message, err)
|
return status.Errorf(codes.Internal, message, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return status.Errorf(currentStatus, message, err)
|
return status.Errorf(currentStatus, message, err)
|
||||||
}
|
}
|
||||||
|
@ -1,110 +1,109 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"google.golang.org/protobuf/types/known/emptypb"
|
"google.golang.org/protobuf/types/known/emptypb"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
)
|
||||||
)
|
|
||||||
|
type DiscountService interface {
|
||||||
type DiscountService interface {
|
ApplyDiscounts(ctx context.Context, request *discount.ApplyDiscountRequest) (*discount.ApplyDiscountResponse, error)
|
||||||
ApplyDiscounts(ctx context.Context, request *discount.ApplyDiscountRequest) (*discount.ApplyDiscountResponse, error)
|
GetDiscountByID(ctx context.Context, id string) (*models.Discount, error)
|
||||||
GetDiscountByID(ctx context.Context, id string) (*models.Discount, error)
|
GetDiscountsByUserID(ctx context.Context, id string) ([]models.Discount, error)
|
||||||
GetDiscountsByUserID(ctx context.Context, id string) ([]models.Discount, error)
|
GetAllDiscounts(ctx context.Context) ([]models.Discount, error)
|
||||||
GetAllDiscounts(ctx context.Context) ([]models.Discount, error)
|
DeleteDiscount(ctx context.Context, id string) (*models.Discount, error)
|
||||||
DeleteDiscount(ctx context.Context, id string) (*models.Discount, error)
|
CreateDiscount(ctx context.Context, discount *models.Discount) (*models.Discount, error)
|
||||||
CreateDiscount(ctx context.Context, discount *models.Discount) (*models.Discount, error)
|
}
|
||||||
}
|
|
||||||
|
type DiscountControllerDeps struct {
|
||||||
type DiscountControllerDeps struct {
|
Logger *logrus.Logger
|
||||||
Logger *logrus.Logger
|
DiscountService DiscountService
|
||||||
DiscountService DiscountService
|
}
|
||||||
}
|
|
||||||
|
/*
|
||||||
/*
|
TODO:
|
||||||
TODO:
|
|
||||||
|
1) Добавить трассировку
|
||||||
1) Добавить трассировку
|
2) Добавить валидацию
|
||||||
2) Добавить валидацию
|
*/
|
||||||
*/
|
|
||||||
|
type DiscountController struct {
|
||||||
type DiscountController struct {
|
logger *logrus.Logger
|
||||||
logger *logrus.Logger
|
discountService DiscountService
|
||||||
discountService DiscountService
|
|
||||||
|
discount.UnimplementedDiscountServiceServer
|
||||||
discount.UnimplementedDiscountServiceServer
|
}
|
||||||
}
|
|
||||||
|
func NewDiscountController(deps *DiscountControllerDeps) *DiscountController {
|
||||||
func NewDiscountController(deps *DiscountControllerDeps) *DiscountController {
|
return &DiscountController{
|
||||||
return &DiscountController{
|
discountService: deps.DiscountService,
|
||||||
discountService: deps.DiscountService,
|
logger: deps.Logger,
|
||||||
logger: deps.Logger,
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
func (receiver *DiscountController) ApplyDiscounts(ctx context.Context, request *discount.ApplyDiscountRequest) (*discount.ApplyDiscountResponse, error) {
|
||||||
func (receiver *DiscountController) ApplyDiscounts(ctx context.Context, request *discount.ApplyDiscountRequest) (*discount.ApplyDiscountResponse, error) {
|
response, err := receiver.discountService.ApplyDiscounts(ctx, request)
|
||||||
response, err := receiver.discountService.ApplyDiscounts(ctx, request)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, determineError("failed to apply discounts: %v", err)
|
||||||
return nil, determineError("failed to apply discounts: %v", err)
|
}
|
||||||
}
|
|
||||||
|
return response, nil
|
||||||
return response, nil
|
}
|
||||||
}
|
|
||||||
|
func (receiver *DiscountController) GetDiscountByID(ctx context.Context, request *discount.GetDiscountByIDRequest) (*discount.Discount, error) {
|
||||||
func (receiver *DiscountController) GetDiscountByID(ctx context.Context, request *discount.GetDiscountByIDRequest) (*discount.Discount, error) {
|
findedDiscount, err := receiver.discountService.GetDiscountByID(ctx, request.ID)
|
||||||
findedDiscount, err := receiver.discountService.GetDiscountByID(ctx, request.ID)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, determineError("failed to get discount by id: %v", err)
|
||||||
return nil, determineError("failed to get discount by id: %v", err)
|
}
|
||||||
}
|
|
||||||
|
return transfer.DiscountModelToProto(*findedDiscount), nil
|
||||||
return transfer.DiscountModelToProto(*findedDiscount), nil
|
}
|
||||||
}
|
|
||||||
|
func (receiver *DiscountController) CreateDiscount(ctx context.Context, request *discount.CreateDiscountRequest) (*discount.Discount, error) {
|
||||||
func (receiver *DiscountController) CreateDiscount(ctx context.Context, request *discount.CreateDiscountRequest) (*discount.Discount, error) {
|
target := transfer.DiscountCalculationTargetProtoToModel(request.Target)
|
||||||
target := transfer.DiscountCalculationTargetProtoToModel(request.Target)
|
condition := transfer.DiscountConditionProtoToModel(request.Condition)
|
||||||
condition := transfer.DiscountConditionProtoToModel(request.Condition)
|
|
||||||
|
findedDiscount, err := receiver.discountService.CreateDiscount(ctx, &models.Discount{
|
||||||
findedDiscount, err := receiver.discountService.CreateDiscount(ctx, &models.Discount{
|
Target: *target,
|
||||||
Target: *target,
|
Condition: *condition,
|
||||||
Condition: *condition,
|
Name: request.Name,
|
||||||
Name: request.Name,
|
Description: request.Description,
|
||||||
Description: request.Description,
|
Layer: request.Layer,
|
||||||
Layer: request.Layer,
|
})
|
||||||
})
|
if err != nil {
|
||||||
if err != nil {
|
return nil, determineError("failed to create discount: %v", err)
|
||||||
return nil, determineError("failed to create discount: %v", err)
|
}
|
||||||
}
|
|
||||||
|
return transfer.DiscountModelToProto(*findedDiscount), nil
|
||||||
return transfer.DiscountModelToProto(*findedDiscount), nil
|
}
|
||||||
}
|
|
||||||
|
func (receiver *DiscountController) DeleteDiscount(ctx context.Context, request *discount.GetDiscountByIDRequest) (*discount.Discount, error) {
|
||||||
func (receiver *DiscountController) DeleteDiscount(ctx context.Context, request *discount.GetDiscountByIDRequest) (*discount.Discount, error) {
|
deletedDiscount, err := receiver.discountService.DeleteDiscount(ctx, request.ID)
|
||||||
deletedDiscount, err := receiver.discountService.DeleteDiscount(ctx, request.ID)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, determineError("failed to delete discount: %v", err)
|
||||||
return nil, determineError("failed to delete discount: %v", err)
|
}
|
||||||
}
|
|
||||||
|
return transfer.DiscountModelToProto(*deletedDiscount), nil
|
||||||
return transfer.DiscountModelToProto(*deletedDiscount), nil
|
}
|
||||||
}
|
|
||||||
|
func (receiver *DiscountController) GetUserDiscounts(ctx context.Context, request *discount.GetDiscountByIDRequest) (*discount.Discounts, error) {
|
||||||
func (receiver *DiscountController) GetUserDiscounts(ctx context.Context, request *discount.GetDiscountByIDRequest) (*discount.Discounts, error) {
|
userDiscounts, err := receiver.discountService.GetDiscountsByUserID(ctx, request.ID)
|
||||||
userDiscounts, err := receiver.discountService.GetDiscountsByUserID(ctx, request.ID)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, determineError("failed to get user discounts: %v", err)
|
||||||
return nil, determineError("failed to get user discounts: %v", err)
|
}
|
||||||
}
|
|
||||||
|
return transfer.DiscountsModelToProto(userDiscounts), nil
|
||||||
return transfer.DiscountsModelToProto(userDiscounts), nil
|
}
|
||||||
}
|
|
||||||
|
func (receiver *DiscountController) GetAllDiscounts(ctx context.Context, _ *emptypb.Empty) (*discount.Discounts, error) {
|
||||||
func (receiver *DiscountController) GetAllDiscounts(ctx context.Context, _ *emptypb.Empty) (*discount.Discounts, error) {
|
discounts, err := receiver.discountService.GetAllDiscounts(ctx)
|
||||||
discounts, err := receiver.discountService.GetAllDiscounts(ctx)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, determineError("failed to delete discount: %v", err)
|
||||||
return nil, determineError("failed to delete discount: %v", err)
|
}
|
||||||
}
|
|
||||||
|
return transfer.DiscountsModelToProto(discounts), nil
|
||||||
return transfer.DiscountsModelToProto(discounts), nil
|
}
|
||||||
}
|
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/mongo"
|
import "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/mongo"
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
GRPC GRPCConfiguration
|
GRPC GRPCConfiguration
|
||||||
HTTP HTTPConfiguration
|
HTTP HTTPConfiguration
|
||||||
Database DatabaseConfiguration
|
Database DatabaseConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
type GRPCConfiguration struct {
|
type GRPCConfiguration struct {
|
||||||
Host string `env:"GRPC_HOST,default=localhost"`
|
Host string `env:"GRPC_HOST,default=localhost"`
|
||||||
Port string `env:"GPRC_PORT,default=9001"`
|
Port string `env:"GPRC_PORT,default=9001"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTPConfiguration struct {
|
type HTTPConfiguration struct {
|
||||||
Port string `env:"HTTP_PORT,default=8001"`
|
Port string `env:"HTTP_PORT,default=8001"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DatabaseConfiguration struct {
|
type DatabaseConfiguration struct {
|
||||||
Connection mongo.Configuration
|
Connection mongo.Configuration
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,31 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type DiscountConditions struct {
|
type DiscountConditions struct {
|
||||||
Common CommonDiscountCondition `json:"common"`
|
Common CommonDiscountCondition `json:"common"`
|
||||||
Optionals []OptionalDiscounCondition `json:"optionals"`
|
Optionals []OptionalDiscounCondition `json:"optionals"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommonDiscountCondition struct {
|
type CommonDiscountCondition struct {
|
||||||
Period models.PeriodCondition `json:"period"`
|
Period models.PeriodCondition `json:"period"`
|
||||||
User string `json:"user"`
|
User string `json:"user"`
|
||||||
UserType string `json:"userType"`
|
UserType string `json:"userType"`
|
||||||
Coupon *string `json:"coupon"`
|
Coupon *string `json:"coupon"`
|
||||||
PurchasesAmount float64 `json:"purchasesAmount"`
|
PurchasesAmount uint64 `json:"purchasesAmount"`
|
||||||
CartPurchasesAmount float64 `json:"cartPurchasesAmount"`
|
CartPurchasesAmount uint64 `json:"cartPurchasesAmount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OptionalDiscounCondition struct {
|
type OptionalDiscounCondition struct {
|
||||||
Product *string `json:"product"`
|
Product *string `json:"product"`
|
||||||
Group *string `json:"group"`
|
Group *string `json:"group"`
|
||||||
PriceFrom *float64 `json:"priceFrom"`
|
PriceFrom *uint64 `json:"priceFrom"`
|
||||||
|
|
||||||
/* Срок использования (количество дней использования) */
|
/* Срок использования (количество дней использования) */
|
||||||
Term *uint64 `json:"term"`
|
Term *uint64 `json:"term"`
|
||||||
|
|
||||||
/* Количество использований (количество попыток) */
|
/* Количество использований (количество попыток) */
|
||||||
Usage *uint64 `json:"usage"`
|
Usage *uint64 `json:"usage"`
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
type Product struct {
|
type Product struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Price float64 `json:"price"`
|
Price float64 `json:"price"`
|
||||||
Group string `json:"group"`
|
Group string `json:"group"`
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,31 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
import "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
|
|
||||||
type UpdateDiscountSettings struct {
|
type UpdateDiscountSettings struct {
|
||||||
ID string
|
ID string
|
||||||
Condition *models.DiscountCondition
|
Condition *models.DiscountCondition
|
||||||
Name *string
|
Name *string
|
||||||
Description *string
|
Description *string
|
||||||
Layer *uint32
|
Layer *uint32
|
||||||
Deprecated *bool
|
Deprecated *bool
|
||||||
Products *[]models.ProductTarget
|
Products *[]models.ProductTarget
|
||||||
Factor *float64
|
Factor *float64
|
||||||
TargetScope *models.TargetScope
|
TargetScope *models.TargetScope
|
||||||
TargetGroup *string
|
TargetGroup *string
|
||||||
Overhelm *bool
|
Overhelm *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type FilterDiscountSettings struct {
|
type FilterDiscountSettings struct {
|
||||||
ID *string
|
ID *string
|
||||||
Condition *models.DiscountCondition
|
Condition *models.DiscountCondition
|
||||||
Name *string
|
Name *string
|
||||||
Description *string
|
Description *string
|
||||||
Layer *uint32
|
Layer *uint32
|
||||||
Deprecated *bool
|
Deprecated *bool
|
||||||
Products *[]models.ProductTarget
|
Products *[]models.ProductTarget
|
||||||
Factor *float64
|
Factor *float64
|
||||||
TargetScope *models.TargetScope
|
TargetScope *models.TargetScope
|
||||||
TargetGroup *string
|
TargetGroup *string
|
||||||
Overhelm *bool
|
Overhelm *bool
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package fields
|
package fields
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
var Audit = struct {
|
var Audit = struct {
|
||||||
UpdatedAt string
|
UpdatedAt string
|
||||||
DeletedAt string
|
DeletedAt string
|
||||||
CreatedAt string
|
CreatedAt string
|
||||||
Deleted string
|
Deleted string
|
||||||
}{
|
}{
|
||||||
UpdatedAt: fmt.Sprintf("%s.updatedAt", Discount.Audit),
|
UpdatedAt: fmt.Sprintf("%s.updatedAt", Discount.Audit),
|
||||||
DeletedAt: fmt.Sprintf("%s.deletedAt", Discount.Audit),
|
DeletedAt: fmt.Sprintf("%s.deletedAt", Discount.Audit),
|
||||||
CreatedAt: fmt.Sprintf("%s.createdAt", Discount.Audit),
|
CreatedAt: fmt.Sprintf("%s.createdAt", Discount.Audit),
|
||||||
Deleted: fmt.Sprintf("%s.deleted", Discount.Audit),
|
Deleted: fmt.Sprintf("%s.deleted", Discount.Audit),
|
||||||
}
|
}
|
||||||
|
@ -1,71 +1,71 @@
|
|||||||
package fields
|
package fields
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
var Discount = struct {
|
var Discount = struct {
|
||||||
ID string
|
ID string
|
||||||
Name string
|
Name string
|
||||||
Description string
|
Description string
|
||||||
Target string
|
Target string
|
||||||
Condition string
|
Condition string
|
||||||
Layer string
|
Layer string
|
||||||
Deprecated string
|
Deprecated string
|
||||||
Audit string
|
Audit string
|
||||||
}{
|
}{
|
||||||
ID: "_id",
|
ID: "_id",
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Description: "description",
|
Description: "description",
|
||||||
Target: "target",
|
Target: "target",
|
||||||
Condition: "condition",
|
Condition: "condition",
|
||||||
Layer: "layer",
|
Layer: "layer",
|
||||||
Deprecated: "deprecated",
|
Deprecated: "deprecated",
|
||||||
Audit: "audit",
|
Audit: "audit",
|
||||||
}
|
}
|
||||||
|
|
||||||
var DiscountTarget = struct {
|
var DiscountTarget = struct {
|
||||||
Products string
|
Products string
|
||||||
Factor string
|
Factor string
|
||||||
TargetScope string
|
TargetScope string
|
||||||
TargetGroup string
|
TargetGroup string
|
||||||
Overhelm string
|
Overhelm string
|
||||||
}{
|
}{
|
||||||
Products: fmt.Sprintf("%s.products", Discount.Target),
|
Products: fmt.Sprintf("%s.products", Discount.Target),
|
||||||
Factor: fmt.Sprintf("%s.factor", Discount.Target),
|
Factor: fmt.Sprintf("%s.factor", Discount.Target),
|
||||||
TargetScope: fmt.Sprintf("%s.scope", Discount.Target),
|
TargetScope: fmt.Sprintf("%s.scope", Discount.Target),
|
||||||
TargetGroup: fmt.Sprintf("%s.group", Discount.Target),
|
TargetGroup: fmt.Sprintf("%s.group", Discount.Target),
|
||||||
Overhelm: fmt.Sprintf("%s.overhelm", Discount.Target),
|
Overhelm: fmt.Sprintf("%s.overhelm", Discount.Target),
|
||||||
}
|
}
|
||||||
|
|
||||||
var DiscountCondition = struct {
|
var DiscountCondition = struct {
|
||||||
Period string
|
Period string
|
||||||
Product string
|
Product string
|
||||||
Term string
|
Term string
|
||||||
Usage string
|
Usage string
|
||||||
PriceFrom string
|
PriceFrom string
|
||||||
Group string
|
Group string
|
||||||
User string
|
User string
|
||||||
UserType string
|
UserType string
|
||||||
Coupon string
|
Coupon string
|
||||||
PurchasesAmount string
|
PurchasesAmount string
|
||||||
CartPurchasesAmount string
|
CartPurchasesAmount string
|
||||||
}{
|
}{
|
||||||
Period: fmt.Sprintf("%s.period", Discount.Condition),
|
Period: fmt.Sprintf("%s.period", Discount.Condition),
|
||||||
Product: fmt.Sprintf("%s.product", Discount.Condition),
|
Product: fmt.Sprintf("%s.product", Discount.Condition),
|
||||||
Term: fmt.Sprintf("%s.term", Discount.Condition),
|
Term: fmt.Sprintf("%s.term", Discount.Condition),
|
||||||
Usage: fmt.Sprintf("%s.usage", Discount.Condition),
|
Usage: fmt.Sprintf("%s.usage", Discount.Condition),
|
||||||
PriceFrom: fmt.Sprintf("%s.priceFrom", Discount.Condition),
|
PriceFrom: fmt.Sprintf("%s.priceFrom", Discount.Condition),
|
||||||
Group: fmt.Sprintf("%s.group", Discount.Condition),
|
Group: fmt.Sprintf("%s.group", Discount.Condition),
|
||||||
User: fmt.Sprintf("%s.user", Discount.Condition),
|
User: fmt.Sprintf("%s.user", Discount.Condition),
|
||||||
UserType: fmt.Sprintf("%s.userType", Discount.Condition),
|
UserType: fmt.Sprintf("%s.userType", Discount.Condition),
|
||||||
Coupon: fmt.Sprintf("%s.coupon", Discount.Condition),
|
Coupon: fmt.Sprintf("%s.coupon", Discount.Condition),
|
||||||
PurchasesAmount: fmt.Sprintf("%s.purchasesAmount", Discount.Condition),
|
PurchasesAmount: fmt.Sprintf("%s.purchasesAmount", Discount.Condition),
|
||||||
CartPurchasesAmount: fmt.Sprintf("%s.cartPurchasesAmount", Discount.Condition),
|
CartPurchasesAmount: fmt.Sprintf("%s.cartPurchasesAmount", Discount.Condition),
|
||||||
}
|
}
|
||||||
|
|
||||||
var PeriodCondition = struct {
|
var PeriodCondition = struct {
|
||||||
From string
|
From string
|
||||||
To string
|
To string
|
||||||
}{
|
}{
|
||||||
From: fmt.Sprintf("%s.from", DiscountCondition.Period),
|
From: fmt.Sprintf("%s.from", DiscountCondition.Period),
|
||||||
To: fmt.Sprintf("%s.to", DiscountCondition.Period),
|
To: fmt.Sprintf("%s.to", DiscountCondition.Period),
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
package initialize
|
package initialize
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/controller"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/controller"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ControllersDeps struct {
|
type ControllersDeps struct {
|
||||||
Logger *logrus.Logger
|
Logger *logrus.Logger
|
||||||
Services *Services
|
Services *Services
|
||||||
}
|
}
|
||||||
|
|
||||||
type Controllers struct {
|
type Controllers struct {
|
||||||
DiscountController *controller.DiscountController
|
DiscountController *controller.DiscountController
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewControllers(deps *ControllersDeps) *Controllers {
|
func NewControllers(deps *ControllersDeps) *Controllers {
|
||||||
return &Controllers{
|
return &Controllers{
|
||||||
DiscountController: controller.NewDiscountController(&controller.DiscountControllerDeps{
|
DiscountController: controller.NewDiscountController(&controller.DiscountControllerDeps{
|
||||||
Logger: deps.Logger,
|
Logger: deps.Logger,
|
||||||
DiscountService: deps.Services.DiscountService,
|
DiscountService: deps.Services.DiscountService,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
package initialize
|
package initialize
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/repository"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/repository"
|
)
|
||||||
)
|
|
||||||
|
type RepositoriesDeps struct {
|
||||||
type RepositoriesDeps struct {
|
Database *mongo.Database
|
||||||
Database *mongo.Database
|
Logger *logrus.Logger
|
||||||
Logger *logrus.Logger
|
}
|
||||||
}
|
|
||||||
|
type Repositories struct {
|
||||||
type Repositories struct {
|
DiscountRepository *repository.DiscountRepository
|
||||||
DiscountRepository *repository.DiscountRepository
|
}
|
||||||
}
|
|
||||||
|
func NewRepositories(deps *RepositoriesDeps) *Repositories {
|
||||||
func NewRepositories(deps *RepositoriesDeps) *Repositories {
|
return &Repositories{
|
||||||
return &Repositories{
|
DiscountRepository: repository.NewDiscountRepository(deps.Database.Collection("discounts"), deps.Logger),
|
||||||
DiscountRepository: repository.NewDiscountRepository(deps.Database.Collection("discounts"), deps.Logger),
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
package initialize
|
package initialize
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/service"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServicesDeps struct {
|
type ServicesDeps struct {
|
||||||
Logger *logrus.Logger
|
Logger *logrus.Logger
|
||||||
Respositories *Repositories
|
Repositories *Repositories
|
||||||
}
|
}
|
||||||
|
|
||||||
type Services struct {
|
type Services struct {
|
||||||
DiscountService *service.DiscountService
|
DiscountService *service.DiscountService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServices(deps *ServicesDeps) *Services {
|
func NewServices(deps *ServicesDeps) *Services {
|
||||||
return &Services{
|
return &Services{
|
||||||
DiscountService: service.NewDiscountService(&service.DiscountServiceDeps{
|
DiscountService: service.NewDiscountService(&service.DiscountServiceDeps{
|
||||||
Logger: deps.Logger,
|
Logger: deps.Logger,
|
||||||
DiscountRepository: deps.Respositories.DiscountRepository,
|
DiscountRepository: deps.Repositories.DiscountRepository,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,19 +36,19 @@ type DiscountCalculationTarget struct {
|
|||||||
type DiscountCondition struct {
|
type DiscountCondition struct {
|
||||||
Period *PeriodCondition `json:"period,omitempty" bson:"period,omitempty"`
|
Period *PeriodCondition `json:"period,omitempty" bson:"period,omitempty"`
|
||||||
Product *string `json:"product,omitempty" bson:"product,omitempty"`
|
Product *string `json:"product,omitempty" bson:"product,omitempty"`
|
||||||
PriceFrom *float64 `json:"priceFrom,omitempty" bson:"priceFrom,omitempty"`
|
PriceFrom *uint64 `json:"priceFrom,omitempty" bson:"priceFrom,omitempty"`
|
||||||
Group *string `json:"group,omitempty" bson:"group,omitempty"`
|
Group *string `json:"group,omitempty" bson:"group,omitempty"`
|
||||||
User *string `json:"user,omitempty" bson:"user,omitempty"`
|
User *string `json:"user,omitempty" bson:"user,omitempty"`
|
||||||
UserType *string `json:"userType,omitempty" bson:"userType,omitempty"`
|
UserType *string `json:"userType,omitempty" bson:"userType,omitempty"`
|
||||||
Coupon *string `json:"coupon,omitempty" bson:"coupon,omitempty"`
|
Coupon *string `json:"coupon,omitempty" bson:"coupon,omitempty"`
|
||||||
PurchasesAmount *float64 `json:"purchasesAmount,omitempty" bson:"purchasesAmount,omitempty"`
|
PurchasesAmount *uint64 `json:"purchasesAmount,omitempty" bson:"purchasesAmount,omitempty"`
|
||||||
CartPurchasesAmount *float64 `json:"cartPurchasesAmount,omitempty" bson:"cartPurchasesAmount,omitempty"`
|
CartPurchasesAmount *uint64 `json:"cartPurchasesAmount,omitempty" bson:"cartPurchasesAmount,omitempty"`
|
||||||
|
|
||||||
/* Срок использования (количество дней использования) */
|
/* Срок использования (количество дней использования) */
|
||||||
Term *uint64 `json:"term,omitempty" bson:"term,omitempty"`
|
Term *uint64 `json:"term" bson:"term"`
|
||||||
|
|
||||||
/* Количество использований (количество попыток) */
|
/* Количество использований (количество попыток) */
|
||||||
Usage *uint64 `json:"usage,omitempty" bson:"usage,omitempty"`
|
Usage *uint64 `json:"usage" bson:"usage,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProductTarget struct {
|
type ProductTarget struct {
|
||||||
@ -65,9 +65,14 @@ type PeriodCondition struct {
|
|||||||
type TargetScope string
|
type TargetScope string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TargetSum TargetScope = "sum"
|
// TargetSum тип скидки, применяющийся на финальную сформированную сумму всех товаров.
|
||||||
|
TargetSum TargetScope = "sum"
|
||||||
|
|
||||||
|
// TargetGroup тип скидки, применяющийся на сумму товаров определённой группы.
|
||||||
TargetGroup TargetScope = "group"
|
TargetGroup TargetScope = "group"
|
||||||
TargetEach TargetScope = "each"
|
|
||||||
|
// TargetEach тип скидки, применяющийся на определённый товар.
|
||||||
|
TargetEach TargetScope = "each"
|
||||||
)
|
)
|
||||||
|
|
||||||
var TargetScopeModelMap = map[discount.TargetScope]TargetScope{
|
var TargetScopeModelMap = map[discount.TargetScope]TargetScope{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.26.0
|
// protoc-gen-go v1.31.0
|
||||||
// protoc (unknown)
|
// protoc (unknown)
|
||||||
// source: discount/audit.model.proto
|
// source: discount/audit.model.proto
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
"details": {
|
"details": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
"type": "object",
|
||||||
"$ref": "#/definitions/protobufAny"
|
"$ref": "#/definitions/protobufAny"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.26.0
|
// protoc-gen-go v1.31.0
|
||||||
// protoc (unknown)
|
// protoc (unknown)
|
||||||
// source: discount/discount.model.proto
|
// source: discount/discount.model.proto
|
||||||
|
|
||||||
@ -397,12 +397,12 @@ type DiscountCondition struct {
|
|||||||
User *string `protobuf:"bytes,2,opt,name=User,proto3,oneof" json:"User,omitempty"`
|
User *string `protobuf:"bytes,2,opt,name=User,proto3,oneof" json:"User,omitempty"`
|
||||||
UserType *string `protobuf:"bytes,3,opt,name=UserType,proto3,oneof" json:"UserType,omitempty"`
|
UserType *string `protobuf:"bytes,3,opt,name=UserType,proto3,oneof" json:"UserType,omitempty"`
|
||||||
Coupon *string `protobuf:"bytes,4,opt,name=Coupon,proto3,oneof" json:"Coupon,omitempty"`
|
Coupon *string `protobuf:"bytes,4,opt,name=Coupon,proto3,oneof" json:"Coupon,omitempty"`
|
||||||
PurchasesAmount *float64 `protobuf:"fixed64,5,opt,name=PurchasesAmount,proto3,oneof" json:"PurchasesAmount,omitempty"`
|
PurchasesAmount *uint64 `protobuf:"varint,5,opt,name=PurchasesAmount,proto3,oneof" json:"PurchasesAmount,omitempty"`
|
||||||
CartPurchasesAmount *float64 `protobuf:"fixed64,6,opt,name=CartPurchasesAmount,proto3,oneof" json:"CartPurchasesAmount,omitempty"`
|
CartPurchasesAmount *uint64 `protobuf:"varint,6,opt,name=CartPurchasesAmount,proto3,oneof" json:"CartPurchasesAmount,omitempty"`
|
||||||
Product *string `protobuf:"bytes,7,opt,name=Product,proto3,oneof" json:"Product,omitempty"`
|
Product *string `protobuf:"bytes,7,opt,name=Product,proto3,oneof" json:"Product,omitempty"`
|
||||||
Term *uint64 `protobuf:"varint,8,opt,name=Term,proto3,oneof" json:"Term,omitempty"`
|
Term *uint64 `protobuf:"varint,8,opt,name=Term,proto3,oneof" json:"Term,omitempty"`
|
||||||
Usage *uint64 `protobuf:"varint,9,opt,name=Usage,proto3,oneof" json:"Usage,omitempty"`
|
Usage *uint64 `protobuf:"varint,9,opt,name=Usage,proto3,oneof" json:"Usage,omitempty"`
|
||||||
PriceFrom *float64 `protobuf:"fixed64,10,opt,name=PriceFrom,proto3,oneof" json:"PriceFrom,omitempty"`
|
PriceFrom *uint64 `protobuf:"varint,10,opt,name=PriceFrom,proto3,oneof" json:"PriceFrom,omitempty"`
|
||||||
Group *string `protobuf:"bytes,11,opt,name=Group,proto3,oneof" json:"Group,omitempty"`
|
Group *string `protobuf:"bytes,11,opt,name=Group,proto3,oneof" json:"Group,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,14 +466,14 @@ func (x *DiscountCondition) GetCoupon() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *DiscountCondition) GetPurchasesAmount() float64 {
|
func (x *DiscountCondition) GetPurchasesAmount() uint64 {
|
||||||
if x != nil && x.PurchasesAmount != nil {
|
if x != nil && x.PurchasesAmount != nil {
|
||||||
return *x.PurchasesAmount
|
return *x.PurchasesAmount
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *DiscountCondition) GetCartPurchasesAmount() float64 {
|
func (x *DiscountCondition) GetCartPurchasesAmount() uint64 {
|
||||||
if x != nil && x.CartPurchasesAmount != nil {
|
if x != nil && x.CartPurchasesAmount != nil {
|
||||||
return *x.CartPurchasesAmount
|
return *x.CartPurchasesAmount
|
||||||
}
|
}
|
||||||
@ -501,7 +501,7 @@ func (x *DiscountCondition) GetUsage() uint64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *DiscountCondition) GetPriceFrom() float64 {
|
func (x *DiscountCondition) GetPriceFrom() uint64 {
|
||||||
if x != nil && x.PriceFrom != nil {
|
if x != nil && x.PriceFrom != nil {
|
||||||
return *x.PriceFrom
|
return *x.PriceFrom
|
||||||
}
|
}
|
||||||
@ -638,10 +638,10 @@ type UserInformation struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||||
Type string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"`
|
Type string `protobuf:"bytes,2,opt,name=Type,proto3" json:"Type,omitempty"`
|
||||||
PurchasesAmount float64 `protobuf:"fixed64,3,opt,name=PurchasesAmount,proto3" json:"PurchasesAmount,omitempty"`
|
PurchasesAmount uint64 `protobuf:"varint,3,opt,name=PurchasesAmount,proto3" json:"PurchasesAmount,omitempty"`
|
||||||
CartPurchasesAmount float64 `protobuf:"fixed64,4,opt,name=CartPurchasesAmount,proto3" json:"CartPurchasesAmount,omitempty"`
|
CartPurchasesAmount uint64 `protobuf:"varint,4,opt,name=CartPurchasesAmount,proto3" json:"CartPurchasesAmount,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *UserInformation) Reset() {
|
func (x *UserInformation) Reset() {
|
||||||
@ -690,14 +690,14 @@ func (x *UserInformation) GetType() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *UserInformation) GetPurchasesAmount() float64 {
|
func (x *UserInformation) GetPurchasesAmount() uint64 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.PurchasesAmount
|
return x.PurchasesAmount
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *UserInformation) GetCartPurchasesAmount() float64 {
|
func (x *UserInformation) GetCartPurchasesAmount() uint64 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.CartPurchasesAmount
|
return x.CartPurchasesAmount
|
||||||
}
|
}
|
||||||
@ -710,7 +710,7 @@ type ProductInformation struct {
|
|||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
|
||||||
Price float64 `protobuf:"fixed64,2,opt,name=Price,proto3" json:"Price,omitempty"`
|
Price uint64 `protobuf:"varint,2,opt,name=Price,proto3" json:"Price,omitempty"`
|
||||||
Term *uint64 `protobuf:"varint,3,opt,name=Term,proto3,oneof" json:"Term,omitempty"`
|
Term *uint64 `protobuf:"varint,3,opt,name=Term,proto3,oneof" json:"Term,omitempty"`
|
||||||
Usage *uint64 `protobuf:"varint,4,opt,name=Usage,proto3,oneof" json:"Usage,omitempty"`
|
Usage *uint64 `protobuf:"varint,4,opt,name=Usage,proto3,oneof" json:"Usage,omitempty"`
|
||||||
Group *string `protobuf:"bytes,5,opt,name=Group,proto3,oneof" json:"Group,omitempty"`
|
Group *string `protobuf:"bytes,5,opt,name=Group,proto3,oneof" json:"Group,omitempty"`
|
||||||
@ -755,7 +755,7 @@ func (x *ProductInformation) GetID() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ProductInformation) GetPrice() float64 {
|
func (x *ProductInformation) GetPrice() uint64 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Price
|
return x.Price
|
||||||
}
|
}
|
||||||
@ -868,10 +868,10 @@ var file_discount_discount_model_proto_rawDesc = []byte{
|
|||||||
0x43, 0x6f, 0x75, 0x70, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x06,
|
0x43, 0x6f, 0x75, 0x70, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x06,
|
||||||
0x43, 0x6f, 0x75, 0x70, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x0f, 0x50, 0x75, 0x72,
|
0x43, 0x6f, 0x75, 0x70, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x0f, 0x50, 0x75, 0x72,
|
||||||
0x63, 0x68, 0x61, 0x73, 0x65, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01,
|
0x63, 0x68, 0x61, 0x73, 0x65, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01,
|
||||||
0x28, 0x01, 0x48, 0x04, 0x52, 0x0f, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x73, 0x41,
|
0x28, 0x04, 0x48, 0x04, 0x52, 0x0f, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x73, 0x41,
|
||||||
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12, 0x35, 0x0a, 0x13, 0x43, 0x61, 0x72, 0x74,
|
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12, 0x35, 0x0a, 0x13, 0x43, 0x61, 0x72, 0x74,
|
||||||
0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18,
|
0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18,
|
||||||
0x06, 0x20, 0x01, 0x28, 0x01, 0x48, 0x05, 0x52, 0x13, 0x43, 0x61, 0x72, 0x74, 0x50, 0x75, 0x72,
|
0x06, 0x20, 0x01, 0x28, 0x04, 0x48, 0x05, 0x52, 0x13, 0x43, 0x61, 0x72, 0x74, 0x50, 0x75, 0x72,
|
||||||
0x63, 0x68, 0x61, 0x73, 0x65, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12,
|
0x63, 0x68, 0x61, 0x73, 0x65, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x88, 0x01, 0x01, 0x12,
|
||||||
0x1d, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
|
0x1d, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x48, 0x06, 0x52, 0x07, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x88, 0x01, 0x01, 0x12, 0x17,
|
0x48, 0x06, 0x52, 0x07, 0x50, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x88, 0x01, 0x01, 0x12, 0x17,
|
||||||
@ -879,7 +879,7 @@ var file_discount_discount_model_proto_rawDesc = []byte{
|
|||||||
0x54, 0x65, 0x72, 0x6d, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65,
|
0x54, 0x65, 0x72, 0x6d, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65,
|
||||||
0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x48, 0x08, 0x52, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x88,
|
0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x48, 0x08, 0x52, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x88,
|
||||||
0x01, 0x01, 0x12, 0x21, 0x0a, 0x09, 0x50, 0x72, 0x69, 0x63, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x18,
|
0x01, 0x01, 0x12, 0x21, 0x0a, 0x09, 0x50, 0x72, 0x69, 0x63, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x18,
|
||||||
0x0a, 0x20, 0x01, 0x28, 0x01, 0x48, 0x09, 0x52, 0x09, 0x50, 0x72, 0x69, 0x63, 0x65, 0x46, 0x72,
|
0x0a, 0x20, 0x01, 0x28, 0x04, 0x48, 0x09, 0x52, 0x09, 0x50, 0x72, 0x69, 0x63, 0x65, 0x46, 0x72,
|
||||||
0x6f, 0x6d, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x0b,
|
0x6f, 0x6d, 0x88, 0x01, 0x01, 0x12, 0x19, 0x0a, 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x0b,
|
||||||
0x20, 0x01, 0x28, 0x09, 0x48, 0x0a, 0x52, 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x88, 0x01, 0x01,
|
0x20, 0x01, 0x28, 0x09, 0x48, 0x0a, 0x52, 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x88, 0x01, 0x01,
|
||||||
0x42, 0x09, 0x0a, 0x07, 0x5f, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x5f,
|
0x42, 0x09, 0x0a, 0x07, 0x5f, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x5f,
|
||||||
@ -909,14 +909,14 @@ var file_discount_discount_model_proto_rawDesc = []byte{
|
|||||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70,
|
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70,
|
||||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a,
|
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a,
|
||||||
0x0f, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
|
0x0f, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
|
||||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0f, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65,
|
0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65,
|
||||||
0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x13, 0x43, 0x61, 0x72, 0x74, 0x50,
|
0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x13, 0x43, 0x61, 0x72, 0x74, 0x50,
|
||||||
0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04,
|
0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04,
|
||||||
0x20, 0x01, 0x28, 0x01, 0x52, 0x13, 0x43, 0x61, 0x72, 0x74, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61,
|
0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x43, 0x61, 0x72, 0x74, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61,
|
||||||
0x73, 0x65, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xa6, 0x01, 0x0a, 0x12, 0x50, 0x72,
|
0x73, 0x65, 0x73, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xa6, 0x01, 0x0a, 0x12, 0x50, 0x72,
|
||||||
0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||||
0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44,
|
0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44,
|
||||||
0x12, 0x14, 0x0a, 0x05, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52,
|
0x12, 0x14, 0x0a, 0x05, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||||
0x05, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x17, 0x0a, 0x04, 0x54, 0x65, 0x72, 0x6d, 0x18, 0x03,
|
0x05, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x17, 0x0a, 0x04, 0x54, 0x65, 0x72, 0x6d, 0x18, 0x03,
|
||||||
0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x04, 0x54, 0x65, 0x72, 0x6d, 0x88, 0x01, 0x01, 0x12,
|
0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x04, 0x54, 0x65, 0x72, 0x6d, 0x88, 0x01, 0x01, 0x12,
|
||||||
0x19, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x48, 0x01,
|
0x19, 0x0a, 0x05, 0x55, 0x73, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x48, 0x01,
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
"details": {
|
"details": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
"type": "object",
|
||||||
"$ref": "#/definitions/protobufAny"
|
"$ref": "#/definitions/protobufAny"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.26.0
|
// protoc-gen-go v1.31.0
|
||||||
// protoc (unknown)
|
// protoc (unknown)
|
||||||
// source: discount/service.proto
|
// source: discount/service.proto
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ type ApplyDiscountResponse struct {
|
|||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Price float64 `protobuf:"fixed64,1,opt,name=Price,proto3" json:"Price,omitempty"`
|
Price uint64 `protobuf:"varint,1,opt,name=Price,proto3" json:"Price,omitempty"`
|
||||||
AppliedDiscounts []*Discount `protobuf:"bytes,2,rep,name=AppliedDiscounts,proto3" json:"AppliedDiscounts,omitempty"`
|
AppliedDiscounts []*Discount `protobuf:"bytes,2,rep,name=AppliedDiscounts,proto3" json:"AppliedDiscounts,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ func (*ApplyDiscountResponse) Descriptor() ([]byte, []int) {
|
|||||||
return file_discount_service_proto_rawDescGZIP(), []int{2}
|
return file_discount_service_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ApplyDiscountResponse) GetPrice() float64 {
|
func (x *ApplyDiscountResponse) GetPrice() uint64 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Price
|
return x.Price
|
||||||
}
|
}
|
||||||
@ -307,7 +307,7 @@ var file_discount_service_proto_rawDesc = []byte{
|
|||||||
0x00, 0x52, 0x06, 0x43, 0x6f, 0x75, 0x70, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07,
|
0x00, 0x52, 0x06, 0x43, 0x6f, 0x75, 0x70, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07,
|
||||||
0x5f, 0x43, 0x6f, 0x75, 0x70, 0x6f, 0x6e, 0x22, 0x6d, 0x0a, 0x15, 0x41, 0x70, 0x70, 0x6c, 0x79,
|
0x5f, 0x43, 0x6f, 0x75, 0x70, 0x6f, 0x6e, 0x22, 0x6d, 0x0a, 0x15, 0x41, 0x70, 0x70, 0x6c, 0x79,
|
||||||
0x44, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
0x44, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||||
0x12, 0x14, 0x0a, 0x05, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52,
|
0x12, 0x14, 0x0a, 0x05, 0x50, 0x72, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||||
0x05, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x10, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65,
|
0x05, 0x50, 0x72, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x10, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x65,
|
||||||
0x64, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
|
0x64, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
|
||||||
0x32, 0x12, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x44, 0x69, 0x73, 0x63,
|
0x32, 0x12, 0x2e, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x2e, 0x44, 0x69, 0x73, 0x63,
|
||||||
|
@ -681,7 +681,7 @@ func RegisterDiscountServiceHandlerServer(ctx context.Context, mux *runtime.Serv
|
|||||||
// RegisterDiscountServiceHandlerFromEndpoint is same as RegisterDiscountServiceHandler but
|
// RegisterDiscountServiceHandlerFromEndpoint is same as RegisterDiscountServiceHandler but
|
||||||
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||||
func RegisterDiscountServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
func RegisterDiscountServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||||
conn, err := grpc.Dial(endpoint, opts...)
|
conn, err := grpc.DialContext(ctx, endpoint, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -341,6 +341,7 @@
|
|||||||
"Products": {
|
"Products": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
"type": "object",
|
||||||
"$ref": "#/definitions/discountProductInformation"
|
"$ref": "#/definitions/discountProductInformation"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -363,6 +364,7 @@
|
|||||||
"AppliedDiscounts": {
|
"AppliedDiscounts": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
"type": "object",
|
||||||
"$ref": "#/definitions/discountDiscount"
|
"$ref": "#/definitions/discountDiscount"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -445,6 +447,7 @@
|
|||||||
"Products": {
|
"Products": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
"type": "object",
|
||||||
"$ref": "#/definitions/discountProductTarget"
|
"$ref": "#/definitions/discountProductTarget"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -512,6 +515,7 @@
|
|||||||
"Discounts": {
|
"Discounts": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
"type": "object",
|
||||||
"$ref": "#/definitions/discountDiscount"
|
"$ref": "#/definitions/discountDiscount"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -618,6 +622,7 @@
|
|||||||
"details": {
|
"details": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
"type": "object",
|
||||||
"$ref": "#/definitions/protobufAny"
|
"$ref": "#/definitions/protobufAny"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.3.0
|
||||||
|
// - protoc (unknown)
|
||||||
|
// source: discount/service.proto
|
||||||
|
|
||||||
package discount
|
package discount
|
||||||
|
|
||||||
@ -15,6 +19,18 @@ import (
|
|||||||
// Requires gRPC-Go v1.32.0 or later.
|
// Requires gRPC-Go v1.32.0 or later.
|
||||||
const _ = grpc.SupportPackageIsVersion7
|
const _ = grpc.SupportPackageIsVersion7
|
||||||
|
|
||||||
|
const (
|
||||||
|
DiscountService_GetAllDiscounts_FullMethodName = "/discount.DiscountService/GetAllDiscounts"
|
||||||
|
DiscountService_GetUserDiscounts_FullMethodName = "/discount.DiscountService/GetUserDiscounts"
|
||||||
|
DiscountService_DetermineDiscounts_FullMethodName = "/discount.DiscountService/DetermineDiscounts"
|
||||||
|
DiscountService_ApplyDiscounts_FullMethodName = "/discount.DiscountService/ApplyDiscounts"
|
||||||
|
DiscountService_GetDiscountByID_FullMethodName = "/discount.DiscountService/GetDiscountByID"
|
||||||
|
DiscountService_CreateDiscount_FullMethodName = "/discount.DiscountService/CreateDiscount"
|
||||||
|
DiscountService_ReplaceDiscount_FullMethodName = "/discount.DiscountService/ReplaceDiscount"
|
||||||
|
DiscountService_UpdateDiscount_FullMethodName = "/discount.DiscountService/UpdateDiscount"
|
||||||
|
DiscountService_DeleteDiscount_FullMethodName = "/discount.DiscountService/DeleteDiscount"
|
||||||
|
)
|
||||||
|
|
||||||
// DiscountServiceClient is the client API for DiscountService service.
|
// DiscountServiceClient is the client API for DiscountService 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.
|
// 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.
|
||||||
@ -40,7 +56,7 @@ func NewDiscountServiceClient(cc grpc.ClientConnInterface) DiscountServiceClient
|
|||||||
|
|
||||||
func (c *discountServiceClient) GetAllDiscounts(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Discounts, error) {
|
func (c *discountServiceClient) GetAllDiscounts(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Discounts, error) {
|
||||||
out := new(Discounts)
|
out := new(Discounts)
|
||||||
err := c.cc.Invoke(ctx, "/discount.DiscountService/GetAllDiscounts", in, out, opts...)
|
err := c.cc.Invoke(ctx, DiscountService_GetAllDiscounts_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -49,7 +65,7 @@ func (c *discountServiceClient) GetAllDiscounts(ctx context.Context, in *emptypb
|
|||||||
|
|
||||||
func (c *discountServiceClient) GetUserDiscounts(ctx context.Context, in *GetDiscountByIDRequest, opts ...grpc.CallOption) (*Discounts, error) {
|
func (c *discountServiceClient) GetUserDiscounts(ctx context.Context, in *GetDiscountByIDRequest, opts ...grpc.CallOption) (*Discounts, error) {
|
||||||
out := new(Discounts)
|
out := new(Discounts)
|
||||||
err := c.cc.Invoke(ctx, "/discount.DiscountService/GetUserDiscounts", in, out, opts...)
|
err := c.cc.Invoke(ctx, DiscountService_GetUserDiscounts_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -58,7 +74,7 @@ func (c *discountServiceClient) GetUserDiscounts(ctx context.Context, in *GetDis
|
|||||||
|
|
||||||
func (c *discountServiceClient) DetermineDiscounts(ctx context.Context, in *ApplyDiscountRequest, opts ...grpc.CallOption) (*Discounts, error) {
|
func (c *discountServiceClient) DetermineDiscounts(ctx context.Context, in *ApplyDiscountRequest, opts ...grpc.CallOption) (*Discounts, error) {
|
||||||
out := new(Discounts)
|
out := new(Discounts)
|
||||||
err := c.cc.Invoke(ctx, "/discount.DiscountService/DetermineDiscounts", in, out, opts...)
|
err := c.cc.Invoke(ctx, DiscountService_DetermineDiscounts_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -67,7 +83,7 @@ func (c *discountServiceClient) DetermineDiscounts(ctx context.Context, in *Appl
|
|||||||
|
|
||||||
func (c *discountServiceClient) ApplyDiscounts(ctx context.Context, in *ApplyDiscountRequest, opts ...grpc.CallOption) (*ApplyDiscountResponse, error) {
|
func (c *discountServiceClient) ApplyDiscounts(ctx context.Context, in *ApplyDiscountRequest, opts ...grpc.CallOption) (*ApplyDiscountResponse, error) {
|
||||||
out := new(ApplyDiscountResponse)
|
out := new(ApplyDiscountResponse)
|
||||||
err := c.cc.Invoke(ctx, "/discount.DiscountService/ApplyDiscounts", in, out, opts...)
|
err := c.cc.Invoke(ctx, DiscountService_ApplyDiscounts_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -76,7 +92,7 @@ func (c *discountServiceClient) ApplyDiscounts(ctx context.Context, in *ApplyDis
|
|||||||
|
|
||||||
func (c *discountServiceClient) GetDiscountByID(ctx context.Context, in *GetDiscountByIDRequest, opts ...grpc.CallOption) (*Discount, error) {
|
func (c *discountServiceClient) GetDiscountByID(ctx context.Context, in *GetDiscountByIDRequest, opts ...grpc.CallOption) (*Discount, error) {
|
||||||
out := new(Discount)
|
out := new(Discount)
|
||||||
err := c.cc.Invoke(ctx, "/discount.DiscountService/GetDiscountByID", in, out, opts...)
|
err := c.cc.Invoke(ctx, DiscountService_GetDiscountByID_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -85,7 +101,7 @@ func (c *discountServiceClient) GetDiscountByID(ctx context.Context, in *GetDisc
|
|||||||
|
|
||||||
func (c *discountServiceClient) CreateDiscount(ctx context.Context, in *CreateDiscountRequest, opts ...grpc.CallOption) (*Discount, error) {
|
func (c *discountServiceClient) CreateDiscount(ctx context.Context, in *CreateDiscountRequest, opts ...grpc.CallOption) (*Discount, error) {
|
||||||
out := new(Discount)
|
out := new(Discount)
|
||||||
err := c.cc.Invoke(ctx, "/discount.DiscountService/CreateDiscount", in, out, opts...)
|
err := c.cc.Invoke(ctx, DiscountService_CreateDiscount_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -94,7 +110,7 @@ func (c *discountServiceClient) CreateDiscount(ctx context.Context, in *CreateDi
|
|||||||
|
|
||||||
func (c *discountServiceClient) ReplaceDiscount(ctx context.Context, in *DiscountOptional, opts ...grpc.CallOption) (*Discount, error) {
|
func (c *discountServiceClient) ReplaceDiscount(ctx context.Context, in *DiscountOptional, opts ...grpc.CallOption) (*Discount, error) {
|
||||||
out := new(Discount)
|
out := new(Discount)
|
||||||
err := c.cc.Invoke(ctx, "/discount.DiscountService/ReplaceDiscount", in, out, opts...)
|
err := c.cc.Invoke(ctx, DiscountService_ReplaceDiscount_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -103,7 +119,7 @@ func (c *discountServiceClient) ReplaceDiscount(ctx context.Context, in *Discoun
|
|||||||
|
|
||||||
func (c *discountServiceClient) UpdateDiscount(ctx context.Context, in *DiscountOptional, opts ...grpc.CallOption) (*Discount, error) {
|
func (c *discountServiceClient) UpdateDiscount(ctx context.Context, in *DiscountOptional, opts ...grpc.CallOption) (*Discount, error) {
|
||||||
out := new(Discount)
|
out := new(Discount)
|
||||||
err := c.cc.Invoke(ctx, "/discount.DiscountService/UpdateDiscount", in, out, opts...)
|
err := c.cc.Invoke(ctx, DiscountService_UpdateDiscount_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -112,7 +128,7 @@ func (c *discountServiceClient) UpdateDiscount(ctx context.Context, in *Discount
|
|||||||
|
|
||||||
func (c *discountServiceClient) DeleteDiscount(ctx context.Context, in *GetDiscountByIDRequest, opts ...grpc.CallOption) (*Discount, error) {
|
func (c *discountServiceClient) DeleteDiscount(ctx context.Context, in *GetDiscountByIDRequest, opts ...grpc.CallOption) (*Discount, error) {
|
||||||
out := new(Discount)
|
out := new(Discount)
|
||||||
err := c.cc.Invoke(ctx, "/discount.DiscountService/DeleteDiscount", in, out, opts...)
|
err := c.cc.Invoke(ctx, DiscountService_DeleteDiscount_FullMethodName, in, out, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -187,7 +203,7 @@ func _DiscountService_GetAllDiscounts_Handler(srv interface{}, ctx context.Conte
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: "/discount.DiscountService/GetAllDiscounts",
|
FullMethod: DiscountService_GetAllDiscounts_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(DiscountServiceServer).GetAllDiscounts(ctx, req.(*emptypb.Empty))
|
return srv.(DiscountServiceServer).GetAllDiscounts(ctx, req.(*emptypb.Empty))
|
||||||
@ -205,7 +221,7 @@ func _DiscountService_GetUserDiscounts_Handler(srv interface{}, ctx context.Cont
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: "/discount.DiscountService/GetUserDiscounts",
|
FullMethod: DiscountService_GetUserDiscounts_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(DiscountServiceServer).GetUserDiscounts(ctx, req.(*GetDiscountByIDRequest))
|
return srv.(DiscountServiceServer).GetUserDiscounts(ctx, req.(*GetDiscountByIDRequest))
|
||||||
@ -223,7 +239,7 @@ func _DiscountService_DetermineDiscounts_Handler(srv interface{}, ctx context.Co
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: "/discount.DiscountService/DetermineDiscounts",
|
FullMethod: DiscountService_DetermineDiscounts_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(DiscountServiceServer).DetermineDiscounts(ctx, req.(*ApplyDiscountRequest))
|
return srv.(DiscountServiceServer).DetermineDiscounts(ctx, req.(*ApplyDiscountRequest))
|
||||||
@ -241,7 +257,7 @@ func _DiscountService_ApplyDiscounts_Handler(srv interface{}, ctx context.Contex
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: "/discount.DiscountService/ApplyDiscounts",
|
FullMethod: DiscountService_ApplyDiscounts_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(DiscountServiceServer).ApplyDiscounts(ctx, req.(*ApplyDiscountRequest))
|
return srv.(DiscountServiceServer).ApplyDiscounts(ctx, req.(*ApplyDiscountRequest))
|
||||||
@ -259,7 +275,7 @@ func _DiscountService_GetDiscountByID_Handler(srv interface{}, ctx context.Conte
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: "/discount.DiscountService/GetDiscountByID",
|
FullMethod: DiscountService_GetDiscountByID_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(DiscountServiceServer).GetDiscountByID(ctx, req.(*GetDiscountByIDRequest))
|
return srv.(DiscountServiceServer).GetDiscountByID(ctx, req.(*GetDiscountByIDRequest))
|
||||||
@ -277,7 +293,7 @@ func _DiscountService_CreateDiscount_Handler(srv interface{}, ctx context.Contex
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: "/discount.DiscountService/CreateDiscount",
|
FullMethod: DiscountService_CreateDiscount_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(DiscountServiceServer).CreateDiscount(ctx, req.(*CreateDiscountRequest))
|
return srv.(DiscountServiceServer).CreateDiscount(ctx, req.(*CreateDiscountRequest))
|
||||||
@ -295,7 +311,7 @@ func _DiscountService_ReplaceDiscount_Handler(srv interface{}, ctx context.Conte
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: "/discount.DiscountService/ReplaceDiscount",
|
FullMethod: DiscountService_ReplaceDiscount_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(DiscountServiceServer).ReplaceDiscount(ctx, req.(*DiscountOptional))
|
return srv.(DiscountServiceServer).ReplaceDiscount(ctx, req.(*DiscountOptional))
|
||||||
@ -313,7 +329,7 @@ func _DiscountService_UpdateDiscount_Handler(srv interface{}, ctx context.Contex
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: "/discount.DiscountService/UpdateDiscount",
|
FullMethod: DiscountService_UpdateDiscount_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(DiscountServiceServer).UpdateDiscount(ctx, req.(*DiscountOptional))
|
return srv.(DiscountServiceServer).UpdateDiscount(ctx, req.(*DiscountOptional))
|
||||||
@ -331,7 +347,7 @@ func _DiscountService_DeleteDiscount_Handler(srv interface{}, ctx context.Contex
|
|||||||
}
|
}
|
||||||
info := &grpc.UnaryServerInfo{
|
info := &grpc.UnaryServerInfo{
|
||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: "/discount.DiscountService/DeleteDiscount",
|
FullMethod: DiscountService_DeleteDiscount_FullMethodName,
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return srv.(DiscountServiceServer).DeleteDiscount(ctx, req.(*GetDiscountByIDRequest))
|
return srv.(DiscountServiceServer).DeleteDiscount(ctx, req.(*GetDiscountByIDRequest))
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
"go.mongodb.org/mongo-driver/mongo/options"
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
"go.mongodb.org/mongo-driver/mongo/readconcern"
|
"go.mongodb.org/mongo-driver/mongo/readconcern"
|
||||||
"go.mongodb.org/mongo-driver/mongo/writeconcern"
|
"go.mongodb.org/mongo-driver/mongo/writeconcern"
|
||||||
|
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
@ -184,7 +183,9 @@ func (receiver *DiscountRepository) UpdateMany(ctx context.Context, updates []co
|
|||||||
|
|
||||||
if _, transactionError := session.WithTransaction(ctx, func(sessionContext mongo.SessionContext) (interface{}, error) {
|
if _, transactionError := session.WithTransaction(ctx, func(sessionContext mongo.SessionContext) (interface{}, error) {
|
||||||
for _, update := range updates {
|
for _, update := range updates {
|
||||||
if err := receiver.UpdateOne(sessionContext, &update); err != nil {
|
updateCopy := update
|
||||||
|
|
||||||
|
if err := receiver.UpdateOne(sessionContext, &updateCopy); err != nil {
|
||||||
receiver.logger.Errorf("failed to update <%s> in transaction on <UpdateMany> of <DiscountRepository>: %v", update.ID, err)
|
receiver.logger.Errorf("failed to update <%s> in transaction on <UpdateMany> of <DiscountRepository>: %v", update.ID, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1,73 +1,72 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"context"
|
||||||
"net"
|
"fmt"
|
||||||
|
"net"
|
||||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
|
||||||
grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
|
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||||
grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
|
grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
|
||||||
"github.com/sirupsen/logrus"
|
grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
|
||||||
"google.golang.org/grpc"
|
"github.com/sirupsen/logrus"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"google.golang.org/grpc"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
)
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
|
)
|
||||||
type GRPC struct {
|
|
||||||
logger *logrus.Entry
|
type GRPC struct {
|
||||||
grpc *grpc.Server
|
logger *logrus.Entry
|
||||||
}
|
grpc *grpc.Server
|
||||||
|
}
|
||||||
func NewGRPC(logger *logrus.Logger) *GRPC {
|
|
||||||
grpcLogger := logrus.NewEntry(logger)
|
func NewGRPC(logger *logrus.Logger) *GRPC {
|
||||||
|
grpcLogger := logrus.NewEntry(logger)
|
||||||
grpcStreamInterceptor := grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
|
|
||||||
grpc_logrus.StreamServerInterceptor(grpcLogger),
|
grpcStreamInterceptor := grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
|
||||||
grpc_recovery.StreamServerInterceptor(),
|
grpc_logrus.StreamServerInterceptor(grpcLogger),
|
||||||
))
|
grpc_recovery.StreamServerInterceptor(),
|
||||||
|
))
|
||||||
grpcUnaryInterceptor := grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
|
|
||||||
grpc_logrus.UnaryServerInterceptor(grpcLogger),
|
grpcUnaryInterceptor := grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
|
||||||
grpc_recovery.UnaryServerInterceptor(),
|
grpc_logrus.UnaryServerInterceptor(grpcLogger),
|
||||||
))
|
grpc_recovery.UnaryServerInterceptor(),
|
||||||
|
))
|
||||||
return &GRPC{
|
|
||||||
grpc: grpc.NewServer(grpcStreamInterceptor, grpcUnaryInterceptor),
|
return &GRPC{
|
||||||
logger: grpcLogger,
|
grpc: grpc.NewServer(grpcStreamInterceptor, grpcUnaryInterceptor),
|
||||||
}
|
logger: grpcLogger,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
func (receiver *GRPC) Run(config *core.GRPCConfiguration) {
|
|
||||||
connectionString := fmt.Sprintf("%s:%s", config.Host, config.Port)
|
func (receiver *GRPC) Run(config *core.GRPCConfiguration) {
|
||||||
|
connectionString := fmt.Sprintf("%s:%s", config.Host, config.Port)
|
||||||
receiver.logger.Infof("Starting GRPC Server on %s", connectionString)
|
|
||||||
|
receiver.logger.Infof("Starting GRPC Server on %s", connectionString)
|
||||||
if err := receiver.listen(connectionString); err != nil && err != grpc.ErrServerStopped {
|
|
||||||
receiver.logger.Errorf("GRPC Listen error: %v", err)
|
if err := receiver.listen(connectionString); err != nil && err != grpc.ErrServerStopped {
|
||||||
panic(err)
|
receiver.logger.Errorf("GRPC Listen error: %v", err)
|
||||||
}
|
panic(err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
func (receiver *GRPC) Register(server discount.DiscountServiceServer) *GRPC {
|
|
||||||
discount.RegisterDiscountServiceServer(receiver.grpc, server)
|
func (receiver *GRPC) Register(server discount.DiscountServiceServer) *GRPC {
|
||||||
|
discount.RegisterDiscountServiceServer(receiver.grpc, server)
|
||||||
return receiver
|
|
||||||
}
|
return receiver
|
||||||
|
}
|
||||||
func (receiver *GRPC) listen(address string) error {
|
|
||||||
listener, err := net.Listen("tcp", address)
|
func (receiver *GRPC) listen(address string) error {
|
||||||
if err != nil {
|
listener, err := net.Listen("tcp", address)
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
if err := receiver.grpc.Serve(listener); err != nil {
|
|
||||||
return err
|
return receiver.grpc.Serve(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
func (receiver *GRPC) Stop(_ context.Context) error {
|
||||||
}
|
receiver.grpc.GracefulStop()
|
||||||
|
receiver.logger.Infoln("Shutting down GRPC server...")
|
||||||
func (receiver *GRPC) Stop() {
|
|
||||||
receiver.grpc.GracefulStop()
|
return nil
|
||||||
receiver.logger.Infoln("Shutting down GRPC server...")
|
}
|
||||||
}
|
|
||||||
|
@ -1,50 +1,64 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||||
"google.golang.org/grpc"
|
"github.com/sirupsen/logrus"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HTTP struct {
|
type HTTP struct {
|
||||||
logger *logrus.Logger
|
logger *logrus.Logger
|
||||||
mux *runtime.ServeMux
|
server *http.Server
|
||||||
}
|
mux *runtime.ServeMux
|
||||||
|
}
|
||||||
func NewHTTP(logger *logrus.Logger) *HTTP {
|
|
||||||
return &HTTP{
|
func NewHTTP(logger *logrus.Logger) *HTTP {
|
||||||
logger: logger,
|
return &HTTP{
|
||||||
mux: runtime.NewServeMux(),
|
logger: logger,
|
||||||
}
|
mux: runtime.NewServeMux(),
|
||||||
}
|
server: &http.Server{
|
||||||
|
MaxHeaderBytes: 1 << 20,
|
||||||
func (receiver *HTTP) Register(ctx context.Context, config *core.GRPCConfiguration) *HTTP {
|
ReadTimeout: 20 * time.Second,
|
||||||
options := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
|
WriteTimeout: 20 * time.Second,
|
||||||
endpoint := fmt.Sprintf("%s:%s", config.Host, config.Port)
|
IdleTimeout: 20 * time.Second,
|
||||||
|
},
|
||||||
if err := discount.RegisterDiscountServiceHandlerFromEndpoint(ctx, receiver.mux, endpoint, options); err != nil {
|
}
|
||||||
receiver.logger.Errorf("HTTP register error: %v", err)
|
}
|
||||||
panic(err)
|
|
||||||
}
|
func (receiver *HTTP) Register(ctx context.Context, config *core.GRPCConfiguration) *HTTP {
|
||||||
|
options := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
|
||||||
return receiver
|
endpoint := fmt.Sprintf("%s:%s", config.Host, config.Port)
|
||||||
}
|
|
||||||
|
if err := discount.RegisterDiscountServiceHandlerFromEndpoint(ctx, receiver.mux, endpoint, options); err != nil {
|
||||||
func (receiver *HTTP) Run(config *core.HTTPConfiguration) {
|
receiver.logger.Errorf("HTTP register error: %v", err)
|
||||||
endpoint := fmt.Sprintf(":%s", config.Port)
|
panic(err)
|
||||||
|
}
|
||||||
receiver.logger.Infof("HTTP server started on: <%s>", endpoint)
|
|
||||||
|
return receiver
|
||||||
if err := http.ListenAndServe(endpoint, receiver.mux); err != nil && err != http.ErrServerClosed {
|
}
|
||||||
receiver.logger.Errorf("HTTP listen error: %v", err)
|
|
||||||
panic(err)
|
func (receiver *HTTP) Listen(address string) error {
|
||||||
}
|
receiver.server.Addr = address
|
||||||
}
|
receiver.server.Handler = receiver.mux
|
||||||
|
|
||||||
|
return receiver.server.ListenAndServe()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *HTTP) Run(config *core.HTTPConfiguration) {
|
||||||
|
endpoint := fmt.Sprintf(":%s", config.Port)
|
||||||
|
|
||||||
|
receiver.logger.Infof("HTTP server started on: <%s>", endpoint)
|
||||||
|
|
||||||
|
if err := receiver.Listen(endpoint); err != nil && err != http.ErrServerClosed {
|
||||||
|
receiver.logger.Errorf("HTTP listen error: %v", err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,136 +1,135 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils"
|
discountUtils "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/calculate"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
)
|
||||||
)
|
|
||||||
|
type DiscountRepository interface {
|
||||||
type DiscountRepository interface {
|
Insert(ctx context.Context, discount *models.Discount) (string, error)
|
||||||
Insert(ctx context.Context, discount *models.Discount) (string, error)
|
DeleteByID(ctx context.Context, discountID string) (*models.Discount, error)
|
||||||
DeleteByID(ctx context.Context, discountID string) (*models.Discount, error)
|
FindByID(ctx context.Context, discountID string) (*models.Discount, error)
|
||||||
FindByID(ctx context.Context, discountID string) (*models.Discount, error)
|
FindAll(ctx context.Context) ([]models.Discount, error)
|
||||||
FindAll(ctx context.Context) ([]models.Discount, error)
|
FindByUserID(ctx context.Context, userID string) ([]models.Discount, error)
|
||||||
FindByUserID(ctx context.Context, userID string) ([]models.Discount, error)
|
Determine(ctx context.Context, conditions *core.DiscountConditions) ([]models.Discount, error)
|
||||||
Determine(ctx context.Context, conditions *core.DiscountConditions) ([]models.Discount, error)
|
UpdateOne(ctx context.Context, update *core.UpdateDiscountSettings) error
|
||||||
UpdateOne(ctx context.Context, update *core.UpdateDiscountSettings) error
|
}
|
||||||
}
|
|
||||||
|
type DiscountServiceDeps struct {
|
||||||
type DiscountServiceDeps struct {
|
Logger *logrus.Logger
|
||||||
Logger *logrus.Logger
|
DiscountRepository DiscountRepository
|
||||||
DiscountRepository DiscountRepository
|
}
|
||||||
}
|
|
||||||
|
type DiscountService struct {
|
||||||
type DiscountService struct {
|
logger *logrus.Logger
|
||||||
logger *logrus.Logger
|
discountRepository DiscountRepository
|
||||||
discountRepository DiscountRepository
|
}
|
||||||
}
|
|
||||||
|
func NewDiscountService(deps *DiscountServiceDeps) *DiscountService {
|
||||||
func NewDiscountService(deps *DiscountServiceDeps) *DiscountService {
|
return &DiscountService{
|
||||||
return &DiscountService{
|
logger: deps.Logger,
|
||||||
logger: deps.Logger,
|
discountRepository: deps.DiscountRepository,
|
||||||
discountRepository: deps.DiscountRepository,
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
func (receiver *DiscountService) ApplyDiscounts(ctx context.Context, request *discount.ApplyDiscountRequest) (*discount.ApplyDiscountResponse, error) {
|
||||||
func (receiver *DiscountService) ApplyDiscounts(ctx context.Context, request *discount.ApplyDiscountRequest) (*discount.ApplyDiscountResponse, error) {
|
conditions, err := utils.ConstituteConditions(request)
|
||||||
conditions, err := utils.ConstituteConditions(request)
|
if err != nil {
|
||||||
if err != nil {
|
receiver.logger.Errorf("failed to constitute conditions on <ApplyDiscounts> of <DiscountService>: %v", err)
|
||||||
receiver.logger.Errorf("failed to constitute conditions on <ApplyDiscounts> of <DiscountService>: %v", err)
|
return nil, ErrInvalidInputValue
|
||||||
return nil, ErrInvalidInputValue
|
}
|
||||||
}
|
|
||||||
|
discounts, err := receiver.discountRepository.Determine(ctx, conditions)
|
||||||
discounts, err := receiver.discountRepository.Determine(ctx, conditions)
|
if err != nil {
|
||||||
if err != nil {
|
receiver.logger.Errorf("failed to determine conditions on <ApplyDiscounts> of <DiscountService>: %v", err)
|
||||||
receiver.logger.Errorf("failed to determine conditions on <ApplyDiscounts> of <DiscountService>: %v", err)
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
}
|
|
||||||
|
filteredDiscounts, couponDiscount := utils.FilterCouponDiscounts(discounts)
|
||||||
filteredDiscounts, couponDiscount := utils.FilterCouponDiscounts(discounts)
|
|
||||||
|
if couponDiscount != nil {
|
||||||
if couponDiscount != nil {
|
deprecated := true
|
||||||
deprecated := true
|
|
||||||
|
if err := receiver.discountRepository.UpdateOne(ctx, &core.UpdateDiscountSettings{
|
||||||
if err := receiver.discountRepository.UpdateOne(ctx, &core.UpdateDiscountSettings{
|
ID: couponDiscount.ID,
|
||||||
ID: couponDiscount.ID,
|
Deprecated: &deprecated,
|
||||||
Deprecated: &deprecated,
|
}); err != nil {
|
||||||
}); err != nil {
|
receiver.logger.Errorf("failed to deprecate coupon discount on <ApplyDiscounts> of <DiscountService>: %v", err)
|
||||||
receiver.logger.Errorf("failed to deprecate coupon discount on <ApplyDiscounts> of <DiscountService>: %v", err)
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
products := transfer.ProductsProtoToCore(request.Products)
|
||||||
products := transfer.ProductsProtoToCore(request.Products)
|
|
||||||
|
return &discount.ApplyDiscountResponse{
|
||||||
return &discount.ApplyDiscountResponse{
|
Price: discountUtils.Calculate(products, filteredDiscounts),
|
||||||
Price: calculate.Discount(products, filteredDiscounts),
|
AppliedDiscounts: transfer.DiscountsModelToProto(filteredDiscounts).Discounts,
|
||||||
AppliedDiscounts: transfer.DiscountsModelToProto(filteredDiscounts).Discounts,
|
}, nil
|
||||||
}, nil
|
}
|
||||||
}
|
|
||||||
|
func (receiver *DiscountService) GetDiscountByID(ctx context.Context, id string) (*models.Discount, error) {
|
||||||
func (receiver *DiscountService) GetDiscountByID(ctx context.Context, id string) (*models.Discount, error) {
|
discount, err := receiver.discountRepository.FindByID(ctx, id)
|
||||||
discount, err := receiver.discountRepository.FindByID(ctx, id)
|
if err != nil {
|
||||||
if err != nil {
|
receiver.logger.Errorf("failed to get discount on <GetDiscountByID> of <DiscountService>: %v", err)
|
||||||
receiver.logger.Errorf("failed to get discount on <GetDiscountByID> of <DiscountService>: %v", err)
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
}
|
|
||||||
|
return discount, nil
|
||||||
return discount, nil
|
}
|
||||||
}
|
|
||||||
|
func (receiver *DiscountService) GetDiscountsByUserID(ctx context.Context, id string) ([]models.Discount, error) {
|
||||||
func (receiver *DiscountService) GetDiscountsByUserID(ctx context.Context, id string) ([]models.Discount, error) {
|
discounts, err := receiver.discountRepository.FindByUserID(ctx, id)
|
||||||
discounts, err := receiver.discountRepository.FindByUserID(ctx, id)
|
if err != nil {
|
||||||
if err != nil {
|
receiver.logger.Errorf("failed to get discount on <GetDiscountByUserID> of <DiscountService>: %v", err)
|
||||||
receiver.logger.Errorf("failed to get discount on <GetDiscountByUserID> of <DiscountService>: %v", err)
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
}
|
|
||||||
|
return discounts, nil
|
||||||
return discounts, nil
|
}
|
||||||
}
|
|
||||||
|
func (receiver *DiscountService) GetAllDiscounts(ctx context.Context) ([]models.Discount, error) {
|
||||||
func (receiver *DiscountService) GetAllDiscounts(ctx context.Context) ([]models.Discount, error) {
|
discounts, err := receiver.discountRepository.FindAll(ctx)
|
||||||
discounts, err := receiver.discountRepository.FindAll(ctx)
|
if err != nil {
|
||||||
if err != nil {
|
receiver.logger.Errorf("failed to get all discounts on <GetAllDiscounts> of <DiscountService>: %v", err)
|
||||||
receiver.logger.Errorf("failed to get all discounts on <GetAllDiscounts> of <DiscountService>: %v", err)
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
}
|
|
||||||
|
return discounts, nil
|
||||||
return discounts, nil
|
}
|
||||||
}
|
|
||||||
|
func (receiver *DiscountService) DeleteDiscount(ctx context.Context, id string) (*models.Discount, error) {
|
||||||
func (receiver *DiscountService) DeleteDiscount(ctx context.Context, id string) (*models.Discount, error) {
|
deletedDiscount, err := receiver.discountRepository.DeleteByID(ctx, id)
|
||||||
deletedDiscount, err := receiver.discountRepository.DeleteByID(ctx, id)
|
if err != nil {
|
||||||
if err != nil {
|
receiver.logger.Errorf("failed delete discount on <DeleteDiscount> of <DiscountService>: %v", err)
|
||||||
receiver.logger.Errorf("failed delete discount on <DeleteDiscount> of <DiscountService>: %v", err)
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
}
|
|
||||||
|
return deletedDiscount, nil
|
||||||
return deletedDiscount, nil
|
}
|
||||||
}
|
|
||||||
|
func (receiver *DiscountService) CreateDiscount(ctx context.Context, discount *models.Discount) (*models.Discount, error) {
|
||||||
func (receiver *DiscountService) CreateDiscount(ctx context.Context, discount *models.Discount) (*models.Discount, error) {
|
createdDiscountID, err := receiver.discountRepository.Insert(ctx, discount)
|
||||||
createdDiscountID, err := receiver.discountRepository.Insert(ctx, discount)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, err
|
||||||
return nil, err
|
}
|
||||||
}
|
if createdDiscountID == "" {
|
||||||
if createdDiscountID == "" {
|
receiver.logger.Errorf("empty discount ID on <CreateDiscount> of <DiscountService>")
|
||||||
receiver.logger.Errorf("empty discount ID on <CreateDiscount> of <DiscountService>")
|
return nil, ErrInvalidReturnValue
|
||||||
return nil, ErrInvalidReturnValue
|
}
|
||||||
}
|
|
||||||
|
return &models.Discount{
|
||||||
return &models.Discount{
|
Target: discount.Target,
|
||||||
Target: discount.Target,
|
Condition: discount.Condition,
|
||||||
Condition: discount.Condition,
|
ID: createdDiscountID,
|
||||||
ID: createdDiscountID,
|
Name: discount.Name,
|
||||||
Name: discount.Name,
|
Description: discount.Description,
|
||||||
Description: discount.Description,
|
Layer: discount.Layer,
|
||||||
Layer: discount.Layer,
|
}, nil
|
||||||
}, nil
|
}
|
||||||
}
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidInputValue = errors.New("invalid input value in args of method")
|
ErrInvalidInputValue = errors.New("invalid input value in args of method")
|
||||||
ErrInvalidReturnValue = errors.New("invalid return value of function inside method")
|
ErrInvalidReturnValue = errors.New("invalid return value of function inside method")
|
||||||
)
|
)
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
package calculate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/convert"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
TODO:
|
|
||||||
|
|
||||||
1) Рефактор всех приватных утилит
|
|
||||||
2) Покрытие тестами всех утилит
|
|
||||||
3) Уточнить систему overhelm при высчитывании
|
|
||||||
*/
|
|
||||||
|
|
||||||
func Discount(products []core.Product, discounts []models.Discount) float64 {
|
|
||||||
if len(products) < 1 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
price := calculateProducts(products)
|
|
||||||
|
|
||||||
if len(discounts) < 1 {
|
|
||||||
return price
|
|
||||||
}
|
|
||||||
|
|
||||||
discountTargets := constituteDiscountTargets(divideDiscounts(discounts))
|
|
||||||
productsMap := convert.ArrayToMap(products, func(product core.Product) string {
|
|
||||||
return product.ID
|
|
||||||
})
|
|
||||||
|
|
||||||
if eachTarget, ok := discountTargets[models.TargetEach]; ok {
|
|
||||||
productsMap = calculateEachProduct(productsMap, eachTarget)
|
|
||||||
price = calculateProductsMap(productsMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
if groupTarget, ok := discountTargets[models.TargetGroup]; ok {
|
|
||||||
productGroups := convert.MapToMapArray(productsMap, func(product core.Product) string {
|
|
||||||
return product.Group
|
|
||||||
})
|
|
||||||
|
|
||||||
pricesGroup := calculateGroupProducts(productGroups, groupTarget)
|
|
||||||
price = calculatePricesGroup(pricesGroup)
|
|
||||||
}
|
|
||||||
|
|
||||||
if sumTarget, ok := discountTargets[models.TargetSum]; ok {
|
|
||||||
price = price * sumTarget.Factor
|
|
||||||
}
|
|
||||||
|
|
||||||
return price
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
package calculate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
|
||||||
)
|
|
||||||
|
|
||||||
func calculateProducts(products []core.Product) float64 {
|
|
||||||
productsPrice := float64(0)
|
|
||||||
|
|
||||||
for _, product := range products {
|
|
||||||
productsPrice = productsPrice + product.Price
|
|
||||||
}
|
|
||||||
|
|
||||||
return productsPrice
|
|
||||||
}
|
|
||||||
|
|
||||||
func calculateProductsMap(products map[string]core.Product) float64 {
|
|
||||||
productsPrice := float64(0)
|
|
||||||
|
|
||||||
for _, product := range products {
|
|
||||||
productsPrice = productsPrice + product.Price
|
|
||||||
}
|
|
||||||
|
|
||||||
return productsPrice
|
|
||||||
}
|
|
||||||
|
|
||||||
func calculatePricesGroup(pricesGroup map[string]float64) float64 {
|
|
||||||
finalPrice := float64(0)
|
|
||||||
|
|
||||||
for _, price := range pricesGroup {
|
|
||||||
finalPrice = finalPrice + price
|
|
||||||
}
|
|
||||||
|
|
||||||
return finalPrice
|
|
||||||
}
|
|
||||||
|
|
||||||
func calculateEachProduct(products map[string]core.Product, target models.DiscountCalculationTarget) map[string]core.Product {
|
|
||||||
if target.Products == nil && target.Factor == 0 {
|
|
||||||
return products
|
|
||||||
}
|
|
||||||
|
|
||||||
if target.Products == nil {
|
|
||||||
for key, product := range products {
|
|
||||||
products[key] = core.Product{
|
|
||||||
ID: key,
|
|
||||||
Price: product.Price * target.Factor,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return products
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, productTarget := range target.Products {
|
|
||||||
product, ok := products[productTarget.ID]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if productTarget.Factor != 0 {
|
|
||||||
products[product.ID] = core.Product{
|
|
||||||
ID: product.ID,
|
|
||||||
Price: product.Price * productTarget.Factor,
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
products[product.ID] = core.Product{
|
|
||||||
ID: product.ID,
|
|
||||||
Price: product.Price * target.Factor,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return products
|
|
||||||
}
|
|
||||||
|
|
||||||
func calculateGroupProducts(productsGroup map[string][]core.Product, target models.DiscountCalculationTarget) map[string]float64 {
|
|
||||||
pricesGroup := make(map[string]float64)
|
|
||||||
|
|
||||||
if target.TargetGroup == "" && target.Factor == 0 {
|
|
||||||
for group, products := range productsGroup {
|
|
||||||
pricesGroup[group] = calculateProducts(products)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pricesGroup
|
|
||||||
}
|
|
||||||
|
|
||||||
for group, products := range productsGroup {
|
|
||||||
pricesGroup[group] = calculateProducts(products) * target.Factor
|
|
||||||
}
|
|
||||||
|
|
||||||
return pricesGroup
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
package calculate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/convert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func constituteDiscountTargets(dividedDiscounts map[models.TargetScope][]models.Discount) map[models.TargetScope]models.DiscountCalculationTarget {
|
|
||||||
discountTargets := make(map[models.TargetScope]models.DiscountCalculationTarget, 3)
|
|
||||||
|
|
||||||
for group, discounts := range dividedDiscounts {
|
|
||||||
switch group {
|
|
||||||
case models.TargetEach:
|
|
||||||
discountTargets[group] = models.DiscountCalculationTarget{
|
|
||||||
Products: sumEachFactor(discounts),
|
|
||||||
}
|
|
||||||
case models.TargetGroup, models.TargetSum:
|
|
||||||
discountTargets[group] = models.DiscountCalculationTarget{
|
|
||||||
Factor: sumCommonFactor(discounts),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return discountTargets
|
|
||||||
}
|
|
||||||
|
|
||||||
func divideDiscounts(discounts []models.Discount) map[models.TargetScope][]models.Discount {
|
|
||||||
dividedDiscounts := make(map[models.TargetScope][]models.Discount, 3)
|
|
||||||
|
|
||||||
for _, discount := range discounts {
|
|
||||||
if len(discount.Target.Products) > 0 {
|
|
||||||
dividedDiscounts[models.TargetEach] = append(dividedDiscounts[models.TargetEach], discount)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if discount.Target.TargetScope == "" && len(discount.Target.Products) < 1 {
|
|
||||||
dividedDiscounts[models.TargetSum] = append(dividedDiscounts[models.TargetSum], discount)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if discount.Target.TargetScope == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
dividedDiscounts[discount.Target.TargetScope] = append(dividedDiscounts[discount.Target.TargetScope], discount)
|
|
||||||
}
|
|
||||||
|
|
||||||
return dividedDiscounts
|
|
||||||
}
|
|
||||||
|
|
||||||
func sumCommonFactor(discounts []models.Discount) float64 {
|
|
||||||
sum := float64(1)
|
|
||||||
|
|
||||||
for _, discount := range discounts {
|
|
||||||
if discount.Target.Overhelm {
|
|
||||||
sum = discount.Target.Factor
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
sum = sum * discount.Target.Factor
|
|
||||||
}
|
|
||||||
|
|
||||||
return sum
|
|
||||||
}
|
|
||||||
|
|
||||||
func sumEachFactor(discounts []models.Discount) []models.ProductTarget {
|
|
||||||
productTargetsMap := make(map[string]models.ProductTarget)
|
|
||||||
|
|
||||||
for _, discount := range discounts {
|
|
||||||
for _, productTarget := range discount.Target.Products {
|
|
||||||
if productTargetsMap[productTarget.ID].Overhelm {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if productTargetsMap[productTarget.ID].Factor > 0 {
|
|
||||||
productTargetsMap[productTarget.ID] = models.ProductTarget{
|
|
||||||
ID: productTarget.ID,
|
|
||||||
Factor: productTargetsMap[productTarget.ID].Factor * productTarget.Factor,
|
|
||||||
Overhelm: productTargetsMap[productTarget.ID].Overhelm,
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
productTargetsMap[productTarget.ID] = models.ProductTarget{
|
|
||||||
ID: productTarget.ID,
|
|
||||||
Factor: 1 * productTarget.Factor,
|
|
||||||
Overhelm: productTargetsMap[productTarget.ID].Overhelm,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return convert.MapToArray(productTargetsMap)
|
|
||||||
}
|
|
@ -1,58 +1,58 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ConstituteConditions(request *discount.ApplyDiscountRequest) (*core.DiscountConditions, error) {
|
func ConstituteConditions(request *discount.ApplyDiscountRequest) (*core.DiscountConditions, error) {
|
||||||
if request == nil {
|
if request == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(request.GetProducts()) < 1 {
|
if len(request.GetProducts()) < 1 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
optionalConditions := make([]core.OptionalDiscounCondition, len(request.GetProducts())*2)
|
optionalConditions := make([]core.OptionalDiscounCondition, len(request.GetProducts())*2)
|
||||||
optionalConditionsIndex := 0
|
optionalConditionsIndex := 0
|
||||||
|
|
||||||
for _, product := range request.Products {
|
for _, product := range request.Products {
|
||||||
if product == nil {
|
if product == nil {
|
||||||
return nil, errors.New("some of products are nil")
|
return nil, errors.New("some of products are nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
optionalConditions[optionalConditionsIndex] = core.OptionalDiscounCondition{
|
optionalConditions[optionalConditionsIndex] = core.OptionalDiscounCondition{
|
||||||
Product: &product.ID,
|
Product: &product.ID,
|
||||||
PriceFrom: &product.Price,
|
PriceFrom: &product.Price,
|
||||||
Group: product.Group,
|
Group: product.Group,
|
||||||
Term: product.Term,
|
Term: product.Term,
|
||||||
Usage: product.Usage,
|
Usage: product.Usage,
|
||||||
}
|
}
|
||||||
optionalConditions[optionalConditionsIndex+1] = core.OptionalDiscounCondition{
|
optionalConditions[optionalConditionsIndex+1] = core.OptionalDiscounCondition{
|
||||||
Product: &product.ID,
|
Product: &product.ID,
|
||||||
Group: product.Group,
|
Group: product.Group,
|
||||||
Term: product.Term,
|
Term: product.Term,
|
||||||
Usage: product.Usage,
|
Usage: product.Usage,
|
||||||
}
|
}
|
||||||
optionalConditionsIndex = optionalConditionsIndex + 2
|
optionalConditionsIndex += 2
|
||||||
}
|
}
|
||||||
|
|
||||||
return &core.DiscountConditions{
|
return &core.DiscountConditions{
|
||||||
Common: core.CommonDiscountCondition{
|
Common: core.CommonDiscountCondition{
|
||||||
User: request.UserInformation.ID,
|
User: request.UserInformation.ID,
|
||||||
UserType: request.UserInformation.Type,
|
UserType: request.UserInformation.Type,
|
||||||
PurchasesAmount: request.UserInformation.PurchasesAmount,
|
PurchasesAmount: request.UserInformation.PurchasesAmount,
|
||||||
CartPurchasesAmount: request.UserInformation.CartPurchasesAmount,
|
CartPurchasesAmount: request.UserInformation.CartPurchasesAmount,
|
||||||
Coupon: request.Coupon,
|
Coupon: request.Coupon,
|
||||||
Period: models.PeriodCondition{
|
Period: models.PeriodCondition{
|
||||||
From: request.Date.AsTime(),
|
From: request.Date.AsTime(),
|
||||||
To: request.Date.AsTime(),
|
To: request.Date.AsTime(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Optionals: optionalConditions,
|
Optionals: optionalConditions,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -1,151 +1,150 @@
|
|||||||
package utils_test
|
package utils_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils"
|
)
|
||||||
)
|
|
||||||
|
func TestConstituteConditions(t *testing.T) {
|
||||||
func TestConstituteConditions(t *testing.T) {
|
userID := "1"
|
||||||
userID := "1"
|
userType := "nkvo"
|
||||||
userType := "nkvo"
|
purchasesAmount := uint64(100000)
|
||||||
purchasesAmount := float64(100000)
|
cartPurchasesAmount := uint64(5000)
|
||||||
cartPurchasesAmount := float64(5000)
|
productsGroup := "group"
|
||||||
productsGroup := "group"
|
productID1 := "1"
|
||||||
productID1 := "1"
|
productID2 := "2"
|
||||||
productID2 := "2"
|
productID3 := "3"
|
||||||
productID3 := "3"
|
productID4 := "4"
|
||||||
productID4 := "4"
|
productPrice1 := uint64(1000)
|
||||||
productPrice1 := float64(1000)
|
productPrice2 := uint64(6000)
|
||||||
productPrice2 := float64(6000)
|
productPrice3 := uint64(10000)
|
||||||
productPrice3 := float64(10000)
|
productPrice4 := uint64(4000)
|
||||||
productPrice4 := float64(4000)
|
productTerm1 := uint64(14)
|
||||||
productTerm1 := uint64(14)
|
productTerm2 := uint64(16)
|
||||||
productTerm2 := uint64(16)
|
productUsage1 := uint64(24)
|
||||||
productUsage1 := uint64(24)
|
productUsage2 := uint64(14)
|
||||||
productUsage2 := uint64(14)
|
coupon := "coupon"
|
||||||
coupon := "coupon"
|
period := models.PeriodCondition{
|
||||||
period := models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
}
|
||||||
}
|
|
||||||
|
t.Run("Формирование условий поиска с пустыми значениями", func(t *testing.T) {
|
||||||
t.Run("Формирование условий поиска с пустыми значениями", func(t *testing.T) {
|
conditions, _ := utils.ConstituteConditions(&discount.ApplyDiscountRequest{})
|
||||||
conditions, _ := utils.ConstituteConditions(&discount.ApplyDiscountRequest{})
|
|
||||||
|
assert.Nil(t, conditions)
|
||||||
assert.Nil(t, conditions)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование условий поиска с nil", func(t *testing.T) {
|
||||||
t.Run("Формирование условий поиска с nil", func(t *testing.T) {
|
conditions, _ := utils.ConstituteConditions(nil)
|
||||||
conditions, _ := utils.ConstituteConditions(nil)
|
|
||||||
|
assert.Nil(t, conditions)
|
||||||
assert.Nil(t, conditions)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование условий поиска с заполненной информацией", func(t *testing.T) {
|
||||||
t.Run("Формирование условий поиска с заполненной информацией", func(t *testing.T) {
|
conditions, err := utils.ConstituteConditions(&discount.ApplyDiscountRequest{
|
||||||
conditions, err := utils.ConstituteConditions(&discount.ApplyDiscountRequest{
|
UserInformation: &discount.UserInformation{
|
||||||
UserInformation: &discount.UserInformation{
|
ID: userID,
|
||||||
ID: userID,
|
Type: userType,
|
||||||
Type: userType,
|
PurchasesAmount: purchasesAmount,
|
||||||
PurchasesAmount: purchasesAmount,
|
CartPurchasesAmount: cartPurchasesAmount,
|
||||||
CartPurchasesAmount: cartPurchasesAmount,
|
},
|
||||||
},
|
Products: []*discount.ProductInformation{
|
||||||
Products: []*discount.ProductInformation{
|
{ID: productID1, Price: productPrice1, Term: &productTerm1, Group: &productsGroup},
|
||||||
{ID: productID1, Price: productPrice1, Term: &productTerm1, Group: &productsGroup},
|
{ID: productID2, Price: productPrice2, Term: &productTerm2, Group: &productsGroup},
|
||||||
{ID: productID2, Price: productPrice2, Term: &productTerm2, Group: &productsGroup},
|
{ID: productID3, Price: productPrice3, Usage: &productUsage1},
|
||||||
{ID: productID3, Price: productPrice3, Usage: &productUsage1},
|
{ID: productID4, Price: productPrice4, Term: &productTerm2, Usage: &productUsage2},
|
||||||
{ID: productID4, Price: productPrice4, Term: &productTerm2, Usage: &productUsage2},
|
},
|
||||||
},
|
Coupon: &coupon,
|
||||||
Coupon: &coupon,
|
Date: ×tamppb.Timestamp{
|
||||||
Date: ×tamppb.Timestamp{
|
Seconds: 1674546287,
|
||||||
Seconds: 1674546287,
|
Nanos: 0,
|
||||||
Nanos: 0,
|
},
|
||||||
},
|
})
|
||||||
})
|
|
||||||
|
assert.Nil(t, err)
|
||||||
assert.Nil(t, err)
|
assert.Equal(t, &core.DiscountConditions{
|
||||||
assert.Equal(t, &core.DiscountConditions{
|
Common: core.CommonDiscountCondition{
|
||||||
Common: core.CommonDiscountCondition{
|
User: userID,
|
||||||
User: userID,
|
UserType: userType,
|
||||||
UserType: userType,
|
PurchasesAmount: purchasesAmount,
|
||||||
PurchasesAmount: purchasesAmount,
|
CartPurchasesAmount: cartPurchasesAmount,
|
||||||
CartPurchasesAmount: cartPurchasesAmount,
|
Coupon: &coupon,
|
||||||
Coupon: &coupon,
|
Period: period,
|
||||||
Period: period,
|
},
|
||||||
},
|
Optionals: []core.OptionalDiscounCondition{
|
||||||
Optionals: []core.OptionalDiscounCondition{
|
{
|
||||||
{
|
Product: &productID1,
|
||||||
Product: &productID1,
|
PriceFrom: &productPrice1,
|
||||||
PriceFrom: &productPrice1,
|
Group: &productsGroup,
|
||||||
Group: &productsGroup,
|
Term: &productTerm1,
|
||||||
Term: &productTerm1,
|
},
|
||||||
},
|
{
|
||||||
{
|
Product: &productID1,
|
||||||
Product: &productID1,
|
Group: &productsGroup,
|
||||||
Group: &productsGroup,
|
Term: &productTerm1,
|
||||||
Term: &productTerm1,
|
},
|
||||||
},
|
{
|
||||||
{
|
Product: &productID2,
|
||||||
Product: &productID2,
|
PriceFrom: &productPrice2,
|
||||||
PriceFrom: &productPrice2,
|
Group: &productsGroup,
|
||||||
Group: &productsGroup,
|
Term: &productTerm2,
|
||||||
Term: &productTerm2,
|
},
|
||||||
},
|
{
|
||||||
{
|
Product: &productID2,
|
||||||
Product: &productID2,
|
Group: &productsGroup,
|
||||||
Group: &productsGroup,
|
Term: &productTerm2,
|
||||||
Term: &productTerm2,
|
},
|
||||||
},
|
{
|
||||||
{
|
Product: &productID3,
|
||||||
Product: &productID3,
|
PriceFrom: &productPrice3,
|
||||||
PriceFrom: &productPrice3,
|
Usage: &productUsage1,
|
||||||
Usage: &productUsage1,
|
},
|
||||||
},
|
{
|
||||||
{
|
Product: &productID3,
|
||||||
Product: &productID3,
|
Usage: &productUsage1,
|
||||||
Usage: &productUsage1,
|
},
|
||||||
},
|
{
|
||||||
{
|
Product: &productID4,
|
||||||
Product: &productID4,
|
PriceFrom: &productPrice4,
|
||||||
PriceFrom: &productPrice4,
|
Term: &productTerm2,
|
||||||
Term: &productTerm2,
|
Usage: &productUsage2,
|
||||||
Usage: &productUsage2,
|
},
|
||||||
},
|
{
|
||||||
{
|
Product: &productID4,
|
||||||
Product: &productID4,
|
Term: &productTerm2,
|
||||||
Term: &productTerm2,
|
Usage: &productUsage2,
|
||||||
Usage: &productUsage2,
|
},
|
||||||
},
|
},
|
||||||
},
|
}, conditions)
|
||||||
}, conditions)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование условий поиска с наличием nil'ого продукта", func(t *testing.T) {
|
||||||
t.Run("Формирование условий поиска с наличием nil'ого продукта", func(t *testing.T) {
|
conditions, err := utils.ConstituteConditions(&discount.ApplyDiscountRequest{
|
||||||
conditions, err := utils.ConstituteConditions(&discount.ApplyDiscountRequest{
|
UserInformation: &discount.UserInformation{
|
||||||
UserInformation: &discount.UserInformation{
|
ID: userID,
|
||||||
ID: userID,
|
Type: userType,
|
||||||
Type: userType,
|
PurchasesAmount: purchasesAmount,
|
||||||
PurchasesAmount: purchasesAmount,
|
CartPurchasesAmount: cartPurchasesAmount,
|
||||||
CartPurchasesAmount: cartPurchasesAmount,
|
},
|
||||||
},
|
Products: []*discount.ProductInformation{
|
||||||
Products: []*discount.ProductInformation{
|
{ID: productID1, Price: productPrice1, Term: &productTerm1, Group: &productsGroup},
|
||||||
{ID: productID1, Price: productPrice1, Term: &productTerm1, Group: &productsGroup},
|
nil,
|
||||||
nil,
|
},
|
||||||
},
|
Date: ×tamppb.Timestamp{
|
||||||
Date: ×tamppb.Timestamp{
|
Seconds: 1674546287,
|
||||||
Seconds: 1674546287,
|
Nanos: 0,
|
||||||
Nanos: 0,
|
},
|
||||||
},
|
})
|
||||||
})
|
|
||||||
|
assert.Nil(t, conditions)
|
||||||
assert.Nil(t, conditions)
|
assert.Error(t, err)
|
||||||
assert.Error(t, err)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
144
internal/utils/discount/calculate.go
Normal file
144
internal/utils/discount/calculate.go
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
package discount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/convert"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO:
|
||||||
|
|
||||||
|
1) Рефактор всех приватных утилит
|
||||||
|
2) Покрытие тестами всех утилит
|
||||||
|
*/
|
||||||
|
|
||||||
|
func Calculate(products []core.Product, discounts []models.Discount) uint64 {
|
||||||
|
if len(products) < 1 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
price := calculateProducts(products)
|
||||||
|
|
||||||
|
if len(discounts) < 1 {
|
||||||
|
return convert.FloatToUint64(price)
|
||||||
|
}
|
||||||
|
|
||||||
|
discountTargetsMap := SortOverhelmingDiscounts(discounts)
|
||||||
|
productsMap := convert.ArrayToMap(products, func(product core.Product) string {
|
||||||
|
return product.ID
|
||||||
|
})
|
||||||
|
|
||||||
|
if targetsEach, ok := discountTargetsMap[models.TargetEach]; ok {
|
||||||
|
for _, target := range targetsEach {
|
||||||
|
productsMap = calculateEachProductWithTarget(productsMap, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
price = calculateProductsMap(productsMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
if targetsGroup, ok := discountTargetsMap[models.TargetGroup]; ok {
|
||||||
|
productGroups := convert.MapToMapArray(productsMap, func(product core.Product) string {
|
||||||
|
return product.Group
|
||||||
|
})
|
||||||
|
|
||||||
|
pricesGroup := calculateProductsGroup(productGroups)
|
||||||
|
|
||||||
|
for _, target := range targetsGroup {
|
||||||
|
pricesGroup[target.TargetGroup] *= target.Factor
|
||||||
|
}
|
||||||
|
|
||||||
|
price = calculatePricesGroupSum(pricesGroup)
|
||||||
|
}
|
||||||
|
|
||||||
|
if targetsSum, ok := discountTargetsMap[models.TargetSum]; ok {
|
||||||
|
for _, target := range targetsSum {
|
||||||
|
price *= target.Factor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return convert.FloatToUint64(price)
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateProducts(products []core.Product) float64 {
|
||||||
|
productsPrice := float64(0)
|
||||||
|
|
||||||
|
for _, product := range products {
|
||||||
|
productsPrice += product.Price
|
||||||
|
}
|
||||||
|
|
||||||
|
return productsPrice
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateProductsMap(products map[string]core.Product) float64 {
|
||||||
|
productsPrice := float64(0)
|
||||||
|
|
||||||
|
for _, product := range products {
|
||||||
|
productsPrice += product.Price
|
||||||
|
}
|
||||||
|
|
||||||
|
return productsPrice
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculatePricesGroupSum(pricesGroup map[string]float64) float64 {
|
||||||
|
finalPrice := float64(0)
|
||||||
|
|
||||||
|
for _, price := range pricesGroup {
|
||||||
|
finalPrice += price
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalPrice
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateEachProductWithTarget(products map[string]core.Product, target models.DiscountCalculationTarget) map[string]core.Product {
|
||||||
|
if target.Products == nil && target.Factor == 0 {
|
||||||
|
return products
|
||||||
|
}
|
||||||
|
|
||||||
|
if target.Products == nil {
|
||||||
|
for key, product := range products {
|
||||||
|
products[key] = core.Product{
|
||||||
|
ID: key,
|
||||||
|
Price: product.Price * target.Factor,
|
||||||
|
Group: product.Group,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return products
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, productTarget := range target.Products {
|
||||||
|
product, ok := products[productTarget.ID]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if productTarget.Factor != 0 {
|
||||||
|
products[product.ID] = core.Product{
|
||||||
|
ID: product.ID,
|
||||||
|
Price: product.Price * productTarget.Factor,
|
||||||
|
Group: product.Group,
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
products[product.ID] = core.Product{
|
||||||
|
ID: product.ID,
|
||||||
|
Price: product.Price * target.Factor,
|
||||||
|
Group: product.Group,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return products
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateProductsGroup(productsGroup map[string][]core.Product) map[string]float64 {
|
||||||
|
pricesGroup := make(map[string]float64)
|
||||||
|
|
||||||
|
for group, products := range productsGroup {
|
||||||
|
pricesGroup[group] = calculateProducts(products)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pricesGroup
|
||||||
|
}
|
@ -1,344 +1,346 @@
|
|||||||
package calculate_test
|
package discount_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/calculate"
|
)
|
||||||
)
|
|
||||||
|
func TestCalculate(t *testing.T) {
|
||||||
func TestCalculate(t *testing.T) {
|
t.Run("Покупка продуктов в количестве не больше 1 при отсутствии скидок", func(t *testing.T) {
|
||||||
t.Run("Покупка продуктов в количестве не больше 1 при отсутствии скидок", func(t *testing.T) {
|
assert.Equal(t, uint64(3), discount.Calculate(
|
||||||
assert.Equal(t, 3.0, calculate.Discount(
|
[]core.Product{
|
||||||
[]core.Product{
|
{ID: "p1", Price: 1},
|
||||||
{ID: "p1", Price: 1.0},
|
{ID: "p2", Price: 2},
|
||||||
{ID: "p2", Price: 2.0},
|
},
|
||||||
},
|
[]models.Discount{},
|
||||||
[]models.Discount{},
|
))
|
||||||
))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Сумма корзины достигла 5к", func(t *testing.T) {
|
||||||
t.Run("Сумма корзины достигла 5к", func(t *testing.T) {
|
assert.Equal(t, uint64(4925), discount.Calculate(
|
||||||
assert.Equal(t, 4925.0, calculate.Discount(
|
[]core.Product{
|
||||||
[]core.Product{
|
{ID: "p1", Price: 2000},
|
||||||
{ID: "p1", Price: 2000.0},
|
{ID: "p2", Price: 3000},
|
||||||
{ID: "p2", Price: 3000.0},
|
},
|
||||||
},
|
[]models.Discount{
|
||||||
[]models.Discount{
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
TargetScope: models.TargetSum,
|
||||||
TargetScope: models.TargetSum,
|
Factor: 0.985,
|
||||||
Factor: 0.985,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
))
|
||||||
))
|
assert.Equal(t, uint64(4925), discount.Calculate(
|
||||||
assert.Equal(t, 4925.0, calculate.Discount(
|
[]core.Product{
|
||||||
[]core.Product{
|
{ID: "p1", Price: 2000},
|
||||||
{ID: "p1", Price: 2000.0},
|
{ID: "p2", Price: 3000},
|
||||||
{ID: "p2", Price: 3000.0},
|
},
|
||||||
},
|
[]models.Discount{
|
||||||
[]models.Discount{
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
Factor: 0.985,
|
||||||
Factor: 0.985,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
))
|
||||||
))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Наложение несколько скидок разного формата", func(t *testing.T) {
|
||||||
t.Run("Наложение несколько скидок разного формата", func(t *testing.T) {
|
assert.Equal(t, uint64(5025), discount.Calculate(
|
||||||
assert.InEpsilon(t, 5025.32, calculate.Discount(
|
[]core.Product{
|
||||||
[]core.Product{
|
{ID: "p1", Price: 2000},
|
||||||
{ID: "p1", Price: 2000.0},
|
{ID: "p2", Price: 3000},
|
||||||
{ID: "p2", Price: 3000.0},
|
{ID: "p3", Price: 105},
|
||||||
{ID: "p3", Price: 105.0},
|
},
|
||||||
},
|
[]models.Discount{
|
||||||
[]models.Discount{
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
Products: []models.ProductTarget{{ID: "p3", Factor: 0.97}},
|
||||||
Products: []models.ProductTarget{{ID: "p3", Factor: 0.97}},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
TargetScope: models.TargetSum,
|
||||||
TargetScope: models.TargetSum,
|
Factor: 0.985,
|
||||||
Factor: 0.985,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
))
|
||||||
), 0.001)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Наложение несколько скидок разного формата с несколькими таргетами", func(t *testing.T) {
|
||||||
t.Run("Наложение несколько скидок разного формата с несколькими таргетами", func(t *testing.T) {
|
assert.Equal(t, uint64(5223), discount.Calculate(
|
||||||
assert.InEpsilon(t, 5223.89, calculate.Discount(
|
[]core.Product{
|
||||||
[]core.Product{
|
{ID: "p1", Price: 2000},
|
||||||
{ID: "p1", Price: 2000.0},
|
{ID: "p2", Price: 3000},
|
||||||
{ID: "p2", Price: 3000.0},
|
{ID: "p3", Price: 105},
|
||||||
{ID: "p3", Price: 105.0},
|
{ID: "p4", Price: 210},
|
||||||
{ID: "p4", Price: 210.0},
|
},
|
||||||
},
|
[]models.Discount{
|
||||||
[]models.Discount{
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
Products: []models.ProductTarget{
|
||||||
Products: []models.ProductTarget{
|
{ID: "p3", Factor: 0.97},
|
||||||
{ID: "p3", Factor: 0.97},
|
{ID: "p4", Factor: 0.96},
|
||||||
{ID: "p4", Factor: 0.96},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
TargetScope: models.TargetSum,
|
||||||
TargetScope: models.TargetSum,
|
Factor: 0.985,
|
||||||
Factor: 0.985,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
))
|
||||||
), 0.001)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Наложение несколько скидок с наличием скидки на лояльность", func(t *testing.T) {
|
||||||
t.Run("Наложение несколько скидок с наличием скидки на лояльность", func(t *testing.T) {
|
assert.Equal(t, uint64(5171), discount.Calculate(
|
||||||
assert.InEpsilon(t, 5171.66, calculate.Discount(
|
[]core.Product{
|
||||||
[]core.Product{
|
{ID: "p1", Price: 2000},
|
||||||
{ID: "p1", Price: 2000.0},
|
{ID: "p2", Price: 3000},
|
||||||
{ID: "p2", Price: 3000.0},
|
{ID: "p3", Price: 105},
|
||||||
{ID: "p3", Price: 105.0},
|
{ID: "p4", Price: 210},
|
||||||
{ID: "p4", Price: 210.0},
|
},
|
||||||
},
|
[]models.Discount{
|
||||||
[]models.Discount{
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
Products: []models.ProductTarget{
|
||||||
Products: []models.ProductTarget{
|
{ID: "p3", Factor: 0.97},
|
||||||
{ID: "p3", Factor: 0.97},
|
{ID: "p4", Factor: 0.96},
|
||||||
{ID: "p4", Factor: 0.96},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
TargetScope: models.TargetSum,
|
||||||
TargetScope: models.TargetSum,
|
Factor: 0.985,
|
||||||
Factor: 0.985,
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
TargetScope: models.TargetSum,
|
||||||
TargetScope: models.TargetSum,
|
Factor: 0.99,
|
||||||
Factor: 0.99,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
), 0.001)
|
||||||
), 0.001)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Наложение несколько скидок на привелегии", func(t *testing.T) {
|
||||||
t.Run("Наложение несколько скидок на привелегии", func(t *testing.T) {
|
assert.Equal(t, uint64(422), discount.Calculate(
|
||||||
assert.InEpsilon(t, 422.28, calculate.Discount(
|
[]core.Product{
|
||||||
[]core.Product{
|
{ID: "p5", Price: 30},
|
||||||
{ID: "p5", Price: 30},
|
{ID: "p6", Price: 70},
|
||||||
{ID: "p6", Price: 70},
|
{ID: "p7", Price: 400},
|
||||||
{ID: "p7", Price: 400},
|
},
|
||||||
},
|
[]models.Discount{
|
||||||
[]models.Discount{
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
Products: []models.ProductTarget{
|
||||||
Products: []models.ProductTarget{
|
{ID: "p5", Factor: 0.97},
|
||||||
{ID: "p5", Factor: 0.97},
|
{ID: "p6", Factor: 0.935},
|
||||||
{ID: "p6", Factor: 0.935},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
Products: []models.ProductTarget{
|
||||||
Products: []models.ProductTarget{
|
{ID: "p7", Factor: 0.83},
|
||||||
{ID: "p7", Factor: 0.83},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
TargetScope: models.TargetSum,
|
||||||
TargetScope: models.TargetSum,
|
Factor: 0.99,
|
||||||
Factor: 0.99,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
))
|
||||||
), 0.001)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Наложение несколько скидок на привелегии без лояльности", func(t *testing.T) {
|
||||||
t.Run("Наложение несколько скидок на привелегии без лояльности", func(t *testing.T) {
|
assert.Equal(t, uint64(426), discount.Calculate(
|
||||||
assert.InEpsilon(t, 426.55, calculate.Discount(
|
[]core.Product{
|
||||||
[]core.Product{
|
{ID: "p5", Price: 30},
|
||||||
{ID: "p5", Price: 30},
|
{ID: "p6", Price: 70},
|
||||||
{ID: "p6", Price: 70},
|
{ID: "p7", Price: 400},
|
||||||
{ID: "p7", Price: 400},
|
},
|
||||||
},
|
[]models.Discount{
|
||||||
[]models.Discount{
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
Products: []models.ProductTarget{
|
||||||
Products: []models.ProductTarget{
|
{ID: "p5", Factor: 0.97},
|
||||||
{ID: "p5", Factor: 0.97},
|
{ID: "p6", Factor: 0.935},
|
||||||
{ID: "p6", Factor: 0.935},
|
{ID: "p7", Factor: 0.83},
|
||||||
{ID: "p7", Factor: 0.83},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
))
|
||||||
), 0.001)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Вычисление скидки за привелегии и сервис", func(t *testing.T) {
|
||||||
t.Run("Вычисление скидки за привелегии и сервис", func(t *testing.T) {
|
assert.Equal(t, uint64(743), discount.Calculate(
|
||||||
assert.InEpsilon(t, 743.45, calculate.Discount(
|
[]core.Product{
|
||||||
[]core.Product{
|
{ID: "p5", Price: 30, Group: "dwarfener"},
|
||||||
{ID: "p5", Price: 30, Group: "dwarfener"},
|
{ID: "p6", Price: 70, Group: "dwarfener"},
|
||||||
{ID: "p6", Price: 70, Group: "dwarfener"},
|
{ID: "p7", Price: 800, Group: "dwarfener"},
|
||||||
{ID: "p7", Price: 800, Group: "dwarfener"},
|
},
|
||||||
},
|
[]models.Discount{
|
||||||
[]models.Discount{
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
Products: []models.ProductTarget{
|
||||||
Products: []models.ProductTarget{
|
{ID: "p5", Factor: 0.97},
|
||||||
{ID: "p5", Factor: 0.97},
|
{ID: "p6", Factor: 0.935},
|
||||||
{ID: "p6", Factor: 0.935},
|
{ID: "p7", Factor: 0.83},
|
||||||
{ID: "p7", Factor: 0.83},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
Factor: 0.99,
|
||||||
Factor: 0.99,
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
TargetScope: models.TargetGroup,
|
||||||
TargetScope: models.TargetGroup,
|
TargetGroup: "dwarfener",
|
||||||
TargetGroup: "dwarfener",
|
Factor: 0.99,
|
||||||
Factor: 0.99,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
))
|
||||||
), 0.001)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Наложение скидок на несколько сервисов", func(t *testing.T) {
|
||||||
t.Run("Наложение скидок на несколько сервисов", func(t *testing.T) {
|
assert.Equal(t, uint64(2398), discount.Calculate(
|
||||||
assert.InEpsilon(t, 2398.5, calculate.Discount(
|
[]core.Product{
|
||||||
[]core.Product{
|
{ID: "p1", Price: 1500, Group: "templategen"},
|
||||||
{ID: "p1", Price: 1500, Group: "templategen"},
|
{ID: "p2", Price: 300, Group: "templategen"},
|
||||||
{ID: "p2", Price: 300, Group: "templategen"},
|
{ID: "p5", Price: 30, Group: "dwarfener"},
|
||||||
{ID: "p5", Price: 30, Group: "dwarfener"},
|
{ID: "p6", Price: 70, Group: "dwarfener"},
|
||||||
{ID: "p6", Price: 70, Group: "dwarfener"},
|
{ID: "p7", Price: 800, Group: "dwarfener"},
|
||||||
{ID: "p7", Price: 800, Group: "dwarfener"},
|
},
|
||||||
},
|
[]models.Discount{
|
||||||
[]models.Discount{
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
Products: []models.ProductTarget{
|
||||||
Products: []models.ProductTarget{
|
{ID: "p1", Factor: 0.93},
|
||||||
{ID: "p1", Factor: 0.93},
|
{ID: "p2", Factor: 0.945},
|
||||||
{ID: "p2", Factor: 0.945},
|
{ID: "p5", Factor: 0.97},
|
||||||
{ID: "p5", Factor: 0.97},
|
{ID: "p6", Factor: 0.935},
|
||||||
{ID: "p6", Factor: 0.935},
|
{ID: "p7", Factor: 0.83},
|
||||||
{ID: "p7", Factor: 0.83},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
Factor: 0.99,
|
||||||
Factor: 0.99,
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
TargetScope: models.TargetGroup,
|
||||||
TargetScope: models.TargetGroup,
|
TargetGroup: "templategen",
|
||||||
TargetGroup: "templategen",
|
Factor: 0.996,
|
||||||
Factor: 0.996,
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
TargetScope: models.TargetGroup,
|
||||||
TargetScope: models.TargetGroup,
|
TargetGroup: "dwarfener",
|
||||||
TargetGroup: "dwarfener",
|
Factor: 0.99,
|
||||||
Factor: 0.99,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
))
|
||||||
), 0.01)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Наложение скидок с промокодом", func(t *testing.T) {
|
||||||
t.Run("Наложение скидок с промокодом", func(t *testing.T) {
|
assert.Equal(t, uint64(2368), discount.Calculate(
|
||||||
assert.InEpsilon(t, 2368.68, calculate.Discount(
|
[]core.Product{
|
||||||
[]core.Product{
|
{ID: "p1", Price: 1500, Group: "templategen"},
|
||||||
{ID: "p1", Price: 1500, Group: "templategen"},
|
{ID: "p2", Price: 300, Group: "templategen"},
|
||||||
{ID: "p2", Price: 300, Group: "templategen"},
|
{ID: "p5", Price: 30, Group: "dwarfener"},
|
||||||
{ID: "p5", Price: 30, Group: "dwarfener"},
|
{ID: "p6", Price: 70, Group: "dwarfener"},
|
||||||
{ID: "p6", Price: 70, Group: "dwarfener"},
|
{ID: "p7", Price: 800, Group: "dwarfener"},
|
||||||
{ID: "p7", Price: 800, Group: "dwarfener"},
|
},
|
||||||
},
|
[]models.Discount{
|
||||||
[]models.Discount{
|
{
|
||||||
{
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
Products: []models.ProductTarget{
|
||||||
Products: []models.ProductTarget{
|
{ID: "p1", Factor: 0.93},
|
||||||
{ID: "p1", Factor: 0.93},
|
{ID: "p2", Factor: 0.945},
|
||||||
{ID: "p2", Factor: 0.945},
|
{ID: "p5", Factor: 0.97},
|
||||||
{ID: "p5", Factor: 0.97},
|
{ID: "p6", Factor: 0.97},
|
||||||
{ID: "p6", Factor: 0.97},
|
{ID: "p7", Factor: 0.83},
|
||||||
{ID: "p7", Factor: 0.83},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
Layer: 2,
|
||||||
Target: models.DiscountCalculationTarget{
|
Target: models.DiscountCalculationTarget{
|
||||||
Products: []models.ProductTarget{
|
Products: []models.ProductTarget{
|
||||||
{ID: "p6", Factor: 0.5, Overhelm: true},
|
{ID: "p6", Factor: 0.5, Overhelm: true},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Target: models.DiscountCalculationTarget{
|
Target: models.DiscountCalculationTarget{
|
||||||
Factor: 0.94,
|
Factor: 0.94,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Target: models.DiscountCalculationTarget{
|
ID: "2",
|
||||||
Factor: 0.99,
|
Layer: 2,
|
||||||
Overhelm: true,
|
Target: models.DiscountCalculationTarget{
|
||||||
},
|
Factor: 0.99,
|
||||||
},
|
Overhelm: true,
|
||||||
{
|
},
|
||||||
Target: models.DiscountCalculationTarget{
|
},
|
||||||
TargetScope: models.TargetGroup,
|
{
|
||||||
TargetGroup: "templategen",
|
Target: models.DiscountCalculationTarget{
|
||||||
Factor: 0.996,
|
TargetScope: models.TargetGroup,
|
||||||
},
|
TargetGroup: "templategen",
|
||||||
},
|
Factor: 0.996,
|
||||||
{
|
},
|
||||||
Target: models.DiscountCalculationTarget{
|
},
|
||||||
TargetScope: models.TargetGroup,
|
{
|
||||||
TargetGroup: "dwarfener",
|
Target: models.DiscountCalculationTarget{
|
||||||
Factor: 0.99,
|
TargetScope: models.TargetGroup,
|
||||||
},
|
TargetGroup: "dwarfener",
|
||||||
},
|
Factor: 0.99,
|
||||||
},
|
},
|
||||||
), 0.01)
|
},
|
||||||
})
|
},
|
||||||
|
))
|
||||||
t.Run("Наложение скидок по типу пользователя", func(t *testing.T) {
|
})
|
||||||
assert.InEpsilon(t, 540, calculate.Discount(
|
|
||||||
[]core.Product{
|
t.Run("Наложение скидок по типу пользователя", func(t *testing.T) {
|
||||||
{ID: "p1", Price: 1500, Group: "templategen"},
|
assert.Equal(t, uint64(540), discount.Calculate(
|
||||||
{ID: "p2", Price: 300, Group: "templategen"},
|
[]core.Product{
|
||||||
{ID: "p5", Price: 30, Group: "dwarfener"},
|
{ID: "p1", Price: 1500, Group: "templategen"},
|
||||||
{ID: "p6", Price: 70, Group: "dwarfener"},
|
{ID: "p2", Price: 300, Group: "templategen"},
|
||||||
{ID: "p7", Price: 800, Group: "dwarfener"},
|
{ID: "p5", Price: 30, Group: "dwarfener"},
|
||||||
},
|
{ID: "p6", Price: 70, Group: "dwarfener"},
|
||||||
[]models.Discount{
|
{ID: "p7", Price: 800, Group: "dwarfener"},
|
||||||
{
|
},
|
||||||
Target: models.DiscountCalculationTarget{
|
[]models.Discount{
|
||||||
TargetScope: models.TargetSum,
|
{
|
||||||
Factor: 0.2,
|
Target: models.DiscountCalculationTarget{
|
||||||
},
|
TargetScope: models.TargetSum,
|
||||||
},
|
Factor: 0.2,
|
||||||
},
|
},
|
||||||
), 0.01)
|
},
|
||||||
})
|
},
|
||||||
}
|
))
|
||||||
|
})
|
||||||
|
}
|
147
internal/utils/discount/sort.go
Normal file
147
internal/utils/discount/sort.go
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
package discount
|
||||||
|
|
||||||
|
import (
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SortOverhelmingDiscounts(discounts []models.Discount) map[models.TargetScope][]models.DiscountCalculationTarget {
|
||||||
|
dividedDiscounts := divideDiscountsByScope(discounts)
|
||||||
|
|
||||||
|
return map[models.TargetScope][]models.DiscountCalculationTarget{
|
||||||
|
models.TargetEach: sortOverhelmingDiscountsEach(dividedDiscounts[models.TargetEach]),
|
||||||
|
models.TargetGroup: sortOverhelmingDiscounts(dividedDiscounts[models.TargetGroup]),
|
||||||
|
models.TargetSum: sortOverhelmingDiscounts(dividedDiscounts[models.TargetSum]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func constituteOverhelmingProductTargetLayersMap(discounts []models.Discount) map[string]uint32 {
|
||||||
|
overhelmingProductTargetLayers := make(map[string]uint32)
|
||||||
|
|
||||||
|
for _, discount := range discounts {
|
||||||
|
for _, productTarget := range discount.Target.Products {
|
||||||
|
if existingLayer, ok := overhelmingProductTargetLayers[productTarget.ID]; ok {
|
||||||
|
if productTarget.Overhelm && existingLayer < discount.Layer {
|
||||||
|
overhelmingProductTargetLayers[productTarget.ID] = discount.Layer
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if productTarget.Overhelm {
|
||||||
|
overhelmingProductTargetLayers[productTarget.ID] = discount.Layer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return overhelmingProductTargetLayers
|
||||||
|
}
|
||||||
|
|
||||||
|
func constituteOverhelmingDiscountLayer(discounts []models.Discount) uint32 {
|
||||||
|
overhelmingDiscountLayer := uint32(0)
|
||||||
|
|
||||||
|
for _, discount := range discounts {
|
||||||
|
if discount.Target.Overhelm && overhelmingDiscountLayer < discount.Layer {
|
||||||
|
overhelmingDiscountLayer = discount.Layer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return overhelmingDiscountLayer
|
||||||
|
}
|
||||||
|
|
||||||
|
func sortOverhelmingDiscountsEach(discounts []models.Discount) []models.DiscountCalculationTarget {
|
||||||
|
if len(discounts) < 1 {
|
||||||
|
return []models.DiscountCalculationTarget{}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortedDiscountCalculationTargetsEach := make([]models.DiscountCalculationTarget, 0, len(discounts))
|
||||||
|
|
||||||
|
overhelmingProductTargetLayers := constituteOverhelmingProductTargetLayersMap(discounts)
|
||||||
|
overhelmingDiscountLayer := constituteOverhelmingDiscountLayer(discounts)
|
||||||
|
|
||||||
|
for _, discount := range discounts {
|
||||||
|
if overhelmingDiscountLayer > discount.Layer {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedProductTargets := make([]models.ProductTarget, 0, len(discount.Target.Products))
|
||||||
|
|
||||||
|
for _, productTarget := range discount.Target.Products {
|
||||||
|
if overhelmingProductTarget, ok := overhelmingProductTargetLayers[productTarget.ID]; ok && overhelmingProductTarget > discount.Layer {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedProductTargets = append(updatedProductTargets, models.ProductTarget{
|
||||||
|
ID: productTarget.ID,
|
||||||
|
Factor: productTarget.Factor,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
sortedDiscountCalculationTargetsEach = append(sortedDiscountCalculationTargetsEach, models.DiscountCalculationTarget{
|
||||||
|
Products: updatedProductTargets,
|
||||||
|
Factor: discount.Target.Factor,
|
||||||
|
TargetScope: discount.Target.TargetScope,
|
||||||
|
TargetGroup: discount.Target.TargetGroup,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortedDiscountCalculationTargetsEach
|
||||||
|
}
|
||||||
|
|
||||||
|
func sortOverhelmingDiscounts(discounts []models.Discount) []models.DiscountCalculationTarget {
|
||||||
|
if len(discounts) < 1 {
|
||||||
|
return []models.DiscountCalculationTarget{}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortedDiscountCalculationTargets := make([]models.DiscountCalculationTarget, 0, len(discounts))
|
||||||
|
overhelmingDiscountLayer := constituteOverhelmingDiscountLayer(discounts)
|
||||||
|
|
||||||
|
for _, discount := range discounts {
|
||||||
|
if overhelmingDiscountLayer > discount.Layer {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
sortedDiscountCalculationTargets = append(sortedDiscountCalculationTargets, models.DiscountCalculationTarget{
|
||||||
|
Factor: discount.Target.Factor,
|
||||||
|
TargetScope: discount.Target.TargetScope,
|
||||||
|
TargetGroup: discount.Target.TargetGroup,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortedDiscountCalculationTargets
|
||||||
|
}
|
||||||
|
|
||||||
|
func divideDiscountsByScope(discounts []models.Discount) map[models.TargetScope][]models.Discount {
|
||||||
|
dividedTargets := make(map[models.TargetScope][]models.Discount, 3)
|
||||||
|
|
||||||
|
for _, discount := range discounts {
|
||||||
|
if discount.Target.TargetScope == "" && len(discount.Target.Products) > 0 {
|
||||||
|
dividedTargets[models.TargetEach] = append(dividedTargets[models.TargetEach], models.Discount{
|
||||||
|
Layer: discount.Layer,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
Products: discount.Target.Products,
|
||||||
|
Factor: discount.Target.Factor,
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Overhelm: discount.Target.Overhelm,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if discount.Target.TargetScope == "" && len(discount.Target.Products) < 1 {
|
||||||
|
dividedTargets[models.TargetSum] = append(dividedTargets[models.TargetSum], models.Discount{
|
||||||
|
Layer: discount.Layer,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
Factor: discount.Target.Factor,
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Overhelm: discount.Target.Overhelm,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
dividedTargets[discount.Target.TargetScope] = append(dividedTargets[discount.Target.TargetScope], discount)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dividedTargets
|
||||||
|
}
|
743
internal/utils/discount/sort_test.go
Normal file
743
internal/utils/discount/sort_test.go
Normal file
@ -0,0 +1,743 @@
|
|||||||
|
package discount_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/discount"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSortOverhelmingDiscounts(t *testing.T) {
|
||||||
|
t.Run("Успешная сортировка скидок по каждому продукту при наличии перекрывающией скидки на каждый продукт и на определённый продукт", func(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
|
map[models.TargetScope][]models.DiscountCalculationTarget{
|
||||||
|
models.TargetEach: {
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p1", Factor: 0.93},
|
||||||
|
{ID: "p2", Factor: 0.945},
|
||||||
|
{ID: "p5", Factor: 0.97},
|
||||||
|
{ID: "p7", Factor: 0.83},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.8,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p6", Factor: 0.5},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
models.TargetGroup: {},
|
||||||
|
models.TargetSum: {},
|
||||||
|
},
|
||||||
|
discount.SortOverhelmingDiscounts([]models.Discount{
|
||||||
|
{
|
||||||
|
ID: "1",
|
||||||
|
Layer: 1,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p7", Factor: 0.94},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "2",
|
||||||
|
Layer: 2,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p7", Factor: 0.91},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "3",
|
||||||
|
Layer: 3,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Overhelm: true,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p1", Factor: 0.93},
|
||||||
|
{ID: "p2", Factor: 0.945},
|
||||||
|
{ID: "p5", Factor: 0.97},
|
||||||
|
{ID: "p6", Factor: 0.97},
|
||||||
|
{ID: "p7", Factor: 0.83},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "4",
|
||||||
|
Layer: 4,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.8,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p6", Factor: 0.5, Overhelm: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Успешная сортировка скидок по каждому продукту при наличии самой перекрывающей скидки", func(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
|
map[models.TargetScope][]models.DiscountCalculationTarget{
|
||||||
|
models.TargetEach: {
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p2", Factor: 0.94},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
models.TargetGroup: {},
|
||||||
|
models.TargetSum: {},
|
||||||
|
},
|
||||||
|
discount.SortOverhelmingDiscounts([]models.Discount{
|
||||||
|
{
|
||||||
|
ID: "5",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Overhelm: true,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p2", Factor: 0.94},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "6",
|
||||||
|
Layer: 2,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p7", Factor: 0.91, Overhelm: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "7",
|
||||||
|
Layer: 3,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Overhelm: true,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p1", Factor: 0.93},
|
||||||
|
{ID: "p2", Factor: 0.945},
|
||||||
|
{ID: "p5", Factor: 0.97},
|
||||||
|
{ID: "p6", Factor: 0.97},
|
||||||
|
{ID: "p7", Factor: 0.83},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "8",
|
||||||
|
Layer: 4,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.8,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p6", Factor: 0.5, Overhelm: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Успешная сортировка скидок по каждому продукту при наличии скидок с одинаковым значением слоя", func(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
|
map[models.TargetScope][]models.DiscountCalculationTarget{
|
||||||
|
models.TargetEach: {
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p2", Factor: 0.94},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p7", Factor: 0.91},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p1", Factor: 0.93},
|
||||||
|
{ID: "p2", Factor: 0.945},
|
||||||
|
{ID: "p5", Factor: 0.97},
|
||||||
|
{ID: "p6", Factor: 0.97},
|
||||||
|
{ID: "p7", Factor: 0.83},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
models.TargetGroup: {},
|
||||||
|
models.TargetSum: {},
|
||||||
|
},
|
||||||
|
discount.SortOverhelmingDiscounts([]models.Discount{
|
||||||
|
{
|
||||||
|
ID: "9",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Overhelm: true,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p2", Factor: 0.94},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "1",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p7", Factor: 0.91, Overhelm: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "2",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Overhelm: true,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p1", Factor: 0.93},
|
||||||
|
{ID: "p2", Factor: 0.945},
|
||||||
|
{ID: "p5", Factor: 0.97},
|
||||||
|
{ID: "p6", Factor: 0.97},
|
||||||
|
{ID: "p7", Factor: 0.83},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "3",
|
||||||
|
Layer: 4,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.8,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p6", Factor: 0.5, Overhelm: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Успешная сортировка скидок по каждому продукту при наличии скидок с одинаковым значением слоя и полностью перекрывающими другие", func(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
|
map[models.TargetScope][]models.DiscountCalculationTarget{
|
||||||
|
models.TargetEach: {
|
||||||
|
{
|
||||||
|
Factor: 0.92,
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p2", Factor: 0.94},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Factor: 0.92,
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p7", Factor: 0.91},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
models.TargetGroup: {},
|
||||||
|
models.TargetSum: {},
|
||||||
|
},
|
||||||
|
discount.SortOverhelmingDiscounts([]models.Discount{
|
||||||
|
{
|
||||||
|
ID: "4",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Overhelm: true,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p2", Factor: 0.94},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "7",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p7", Factor: 0.91, Overhelm: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "4",
|
||||||
|
Layer: 4,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.8,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p7", Factor: 0.5, Overhelm: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Успешная сортировка скидок по каждому продукту при наличии скидок, где одна полностью перекрывает продукты другой", func(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
|
map[models.TargetScope][]models.DiscountCalculationTarget{
|
||||||
|
models.TargetEach: {
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p2", Factor: 0.94},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Factor: 0.92,
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Products: []models.ProductTarget{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
models.TargetGroup: {},
|
||||||
|
models.TargetSum: {},
|
||||||
|
},
|
||||||
|
discount.SortOverhelmingDiscounts([]models.Discount{
|
||||||
|
{
|
||||||
|
ID: "5",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p2", Factor: 0.94, Overhelm: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "6",
|
||||||
|
Layer: 4,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p2", Factor: 0.5, Overhelm: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Успешная сортировка скидок по группе продуктов при наличии перекрывающих скидок", func(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
|
map[models.TargetScope][]models.DiscountCalculationTarget{
|
||||||
|
models.TargetEach: {},
|
||||||
|
models.TargetGroup: {
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "123",
|
||||||
|
Factor: 0.92,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
models.TargetSum: {},
|
||||||
|
},
|
||||||
|
discount.SortOverhelmingDiscounts([]models.Discount{
|
||||||
|
{
|
||||||
|
ID: "7",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
Overhelm: true,
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "123",
|
||||||
|
Factor: 0.92,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "8",
|
||||||
|
Layer: 4,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "123",
|
||||||
|
Factor: 0.96,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "9",
|
||||||
|
Layer: 3,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "123",
|
||||||
|
Factor: 0.91,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Успешная сортировка скидок по группе продуктов при наличии перекрывающих скидок и разных групп", func(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
|
map[models.TargetScope][]models.DiscountCalculationTarget{
|
||||||
|
models.TargetEach: {},
|
||||||
|
models.TargetGroup: {
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "123",
|
||||||
|
Factor: 0.92,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
models.TargetSum: {},
|
||||||
|
},
|
||||||
|
discount.SortOverhelmingDiscounts([]models.Discount{
|
||||||
|
{
|
||||||
|
ID: "1",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
Overhelm: true,
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "123",
|
||||||
|
Factor: 0.92,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "2",
|
||||||
|
Layer: 4,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "123",
|
||||||
|
Factor: 0.42,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "3",
|
||||||
|
Layer: 5,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
Overhelm: true,
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "111",
|
||||||
|
Factor: 0.9,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "4",
|
||||||
|
Layer: 2,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "111",
|
||||||
|
Factor: 0.8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Успешная сортировка скидок по сумме при наличии скидки, перекрывающая все остальные", func(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
|
map[models.TargetScope][]models.DiscountCalculationTarget{
|
||||||
|
models.TargetEach: {},
|
||||||
|
models.TargetGroup: {},
|
||||||
|
models.TargetSum: {
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.92,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
discount.SortOverhelmingDiscounts([]models.Discount{
|
||||||
|
{
|
||||||
|
ID: "1",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
Overhelm: true,
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.92,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "2",
|
||||||
|
Layer: 4,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.42,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "3",
|
||||||
|
Layer: 5,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Overhelm: true,
|
||||||
|
Factor: 0.9,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "4",
|
||||||
|
Layer: 2,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Успешная сортировка скидок по сумме при наличии перекрывающей скидки", func(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
|
map[models.TargetScope][]models.DiscountCalculationTarget{
|
||||||
|
models.TargetEach: {},
|
||||||
|
models.TargetGroup: {},
|
||||||
|
models.TargetSum: {
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.92,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.42,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.9,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
discount.SortOverhelmingDiscounts([]models.Discount{
|
||||||
|
{
|
||||||
|
ID: "1",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.92,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "2",
|
||||||
|
Layer: 4,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Overhelm: true,
|
||||||
|
Factor: 0.42,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "3",
|
||||||
|
Layer: 5,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.9,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "4",
|
||||||
|
Layer: 2,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Успешная сортировка смешанных скидок при наличии перекрывающих", func(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
|
map[models.TargetScope][]models.DiscountCalculationTarget{
|
||||||
|
models.TargetEach: {
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p2", Factor: 0.94},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p7", Factor: 0.91},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p1", Factor: 0.93},
|
||||||
|
{ID: "p2", Factor: 0.945},
|
||||||
|
{ID: "p5", Factor: 0.97},
|
||||||
|
{ID: "p6", Factor: 0.97},
|
||||||
|
{ID: "p7", Factor: 0.83},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
models.TargetGroup: {
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "123",
|
||||||
|
Factor: 0.92,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
models.TargetSum: {
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.92,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.42,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.9,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
discount.SortOverhelmingDiscounts([]models.Discount{
|
||||||
|
{
|
||||||
|
ID: "1",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.92,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "2",
|
||||||
|
Layer: 4,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Overhelm: true,
|
||||||
|
Factor: 0.42,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "3",
|
||||||
|
Layer: 5,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.9,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "4",
|
||||||
|
Layer: 2,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetSum,
|
||||||
|
Factor: 0.8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "5",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
Overhelm: true,
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "123",
|
||||||
|
Factor: 0.92,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "6",
|
||||||
|
Layer: 4,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "123",
|
||||||
|
Factor: 0.42,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "7",
|
||||||
|
Layer: 5,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
Overhelm: true,
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "111",
|
||||||
|
Factor: 0.9,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "8",
|
||||||
|
Layer: 2,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetGroup,
|
||||||
|
TargetGroup: "111",
|
||||||
|
Factor: 0.8,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "9",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Overhelm: true,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p2", Factor: 0.94},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "10",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p7", Factor: 0.91, Overhelm: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "11",
|
||||||
|
Layer: 6,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.92,
|
||||||
|
Overhelm: true,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p1", Factor: 0.93},
|
||||||
|
{ID: "p2", Factor: 0.945},
|
||||||
|
{ID: "p5", Factor: 0.97},
|
||||||
|
{ID: "p6", Factor: 0.97},
|
||||||
|
{ID: "p7", Factor: 0.83},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "12",
|
||||||
|
Layer: 4,
|
||||||
|
Target: models.DiscountCalculationTarget{
|
||||||
|
TargetScope: models.TargetEach,
|
||||||
|
Factor: 0.8,
|
||||||
|
Products: []models.ProductTarget{
|
||||||
|
{ID: "p6", Factor: 0.5, Overhelm: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
@ -1,45 +1,44 @@
|
|||||||
package expression
|
package expression
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
"golang.org/x/exp/constraints"
|
"golang.org/x/exp/constraints"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
)
|
||||||
)
|
|
||||||
|
type PeriodFieldPaths struct {
|
||||||
type PeriodFieldPaths struct {
|
From string
|
||||||
From string
|
To string
|
||||||
To string
|
}
|
||||||
}
|
|
||||||
|
func GetAscRangeConditionBSON[T constraints.Ordered](key string, value T) []bson.D {
|
||||||
func GetAscRangeConditionBSON[T constraints.Ordered](key string, value T) []bson.D {
|
return []bson.D{
|
||||||
return []bson.D{
|
{{Key: key, Value: bson.M{"$lte": value}}},
|
||||||
{{Key: key, Value: bson.M{"$lte": value}}},
|
{{Key: key, Value: nil}},
|
||||||
{{Key: key, Value: nil}},
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
func GetValueConditionBSON(key string, value any) []bson.D {
|
||||||
func GetValueConditionBSON(key string, value any) []bson.D {
|
return []bson.D{
|
||||||
return []bson.D{
|
{{Key: key, Value: value}},
|
||||||
{{Key: key, Value: value}},
|
{{Key: key, Value: nil}},
|
||||||
{{Key: key, Value: nil}},
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
func GetPerionConditionBSON(period models.PeriodCondition, paths PeriodFieldPaths) []bson.M {
|
||||||
func GetPerionConditionBSON(period models.PeriodCondition, paths PeriodFieldPaths) []bson.M {
|
return []bson.M{
|
||||||
return []bson.M{
|
{
|
||||||
{
|
"$and": []bson.D{
|
||||||
"$and": []bson.D{
|
{{Key: paths.From, Value: bson.M{"$lte": primitive.NewDateTimeFromTime(period.From)}}},
|
||||||
{{Key: paths.From, Value: bson.M{"$lte": primitive.NewDateTimeFromTime(period.From)}}},
|
{{Key: paths.To, Value: bson.M{"$gte": primitive.NewDateTimeFromTime(period.To)}}},
|
||||||
{{Key: paths.To, Value: bson.M{"$gte": primitive.NewDateTimeFromTime(period.To)}}},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
"$and": []bson.D{
|
||||||
"$and": []bson.D{
|
{{Key: paths.From, Value: nil}},
|
||||||
{{Key: paths.From, Value: nil}},
|
{{Key: paths.To, Value: nil}},
|
||||||
{{Key: paths.To, Value: nil}},
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -1,84 +1,82 @@
|
|||||||
package expression_test
|
package expression_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression"
|
)
|
||||||
)
|
|
||||||
|
func TestGetAscRangeConditionBSON(t *testing.T) {
|
||||||
func TestGetAscRangeConditionBSON(t *testing.T) {
|
t.Run("Получение bson условия диапазона от меньшего с заполненными данными", func(t *testing.T) {
|
||||||
t.Run("Получение bson условия диапазона от меньшего с заполненными данными", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
[]bson.D{
|
||||||
[]bson.D{
|
{{Key: "test", Value: bson.M{"$lte": "2020"}}},
|
||||||
{{Key: "test", Value: bson.M{"$lte": "2020"}}},
|
{{Key: "test", Value: nil}},
|
||||||
{{Key: "test", Value: nil}},
|
},
|
||||||
},
|
expression.GetAscRangeConditionBSON("test", "2020"),
|
||||||
expression.GetAscRangeConditionBSON("test", "2020"),
|
)
|
||||||
)
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
[]bson.D{
|
||||||
[]bson.D{
|
{{Key: "test2", Value: bson.M{"$lte": 200.00}}},
|
||||||
{{Key: "test2", Value: bson.M{"$lte": 200.00}}},
|
{{Key: "test2", Value: nil}},
|
||||||
{{Key: "test2", Value: nil}},
|
},
|
||||||
},
|
expression.GetAscRangeConditionBSON("test2", 200.00),
|
||||||
expression.GetAscRangeConditionBSON("test2", 200.00),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
func TestGetValueConditionBSON(t *testing.T) {
|
||||||
func TestGetValueConditionBSON(t *testing.T) {
|
t.Run("Получение bson условия значения с заполненными данными", func(t *testing.T) {
|
||||||
t.Run("Получение bson условия значения с заполненными данными", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
[]bson.D{
|
||||||
[]bson.D{
|
{{Key: "test", Value: "2020"}},
|
||||||
{{Key: "test", Value: "2020"}},
|
{{Key: "test", Value: nil}},
|
||||||
{{Key: "test", Value: nil}},
|
},
|
||||||
},
|
expression.GetValueConditionBSON("test", "2020"),
|
||||||
expression.GetValueConditionBSON("test", "2020"),
|
)
|
||||||
)
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
[]bson.D{
|
||||||
[]bson.D{
|
{{Key: "test2", Value: 200.00}},
|
||||||
{{Key: "test2", Value: 200.00}},
|
{{Key: "test2", Value: nil}},
|
||||||
{{Key: "test2", Value: nil}},
|
},
|
||||||
},
|
expression.GetValueConditionBSON("test2", 200.00),
|
||||||
expression.GetValueConditionBSON("test2", 200.00),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
func TestGetPerionConditionBSON(t *testing.T) {
|
||||||
func TestGetPerionConditionBSON(t *testing.T) {
|
t.Run("Получение bson условия периода с заполненными данными", func(t *testing.T) {
|
||||||
|
assert.Equal(t,
|
||||||
t.Run("Получение bson условия периода с заполненными данными", func(t *testing.T) {
|
[]bson.M{
|
||||||
assert.Equal(t,
|
{
|
||||||
[]bson.M{
|
"$and": []bson.D{
|
||||||
{
|
{{Key: fields.PeriodCondition.From, Value: bson.M{"$lte": primitive.NewDateTimeFromTime(time.Unix(1674546287, 0).UTC())}}},
|
||||||
"$and": []bson.D{
|
{{Key: fields.PeriodCondition.To, Value: bson.M{"$gte": primitive.NewDateTimeFromTime(time.Unix(1674546287, 0).UTC())}}},
|
||||||
{{Key: fields.PeriodCondition.From, Value: bson.M{"$lte": primitive.NewDateTimeFromTime(time.Unix(1674546287, 0).UTC())}}},
|
},
|
||||||
{{Key: fields.PeriodCondition.To, Value: bson.M{"$gte": primitive.NewDateTimeFromTime(time.Unix(1674546287, 0).UTC())}}},
|
},
|
||||||
},
|
{
|
||||||
},
|
"$and": []bson.D{
|
||||||
{
|
{{Key: fields.PeriodCondition.From, Value: nil}},
|
||||||
"$and": []bson.D{
|
{{Key: fields.PeriodCondition.To, Value: nil}},
|
||||||
{{Key: fields.PeriodCondition.From, Value: nil}},
|
},
|
||||||
{{Key: fields.PeriodCondition.To, Value: nil}},
|
},
|
||||||
},
|
},
|
||||||
},
|
expression.GetPerionConditionBSON(
|
||||||
},
|
models.PeriodCondition{
|
||||||
expression.GetPerionConditionBSON(
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
models.PeriodCondition{
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
expression.PeriodFieldPaths{
|
||||||
},
|
From: fields.PeriodCondition.From,
|
||||||
expression.PeriodFieldPaths{
|
To: fields.PeriodCondition.To,
|
||||||
From: fields.PeriodCondition.From,
|
},
|
||||||
To: fields.PeriodCondition.To,
|
),
|
||||||
},
|
)
|
||||||
),
|
})
|
||||||
)
|
}
|
||||||
})
|
|
||||||
}
|
|
||||||
|
@ -1,47 +1,46 @@
|
|||||||
package discount
|
package discount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/defaults"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/defaults"
|
)
|
||||||
)
|
|
||||||
|
func ConstituteCommonConditions(conditions *core.CommonDiscountCondition) []bson.M {
|
||||||
func ConstituteCommonConditions(conditions *core.CommonDiscountCondition) []bson.M {
|
if conditions == nil {
|
||||||
if conditions == nil {
|
return []bson.M{}
|
||||||
return []bson.M{}
|
}
|
||||||
}
|
|
||||||
|
return []bson.M{
|
||||||
return []bson.M{
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.User, conditions.User)},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.User, conditions.User)},
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.UserType, conditions.UserType)},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.UserType, conditions.UserType)},
|
{
|
||||||
{
|
"$or": expression.GetPerionConditionBSON(
|
||||||
"$or": expression.GetPerionConditionBSON(
|
conditions.Period,
|
||||||
conditions.Period,
|
expression.PeriodFieldPaths{
|
||||||
expression.PeriodFieldPaths{
|
From: fields.PeriodCondition.From,
|
||||||
From: fields.PeriodCondition.From,
|
To: fields.PeriodCondition.To,
|
||||||
To: fields.PeriodCondition.To,
|
},
|
||||||
},
|
),
|
||||||
),
|
},
|
||||||
},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.PurchasesAmount, conditions.PurchasesAmount)},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.PurchasesAmount, conditions.PurchasesAmount)},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.CartPurchasesAmount, conditions.CartPurchasesAmount)},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.CartPurchasesAmount, conditions.CartPurchasesAmount)},
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Coupon, defaults.GetDefaultValue(conditions.Coupon, ""))},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Coupon, defaults.GetDefaultValue(conditions.Coupon, ""))},
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
func ConstituteOptionalConditions(conditions *core.OptionalDiscounCondition) []bson.M {
|
||||||
func ConstituteOptionalConditions(conditions *core.OptionalDiscounCondition) []bson.M {
|
if conditions == nil {
|
||||||
if conditions == nil {
|
return []bson.M{}
|
||||||
return []bson.M{}
|
}
|
||||||
}
|
|
||||||
|
return []bson.M{
|
||||||
return []bson.M{
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Product, defaults.GetDefaultValue(conditions.Product, ""))},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Product, defaults.GetDefaultValue(conditions.Product, ""))},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.Term, defaults.GetDefaultValue(conditions.Term, uint64(0)))},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.Term, defaults.GetDefaultValue(conditions.Term, uint64(0)))},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.Usage, defaults.GetDefaultValue(conditions.Usage, uint64(0)))},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.Usage, defaults.GetDefaultValue(conditions.Usage, uint64(0)))},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.PriceFrom, defaults.GetDefaultValue(conditions.PriceFrom, uint64(0)))},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.PriceFrom, defaults.GetDefaultValue(conditions.PriceFrom, float64(0)))},
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Group, defaults.GetDefaultValue(conditions.Group, ""))},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Group, defaults.GetDefaultValue(conditions.Group, ""))},
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -1,140 +1,139 @@
|
|||||||
package discount_test
|
package discount_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression/discount"
|
)
|
||||||
)
|
|
||||||
|
func TestConstituteCommonConditions(t *testing.T) {
|
||||||
func TestConstituteCommonConditions(t *testing.T) {
|
userID := "user12"
|
||||||
userID := "user1"
|
userType := "nkvo9"
|
||||||
userType := "nkvo"
|
coupon := "coupon11"
|
||||||
coupon := "coupon"
|
purchasesAmount := uint64(10000)
|
||||||
purchasesAmount := float64(10000)
|
cartPurchasesAmount := uint64(20000)
|
||||||
cartPurchasesAmount := float64(20000)
|
|
||||||
|
t.Run("Формирование фильтра общих условий поиска с nil", func(t *testing.T) {
|
||||||
t.Run("Формирование фильтра общих условий поиска с nil", func(t *testing.T) {
|
assert.Equal(t, []bson.M{}, discount.ConstituteCommonConditions(nil))
|
||||||
assert.Equal(t, []bson.M{}, discount.ConstituteCommonConditions(nil))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование фильтра общих условий поиска с купоном", func(t *testing.T) {
|
||||||
t.Run("Формирование фильтра общих условий поиска с купоном", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
[]bson.M{
|
||||||
[]bson.M{
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.User, userID)},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.User, userID)},
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.UserType, userType)},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.UserType, userType)},
|
{
|
||||||
{
|
"$or": expression.GetPerionConditionBSON(
|
||||||
"$or": expression.GetPerionConditionBSON(
|
models.PeriodCondition{
|
||||||
models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
expression.PeriodFieldPaths{
|
||||||
expression.PeriodFieldPaths{
|
From: fields.PeriodCondition.From,
|
||||||
From: fields.PeriodCondition.From,
|
To: fields.PeriodCondition.To,
|
||||||
To: fields.PeriodCondition.To,
|
},
|
||||||
},
|
),
|
||||||
),
|
},
|
||||||
},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.PurchasesAmount, purchasesAmount)},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.PurchasesAmount, purchasesAmount)},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.CartPurchasesAmount, cartPurchasesAmount)},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.CartPurchasesAmount, cartPurchasesAmount)},
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Coupon, coupon)},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Coupon, coupon)},
|
},
|
||||||
},
|
discount.ConstituteCommonConditions(&core.CommonDiscountCondition{
|
||||||
discount.ConstituteCommonConditions(&core.CommonDiscountCondition{
|
Period: models.PeriodCondition{
|
||||||
Period: models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
User: userID,
|
||||||
User: userID,
|
UserType: userType,
|
||||||
UserType: userType,
|
Coupon: &coupon,
|
||||||
Coupon: &coupon,
|
PurchasesAmount: purchasesAmount,
|
||||||
PurchasesAmount: purchasesAmount,
|
CartPurchasesAmount: cartPurchasesAmount,
|
||||||
CartPurchasesAmount: cartPurchasesAmount,
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование фильтра общих условий поиска без купона", func(t *testing.T) {
|
||||||
t.Run("Формирование фильтра общих условий поиска без купона", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
[]bson.M{
|
||||||
[]bson.M{
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.User, userID)},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.User, userID)},
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.UserType, userType)},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.UserType, userType)},
|
{
|
||||||
{
|
"$or": expression.GetPerionConditionBSON(
|
||||||
"$or": expression.GetPerionConditionBSON(
|
models.PeriodCondition{
|
||||||
models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
expression.PeriodFieldPaths{
|
||||||
expression.PeriodFieldPaths{
|
From: fields.PeriodCondition.From,
|
||||||
From: fields.PeriodCondition.From,
|
To: fields.PeriodCondition.To,
|
||||||
To: fields.PeriodCondition.To,
|
},
|
||||||
},
|
),
|
||||||
),
|
},
|
||||||
},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.PurchasesAmount, purchasesAmount)},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.PurchasesAmount, purchasesAmount)},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.CartPurchasesAmount, cartPurchasesAmount)},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.CartPurchasesAmount, cartPurchasesAmount)},
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Coupon, "")},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Coupon, "")},
|
},
|
||||||
},
|
discount.ConstituteCommonConditions(&core.CommonDiscountCondition{
|
||||||
discount.ConstituteCommonConditions(&core.CommonDiscountCondition{
|
Period: models.PeriodCondition{
|
||||||
Period: models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
User: userID,
|
||||||
User: userID,
|
UserType: userType,
|
||||||
UserType: userType,
|
PurchasesAmount: purchasesAmount,
|
||||||
PurchasesAmount: purchasesAmount,
|
CartPurchasesAmount: cartPurchasesAmount,
|
||||||
CartPurchasesAmount: cartPurchasesAmount,
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
func TestConstituteOptionalConditions(t *testing.T) {
|
||||||
func TestConstituteOptionalConditions(t *testing.T) {
|
productID := "productgg1"
|
||||||
productID := "product1"
|
term := uint64(14)
|
||||||
term := uint64(14)
|
usage := uint64(10)
|
||||||
usage := uint64(10)
|
priceFrom := uint64(13000)
|
||||||
priceFrom := float64(13000)
|
group := "group888"
|
||||||
group := "group"
|
|
||||||
|
t.Run("Формирование фильтра опциональных условий поиска и nil", func(t *testing.T) {
|
||||||
t.Run("Формирование фильтра опциональных условий поиска и nil", func(t *testing.T) {
|
assert.Equal(t, []bson.M{}, discount.ConstituteOptionalConditions(nil))
|
||||||
assert.Equal(t, []bson.M{}, discount.ConstituteOptionalConditions(nil))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование фильтра опциональных условий поиска с заполненными параметрами", func(t *testing.T) {
|
||||||
t.Run("Формирование фильтра опциональных условий поиска с заполненными параметрами", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
[]bson.M{
|
||||||
[]bson.M{
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Product, productID)},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Product, productID)},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.Term, term)},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.Term, term)},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.Usage, usage)},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.Usage, usage)},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.PriceFrom, priceFrom)},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.PriceFrom, priceFrom)},
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Group, group)},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Group, group)},
|
},
|
||||||
},
|
discount.ConstituteOptionalConditions(&core.OptionalDiscounCondition{
|
||||||
discount.ConstituteOptionalConditions(&core.OptionalDiscounCondition{
|
Product: &productID,
|
||||||
Product: &productID,
|
Term: &term,
|
||||||
Term: &term,
|
Usage: &usage,
|
||||||
Usage: &usage,
|
PriceFrom: &priceFrom,
|
||||||
PriceFrom: &priceFrom,
|
Group: &group,
|
||||||
Group: &group,
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование фильтра опциональных условий поиска с пустыми параметрами", func(t *testing.T) {
|
||||||
t.Run("Формирование фильтра опциональных условий поиска с пустыми параметрами", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
[]bson.M{
|
||||||
[]bson.M{
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Product, "")},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Product, "")},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.Term, uint64(0))},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.Term, uint64(0))},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.Usage, uint64(0))},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.Usage, uint64(0))},
|
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.PriceFrom, uint64(0))},
|
||||||
{"$or": expression.GetAscRangeConditionBSON(fields.DiscountCondition.PriceFrom, float64(0))},
|
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Group, "")},
|
||||||
{"$or": expression.GetValueConditionBSON(fields.DiscountCondition.Group, "")},
|
},
|
||||||
},
|
discount.ConstituteOptionalConditions(&core.OptionalDiscounCondition{}),
|
||||||
discount.ConstituteOptionalConditions(&core.OptionalDiscounCondition{}),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
@ -1,34 +1,34 @@
|
|||||||
package discount
|
package discount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
)
|
||||||
)
|
|
||||||
|
func ConditionFilter(conditions *core.DiscountConditions) *bson.M {
|
||||||
func ConditionFilter(conditions *core.DiscountConditions) *bson.M {
|
if conditions == nil {
|
||||||
if conditions == nil {
|
return nil
|
||||||
return nil
|
}
|
||||||
}
|
|
||||||
|
expressions := make([]bson.M, 0)
|
||||||
expressions := make([]bson.M, 0)
|
commonExpressions := ConstituteCommonConditions(&conditions.Common)
|
||||||
commonExpressions := ConstituteCommonConditions(&conditions.Common)
|
|
||||||
|
if len(conditions.Optionals) == 0 {
|
||||||
if len(conditions.Optionals) == 0 {
|
optionalExpressions := ConstituteOptionalConditions(&core.OptionalDiscounCondition{})
|
||||||
optionalExpressions := ConstituteOptionalConditions(&core.OptionalDiscounCondition{})
|
expressions = append(expressions, bson.M{
|
||||||
expressions = append(expressions, bson.M{
|
"$and": append([]bson.M{}, append(commonExpressions, optionalExpressions...)...),
|
||||||
"$and": append([]bson.M{}, append(commonExpressions, optionalExpressions...)...),
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
for _, expression := range conditions.Optionals {
|
||||||
for _, expression := range conditions.Optionals {
|
expressionCopy := expression
|
||||||
optionalExpressions := ConstituteOptionalConditions(&expression)
|
optionalExpressions := ConstituteOptionalConditions(&expressionCopy)
|
||||||
expressions = append(expressions, bson.M{
|
expressions = append(expressions, bson.M{
|
||||||
"$and": append([]bson.M{}, append(commonExpressions, optionalExpressions...)...),
|
"$and": append([]bson.M{}, append(commonExpressions, optionalExpressions...)...),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return &bson.M{
|
return &bson.M{
|
||||||
"$or": expressions,
|
"$or": expressions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,123 +1,122 @@
|
|||||||
package discount_test
|
package discount_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression/discount"
|
)
|
||||||
)
|
|
||||||
|
func TestConditionFilter(t *testing.T) {
|
||||||
func TestConditionFilter(t *testing.T) {
|
productID := "product1"
|
||||||
productID := "product1"
|
productID2 := "product2"
|
||||||
productID2 := "product2"
|
term := uint64(14)
|
||||||
term := uint64(14)
|
usage := uint64(10)
|
||||||
usage := uint64(10)
|
priceFrom := uint64(13000)
|
||||||
priceFrom := float64(13000)
|
group := "groupopo"
|
||||||
group := "group"
|
userID := "user1"
|
||||||
userID := "user1"
|
userType := "nkvo01001"
|
||||||
userType := "nkvo"
|
coupon := "coupon"
|
||||||
coupon := "coupon"
|
purchasesAmount := uint64(10000)
|
||||||
purchasesAmount := float64(10000)
|
cartPurchasesAmount := uint64(20000)
|
||||||
cartPurchasesAmount := float64(20000)
|
|
||||||
|
t.Run("Формирование фильтра условий поиска с пустыми условиями", func(t *testing.T) {
|
||||||
t.Run("Формирование фильтра условий поиска с пустыми условиями", func(t *testing.T) {
|
assert.NotNil(t, discount.ConditionFilter(&core.DiscountConditions{}))
|
||||||
assert.NotNil(t, discount.ConditionFilter(&core.DiscountConditions{}))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование фильтра условий поиска с nil", func(t *testing.T) {
|
||||||
t.Run("Формирование фильтра условий поиска с nil", func(t *testing.T) {
|
assert.Nil(t, discount.ConditionFilter(nil))
|
||||||
assert.Nil(t, discount.ConditionFilter(nil))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование фильтра условий поиска со всеми условиями", func(t *testing.T) {
|
||||||
t.Run("Формирование фильтра условий поиска со всеми условиями", func(t *testing.T) {
|
commonConditions := discount.ConstituteCommonConditions(&core.CommonDiscountCondition{
|
||||||
commonConditions := discount.ConstituteCommonConditions(&core.CommonDiscountCondition{
|
Period: models.PeriodCondition{
|
||||||
Period: models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
User: userID,
|
||||||
User: userID,
|
UserType: userType,
|
||||||
UserType: userType,
|
Coupon: &coupon,
|
||||||
Coupon: &coupon,
|
PurchasesAmount: purchasesAmount,
|
||||||
PurchasesAmount: purchasesAmount,
|
CartPurchasesAmount: cartPurchasesAmount,
|
||||||
CartPurchasesAmount: cartPurchasesAmount,
|
})
|
||||||
})
|
|
||||||
|
productCondition1 := discount.ConstituteOptionalConditions(&core.OptionalDiscounCondition{
|
||||||
productCondition1 := discount.ConstituteOptionalConditions(&core.OptionalDiscounCondition{
|
Product: &productID,
|
||||||
Product: &productID,
|
Term: &term,
|
||||||
Term: &term,
|
Usage: &usage,
|
||||||
Usage: &usage,
|
PriceFrom: &priceFrom,
|
||||||
PriceFrom: &priceFrom,
|
Group: &group,
|
||||||
Group: &group,
|
})
|
||||||
})
|
|
||||||
|
productCondition2 := discount.ConstituteOptionalConditions(&core.OptionalDiscounCondition{
|
||||||
productCondition2 := discount.ConstituteOptionalConditions(&core.OptionalDiscounCondition{
|
Product: &productID2,
|
||||||
Product: &productID2,
|
PriceFrom: &priceFrom,
|
||||||
PriceFrom: &priceFrom,
|
})
|
||||||
})
|
|
||||||
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&bson.M{
|
||||||
&bson.M{
|
"$or": []bson.M{
|
||||||
"$or": []bson.M{
|
{"$and": append([]bson.M{}, append(commonConditions, productCondition1...)...)},
|
||||||
{"$and": append([]bson.M{}, append(commonConditions, productCondition1...)...)},
|
{"$and": append([]bson.M{}, append(commonConditions, productCondition2...)...)},
|
||||||
{"$and": append([]bson.M{}, append(commonConditions, productCondition2...)...)},
|
},
|
||||||
},
|
},
|
||||||
},
|
discount.ConditionFilter(&core.DiscountConditions{
|
||||||
discount.ConditionFilter(&core.DiscountConditions{
|
Common: core.CommonDiscountCondition{
|
||||||
Common: core.CommonDiscountCondition{
|
Period: models.PeriodCondition{
|
||||||
Period: models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
User: userID,
|
||||||
User: userID,
|
UserType: userType,
|
||||||
UserType: userType,
|
Coupon: &coupon,
|
||||||
Coupon: &coupon,
|
PurchasesAmount: purchasesAmount,
|
||||||
PurchasesAmount: purchasesAmount,
|
CartPurchasesAmount: cartPurchasesAmount,
|
||||||
CartPurchasesAmount: cartPurchasesAmount,
|
},
|
||||||
},
|
Optionals: []core.OptionalDiscounCondition{
|
||||||
Optionals: []core.OptionalDiscounCondition{
|
{
|
||||||
{
|
Product: &productID,
|
||||||
Product: &productID,
|
Term: &term,
|
||||||
Term: &term,
|
Usage: &usage,
|
||||||
Usage: &usage,
|
PriceFrom: &priceFrom,
|
||||||
PriceFrom: &priceFrom,
|
Group: &group,
|
||||||
Group: &group,
|
},
|
||||||
},
|
{
|
||||||
{
|
Product: &productID2,
|
||||||
Product: &productID2,
|
PriceFrom: &priceFrom,
|
||||||
PriceFrom: &priceFrom,
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование фильтра условий поиска с периодом", func(t *testing.T) {
|
||||||
t.Run("Формирование фильтра условий поиска с периодом", func(t *testing.T) {
|
productCondition := discount.ConstituteOptionalConditions(&core.OptionalDiscounCondition{})
|
||||||
productCondition := discount.ConstituteOptionalConditions(&core.OptionalDiscounCondition{})
|
commonConditions := discount.ConstituteCommonConditions(&core.CommonDiscountCondition{
|
||||||
commonConditions := discount.ConstituteCommonConditions(&core.CommonDiscountCondition{
|
Period: models.PeriodCondition{
|
||||||
Period: models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
})
|
||||||
})
|
|
||||||
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&bson.M{
|
||||||
&bson.M{
|
"$or": []bson.M{
|
||||||
"$or": []bson.M{
|
{"$and": append([]bson.M{}, append(commonConditions, productCondition...)...)},
|
||||||
{"$and": append([]bson.M{}, append(commonConditions, productCondition...)...)},
|
},
|
||||||
},
|
},
|
||||||
},
|
discount.ConditionFilter(&core.DiscountConditions{
|
||||||
discount.ConditionFilter(&core.DiscountConditions{
|
Common: core.CommonDiscountCondition{
|
||||||
Common: core.CommonDiscountCondition{
|
Period: models.PeriodCondition{
|
||||||
Period: models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
@ -1,145 +1,144 @@
|
|||||||
package discount
|
package discount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/utils"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/utils"
|
)
|
||||||
)
|
|
||||||
|
func GetDiscountExpression(settings *core.FilterDiscountSettings) *bson.M {
|
||||||
func GetDiscountExpression(settings *core.FilterDiscountSettings) *bson.M {
|
if settings == nil || utils.GetFilledFieldsCount(settings) < 2 {
|
||||||
if settings == nil || utils.GetFilledFieldsCount(settings) < 2 {
|
return nil
|
||||||
return nil
|
}
|
||||||
}
|
|
||||||
|
expression := bson.M{}
|
||||||
expression := bson.M{}
|
commonExpression := getCommonDiscountExpression(settings)
|
||||||
commonExpression := getCommonDiscountExpression(settings)
|
conditionExpression := getDiscountConditionExpression(settings)
|
||||||
conditionExpression := getDiscountConditionExpression(settings)
|
targetExpression := getDiscountTargetExpression(settings)
|
||||||
targetExpression := getDiscountTargetExpression(settings)
|
|
||||||
|
for key, value := range commonExpression {
|
||||||
for key, value := range commonExpression {
|
expression[key] = value
|
||||||
expression[key] = value
|
}
|
||||||
}
|
|
||||||
|
for key, value := range conditionExpression {
|
||||||
for key, value := range conditionExpression {
|
expression[key] = value
|
||||||
expression[key] = value
|
}
|
||||||
}
|
|
||||||
|
for key, value := range targetExpression {
|
||||||
for key, value := range targetExpression {
|
expression[key] = value
|
||||||
expression[key] = value
|
}
|
||||||
}
|
|
||||||
|
return &expression
|
||||||
return &expression
|
}
|
||||||
}
|
|
||||||
|
func getCommonDiscountExpression(deps *core.FilterDiscountSettings) bson.M {
|
||||||
func getCommonDiscountExpression(deps *core.FilterDiscountSettings) bson.M {
|
expression := bson.M{}
|
||||||
expression := bson.M{}
|
|
||||||
|
if deps.ID != nil {
|
||||||
if deps.ID != nil {
|
expression[fields.Discount.ID] = *deps.ID
|
||||||
expression[fields.Discount.ID] = *deps.ID
|
}
|
||||||
}
|
|
||||||
|
if deps.Name != nil {
|
||||||
if deps.Name != nil {
|
expression[fields.Discount.Name] = *deps.Name
|
||||||
expression[fields.Discount.Name] = *deps.Name
|
}
|
||||||
}
|
|
||||||
|
if deps.Description != nil {
|
||||||
if deps.Description != nil {
|
expression[fields.Discount.Description] = *deps.Description
|
||||||
expression[fields.Discount.Description] = *deps.Description
|
}
|
||||||
}
|
|
||||||
|
if deps.Layer != nil {
|
||||||
if deps.Layer != nil {
|
expression[fields.Discount.Layer] = *deps.Layer
|
||||||
expression[fields.Discount.Layer] = *deps.Layer
|
}
|
||||||
}
|
|
||||||
|
if deps.Deprecated != nil {
|
||||||
if deps.Deprecated != nil {
|
expression[fields.Discount.Deprecated] = *deps.Deprecated
|
||||||
expression[fields.Discount.Deprecated] = *deps.Deprecated
|
}
|
||||||
}
|
|
||||||
|
return expression
|
||||||
return expression
|
}
|
||||||
}
|
|
||||||
|
func getDiscountConditionExpression(deps *core.FilterDiscountSettings) bson.M {
|
||||||
func getDiscountConditionExpression(deps *core.FilterDiscountSettings) bson.M {
|
expression := bson.M{}
|
||||||
expression := bson.M{}
|
|
||||||
|
if deps.Condition == nil {
|
||||||
if deps.Condition == nil {
|
return expression
|
||||||
return expression
|
}
|
||||||
}
|
|
||||||
|
if deps.Condition.Period != nil {
|
||||||
if deps.Condition.Period != nil {
|
from := primitive.NewDateTimeFromTime(deps.Condition.Period.From)
|
||||||
from := primitive.NewDateTimeFromTime(deps.Condition.Period.From)
|
to := primitive.NewDateTimeFromTime(deps.Condition.Period.To)
|
||||||
to := primitive.NewDateTimeFromTime(deps.Condition.Period.To)
|
|
||||||
|
expression[fields.PeriodCondition.From] = from
|
||||||
expression[fields.PeriodCondition.From] = from
|
expression[fields.PeriodCondition.To] = to
|
||||||
expression[fields.PeriodCondition.To] = to
|
}
|
||||||
}
|
|
||||||
|
if deps.Condition.Product != nil {
|
||||||
if deps.Condition.Product != nil {
|
expression[fields.DiscountCondition.Product] = *deps.Condition.Product
|
||||||
expression[fields.DiscountCondition.Product] = *deps.Condition.Product
|
}
|
||||||
}
|
|
||||||
|
if deps.Condition.PriceFrom != nil {
|
||||||
if deps.Condition.PriceFrom != nil {
|
expression[fields.DiscountCondition.PriceFrom] = *deps.Condition.PriceFrom
|
||||||
expression[fields.DiscountCondition.PriceFrom] = *deps.Condition.PriceFrom
|
}
|
||||||
}
|
|
||||||
|
if deps.Condition.Group != nil {
|
||||||
if deps.Condition.Group != nil {
|
expression[fields.DiscountCondition.Group] = *deps.Condition.Group
|
||||||
expression[fields.DiscountCondition.Group] = *deps.Condition.Group
|
}
|
||||||
}
|
|
||||||
|
if deps.Condition.User != nil {
|
||||||
if deps.Condition.User != nil {
|
expression[fields.DiscountCondition.User] = *deps.Condition.User
|
||||||
expression[fields.DiscountCondition.User] = *deps.Condition.User
|
}
|
||||||
}
|
|
||||||
|
if deps.Condition.UserType != nil {
|
||||||
if deps.Condition.UserType != nil {
|
expression[fields.DiscountCondition.UserType] = *deps.Condition.UserType
|
||||||
expression[fields.DiscountCondition.UserType] = *deps.Condition.UserType
|
}
|
||||||
}
|
|
||||||
|
if deps.Condition.Coupon != nil {
|
||||||
if deps.Condition.Coupon != nil {
|
expression[fields.DiscountCondition.Coupon] = *deps.Condition.Coupon
|
||||||
expression[fields.DiscountCondition.Coupon] = *deps.Condition.Coupon
|
}
|
||||||
}
|
|
||||||
|
if deps.Condition.PurchasesAmount != nil {
|
||||||
if deps.Condition.PurchasesAmount != nil {
|
expression[fields.DiscountCondition.PurchasesAmount] = *deps.Condition.PurchasesAmount
|
||||||
expression[fields.DiscountCondition.PurchasesAmount] = *deps.Condition.PurchasesAmount
|
}
|
||||||
}
|
|
||||||
|
if deps.Condition.CartPurchasesAmount != nil {
|
||||||
if deps.Condition.CartPurchasesAmount != nil {
|
expression[fields.DiscountCondition.CartPurchasesAmount] = *deps.Condition.CartPurchasesAmount
|
||||||
expression[fields.DiscountCondition.CartPurchasesAmount] = *deps.Condition.CartPurchasesAmount
|
}
|
||||||
}
|
|
||||||
|
if deps.Condition.Term != nil {
|
||||||
if deps.Condition.Term != nil {
|
expression[fields.DiscountCondition.Term] = *deps.Condition.Term
|
||||||
expression[fields.DiscountCondition.Term] = *deps.Condition.Term
|
}
|
||||||
}
|
|
||||||
|
if deps.Condition.Usage != nil {
|
||||||
if deps.Condition.Usage != nil {
|
expression[fields.DiscountCondition.Usage] = *deps.Condition.Usage
|
||||||
expression[fields.DiscountCondition.Usage] = *deps.Condition.Usage
|
}
|
||||||
}
|
|
||||||
|
return expression
|
||||||
return expression
|
}
|
||||||
}
|
|
||||||
|
func getDiscountTargetExpression(deps *core.FilterDiscountSettings) bson.M {
|
||||||
func getDiscountTargetExpression(deps *core.FilterDiscountSettings) bson.M {
|
expression := bson.M{}
|
||||||
expression := bson.M{}
|
|
||||||
|
if deps.Products != nil {
|
||||||
if deps.Products != nil {
|
expression[fields.DiscountTarget.Products] = *deps.Products
|
||||||
expression[fields.DiscountTarget.Products] = *deps.Products
|
}
|
||||||
}
|
|
||||||
|
if deps.Factor != nil {
|
||||||
if deps.Factor != nil {
|
expression[fields.DiscountTarget.Factor] = *deps.Factor
|
||||||
expression[fields.DiscountTarget.Factor] = *deps.Factor
|
}
|
||||||
}
|
|
||||||
|
if deps.TargetScope != nil {
|
||||||
if deps.TargetScope != nil {
|
expression[fields.DiscountTarget.TargetScope] = *deps.TargetScope
|
||||||
expression[fields.DiscountTarget.TargetScope] = *deps.TargetScope
|
}
|
||||||
}
|
|
||||||
|
if deps.TargetGroup != nil {
|
||||||
if deps.TargetGroup != nil {
|
expression[fields.DiscountTarget.TargetGroup] = *deps.TargetGroup
|
||||||
expression[fields.DiscountTarget.TargetGroup] = *deps.TargetGroup
|
}
|
||||||
}
|
|
||||||
|
if deps.Overhelm != nil {
|
||||||
if deps.Overhelm != nil {
|
expression[fields.DiscountTarget.Overhelm] = *deps.Overhelm
|
||||||
expression[fields.DiscountTarget.Overhelm] = *deps.Overhelm
|
}
|
||||||
}
|
|
||||||
|
return expression
|
||||||
return expression
|
}
|
||||||
}
|
|
||||||
|
@ -1,122 +1,121 @@
|
|||||||
package discount_test
|
package discount_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression/discount"
|
)
|
||||||
)
|
|
||||||
|
func TestGetDiscountExpression(t *testing.T) {
|
||||||
func TestGetDiscountExpression(t *testing.T) {
|
id := "id1"
|
||||||
id := "id1"
|
name := "discount1oo"
|
||||||
name := "discount"
|
description := ""
|
||||||
description := ""
|
layer := uint32(3)
|
||||||
layer := uint32(3)
|
deprecated := false
|
||||||
deprecated := false
|
user := "testUser3"
|
||||||
user := "testUser"
|
userType := "nkvo090909"
|
||||||
userType := "nkvo"
|
coupon := "coupon14"
|
||||||
coupon := "coupon1"
|
product := "p12"
|
||||||
product := "p1"
|
priceFrom := uint64(200)
|
||||||
priceFrom := float64(200)
|
cartPurchasesAmount := uint64(20000)
|
||||||
cartPurchasesAmount := float64(20000)
|
purchasesAmount := uint64(10000)
|
||||||
purchasesAmount := float64(10000)
|
usage := uint64(20)
|
||||||
usage := uint64(20)
|
term := uint64(40)
|
||||||
term := uint64(40)
|
factor := 0.95
|
||||||
factor := 0.95
|
targetScope := models.TargetSum
|
||||||
targetScope := models.TargetSum
|
targetGroup := "groupffffff"
|
||||||
targetGroup := "group"
|
overhelm := true
|
||||||
overhelm := true
|
condition := models.DiscountCondition{
|
||||||
condition := models.DiscountCondition{
|
User: &user,
|
||||||
User: &user,
|
Product: &product,
|
||||||
Product: &product,
|
PriceFrom: &priceFrom,
|
||||||
PriceFrom: &priceFrom,
|
Group: &targetGroup,
|
||||||
Group: &targetGroup,
|
Usage: &usage,
|
||||||
Usage: &usage,
|
UserType: &userType,
|
||||||
UserType: &userType,
|
Coupon: &coupon,
|
||||||
Coupon: &coupon,
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
PurchasesAmount: &purchasesAmount,
|
||||||
PurchasesAmount: &purchasesAmount,
|
Term: &term,
|
||||||
Term: &term,
|
Period: &models.PeriodCondition{
|
||||||
Period: &models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
}
|
||||||
}
|
products := []models.ProductTarget{
|
||||||
products := []models.ProductTarget{
|
{
|
||||||
{
|
ID: "p1",
|
||||||
ID: "p1",
|
Factor: 0.42,
|
||||||
Factor: 0.42,
|
Overhelm: false,
|
||||||
Overhelm: false,
|
},
|
||||||
},
|
}
|
||||||
}
|
|
||||||
|
t.Run("Формирование запроса фильтрации с пустыми параметрами", func(t *testing.T) {
|
||||||
t.Run("Формирование запроса фильтрации с пустыми параметрами", func(t *testing.T) {
|
assert.Nil(t, discount.GetDiscountExpression(&core.FilterDiscountSettings{}))
|
||||||
assert.Nil(t, discount.GetDiscountExpression(&core.FilterDiscountSettings{}))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование запроса фильтрации с nil", func(t *testing.T) {
|
||||||
t.Run("Формирование запроса фильтрации с nil", func(t *testing.T) {
|
assert.Nil(t, discount.GetDiscountExpression(nil))
|
||||||
assert.Nil(t, discount.GetDiscountExpression(nil))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование запроса фильтрации с заполненными параметрами", func(t *testing.T) {
|
||||||
t.Run("Формирование запроса фильтрации с заполненными параметрами", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&bson.M{
|
||||||
&bson.M{
|
fields.Discount.ID: id,
|
||||||
fields.Discount.ID: id,
|
fields.Discount.Name: name,
|
||||||
fields.Discount.Name: name,
|
fields.Discount.Description: description,
|
||||||
fields.Discount.Description: description,
|
fields.Discount.Layer: layer,
|
||||||
fields.Discount.Layer: layer,
|
fields.Discount.Deprecated: deprecated,
|
||||||
fields.Discount.Deprecated: deprecated,
|
fields.PeriodCondition.From: primitive.NewDateTimeFromTime(time.Unix(1674546287, 0).UTC()),
|
||||||
fields.PeriodCondition.From: primitive.NewDateTimeFromTime(time.Unix(1674546287, 0).UTC()),
|
fields.PeriodCondition.To: primitive.NewDateTimeFromTime(time.Unix(1674546287, 0).UTC()),
|
||||||
fields.PeriodCondition.To: primitive.NewDateTimeFromTime(time.Unix(1674546287, 0).UTC()),
|
fields.DiscountCondition.Product: product,
|
||||||
fields.DiscountCondition.Product: product,
|
fields.DiscountCondition.PriceFrom: priceFrom,
|
||||||
fields.DiscountCondition.PriceFrom: priceFrom,
|
fields.DiscountCondition.PurchasesAmount: purchasesAmount,
|
||||||
fields.DiscountCondition.PurchasesAmount: purchasesAmount,
|
fields.DiscountCondition.CartPurchasesAmount: cartPurchasesAmount,
|
||||||
fields.DiscountCondition.CartPurchasesAmount: cartPurchasesAmount,
|
fields.DiscountCondition.Group: targetGroup,
|
||||||
fields.DiscountCondition.Group: targetGroup,
|
fields.DiscountCondition.Usage: usage,
|
||||||
fields.DiscountCondition.Usage: usage,
|
fields.DiscountCondition.User: user,
|
||||||
fields.DiscountCondition.User: user,
|
fields.DiscountCondition.UserType: userType,
|
||||||
fields.DiscountCondition.UserType: userType,
|
fields.DiscountCondition.Coupon: coupon,
|
||||||
fields.DiscountCondition.Coupon: coupon,
|
fields.DiscountCondition.Term: term,
|
||||||
fields.DiscountCondition.Term: term,
|
fields.DiscountTarget.TargetGroup: targetGroup,
|
||||||
fields.DiscountTarget.TargetGroup: targetGroup,
|
fields.DiscountTarget.TargetScope: targetScope,
|
||||||
fields.DiscountTarget.TargetScope: targetScope,
|
fields.DiscountTarget.Factor: factor,
|
||||||
fields.DiscountTarget.Factor: factor,
|
fields.DiscountTarget.Overhelm: overhelm,
|
||||||
fields.DiscountTarget.Overhelm: overhelm,
|
fields.DiscountTarget.Products: products,
|
||||||
fields.DiscountTarget.Products: products,
|
},
|
||||||
},
|
discount.GetDiscountExpression(&core.FilterDiscountSettings{
|
||||||
discount.GetDiscountExpression(&core.FilterDiscountSettings{
|
ID: &id,
|
||||||
ID: &id,
|
Name: &name,
|
||||||
Name: &name,
|
Description: &description,
|
||||||
Description: &description,
|
Layer: &layer,
|
||||||
Layer: &layer,
|
Deprecated: &deprecated,
|
||||||
Deprecated: &deprecated,
|
Factor: &factor,
|
||||||
Factor: &factor,
|
TargetScope: &targetScope,
|
||||||
TargetScope: &targetScope,
|
TargetGroup: &targetGroup,
|
||||||
TargetGroup: &targetGroup,
|
Overhelm: &overhelm,
|
||||||
Overhelm: &overhelm,
|
Condition: &condition,
|
||||||
Condition: &condition,
|
Products: &products,
|
||||||
Products: &products,
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование запроса фильтрации с отсутствующими параметрами", func(t *testing.T) {
|
||||||
t.Run("Формирование запроса фильтрации с отсутствующими параметрами", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&bson.M{
|
||||||
&bson.M{
|
fields.Discount.Name: name,
|
||||||
fields.Discount.Name: name,
|
fields.Discount.Description: description,
|
||||||
fields.Discount.Description: description,
|
},
|
||||||
},
|
discount.GetDiscountExpression(&core.FilterDiscountSettings{
|
||||||
discount.GetDiscountExpression(&core.FilterDiscountSettings{
|
Name: &name,
|
||||||
Name: &name,
|
Description: &description,
|
||||||
Description: &description,
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
@ -1,72 +1,71 @@
|
|||||||
package discount
|
package discount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/convert"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/convert"
|
)
|
||||||
)
|
|
||||||
|
type UpdateDiscountExpression struct {
|
||||||
type UpdateDiscountExpression struct {
|
ID string
|
||||||
ID string
|
Expression *bson.M
|
||||||
Expression *bson.M
|
}
|
||||||
}
|
|
||||||
|
func GetUpdateDiscountsExpressions(deps []core.UpdateDiscountSettings) []UpdateDiscountExpression {
|
||||||
func GetUpdateDiscountsExpressions(deps []core.UpdateDiscountSettings) []UpdateDiscountExpression {
|
discounts := make([]UpdateDiscountExpression, 0, len(deps))
|
||||||
discounts := make([]UpdateDiscountExpression, 0, len(deps))
|
requestsMap := convert.ArrayToMap(deps, func(element core.UpdateDiscountSettings) string {
|
||||||
requestsMap := convert.ArrayToMap(deps, func(element core.UpdateDiscountSettings) string {
|
return element.ID
|
||||||
return element.ID
|
})
|
||||||
})
|
|
||||||
|
for _, request := range requestsMap {
|
||||||
for _, request := range requestsMap {
|
updateExpression := GetUpdateDiscountExpression(&core.UpdateDiscountSettings{
|
||||||
updateExpression := GetUpdateDiscountExpression(&core.UpdateDiscountSettings{
|
ID: request.ID,
|
||||||
ID: request.ID,
|
Name: request.Name,
|
||||||
Name: request.Name,
|
Description: request.Description,
|
||||||
Description: request.Description,
|
Layer: request.Layer,
|
||||||
Layer: request.Layer,
|
Deprecated: request.Deprecated,
|
||||||
Deprecated: request.Deprecated,
|
Factor: request.Factor,
|
||||||
Factor: request.Factor,
|
TargetScope: request.TargetScope,
|
||||||
TargetScope: request.TargetScope,
|
TargetGroup: request.TargetGroup,
|
||||||
TargetGroup: request.TargetGroup,
|
Overhelm: request.Overhelm,
|
||||||
Overhelm: request.Overhelm,
|
Condition: request.Condition,
|
||||||
Condition: request.Condition,
|
Products: request.Products,
|
||||||
Products: request.Products,
|
})
|
||||||
})
|
|
||||||
|
if updateExpression == nil {
|
||||||
if updateExpression == nil {
|
continue
|
||||||
continue
|
}
|
||||||
}
|
|
||||||
|
discounts = append(discounts, *updateExpression)
|
||||||
discounts = append(discounts, *updateExpression)
|
}
|
||||||
}
|
|
||||||
|
return discounts
|
||||||
return discounts
|
}
|
||||||
}
|
|
||||||
|
func GetUpdateDiscountExpression(deps *core.UpdateDiscountSettings) *UpdateDiscountExpression {
|
||||||
func GetUpdateDiscountExpression(deps *core.UpdateDiscountSettings) *UpdateDiscountExpression {
|
if deps == nil {
|
||||||
if deps == nil {
|
return nil
|
||||||
return nil
|
}
|
||||||
}
|
|
||||||
|
updateExpression := GetDiscountExpression(&core.FilterDiscountSettings{
|
||||||
updateExpression := GetDiscountExpression(&core.FilterDiscountSettings{
|
Condition: deps.Condition,
|
||||||
Condition: deps.Condition,
|
Name: deps.Name,
|
||||||
Name: deps.Name,
|
Description: deps.Description,
|
||||||
Description: deps.Description,
|
Layer: deps.Layer,
|
||||||
Layer: deps.Layer,
|
Deprecated: deps.Deprecated,
|
||||||
Deprecated: deps.Deprecated,
|
Products: deps.Products,
|
||||||
Products: deps.Products,
|
Factor: deps.Factor,
|
||||||
Factor: deps.Factor,
|
TargetScope: deps.TargetScope,
|
||||||
TargetScope: deps.TargetScope,
|
TargetGroup: deps.TargetGroup,
|
||||||
TargetGroup: deps.TargetGroup,
|
Overhelm: deps.Overhelm,
|
||||||
Overhelm: deps.Overhelm,
|
})
|
||||||
})
|
|
||||||
|
if updateExpression == nil {
|
||||||
if updateExpression == nil {
|
return nil
|
||||||
return nil
|
}
|
||||||
}
|
|
||||||
|
return &UpdateDiscountExpression{
|
||||||
return &UpdateDiscountExpression{
|
ID: deps.ID,
|
||||||
ID: deps.ID,
|
Expression: &bson.M{"$set": *updateExpression},
|
||||||
Expression: &bson.M{"$set": *updateExpression},
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -1,185 +1,184 @@
|
|||||||
package discount_test
|
package discount_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/fields"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/expression/discount"
|
)
|
||||||
)
|
|
||||||
|
func TestGetUpdateDiscountExpression(t *testing.T) {
|
||||||
func TestGetUpdateDiscountExpression(t *testing.T) {
|
name := "discount"
|
||||||
name := "discount"
|
description := ""
|
||||||
description := ""
|
layer := uint32(3)
|
||||||
layer := uint32(3)
|
deprecated := false
|
||||||
deprecated := false
|
user := "testUser"
|
||||||
user := "testUser"
|
userType := "nkvo"
|
||||||
userType := "nkvo"
|
coupon := "coupon1"
|
||||||
coupon := "coupon1"
|
product := "p1"
|
||||||
product := "p1"
|
priceFrom := uint64(200)
|
||||||
priceFrom := float64(200)
|
cartPurchasesAmount := uint64(20000)
|
||||||
cartPurchasesAmount := float64(20000)
|
purchasesAmount := uint64(10000)
|
||||||
purchasesAmount := float64(10000)
|
usage := uint64(20)
|
||||||
usage := uint64(20)
|
term := uint64(40)
|
||||||
term := uint64(40)
|
factor := 0.95
|
||||||
factor := 0.95
|
targetScope := models.TargetSum
|
||||||
targetScope := models.TargetSum
|
targetGroup := "group"
|
||||||
targetGroup := "group"
|
overhelm := true
|
||||||
overhelm := true
|
condition := models.DiscountCondition{
|
||||||
condition := models.DiscountCondition{
|
User: &user,
|
||||||
User: &user,
|
Product: &product,
|
||||||
Product: &product,
|
PriceFrom: &priceFrom,
|
||||||
PriceFrom: &priceFrom,
|
Group: &targetGroup,
|
||||||
Group: &targetGroup,
|
Usage: &usage,
|
||||||
Usage: &usage,
|
UserType: &userType,
|
||||||
UserType: &userType,
|
Coupon: &coupon,
|
||||||
Coupon: &coupon,
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
PurchasesAmount: &purchasesAmount,
|
||||||
PurchasesAmount: &purchasesAmount,
|
Term: &term,
|
||||||
Term: &term,
|
Period: &models.PeriodCondition{
|
||||||
Period: &models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
}
|
||||||
}
|
products := []models.ProductTarget{
|
||||||
products := []models.ProductTarget{
|
{
|
||||||
{
|
ID: "p1",
|
||||||
ID: "p1",
|
Factor: 0.42,
|
||||||
Factor: 0.42,
|
Overhelm: false,
|
||||||
Overhelm: false,
|
},
|
||||||
},
|
}
|
||||||
}
|
|
||||||
|
t.Run("Формирование запроса обновления с пустыми параметрами", func(t *testing.T) {
|
||||||
t.Run("Формирование запроса обновления с пустыми параметрами", func(t *testing.T) {
|
assert.Nil(t, discount.GetUpdateDiscountExpression(&core.UpdateDiscountSettings{}))
|
||||||
assert.Nil(t, discount.GetUpdateDiscountExpression(&core.UpdateDiscountSettings{}))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование запроса обновления с nil", func(t *testing.T) {
|
||||||
t.Run("Формирование запроса обновления с nil", func(t *testing.T) {
|
assert.Nil(t, discount.GetUpdateDiscountExpression(nil))
|
||||||
assert.Nil(t, discount.GetUpdateDiscountExpression(nil))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование запроса обновления с заполненными параметрами", func(t *testing.T) {
|
||||||
t.Run("Формирование запроса обновления с заполненными параметрами", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&discount.UpdateDiscountExpression{
|
||||||
&discount.UpdateDiscountExpression{
|
ID: "test",
|
||||||
ID: "test",
|
Expression: &bson.M{
|
||||||
Expression: &bson.M{
|
"$set": bson.M{
|
||||||
"$set": bson.M{
|
fields.Discount.Name: name,
|
||||||
fields.Discount.Name: name,
|
fields.Discount.Description: description,
|
||||||
fields.Discount.Description: description,
|
fields.Discount.Layer: layer,
|
||||||
fields.Discount.Layer: layer,
|
fields.Discount.Deprecated: deprecated,
|
||||||
fields.Discount.Deprecated: deprecated,
|
fields.PeriodCondition.From: primitive.NewDateTimeFromTime(time.Unix(1674546287, 0).UTC()),
|
||||||
fields.PeriodCondition.From: primitive.NewDateTimeFromTime(time.Unix(1674546287, 0).UTC()),
|
fields.PeriodCondition.To: primitive.NewDateTimeFromTime(time.Unix(1674546287, 0).UTC()),
|
||||||
fields.PeriodCondition.To: primitive.NewDateTimeFromTime(time.Unix(1674546287, 0).UTC()),
|
fields.DiscountCondition.Product: product,
|
||||||
fields.DiscountCondition.Product: product,
|
fields.DiscountCondition.PriceFrom: priceFrom,
|
||||||
fields.DiscountCondition.PriceFrom: priceFrom,
|
fields.DiscountCondition.PurchasesAmount: purchasesAmount,
|
||||||
fields.DiscountCondition.PurchasesAmount: purchasesAmount,
|
fields.DiscountCondition.CartPurchasesAmount: cartPurchasesAmount,
|
||||||
fields.DiscountCondition.CartPurchasesAmount: cartPurchasesAmount,
|
fields.DiscountCondition.Group: targetGroup,
|
||||||
fields.DiscountCondition.Group: targetGroup,
|
fields.DiscountCondition.Usage: usage,
|
||||||
fields.DiscountCondition.Usage: usage,
|
fields.DiscountCondition.User: user,
|
||||||
fields.DiscountCondition.User: user,
|
fields.DiscountCondition.UserType: userType,
|
||||||
fields.DiscountCondition.UserType: userType,
|
fields.DiscountCondition.Coupon: coupon,
|
||||||
fields.DiscountCondition.Coupon: coupon,
|
fields.DiscountCondition.Term: term,
|
||||||
fields.DiscountCondition.Term: term,
|
fields.DiscountTarget.TargetGroup: targetGroup,
|
||||||
fields.DiscountTarget.TargetGroup: targetGroup,
|
fields.DiscountTarget.TargetScope: targetScope,
|
||||||
fields.DiscountTarget.TargetScope: targetScope,
|
fields.DiscountTarget.Factor: factor,
|
||||||
fields.DiscountTarget.Factor: factor,
|
fields.DiscountTarget.Overhelm: overhelm,
|
||||||
fields.DiscountTarget.Overhelm: overhelm,
|
fields.DiscountTarget.Products: products,
|
||||||
fields.DiscountTarget.Products: products,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
discount.GetUpdateDiscountExpression(&core.UpdateDiscountSettings{
|
||||||
discount.GetUpdateDiscountExpression(&core.UpdateDiscountSettings{
|
ID: "test",
|
||||||
ID: "test",
|
Name: &name,
|
||||||
Name: &name,
|
Description: &description,
|
||||||
Description: &description,
|
Layer: &layer,
|
||||||
Layer: &layer,
|
Deprecated: &deprecated,
|
||||||
Deprecated: &deprecated,
|
Factor: &factor,
|
||||||
Factor: &factor,
|
TargetScope: &targetScope,
|
||||||
TargetScope: &targetScope,
|
TargetGroup: &targetGroup,
|
||||||
TargetGroup: &targetGroup,
|
Overhelm: &overhelm,
|
||||||
Overhelm: &overhelm,
|
Condition: &condition,
|
||||||
Condition: &condition,
|
Products: &products,
|
||||||
Products: &products,
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование запроса обновления с отсутствующими параметрами", func(t *testing.T) {
|
||||||
t.Run("Формирование запроса обновления с отсутствующими параметрами", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&discount.UpdateDiscountExpression{
|
||||||
&discount.UpdateDiscountExpression{
|
Expression: &bson.M{
|
||||||
Expression: &bson.M{
|
"$set": bson.M{
|
||||||
"$set": bson.M{
|
fields.Discount.Name: name,
|
||||||
fields.Discount.Name: name,
|
fields.Discount.Description: description,
|
||||||
fields.Discount.Description: description,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
discount.GetUpdateDiscountExpression(&core.UpdateDiscountSettings{
|
||||||
discount.GetUpdateDiscountExpression(&core.UpdateDiscountSettings{
|
Name: &name,
|
||||||
Name: &name,
|
Description: &description,
|
||||||
Description: &description,
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
func TestGetUpdateDiscountsExpressions(t *testing.T) {
|
||||||
func TestGetUpdateDiscountsExpressions(t *testing.T) {
|
name1 := "discount1"
|
||||||
name1 := "discount1"
|
name2 := "discount2"
|
||||||
name2 := "discount2"
|
description := ""
|
||||||
description := ""
|
|
||||||
|
t.Run("Формирование запросов обновления с пустым массивом", func(t *testing.T) {
|
||||||
t.Run("Формирование запросов обновления с пустым массивом", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
[]discount.UpdateDiscountExpression{},
|
||||||
[]discount.UpdateDiscountExpression{},
|
discount.GetUpdateDiscountsExpressions([]core.UpdateDiscountSettings{}),
|
||||||
discount.GetUpdateDiscountsExpressions([]core.UpdateDiscountSettings{}),
|
)
|
||||||
)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Формирование запроса обновления с отсутствующими и пустыми параметрами, а также с одинаковыми ID", func(t *testing.T) {
|
||||||
t.Run("Формирование запроса обновления с отсутствующими и пустыми параметрами, а также с одинаковыми ID", func(t *testing.T) {
|
assert.ElementsMatch(t,
|
||||||
assert.ElementsMatch(t,
|
[]discount.UpdateDiscountExpression{
|
||||||
[]discount.UpdateDiscountExpression{
|
{
|
||||||
{
|
ID: "discount1",
|
||||||
ID: "discount1",
|
Expression: &bson.M{
|
||||||
Expression: &bson.M{
|
"$set": bson.M{
|
||||||
"$set": bson.M{
|
fields.Discount.Name: name1,
|
||||||
fields.Discount.Name: name1,
|
fields.Discount.Description: description,
|
||||||
fields.Discount.Description: description,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "discount2",
|
||||||
ID: "discount2",
|
Expression: &bson.M{
|
||||||
Expression: &bson.M{
|
"$set": bson.M{
|
||||||
"$set": bson.M{
|
fields.Discount.Name: name2,
|
||||||
fields.Discount.Name: name2,
|
fields.Discount.Description: description,
|
||||||
fields.Discount.Description: description,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
discount.GetUpdateDiscountsExpressions([]core.UpdateDiscountSettings{
|
||||||
discount.GetUpdateDiscountsExpressions([]core.UpdateDiscountSettings{
|
{
|
||||||
{
|
ID: "discount1",
|
||||||
ID: "discount1",
|
Name: &name2,
|
||||||
Name: &name2,
|
Description: &description,
|
||||||
Description: &description,
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "discount1",
|
||||||
ID: "discount1",
|
Name: &name1,
|
||||||
Name: &name1,
|
Description: &description,
|
||||||
Description: &description,
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "discount2",
|
||||||
ID: "discount2",
|
Name: &name2,
|
||||||
Name: &name2,
|
Description: &description,
|
||||||
Description: &description,
|
},
|
||||||
},
|
{},
|
||||||
{},
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
@ -1,30 +1,32 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FilterCouponDiscounts(discounts []models.Discount) ([]models.Discount, *models.Discount) {
|
func FilterCouponDiscounts(discounts []models.Discount) ([]models.Discount, *models.Discount) {
|
||||||
if len(discounts) == 0 {
|
if len(discounts) == 0 {
|
||||||
return []models.Discount{}, nil
|
return []models.Discount{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var couponDiscount *models.Discount
|
var couponDiscount *models.Discount
|
||||||
notCouponDiscount := make([]models.Discount, 0, len(discounts))
|
|
||||||
|
notCouponDiscount := make([]models.Discount, 0, len(discounts))
|
||||||
for _, discount := range discounts {
|
|
||||||
isCouponDiscount := discount.Condition.Coupon != nil && *discount.Condition.Coupon != ""
|
for _, discount := range discounts {
|
||||||
currentDiscount := discount
|
isCouponDiscount := discount.Condition.Coupon != nil && *discount.Condition.Coupon != ""
|
||||||
|
currentDiscount := discount
|
||||||
if isCouponDiscount && couponDiscount != nil {
|
|
||||||
continue
|
if isCouponDiscount && couponDiscount != nil {
|
||||||
}
|
continue
|
||||||
if isCouponDiscount && couponDiscount == nil {
|
}
|
||||||
couponDiscount = ¤tDiscount
|
|
||||||
}
|
if isCouponDiscount && couponDiscount == nil {
|
||||||
|
couponDiscount = ¤tDiscount
|
||||||
notCouponDiscount = append(notCouponDiscount, discount)
|
}
|
||||||
}
|
|
||||||
|
notCouponDiscount = append(notCouponDiscount, discount)
|
||||||
return notCouponDiscount, couponDiscount
|
}
|
||||||
}
|
|
||||||
|
return notCouponDiscount, couponDiscount
|
||||||
|
}
|
||||||
|
@ -1,48 +1,47 @@
|
|||||||
package utils_test
|
package utils_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils"
|
)
|
||||||
)
|
|
||||||
|
func TestFilterDiscounts(t *testing.T) {
|
||||||
func TestFilterDiscounts(t *testing.T) {
|
coupon1 := "testCoupon1"
|
||||||
coupon1 := "testCoupon1"
|
coupon2 := "testCoupon2"
|
||||||
coupon2 := "testCoupon2"
|
user := "user1"
|
||||||
user := "user1"
|
|
||||||
|
t.Run("Корректная фильтрация купоночных скидок", func(t *testing.T) {
|
||||||
t.Run("Корректная фильтрация купоночных скидок", func(t *testing.T) {
|
filteredDiscounts, couponDiscount := utils.FilterCouponDiscounts([]models.Discount{
|
||||||
filteredDiscounts, couponDiscount := utils.FilterCouponDiscounts([]models.Discount{
|
{Name: "1", Condition: models.DiscountCondition{Coupon: &coupon1}},
|
||||||
{Name: "1", Condition: models.DiscountCondition{Coupon: &coupon1}},
|
{Name: "11", Condition: models.DiscountCondition{Coupon: &coupon2}},
|
||||||
{Name: "11", Condition: models.DiscountCondition{Coupon: &coupon2}},
|
{Name: "2", Condition: models.DiscountCondition{User: &user}},
|
||||||
{Name: "2", Condition: models.DiscountCondition{User: &user}},
|
{Name: "3"},
|
||||||
{Name: "3"},
|
{Name: "4"},
|
||||||
{Name: "4"},
|
})
|
||||||
})
|
|
||||||
|
assert.ElementsMatch(t, []models.Discount{
|
||||||
assert.ElementsMatch(t, []models.Discount{
|
{Name: "1", Condition: models.DiscountCondition{Coupon: &coupon1}},
|
||||||
{Name: "1", Condition: models.DiscountCondition{Coupon: &coupon1}},
|
{Name: "2", Condition: models.DiscountCondition{User: &user}},
|
||||||
{Name: "2", Condition: models.DiscountCondition{User: &user}},
|
{Name: "3"},
|
||||||
{Name: "3"},
|
{Name: "4"},
|
||||||
{Name: "4"},
|
}, filteredDiscounts)
|
||||||
}, filteredDiscounts)
|
assert.Equal(t, &models.Discount{Name: "1", Condition: models.DiscountCondition{Coupon: &coupon1}}, couponDiscount)
|
||||||
assert.Equal(t, &models.Discount{Name: "1", Condition: models.DiscountCondition{Coupon: &coupon1}}, couponDiscount)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Корректная фильтрация купоночных скидок с пустым значением", func(t *testing.T) {
|
||||||
t.Run("Корректная фильтрация купоночных скидок с пустым значением", func(t *testing.T) {
|
filteredDiscounts, couponDiscount := utils.FilterCouponDiscounts([]models.Discount{})
|
||||||
filteredDiscounts, couponDiscount := utils.FilterCouponDiscounts([]models.Discount{})
|
|
||||||
|
assert.Equal(t, []models.Discount{}, filteredDiscounts)
|
||||||
assert.Equal(t, []models.Discount{}, filteredDiscounts)
|
assert.Nil(t, couponDiscount)
|
||||||
assert.Nil(t, couponDiscount)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Корректная фильтрация купоночных скидок без купоночной скидки", func(t *testing.T) {
|
||||||
t.Run("Корректная фильтрация купоночных скидок без купоночной скидки", func(t *testing.T) {
|
filteredDiscounts, couponDiscount := utils.FilterCouponDiscounts([]models.Discount{{}})
|
||||||
filteredDiscounts, couponDiscount := utils.FilterCouponDiscounts([]models.Discount{{}})
|
|
||||||
|
assert.Equal(t, []models.Discount{{}}, filteredDiscounts)
|
||||||
assert.Equal(t, []models.Discount{{}}, filteredDiscounts)
|
assert.Nil(t, couponDiscount)
|
||||||
assert.Nil(t, couponDiscount)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
@ -1,51 +1,50 @@
|
|||||||
package transfer
|
package transfer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
)
|
||||||
)
|
|
||||||
|
func AuditModelToProto(model *models.Audit) *discount.Audit {
|
||||||
func AuditModelToProto(model *models.Audit) *discount.Audit {
|
proto := discount.Audit{}
|
||||||
proto := discount.Audit{}
|
|
||||||
|
if model == nil {
|
||||||
if model == nil {
|
return &proto
|
||||||
return &proto
|
}
|
||||||
}
|
|
||||||
|
proto.CreatedAt = timestamppb.New(model.CreatedAt)
|
||||||
proto.CreatedAt = timestamppb.New(model.CreatedAt)
|
proto.UpdatedAt = timestamppb.New(model.UpdatedAt)
|
||||||
proto.UpdatedAt = timestamppb.New(model.UpdatedAt)
|
|
||||||
|
if model.DeletedAt != nil {
|
||||||
if model.DeletedAt != nil {
|
proto.DeletedAt = timestamppb.New(*model.DeletedAt)
|
||||||
proto.DeletedAt = timestamppb.New(*model.DeletedAt)
|
proto.Deleted = true
|
||||||
proto.Deleted = true
|
}
|
||||||
}
|
|
||||||
|
return &proto
|
||||||
return &proto
|
}
|
||||||
}
|
|
||||||
|
func AuditProtoToModel(proto *discount.Audit) *models.Audit {
|
||||||
func AuditProtoToModel(proto *discount.Audit) *models.Audit {
|
model := models.Audit{}
|
||||||
model := models.Audit{}
|
|
||||||
|
if proto == nil {
|
||||||
if proto == nil {
|
return &model
|
||||||
return &model
|
}
|
||||||
}
|
|
||||||
|
if proto.GetCreatedAt() != nil {
|
||||||
if proto.GetCreatedAt() != nil {
|
model.CreatedAt = proto.GetCreatedAt().AsTime()
|
||||||
model.CreatedAt = proto.GetCreatedAt().AsTime()
|
}
|
||||||
}
|
|
||||||
|
if proto.GetUpdatedAt() != nil {
|
||||||
if proto.GetUpdatedAt() != nil {
|
model.UpdatedAt = proto.GetUpdatedAt().AsTime()
|
||||||
model.UpdatedAt = proto.GetUpdatedAt().AsTime()
|
}
|
||||||
}
|
|
||||||
|
if proto.GetDeletedAt() != nil {
|
||||||
if proto.GetDeletedAt() != nil {
|
deletedAt := proto.GetDeletedAt().AsTime()
|
||||||
deletedAt := proto.GetDeletedAt().AsTime()
|
model.DeletedAt = &deletedAt
|
||||||
model.DeletedAt = &deletedAt
|
}
|
||||||
}
|
|
||||||
|
model.Deleted = proto.GetDeleted()
|
||||||
model.Deleted = proto.GetDeleted()
|
|
||||||
|
return &model
|
||||||
return &model
|
}
|
||||||
}
|
|
||||||
|
@ -1,135 +1,134 @@
|
|||||||
package transfer_test
|
package transfer_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
)
|
||||||
)
|
|
||||||
|
func TestAuditModelToProto(t *testing.T) {
|
||||||
func TestAuditModelToProto(t *testing.T) {
|
deletedAtModel := time.Unix(1674546287, 0).UTC()
|
||||||
deletedAtModel := time.Unix(1674546287, 0).UTC()
|
deletedAtProto := timestamppb.Timestamp{Seconds: 1674546287}
|
||||||
deletedAtProto := timestamppb.Timestamp{Seconds: 1674546287}
|
|
||||||
|
t.Run("Перевод аудита с пустой модели в прототип", func(t *testing.T) {
|
||||||
t.Run("Перевод аудита с пустой модели в прототип", func(t *testing.T) {
|
assert.Equal(t, &discount.Audit{
|
||||||
assert.Equal(t, &discount.Audit{
|
CreatedAt: timestamppb.New(time.Time{}),
|
||||||
CreatedAt: timestamppb.New(time.Time{}),
|
UpdatedAt: timestamppb.New(time.Time{}),
|
||||||
UpdatedAt: timestamppb.New(time.Time{}),
|
}, transfer.AuditModelToProto(&models.Audit{}))
|
||||||
}, transfer.AuditModelToProto(&models.Audit{}))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Перевод аудита с nil модели в прототип", func(t *testing.T) {
|
||||||
t.Run("Перевод аудита с nil модели в прототип", func(t *testing.T) {
|
assert.Equal(t, &discount.Audit{CreatedAt: nil, UpdatedAt: nil}, transfer.AuditModelToProto(nil))
|
||||||
assert.Equal(t, &discount.Audit{CreatedAt: nil, UpdatedAt: nil}, transfer.AuditModelToProto(nil))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Перевод аудита с модели, которая хранит дату удаления, но флаг deleted при этом false в прототип", func(t *testing.T) {
|
||||||
t.Run("Перевод аудита с модели, которая хранит дату удаления, но флаг deleted при этом false в прототип", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&discount.Audit{
|
||||||
&discount.Audit{
|
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
DeletedAt: &deletedAtProto,
|
||||||
DeletedAt: &deletedAtProto,
|
Deleted: true,
|
||||||
Deleted: true,
|
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
},
|
||||||
},
|
transfer.AuditModelToProto(&models.Audit{
|
||||||
transfer.AuditModelToProto(&models.Audit{
|
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
DeletedAt: &deletedAtModel,
|
||||||
DeletedAt: &deletedAtModel,
|
Deleted: false,
|
||||||
Deleted: false,
|
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Перевод аудита с модели, которая хранит флаг deleted равный true, но при этом не имеет даты удаления в прототип", func(t *testing.T) {
|
||||||
t.Run("Перевод аудита с модели, которая хранит флаг deleted равный true, но при этом не имеет даты удаления в прототип", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&discount.Audit{
|
||||||
&discount.Audit{
|
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
},
|
||||||
},
|
transfer.AuditModelToProto(&models.Audit{
|
||||||
transfer.AuditModelToProto(&models.Audit{
|
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
Deleted: true,
|
||||||
Deleted: true,
|
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Перевод аудита с модели без информации об удалении в прототип", func(t *testing.T) {
|
||||||
t.Run("Перевод аудита с модели без информации об удалении в прототип", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&discount.Audit{
|
||||||
&discount.Audit{
|
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
},
|
||||||
},
|
transfer.AuditModelToProto(&models.Audit{
|
||||||
transfer.AuditModelToProto(&models.Audit{
|
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Перевод аудита с модели в прототип", func(t *testing.T) {
|
||||||
t.Run("Перевод аудита с модели в прототип", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&discount.Audit{
|
||||||
&discount.Audit{
|
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
DeletedAt: &deletedAtProto,
|
||||||
DeletedAt: &deletedAtProto,
|
Deleted: true,
|
||||||
Deleted: true,
|
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
},
|
||||||
},
|
transfer.AuditModelToProto(&models.Audit{
|
||||||
transfer.AuditModelToProto(&models.Audit{
|
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
DeletedAt: &deletedAtModel,
|
||||||
DeletedAt: &deletedAtModel,
|
Deleted: true,
|
||||||
Deleted: true,
|
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
func TestAuditProtoToModel(t *testing.T) {
|
||||||
func TestAuditProtoToModel(t *testing.T) {
|
deletedAtModel := time.Unix(1674546287, 0).UTC()
|
||||||
deletedAtModel := time.Unix(1674546287, 0).UTC()
|
deletedAtProto := timestamppb.Timestamp{Seconds: 1674546287}
|
||||||
deletedAtProto := timestamppb.Timestamp{Seconds: 1674546287}
|
|
||||||
|
t.Run("Перевод аудита с пустого прототипа в модель", func(t *testing.T) {
|
||||||
t.Run("Перевод аудита с пустого прототипа в модель", func(t *testing.T) {
|
assert.Equal(t, &models.Audit{}, transfer.AuditProtoToModel(&discount.Audit{}))
|
||||||
assert.Equal(t, &models.Audit{}, transfer.AuditProtoToModel(&discount.Audit{}))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Перевод аудита с nil прототипа в модель", func(t *testing.T) {
|
||||||
t.Run("Перевод аудита с nil прототипа в модель", func(t *testing.T) {
|
assert.Equal(t, &models.Audit{}, transfer.AuditProtoToModel(nil))
|
||||||
assert.Equal(t, &models.Audit{}, transfer.AuditProtoToModel(nil))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Перевод аудита с прототипа без информации об удалении в модель", func(t *testing.T) {
|
||||||
t.Run("Перевод аудита с прототипа без информации об удалении в модель", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&models.Audit{
|
||||||
&models.Audit{
|
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
Deleted: true,
|
||||||
Deleted: true,
|
},
|
||||||
},
|
transfer.AuditProtoToModel(&discount.Audit{
|
||||||
transfer.AuditProtoToModel(&discount.Audit{
|
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
Deleted: true,
|
||||||
Deleted: true,
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Перевод аудита с прототипа в модель", func(t *testing.T) {
|
||||||
t.Run("Перевод аудита с прототипа в модель", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&models.Audit{
|
||||||
&models.Audit{
|
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
DeletedAt: &deletedAtModel,
|
||||||
DeletedAt: &deletedAtModel,
|
Deleted: true,
|
||||||
Deleted: true,
|
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
transfer.AuditProtoToModel(&discount.Audit{
|
||||||
transfer.AuditProtoToModel(&discount.Audit{
|
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
DeletedAt: &deletedAtProto,
|
||||||
DeletedAt: &deletedAtProto,
|
Deleted: true,
|
||||||
Deleted: true,
|
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
package transfer
|
package transfer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
proto "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
proto "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/defaults"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/defaults"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DiscountCalculationTargetProtoToModel(discountTarget *proto.DiscountCalculationTarget) *models.DiscountCalculationTarget {
|
func DiscountCalculationTargetProtoToModel(discountTarget *proto.DiscountCalculationTarget) *models.DiscountCalculationTarget {
|
||||||
if discountTarget == nil {
|
if discountTarget == nil {
|
||||||
return &models.DiscountCalculationTarget{TargetScope: models.TargetSum}
|
return &models.DiscountCalculationTarget{TargetScope: models.TargetSum}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &models.DiscountCalculationTarget{
|
return &models.DiscountCalculationTarget{
|
||||||
Products: ProductTargetsProtoToModel(discountTarget.Products),
|
Products: ProductTargetsProtoToModel(discountTarget.Products),
|
||||||
Factor: discountTarget.Factor,
|
Factor: discountTarget.Factor,
|
||||||
TargetScope: models.TargetScopeModelMap[defaults.GetDefaultValue(discountTarget.TargetScope, 0)],
|
TargetScope: models.TargetScopeModelMap[defaults.GetDefaultValue(discountTarget.TargetScope, 0)],
|
||||||
TargetGroup: defaults.GetDefaultValue(discountTarget.TargetGroup, ""),
|
TargetGroup: defaults.GetDefaultValue(discountTarget.TargetGroup, ""),
|
||||||
Overhelm: defaults.GetDefaultValue(discountTarget.Overhelm, false),
|
Overhelm: defaults.GetDefaultValue(discountTarget.Overhelm, false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DiscountCalculationTargetModelToProto(discountTarget models.DiscountCalculationTarget) *proto.DiscountCalculationTarget {
|
func DiscountCalculationTargetModelToProto(discountTarget models.DiscountCalculationTarget) *proto.DiscountCalculationTarget {
|
||||||
scope := models.TargetScopeProtoMap[discountTarget.TargetScope]
|
scope := models.TargetScopeProtoMap[discountTarget.TargetScope]
|
||||||
|
|
||||||
return &proto.DiscountCalculationTarget{
|
return &proto.DiscountCalculationTarget{
|
||||||
Products: ProductTargetsModelToProto(discountTarget.Products),
|
Products: ProductTargetsModelToProto(discountTarget.Products),
|
||||||
Factor: discountTarget.Factor,
|
Factor: discountTarget.Factor,
|
||||||
TargetScope: &scope,
|
TargetScope: &scope,
|
||||||
TargetGroup: &discountTarget.TargetGroup,
|
TargetGroup: &discountTarget.TargetGroup,
|
||||||
Overhelm: &discountTarget.Overhelm,
|
Overhelm: &discountTarget.Overhelm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,93 +1,93 @@
|
|||||||
package transfer_test
|
package transfer_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDiscountCalculationTargetProtoToModel(t *testing.T) {
|
func TestDiscountCalculationTargetProtoToModel(t *testing.T) {
|
||||||
t.Run("Перевод цели высчитывания из proto в модель", func(t *testing.T) {
|
t.Run("Перевод цели высчитывания из proto в модель", func(t *testing.T) {
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
&models.DiscountCalculationTarget{
|
&models.DiscountCalculationTarget{
|
||||||
TargetScope: models.TargetSum,
|
TargetScope: models.TargetSum,
|
||||||
Products: []models.ProductTarget{
|
Products: []models.ProductTarget{
|
||||||
{ID: "1", Factor: 20},
|
{ID: "1", Factor: 20},
|
||||||
{ID: "2", Factor: 20},
|
{ID: "2", Factor: 20},
|
||||||
{ID: "3", Factor: 10},
|
{ID: "3", Factor: 10},
|
||||||
},
|
},
|
||||||
Factor: 20,
|
Factor: 20,
|
||||||
},
|
},
|
||||||
transfer.DiscountCalculationTargetProtoToModel(&discount.DiscountCalculationTarget{
|
transfer.DiscountCalculationTargetProtoToModel(&discount.DiscountCalculationTarget{
|
||||||
TargetScope: discount.TargetScope_Sum.Enum(),
|
TargetScope: discount.TargetScope_Sum.Enum(),
|
||||||
Products: []*discount.ProductTarget{
|
Products: []*discount.ProductTarget{
|
||||||
{ID: "1", Factor: 20},
|
{ID: "1", Factor: 20},
|
||||||
{ID: "2", Factor: 20},
|
{ID: "2", Factor: 20},
|
||||||
{ID: "3", Factor: 10},
|
{ID: "3", Factor: 10},
|
||||||
},
|
},
|
||||||
Factor: 20,
|
Factor: 20,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Перевод цели высчитывания из proto в модель с пустынми данными", func(t *testing.T) {
|
t.Run("Перевод цели высчитывания из proto в модель с пустынми данными", func(t *testing.T) {
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
&models.DiscountCalculationTarget{
|
&models.DiscountCalculationTarget{
|
||||||
Products: []models.ProductTarget{},
|
Products: []models.ProductTarget{},
|
||||||
TargetScope: models.TargetSum,
|
TargetScope: models.TargetSum,
|
||||||
},
|
},
|
||||||
transfer.DiscountCalculationTargetProtoToModel(&discount.DiscountCalculationTarget{}),
|
transfer.DiscountCalculationTargetProtoToModel(&discount.DiscountCalculationTarget{}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Перевод цели высчитывания из proto в модель с nil", func(t *testing.T) {
|
t.Run("Перевод цели высчитывания из proto в модель с nil", func(t *testing.T) {
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
&models.DiscountCalculationTarget{TargetScope: models.TargetSum},
|
&models.DiscountCalculationTarget{TargetScope: models.TargetSum},
|
||||||
transfer.DiscountCalculationTargetProtoToModel(nil),
|
transfer.DiscountCalculationTargetProtoToModel(nil),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDiscountCalculationTargetModelToProto(t *testing.T) {
|
func TestDiscountCalculationTargetModelToProto(t *testing.T) {
|
||||||
t.Run("Перевод цели высчитывания из модели в proto", func(t *testing.T) {
|
t.Run("Перевод цели высчитывания из модели в proto", func(t *testing.T) {
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
&discount.DiscountCalculationTarget{
|
&discount.DiscountCalculationTarget{
|
||||||
TargetScope: discount.TargetScope_Sum.Enum(),
|
TargetScope: discount.TargetScope_Sum.Enum(),
|
||||||
Overhelm: new(bool),
|
Overhelm: new(bool),
|
||||||
TargetGroup: new(string),
|
TargetGroup: new(string),
|
||||||
Products: []*discount.ProductTarget{
|
Products: []*discount.ProductTarget{
|
||||||
{ID: "1", Factor: 20, Overhelm: new(bool)},
|
{ID: "1", Factor: 20, Overhelm: new(bool)},
|
||||||
{ID: "2", Factor: 20, Overhelm: new(bool)},
|
{ID: "2", Factor: 20, Overhelm: new(bool)},
|
||||||
{ID: "3", Factor: 10, Overhelm: new(bool)},
|
{ID: "3", Factor: 10, Overhelm: new(bool)},
|
||||||
},
|
},
|
||||||
Factor: 20,
|
Factor: 20,
|
||||||
},
|
},
|
||||||
transfer.DiscountCalculationTargetModelToProto(models.DiscountCalculationTarget{
|
transfer.DiscountCalculationTargetModelToProto(models.DiscountCalculationTarget{
|
||||||
TargetScope: models.TargetSum,
|
TargetScope: models.TargetSum,
|
||||||
Products: []models.ProductTarget{
|
Products: []models.ProductTarget{
|
||||||
{ID: "1", Factor: 20},
|
{ID: "1", Factor: 20},
|
||||||
{ID: "2", Factor: 20},
|
{ID: "2", Factor: 20},
|
||||||
{ID: "3", Factor: 10},
|
{ID: "3", Factor: 10},
|
||||||
},
|
},
|
||||||
Factor: 20,
|
Factor: 20,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Перевод цели высчитывания из модели в proto с пустыми значениями", func(t *testing.T) {
|
t.Run("Перевод цели высчитывания из модели в proto с пустыми значениями", func(t *testing.T) {
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
&discount.DiscountCalculationTarget{
|
&discount.DiscountCalculationTarget{
|
||||||
TargetScope: discount.TargetScope_Sum.Enum(),
|
TargetScope: discount.TargetScope_Sum.Enum(),
|
||||||
Products: []*discount.ProductTarget{},
|
Products: []*discount.ProductTarget{},
|
||||||
Overhelm: new(bool),
|
Overhelm: new(bool),
|
||||||
TargetGroup: new(string),
|
TargetGroup: new(string),
|
||||||
},
|
},
|
||||||
transfer.DiscountCalculationTargetModelToProto(models.DiscountCalculationTarget{
|
transfer.DiscountCalculationTargetModelToProto(models.DiscountCalculationTarget{
|
||||||
Products: []models.ProductTarget{},
|
Products: []models.ProductTarget{},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,46 +1,46 @@
|
|||||||
package transfer
|
package transfer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
proto "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
proto "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DiscountConditionModelToProto(discountCondition *models.DiscountCondition) *proto.DiscountCondition {
|
func DiscountConditionModelToProto(discountCondition *models.DiscountCondition) *proto.DiscountCondition {
|
||||||
if discountCondition == nil {
|
if discountCondition == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &proto.DiscountCondition{
|
return &proto.DiscountCondition{
|
||||||
Period: PeriodModelToProto(discountCondition.Period),
|
Period: PeriodModelToProto(discountCondition.Period),
|
||||||
User: discountCondition.User,
|
User: discountCondition.User,
|
||||||
UserType: discountCondition.UserType,
|
UserType: discountCondition.UserType,
|
||||||
Coupon: discountCondition.Coupon,
|
Coupon: discountCondition.Coupon,
|
||||||
PurchasesAmount: discountCondition.PurchasesAmount,
|
PurchasesAmount: discountCondition.PurchasesAmount,
|
||||||
CartPurchasesAmount: discountCondition.CartPurchasesAmount,
|
CartPurchasesAmount: discountCondition.CartPurchasesAmount,
|
||||||
Term: discountCondition.Term,
|
Term: discountCondition.Term,
|
||||||
Product: discountCondition.Product,
|
Product: discountCondition.Product,
|
||||||
Usage: discountCondition.Usage,
|
Usage: discountCondition.Usage,
|
||||||
PriceFrom: discountCondition.PriceFrom,
|
PriceFrom: discountCondition.PriceFrom,
|
||||||
Group: discountCondition.Group,
|
Group: discountCondition.Group,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DiscountConditionProtoToModel(discountCondition *proto.DiscountCondition) *models.DiscountCondition {
|
func DiscountConditionProtoToModel(discountCondition *proto.DiscountCondition) *models.DiscountCondition {
|
||||||
if discountCondition == nil {
|
if discountCondition == nil {
|
||||||
return &models.DiscountCondition{}
|
return &models.DiscountCondition{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &models.DiscountCondition{
|
return &models.DiscountCondition{
|
||||||
Period: PeriodProtoToModel(discountCondition.GetPeriod()),
|
Period: PeriodProtoToModel(discountCondition.GetPeriod()),
|
||||||
Product: discountCondition.Product,
|
Product: discountCondition.Product,
|
||||||
User: discountCondition.User,
|
User: discountCondition.User,
|
||||||
UserType: discountCondition.UserType,
|
UserType: discountCondition.UserType,
|
||||||
Coupon: discountCondition.Coupon,
|
Coupon: discountCondition.Coupon,
|
||||||
PurchasesAmount: discountCondition.PurchasesAmount,
|
PurchasesAmount: discountCondition.PurchasesAmount,
|
||||||
CartPurchasesAmount: discountCondition.CartPurchasesAmount,
|
CartPurchasesAmount: discountCondition.CartPurchasesAmount,
|
||||||
Term: discountCondition.Term,
|
Term: discountCondition.Term,
|
||||||
Usage: discountCondition.Usage,
|
Usage: discountCondition.Usage,
|
||||||
PriceFrom: discountCondition.PriceFrom,
|
PriceFrom: discountCondition.PriceFrom,
|
||||||
Group: discountCondition.Group,
|
Group: discountCondition.Group,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,142 +1,141 @@
|
|||||||
package transfer_test
|
package transfer_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
)
|
||||||
)
|
|
||||||
|
func TestDiscountConditionProtoToModel(t *testing.T) {
|
||||||
func TestDiscountConditionProtoToModel(t *testing.T) {
|
userID := "1"
|
||||||
userID := "1"
|
userType := "nkvo11"
|
||||||
userType := "nkvo"
|
coupon := "test22"
|
||||||
coupon := "test"
|
product := "product13"
|
||||||
product := "product1"
|
purchasesAmount := uint64(20000)
|
||||||
purchasesAmount := float64(20000)
|
cartPurchasesAmount := uint64(20000)
|
||||||
cartPurchasesAmount := float64(20000)
|
term := uint64(20)
|
||||||
term := uint64(20)
|
usage := uint64(20)
|
||||||
usage := uint64(20)
|
priceFrom := uint64(20000)
|
||||||
priceFrom := float64(20000)
|
group := "testGroupo"
|
||||||
group := "testGroup"
|
|
||||||
|
t.Run("Перевод не до конца заполненных условий скидок с proto в модель", func(t *testing.T) {
|
||||||
t.Run("Перевод не до конца заполненных условий скидок с proto в модель", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&models.DiscountCondition{CartPurchasesAmount: &cartPurchasesAmount},
|
||||||
&models.DiscountCondition{CartPurchasesAmount: &cartPurchasesAmount},
|
transfer.DiscountConditionProtoToModel(&discount.DiscountCondition{
|
||||||
transfer.DiscountConditionProtoToModel(&discount.DiscountCondition{
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Перевод скидок с nil proto в модель", func(t *testing.T) {
|
||||||
t.Run("Перевод скидок с nil proto в модель", func(t *testing.T) {
|
assert.Equal(t, &models.DiscountCondition{}, transfer.DiscountConditionProtoToModel(nil))
|
||||||
assert.Equal(t, &models.DiscountCondition{}, transfer.DiscountConditionProtoToModel(nil))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Перевод условий скидок с proto в модель", func(t *testing.T) {
|
||||||
t.Run("Перевод условий скидок с proto в модель", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&models.DiscountCondition{
|
||||||
&models.DiscountCondition{
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
User: &userID,
|
||||||
User: &userID,
|
UserType: &userType,
|
||||||
UserType: &userType,
|
PurchasesAmount: &purchasesAmount,
|
||||||
PurchasesAmount: &purchasesAmount,
|
Coupon: &coupon,
|
||||||
Coupon: &coupon,
|
Product: &product,
|
||||||
Product: &product,
|
Term: &term,
|
||||||
Term: &term,
|
Usage: &usage,
|
||||||
Usage: &usage,
|
PriceFrom: &priceFrom,
|
||||||
PriceFrom: &priceFrom,
|
Group: &group,
|
||||||
Group: &group,
|
Period: &models.PeriodCondition{
|
||||||
Period: &models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
},
|
||||||
},
|
transfer.DiscountConditionProtoToModel(&discount.DiscountCondition{
|
||||||
transfer.DiscountConditionProtoToModel(&discount.DiscountCondition{
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
User: &userID,
|
||||||
User: &userID,
|
UserType: &userType,
|
||||||
UserType: &userType,
|
PurchasesAmount: &purchasesAmount,
|
||||||
PurchasesAmount: &purchasesAmount,
|
Coupon: &coupon,
|
||||||
Coupon: &coupon,
|
Product: &product,
|
||||||
Product: &product,
|
Term: &term,
|
||||||
Term: &term,
|
Usage: &usage,
|
||||||
Usage: &usage,
|
PriceFrom: &priceFrom,
|
||||||
PriceFrom: &priceFrom,
|
Group: &group,
|
||||||
Group: &group,
|
Period: &discount.PeriodCondition{
|
||||||
Period: &discount.PeriodCondition{
|
From: ×tamppb.Timestamp{
|
||||||
From: ×tamppb.Timestamp{
|
Seconds: 1674546287,
|
||||||
Seconds: 1674546287,
|
Nanos: 0,
|
||||||
Nanos: 0,
|
},
|
||||||
},
|
To: ×tamppb.Timestamp{
|
||||||
To: ×tamppb.Timestamp{
|
Seconds: 1674546287,
|
||||||
Seconds: 1674546287,
|
Nanos: 0,
|
||||||
Nanos: 0,
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
func TestDiscountConditionModelToProto(t *testing.T) {
|
||||||
func TestDiscountConditionModelToProto(t *testing.T) {
|
userID := "1"
|
||||||
userID := "1"
|
userType := "nkvo"
|
||||||
userType := "nkvo"
|
coupon := "test"
|
||||||
coupon := "test"
|
product := "product1"
|
||||||
product := "product1"
|
purchasesAmount := uint64(20000)
|
||||||
purchasesAmount := float64(20000)
|
cartPurchasesAmount := uint64(20000)
|
||||||
cartPurchasesAmount := float64(20000)
|
term := uint64(20)
|
||||||
term := uint64(20)
|
usage := uint64(20)
|
||||||
usage := uint64(20)
|
priceFrom := uint64(20000)
|
||||||
priceFrom := float64(20000)
|
group := "testGroupbgfbgbgb"
|
||||||
group := "testGroup"
|
|
||||||
|
t.Run("Перевод условий скидки с модели в proto", func(t *testing.T) {
|
||||||
t.Run("Перевод условий скидки с модели в proto", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&discount.DiscountCondition{
|
||||||
&discount.DiscountCondition{
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
User: &userID,
|
||||||
User: &userID,
|
UserType: &userType,
|
||||||
UserType: &userType,
|
PurchasesAmount: &purchasesAmount,
|
||||||
PurchasesAmount: &purchasesAmount,
|
Coupon: &coupon,
|
||||||
Coupon: &coupon,
|
Product: &product,
|
||||||
Product: &product,
|
Term: &term,
|
||||||
Term: &term,
|
Usage: &usage,
|
||||||
Usage: &usage,
|
PriceFrom: &priceFrom,
|
||||||
PriceFrom: &priceFrom,
|
Group: &group,
|
||||||
Group: &group,
|
Period: &discount.PeriodCondition{
|
||||||
Period: &discount.PeriodCondition{
|
From: ×tamppb.Timestamp{
|
||||||
From: ×tamppb.Timestamp{
|
Seconds: 1674546287,
|
||||||
Seconds: 1674546287,
|
Nanos: 0,
|
||||||
Nanos: 0,
|
},
|
||||||
},
|
To: ×tamppb.Timestamp{
|
||||||
To: ×tamppb.Timestamp{
|
Seconds: 1674546287,
|
||||||
Seconds: 1674546287,
|
Nanos: 0,
|
||||||
Nanos: 0,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
transfer.DiscountConditionModelToProto(&models.DiscountCondition{
|
||||||
transfer.DiscountConditionModelToProto(&models.DiscountCondition{
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
User: &userID,
|
||||||
User: &userID,
|
UserType: &userType,
|
||||||
UserType: &userType,
|
PurchasesAmount: &purchasesAmount,
|
||||||
PurchasesAmount: &purchasesAmount,
|
Coupon: &coupon,
|
||||||
Coupon: &coupon,
|
Product: &product,
|
||||||
Product: &product,
|
Term: &term,
|
||||||
Term: &term,
|
Usage: &usage,
|
||||||
Usage: &usage,
|
PriceFrom: &priceFrom,
|
||||||
PriceFrom: &priceFrom,
|
Group: &group,
|
||||||
Group: &group,
|
Period: &models.PeriodCondition{
|
||||||
Period: &models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
|
||||||
|
t.Run("Перевод условий скидки с nil модели в proto", func(t *testing.T) {
|
||||||
t.Run("Перевод условий скидки с nil модели в proto", func(t *testing.T) {
|
assert.Nil(t, transfer.DiscountConditionModelToProto(nil))
|
||||||
assert.Nil(t, transfer.DiscountConditionModelToProto(nil))
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
@ -1,60 +1,60 @@
|
|||||||
package transfer
|
package transfer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
proto "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
proto "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
)
|
)
|
||||||
|
|
||||||
func DiscountsProtoToModel(discounts *proto.Discounts) []*models.Discount {
|
func DiscountsProtoToModel(discounts *proto.Discounts) []*models.Discount {
|
||||||
if discounts == nil {
|
if discounts == nil {
|
||||||
return []*models.Discount{}
|
return []*models.Discount{}
|
||||||
}
|
}
|
||||||
|
|
||||||
modelDiscounts := make([]*models.Discount, len(discounts.Discounts))
|
modelDiscounts := make([]*models.Discount, len(discounts.Discounts))
|
||||||
|
|
||||||
for index, discount := range discounts.Discounts {
|
for index, discount := range discounts.Discounts {
|
||||||
modelDiscounts[index] = DiscountProtoToModel(discount)
|
modelDiscounts[index] = DiscountProtoToModel(discount)
|
||||||
}
|
}
|
||||||
|
|
||||||
return modelDiscounts
|
return modelDiscounts
|
||||||
}
|
}
|
||||||
|
|
||||||
func DiscountProtoToModel(discount *proto.Discount) *models.Discount {
|
func DiscountProtoToModel(discount *proto.Discount) *models.Discount {
|
||||||
if discount == nil {
|
if discount == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &models.Discount{
|
return &models.Discount{
|
||||||
ID: discount.GetID(),
|
ID: discount.GetID(),
|
||||||
Name: discount.GetName(),
|
Name: discount.GetName(),
|
||||||
Layer: discount.GetLayer(),
|
Layer: discount.GetLayer(),
|
||||||
Description: discount.GetDescription(),
|
Description: discount.GetDescription(),
|
||||||
Condition: *DiscountConditionProtoToModel(discount.GetCondition()),
|
Condition: *DiscountConditionProtoToModel(discount.GetCondition()),
|
||||||
Target: *DiscountCalculationTargetProtoToModel(discount.GetTarget()),
|
Target: *DiscountCalculationTargetProtoToModel(discount.GetTarget()),
|
||||||
Audit: *AuditProtoToModel(discount.GetAudit()),
|
Audit: *AuditProtoToModel(discount.GetAudit()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DiscountsModelToProto(discounts []models.Discount) *proto.Discounts {
|
func DiscountsModelToProto(discounts []models.Discount) *proto.Discounts {
|
||||||
protoDiscounts := make([]*proto.Discount, len(discounts))
|
protoDiscounts := make([]*proto.Discount, len(discounts))
|
||||||
|
|
||||||
for index, discount := range discounts {
|
for index, discount := range discounts {
|
||||||
protoDiscounts[index] = DiscountModelToProto(discount)
|
protoDiscounts[index] = DiscountModelToProto(discount)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &proto.Discounts{
|
return &proto.Discounts{
|
||||||
Discounts: protoDiscounts,
|
Discounts: protoDiscounts,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DiscountModelToProto(discount models.Discount) *proto.Discount {
|
func DiscountModelToProto(discount models.Discount) *proto.Discount {
|
||||||
return &proto.Discount{
|
return &proto.Discount{
|
||||||
ID: discount.ID,
|
ID: discount.ID,
|
||||||
Name: discount.Name,
|
Name: discount.Name,
|
||||||
Layer: discount.Layer,
|
Layer: discount.Layer,
|
||||||
Description: discount.Description,
|
Description: discount.Description,
|
||||||
Condition: DiscountConditionModelToProto(&discount.Condition),
|
Condition: DiscountConditionModelToProto(&discount.Condition),
|
||||||
Target: DiscountCalculationTargetModelToProto(discount.Target),
|
Target: DiscountCalculationTargetModelToProto(discount.Target),
|
||||||
Audit: AuditModelToProto(&discount.Audit),
|
Audit: AuditModelToProto(&discount.Audit),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,243 +1,242 @@
|
|||||||
package transfer_test
|
package transfer_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
)
|
||||||
)
|
|
||||||
|
func TestDiscountsProtoToModel(t *testing.T) {
|
||||||
func TestDiscountsProtoToModel(t *testing.T) {
|
cartPurchasesAmount := uint64(20000)
|
||||||
cartPurchasesAmount := float64(20000)
|
purchasesAmount := uint64(20000)
|
||||||
purchasesAmount := float64(20000)
|
userID := string("13")
|
||||||
userID := string("13")
|
userType := string("type")
|
||||||
userType := string("type")
|
coupon := string("coupon1")
|
||||||
coupon := string("coupon1")
|
product := string("product1")
|
||||||
product := string("product1")
|
term := uint64(20)
|
||||||
term := uint64(20)
|
|
||||||
|
t.Run("перевод массива скидок с proto в модель с nil", func(t *testing.T) {
|
||||||
t.Run("перевод массива скидок с proto в модель с nil", func(t *testing.T) {
|
assert.Equal(t, []*models.Discount{}, transfer.DiscountsProtoToModel(nil))
|
||||||
assert.Equal(t, []*models.Discount{}, transfer.DiscountsProtoToModel(nil))
|
})
|
||||||
})
|
|
||||||
|
t.Run("перевод массива скидок с proto в модель", func(t *testing.T) {
|
||||||
t.Run("перевод массива скидок с proto в модель", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
[]*models.Discount{
|
||||||
[]*models.Discount{
|
{
|
||||||
{
|
ID: "1",
|
||||||
ID: "1",
|
Name: "Скидка на объём в корзине 1",
|
||||||
Name: "Скидка на объём в корзине 1",
|
Layer: 8,
|
||||||
Layer: 8,
|
Description: "",
|
||||||
Description: "",
|
Condition: models.DiscountCondition{
|
||||||
Condition: models.DiscountCondition{
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
PurchasesAmount: &purchasesAmount,
|
||||||
PurchasesAmount: &purchasesAmount,
|
User: &userID,
|
||||||
User: &userID,
|
UserType: &userType,
|
||||||
UserType: &userType,
|
Coupon: &coupon,
|
||||||
Coupon: &coupon,
|
Product: &product,
|
||||||
Product: &product,
|
Term: &term,
|
||||||
Term: &term,
|
Period: &models.PeriodCondition{
|
||||||
Period: &models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(0, 0).UTC(),
|
||||||
To: time.Unix(0, 0).UTC(),
|
},
|
||||||
},
|
},
|
||||||
},
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
TargetScope: models.TargetSum,
|
||||||
TargetScope: models.TargetSum,
|
Products: []models.ProductTarget{},
|
||||||
Products: []models.ProductTarget{},
|
Factor: 20,
|
||||||
Factor: 20,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
transfer.DiscountsProtoToModel(&discount.Discounts{
|
||||||
transfer.DiscountsProtoToModel(&discount.Discounts{
|
Discounts: []*discount.Discount{
|
||||||
Discounts: []*discount.Discount{
|
{
|
||||||
{
|
ID: "1",
|
||||||
ID: "1",
|
Name: "Скидка на объём в корзине 1",
|
||||||
Name: "Скидка на объём в корзине 1",
|
Layer: 8,
|
||||||
Layer: 8,
|
Description: "",
|
||||||
Description: "",
|
Condition: &discount.DiscountCondition{
|
||||||
Condition: &discount.DiscountCondition{
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
PurchasesAmount: &purchasesAmount,
|
||||||
PurchasesAmount: &purchasesAmount,
|
User: &userID,
|
||||||
User: &userID,
|
UserType: &userType,
|
||||||
UserType: &userType,
|
Coupon: &coupon,
|
||||||
Coupon: &coupon,
|
Product: &product,
|
||||||
Product: &product,
|
Term: &term,
|
||||||
Term: &term,
|
Period: &discount.PeriodCondition{
|
||||||
Period: &discount.PeriodCondition{
|
From: ×tamppb.Timestamp{
|
||||||
From: ×tamppb.Timestamp{
|
Seconds: 1674546287,
|
||||||
Seconds: 1674546287,
|
},
|
||||||
},
|
To: ×tamppb.Timestamp{},
|
||||||
To: ×tamppb.Timestamp{},
|
},
|
||||||
},
|
},
|
||||||
},
|
Target: &discount.DiscountCalculationTarget{
|
||||||
Target: &discount.DiscountCalculationTarget{
|
TargetScope: discount.TargetScope_Sum.Enum(),
|
||||||
TargetScope: discount.TargetScope_Sum.Enum(),
|
Products: []*discount.ProductTarget{},
|
||||||
Products: []*discount.ProductTarget{},
|
Factor: 20,
|
||||||
Factor: 20,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
func TestDiscountProtoToModel(t *testing.T) {
|
||||||
func TestDiscountProtoToModel(t *testing.T) {
|
cartPurchasesAmount := uint64(20000)
|
||||||
cartPurchasesAmount := float64(20000)
|
deletedAtModel := time.Unix(1674546287, 0).UTC()
|
||||||
deletedAtModel := time.Unix(1674546287, 0).UTC()
|
deletedAtProto := timestamppb.Timestamp{Seconds: 1674546287}
|
||||||
deletedAtProto := timestamppb.Timestamp{Seconds: 1674546287}
|
|
||||||
|
t.Run("Перевод скидки с proto в модель", func(t *testing.T) {
|
||||||
t.Run("Перевод скидки с proto в модель", func(t *testing.T) {
|
assert.Nil(t, transfer.DiscountProtoToModel(nil))
|
||||||
assert.Nil(t, transfer.DiscountProtoToModel(nil))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Перевод скидки с proto в модель", func(t *testing.T) {
|
||||||
t.Run("Перевод скидки с proto в модель", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&models.Discount{
|
||||||
&models.Discount{
|
ID: "1",
|
||||||
ID: "1",
|
Name: "Скидка на объём в корзине 4",
|
||||||
Name: "Скидка на объём в корзине 4",
|
Layer: 8,
|
||||||
Layer: 8,
|
Description: "",
|
||||||
Description: "",
|
Condition: models.DiscountCondition{
|
||||||
Condition: models.DiscountCondition{
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
},
|
||||||
},
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
TargetScope: models.TargetSum,
|
||||||
TargetScope: models.TargetSum,
|
Products: []models.ProductTarget{},
|
||||||
Products: []models.ProductTarget{},
|
Factor: 20,
|
||||||
Factor: 20,
|
},
|
||||||
},
|
Audit: models.Audit{
|
||||||
Audit: models.Audit{
|
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
DeletedAt: &deletedAtModel,
|
||||||
DeletedAt: &deletedAtModel,
|
Deleted: true,
|
||||||
Deleted: true,
|
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
},
|
||||||
},
|
transfer.DiscountProtoToModel(&discount.Discount{
|
||||||
transfer.DiscountProtoToModel(&discount.Discount{
|
ID: "1",
|
||||||
ID: "1",
|
Name: "Скидка на объём в корзине 4",
|
||||||
Name: "Скидка на объём в корзине 4",
|
Layer: 8,
|
||||||
Layer: 8,
|
Description: "",
|
||||||
Description: "",
|
Condition: &discount.DiscountCondition{
|
||||||
Condition: &discount.DiscountCondition{
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
},
|
||||||
},
|
Target: &discount.DiscountCalculationTarget{
|
||||||
Target: &discount.DiscountCalculationTarget{
|
TargetScope: discount.TargetScope_Sum.Enum(),
|
||||||
TargetScope: discount.TargetScope_Sum.Enum(),
|
Products: []*discount.ProductTarget{},
|
||||||
Products: []*discount.ProductTarget{},
|
Factor: 20,
|
||||||
Factor: 20,
|
},
|
||||||
},
|
Audit: &discount.Audit{
|
||||||
Audit: &discount.Audit{
|
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
DeletedAt: &deletedAtProto,
|
||||||
DeletedAt: &deletedAtProto,
|
Deleted: true,
|
||||||
Deleted: true,
|
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
},
|
||||||
},
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
func TestDiscountsModelToProto(t *testing.T) {
|
||||||
func TestDiscountsModelToProto(t *testing.T) {
|
cartPurchasesAmount := uint64(20000)
|
||||||
cartPurchasesAmount := float64(20000)
|
deletedAtModel := time.Unix(1674546287, 0).UTC()
|
||||||
deletedAtModel := time.Unix(1674546287, 0).UTC()
|
deletedAtProto := timestamppb.Timestamp{Seconds: 1674546287}
|
||||||
deletedAtProto := timestamppb.Timestamp{Seconds: 1674546287}
|
|
||||||
|
t.Run("Перевод массива скидок из модели в proto", func(t *testing.T) {
|
||||||
t.Run("Перевод массива скидок из модели в proto", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&discount.Discounts{Discounts: []*discount.Discount{
|
||||||
&discount.Discounts{Discounts: []*discount.Discount{
|
{
|
||||||
{
|
ID: "1",
|
||||||
ID: "1",
|
Name: "Скидка на объём в корзине 5",
|
||||||
Name: "Скидка на объём в корзине 5",
|
Layer: 8,
|
||||||
Layer: 8,
|
Description: "",
|
||||||
Description: "",
|
Condition: &discount.DiscountCondition{
|
||||||
Condition: &discount.DiscountCondition{
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
},
|
||||||
},
|
Target: &discount.DiscountCalculationTarget{
|
||||||
Target: &discount.DiscountCalculationTarget{
|
TargetScope: discount.TargetScope_Sum.Enum(),
|
||||||
TargetScope: discount.TargetScope_Sum.Enum(),
|
Products: []*discount.ProductTarget{},
|
||||||
Products: []*discount.ProductTarget{},
|
Factor: 20,
|
||||||
Factor: 20,
|
Overhelm: new(bool),
|
||||||
Overhelm: new(bool),
|
TargetGroup: new(string),
|
||||||
TargetGroup: new(string),
|
},
|
||||||
},
|
Audit: &discount.Audit{
|
||||||
Audit: &discount.Audit{
|
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
UpdatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
DeletedAt: &deletedAtProto,
|
||||||
DeletedAt: &deletedAtProto,
|
Deleted: true,
|
||||||
Deleted: true,
|
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
||||||
CreatedAt: ×tamppb.Timestamp{Seconds: 1674546287},
|
},
|
||||||
},
|
},
|
||||||
},
|
}},
|
||||||
}},
|
transfer.DiscountsModelToProto([]models.Discount{
|
||||||
transfer.DiscountsModelToProto([]models.Discount{
|
{
|
||||||
{
|
ID: "1",
|
||||||
ID: "1",
|
Name: "Скидка на объём в корзине 5",
|
||||||
Name: "Скидка на объём в корзине 5",
|
Layer: 8,
|
||||||
Layer: 8,
|
Description: "",
|
||||||
Description: "",
|
Condition: models.DiscountCondition{
|
||||||
Condition: models.DiscountCondition{
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
},
|
||||||
},
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
TargetScope: models.TargetSum,
|
||||||
TargetScope: models.TargetSum,
|
Products: []models.ProductTarget{},
|
||||||
Products: []models.ProductTarget{},
|
Factor: 20,
|
||||||
Factor: 20,
|
},
|
||||||
},
|
Audit: models.Audit{
|
||||||
Audit: models.Audit{
|
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
UpdatedAt: time.Unix(1674546287, 0).UTC(),
|
DeletedAt: &deletedAtModel,
|
||||||
DeletedAt: &deletedAtModel,
|
Deleted: true,
|
||||||
Deleted: true,
|
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
||||||
CreatedAt: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
func TestDiscountModelToProto(t *testing.T) {
|
||||||
func TestDiscountModelToProto(t *testing.T) {
|
cartPurchasesAmount := uint64(20000)
|
||||||
cartPurchasesAmount := float64(20000)
|
|
||||||
|
t.Run("Перевод скидки из модели в proto", func(t *testing.T) {
|
||||||
t.Run("Перевод скидки из модели в proto", func(t *testing.T) {
|
assert.Equal(t,
|
||||||
assert.Equal(t,
|
&discount.Discount{
|
||||||
&discount.Discount{
|
ID: "1",
|
||||||
ID: "1",
|
Name: "Скидка на объём в корзине 8",
|
||||||
Name: "Скидка на объём в корзине 8",
|
Layer: 8,
|
||||||
Layer: 8,
|
Description: "",
|
||||||
Description: "",
|
Condition: &discount.DiscountCondition{
|
||||||
Condition: &discount.DiscountCondition{
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
},
|
||||||
},
|
Target: &discount.DiscountCalculationTarget{
|
||||||
Target: &discount.DiscountCalculationTarget{
|
TargetScope: discount.TargetScope_Sum.Enum(),
|
||||||
TargetScope: discount.TargetScope_Sum.Enum(),
|
Products: []*discount.ProductTarget{},
|
||||||
Products: []*discount.ProductTarget{},
|
Factor: 20,
|
||||||
Factor: 20,
|
Overhelm: new(bool),
|
||||||
Overhelm: new(bool),
|
TargetGroup: new(string),
|
||||||
TargetGroup: new(string),
|
},
|
||||||
},
|
Audit: &discount.Audit{
|
||||||
Audit: &discount.Audit{
|
CreatedAt: timestamppb.New(time.Time{}),
|
||||||
CreatedAt: timestamppb.New(time.Time{}),
|
UpdatedAt: timestamppb.New(time.Time{}),
|
||||||
UpdatedAt: timestamppb.New(time.Time{}),
|
},
|
||||||
},
|
},
|
||||||
},
|
transfer.DiscountModelToProto(models.Discount{
|
||||||
transfer.DiscountModelToProto(models.Discount{
|
ID: "1",
|
||||||
ID: "1",
|
Name: "Скидка на объём в корзине 8",
|
||||||
Name: "Скидка на объём в корзине 8",
|
Layer: 8,
|
||||||
Layer: 8,
|
Description: "",
|
||||||
Description: "",
|
Condition: models.DiscountCondition{
|
||||||
Condition: models.DiscountCondition{
|
CartPurchasesAmount: &cartPurchasesAmount,
|
||||||
CartPurchasesAmount: &cartPurchasesAmount,
|
},
|
||||||
},
|
Target: models.DiscountCalculationTarget{
|
||||||
Target: models.DiscountCalculationTarget{
|
TargetScope: models.TargetSum,
|
||||||
TargetScope: models.TargetSum,
|
Products: []models.ProductTarget{},
|
||||||
Products: []models.ProductTarget{},
|
Factor: 20,
|
||||||
Factor: 20,
|
},
|
||||||
},
|
}),
|
||||||
}),
|
)
|
||||||
)
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
@ -1,30 +1,29 @@
|
|||||||
package transfer
|
package transfer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
proto "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
proto "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
)
|
||||||
)
|
|
||||||
|
func PeriodModelToProto(perion *models.PeriodCondition) *proto.PeriodCondition {
|
||||||
func PeriodModelToProto(perion *models.PeriodCondition) *proto.PeriodCondition {
|
if perion == nil {
|
||||||
if perion == nil {
|
return nil
|
||||||
return nil
|
}
|
||||||
}
|
|
||||||
|
return &proto.PeriodCondition{
|
||||||
return &proto.PeriodCondition{
|
From: timestamppb.New(perion.From),
|
||||||
From: timestamppb.New(perion.From),
|
To: timestamppb.New(perion.To),
|
||||||
To: timestamppb.New(perion.To),
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
func PeriodProtoToModel(perion *proto.PeriodCondition) *models.PeriodCondition {
|
||||||
func PeriodProtoToModel(perion *proto.PeriodCondition) *models.PeriodCondition {
|
if perion == nil {
|
||||||
if perion == nil {
|
return nil
|
||||||
return nil
|
}
|
||||||
}
|
|
||||||
|
return &models.PeriodCondition{
|
||||||
return &models.PeriodCondition{
|
From: perion.GetFrom().AsTime(),
|
||||||
From: perion.GetFrom().AsTime(),
|
To: perion.GetTo().AsTime(),
|
||||||
To: perion.GetTo().AsTime(),
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -1,129 +1,128 @@
|
|||||||
package transfer_test
|
package transfer_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
)
|
||||||
)
|
|
||||||
|
/*
|
||||||
/*
|
TODO:
|
||||||
TODO:
|
|
||||||
|
Переписать тесты с testCases в обычный список t.Run тестов
|
||||||
Переписать тесты с testCases в обычный список t.Run тестов
|
*/
|
||||||
*/
|
|
||||||
|
func TestPeriodProtoToModel(t *testing.T) {
|
||||||
func TestPeriodProtoToModel(t *testing.T) {
|
testCases := []struct {
|
||||||
testCases := []struct {
|
name string
|
||||||
name string
|
proto *discount.PeriodCondition
|
||||||
proto *discount.PeriodCondition
|
model *models.PeriodCondition
|
||||||
model *models.PeriodCondition
|
}{
|
||||||
}{
|
{
|
||||||
{
|
name: "correct transfer period from proto to model",
|
||||||
name: "correct transfer period from proto to model",
|
proto: &discount.PeriodCondition{
|
||||||
proto: &discount.PeriodCondition{
|
From: ×tamppb.Timestamp{
|
||||||
From: ×tamppb.Timestamp{
|
Seconds: 1674546287,
|
||||||
Seconds: 1674546287,
|
Nanos: 0,
|
||||||
Nanos: 0,
|
},
|
||||||
},
|
To: ×tamppb.Timestamp{
|
||||||
To: ×tamppb.Timestamp{
|
Seconds: 1674546287,
|
||||||
Seconds: 1674546287,
|
Nanos: 0,
|
||||||
Nanos: 0,
|
},
|
||||||
},
|
},
|
||||||
},
|
model: &models.PeriodCondition{
|
||||||
model: &models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "correct transfer period with empty milliseconds from proto to model",
|
||||||
name: "correct transfer period with empty milliseconds from proto to model",
|
proto: &discount.PeriodCondition{
|
||||||
proto: &discount.PeriodCondition{
|
From: ×tamppb.Timestamp{
|
||||||
From: ×tamppb.Timestamp{
|
Seconds: 1674546287,
|
||||||
Seconds: 1674546287,
|
},
|
||||||
},
|
To: ×tamppb.Timestamp{},
|
||||||
To: ×tamppb.Timestamp{},
|
},
|
||||||
},
|
model: &models.PeriodCondition{
|
||||||
model: &models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(0, 0).UTC(),
|
||||||
To: time.Unix(0, 0).UTC(),
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "correct transfer period with empty fields from proto to model",
|
||||||
name: "correct transfer period with empty fields from proto to model",
|
proto: &discount.PeriodCondition{
|
||||||
proto: &discount.PeriodCondition{
|
From: ×tamppb.Timestamp{},
|
||||||
From: ×tamppb.Timestamp{},
|
},
|
||||||
},
|
model: &models.PeriodCondition{
|
||||||
model: &models.PeriodCondition{
|
From: time.Unix(0, 0).UTC(),
|
||||||
From: time.Unix(0, 0).UTC(),
|
To: time.Unix(0, 0).UTC(),
|
||||||
To: time.Unix(0, 0).UTC(),
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
for _, testCase := range testCases {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
assert.Equal(t, testCase.model, transfer.PeriodProtoToModel(testCase.proto))
|
||||||
assert.Equal(t, testCase.model, transfer.PeriodProtoToModel(testCase.proto))
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
func TestPeriodModelToProto(t *testing.T) {
|
||||||
func TestPeriodModelToProto(t *testing.T) {
|
testCases := []struct {
|
||||||
testCases := []struct {
|
name string
|
||||||
name string
|
proto *discount.PeriodCondition
|
||||||
proto *discount.PeriodCondition
|
model *models.PeriodCondition
|
||||||
model *models.PeriodCondition
|
}{
|
||||||
}{
|
{
|
||||||
{
|
name: "correct transfer period from model to proto",
|
||||||
name: "correct transfer period from model to proto",
|
proto: &discount.PeriodCondition{
|
||||||
proto: &discount.PeriodCondition{
|
From: ×tamppb.Timestamp{
|
||||||
From: ×tamppb.Timestamp{
|
Seconds: 1674546287,
|
||||||
Seconds: 1674546287,
|
Nanos: 0,
|
||||||
Nanos: 0,
|
},
|
||||||
},
|
To: ×tamppb.Timestamp{
|
||||||
To: ×tamppb.Timestamp{
|
Seconds: 1674546287,
|
||||||
Seconds: 1674546287,
|
Nanos: 0,
|
||||||
Nanos: 0,
|
},
|
||||||
},
|
},
|
||||||
},
|
model: &models.PeriodCondition{
|
||||||
model: &models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(1674546287, 0).UTC(),
|
||||||
To: time.Unix(1674546287, 0).UTC(),
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "correct transfer period with empty milliseconds from model to proto",
|
||||||
name: "correct transfer period with empty milliseconds from model to proto",
|
proto: &discount.PeriodCondition{
|
||||||
proto: &discount.PeriodCondition{
|
From: ×tamppb.Timestamp{
|
||||||
From: ×tamppb.Timestamp{
|
Seconds: 1674546287,
|
||||||
Seconds: 1674546287,
|
},
|
||||||
},
|
To: ×tamppb.Timestamp{},
|
||||||
To: ×tamppb.Timestamp{},
|
},
|
||||||
},
|
model: &models.PeriodCondition{
|
||||||
model: &models.PeriodCondition{
|
From: time.Unix(1674546287, 0).UTC(),
|
||||||
From: time.Unix(1674546287, 0).UTC(),
|
To: time.Unix(0, 0).UTC(),
|
||||||
To: time.Unix(0, 0).UTC(),
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "correct transfer period with empty fields from model to proto",
|
||||||
name: "correct transfer period with empty fields from model to proto",
|
proto: &discount.PeriodCondition{
|
||||||
proto: &discount.PeriodCondition{
|
From: ×tamppb.Timestamp{},
|
||||||
From: ×tamppb.Timestamp{},
|
To: timestamppb.New(time.Time{}),
|
||||||
To: timestamppb.New(time.Time{}),
|
},
|
||||||
},
|
model: &models.PeriodCondition{
|
||||||
model: &models.PeriodCondition{
|
From: time.Unix(0, 0).UTC(),
|
||||||
From: time.Unix(0, 0).UTC(),
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
for _, testCase := range testCases {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
assert.Equal(t, testCase.proto, transfer.PeriodModelToProto(testCase.model))
|
||||||
assert.Equal(t, testCase.proto, transfer.PeriodModelToProto(testCase.model))
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -1,85 +1,85 @@
|
|||||||
package transfer
|
package transfer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
proto "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
proto "penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProductTargetsProtoToModel(products []*proto.ProductTarget) []models.ProductTarget {
|
func ProductTargetsProtoToModel(products []*proto.ProductTarget) []models.ProductTarget {
|
||||||
modelProducts := make([]models.ProductTarget, len(products))
|
modelProducts := make([]models.ProductTarget, len(products))
|
||||||
|
|
||||||
for index, product := range products {
|
for index, product := range products {
|
||||||
modelProducts[index] = *ProductTargetProtoToModel(product)
|
modelProducts[index] = *ProductTargetProtoToModel(product)
|
||||||
}
|
}
|
||||||
|
|
||||||
return modelProducts
|
return modelProducts
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProductTargetProtoToModel(product *proto.ProductTarget) *models.ProductTarget {
|
func ProductTargetProtoToModel(product *proto.ProductTarget) *models.ProductTarget {
|
||||||
if product == nil {
|
if product == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
receiveOverhelm := func() bool {
|
receiveOverhelm := func() bool {
|
||||||
if product.Overhelm != nil {
|
if product.Overhelm != nil {
|
||||||
return *product.Overhelm
|
return *product.Overhelm
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return &models.ProductTarget{
|
return &models.ProductTarget{
|
||||||
ID: product.ID,
|
ID: product.ID,
|
||||||
Factor: product.Factor,
|
Factor: product.Factor,
|
||||||
Overhelm: receiveOverhelm(),
|
Overhelm: receiveOverhelm(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProductTargetsModelToProto(products []models.ProductTarget) []*proto.ProductTarget {
|
func ProductTargetsModelToProto(products []models.ProductTarget) []*proto.ProductTarget {
|
||||||
protoProducts := make([]*proto.ProductTarget, len(products))
|
protoProducts := make([]*proto.ProductTarget, len(products))
|
||||||
|
|
||||||
for index, product := range products {
|
for index, product := range products {
|
||||||
protoProducts[index] = ProductTargetModelToProto(product)
|
protoProducts[index] = ProductTargetModelToProto(product)
|
||||||
}
|
}
|
||||||
|
|
||||||
return protoProducts
|
return protoProducts
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProductTargetModelToProto(product models.ProductTarget) *proto.ProductTarget {
|
func ProductTargetModelToProto(product models.ProductTarget) *proto.ProductTarget {
|
||||||
return &proto.ProductTarget{
|
return &proto.ProductTarget{
|
||||||
ID: product.ID,
|
ID: product.ID,
|
||||||
Factor: product.Factor,
|
Factor: product.Factor,
|
||||||
Overhelm: &product.Overhelm,
|
Overhelm: &product.Overhelm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProductsProtoToCore(productInformations []*proto.ProductInformation) []core.Product {
|
func ProductsProtoToCore(productInformations []*proto.ProductInformation) []core.Product {
|
||||||
products := make([]core.Product, len(productInformations))
|
products := make([]core.Product, len(productInformations))
|
||||||
|
|
||||||
if len(productInformations) < 1 {
|
if len(productInformations) < 1 {
|
||||||
return []core.Product{}
|
return []core.Product{}
|
||||||
}
|
}
|
||||||
|
|
||||||
receiveGroup := func(product *proto.ProductInformation) string {
|
receiveGroup := func(product *proto.ProductInformation) string {
|
||||||
if product == nil || product.Group == nil {
|
if product == nil || product.Group == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return *product.Group
|
return *product.Group
|
||||||
}
|
}
|
||||||
|
|
||||||
for index, product := range productInformations {
|
for index, product := range productInformations {
|
||||||
if product == nil {
|
if product == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
products[index] = core.Product{
|
products[index] = core.Product{
|
||||||
ID: product.ID,
|
ID: product.ID,
|
||||||
Price: product.Price,
|
Price: float64(product.Price),
|
||||||
Group: receiveGroup(product),
|
Group: receiveGroup(product),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return products
|
return products
|
||||||
}
|
}
|
||||||
|
@ -1,241 +1,240 @@
|
|||||||
package transfer_test
|
package transfer_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/core"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/proto/discount"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/internal/utils/transfer"
|
)
|
||||||
)
|
|
||||||
|
/*
|
||||||
/*
|
TODO:
|
||||||
TODO:
|
|
||||||
|
1) Переписать тесты с testCases в обычный список t.Run тестов
|
||||||
1) Переписать тесты с testCases в обычный список t.Run тестов
|
2) Отформатировать массив объектов
|
||||||
2) Отформатировать массив объектов
|
3) Убрать глобальные переменные касающиеся других пакетов
|
||||||
3) Убрать глобальные переменные касающиеся других пакетов
|
*/
|
||||||
*/
|
|
||||||
|
var (
|
||||||
var (
|
overhelmTrue = true
|
||||||
overhelmTrue = true
|
)
|
||||||
)
|
|
||||||
|
func TestProductTargetsProtoToModel(t *testing.T) {
|
||||||
func TestProductTargetsProtoToModel(t *testing.T) {
|
testName := "correct transfer product tagrets from proto to model"
|
||||||
testName := "correct transfer product tagrets from proto to model"
|
proto := []*discount.ProductTarget{
|
||||||
proto := []*discount.ProductTarget{
|
{
|
||||||
{
|
ID: "1",
|
||||||
ID: "1",
|
Factor: 20,
|
||||||
Factor: 20,
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "2",
|
||||||
ID: "2",
|
Factor: 20,
|
||||||
Factor: 20,
|
Overhelm: &overhelmTrue,
|
||||||
Overhelm: &overhelmTrue,
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "3",
|
||||||
ID: "3",
|
Factor: 10,
|
||||||
Factor: 10,
|
},
|
||||||
},
|
}
|
||||||
}
|
model := []models.ProductTarget{
|
||||||
model := []models.ProductTarget{
|
{
|
||||||
{
|
ID: "1",
|
||||||
ID: "1",
|
Factor: 20,
|
||||||
Factor: 20,
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "2",
|
||||||
ID: "2",
|
Factor: 20,
|
||||||
Factor: 20,
|
Overhelm: true,
|
||||||
Overhelm: true,
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "3",
|
||||||
ID: "3",
|
Factor: 10,
|
||||||
Factor: 10,
|
},
|
||||||
},
|
}
|
||||||
}
|
|
||||||
|
t.Run(testName, func(t *testing.T) {
|
||||||
t.Run(testName, func(t *testing.T) {
|
assert.Equal(t, model, transfer.ProductTargetsProtoToModel(proto))
|
||||||
assert.Equal(t, model, transfer.ProductTargetsProtoToModel(proto))
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
func TestProductTargetProtoToModel(t *testing.T) {
|
||||||
func TestProductTargetProtoToModel(t *testing.T) {
|
testCases := []struct {
|
||||||
testCases := []struct {
|
name string
|
||||||
name string
|
proto *discount.ProductTarget
|
||||||
proto *discount.ProductTarget
|
model *models.ProductTarget
|
||||||
model *models.ProductTarget
|
}{
|
||||||
}{
|
{
|
||||||
{
|
name: "correct transfer product tagret from proto to model",
|
||||||
name: "correct transfer product tagret from proto to model",
|
proto: &discount.ProductTarget{
|
||||||
proto: &discount.ProductTarget{
|
ID: "1",
|
||||||
ID: "1",
|
Factor: 20,
|
||||||
Factor: 20,
|
},
|
||||||
},
|
model: &models.ProductTarget{
|
||||||
model: &models.ProductTarget{
|
ID: "1",
|
||||||
ID: "1",
|
Factor: 20,
|
||||||
Factor: 20,
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "correct transfer nil product tagret from proto to model",
|
||||||
name: "correct transfer nil product tagret from proto to model",
|
proto: nil,
|
||||||
proto: nil,
|
model: nil,
|
||||||
model: nil,
|
},
|
||||||
},
|
}
|
||||||
}
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
for _, testCase := range testCases {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
assert.Equal(t, testCase.model, transfer.ProductTargetProtoToModel(testCase.proto))
|
||||||
assert.Equal(t, testCase.model, transfer.ProductTargetProtoToModel(testCase.proto))
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
func TestProductTargetsModelToProto(t *testing.T) {
|
||||||
func TestProductTargetsModelToProto(t *testing.T) {
|
testName := "correct transfer product tagrets from model to proto"
|
||||||
testName := "correct transfer product tagrets from model to proto"
|
proto := []*discount.ProductTarget{
|
||||||
proto := []*discount.ProductTarget{
|
{
|
||||||
{
|
ID: "1",
|
||||||
ID: "1",
|
Factor: 50,
|
||||||
Factor: 50,
|
Overhelm: &overhelmTrue,
|
||||||
Overhelm: &overhelmTrue,
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "2",
|
||||||
ID: "2",
|
Factor: 20,
|
||||||
Factor: 20,
|
Overhelm: new(bool),
|
||||||
Overhelm: new(bool),
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "3",
|
||||||
ID: "3",
|
Factor: 10,
|
||||||
Factor: 10,
|
Overhelm: new(bool),
|
||||||
Overhelm: new(bool),
|
},
|
||||||
},
|
}
|
||||||
}
|
model := []models.ProductTarget{
|
||||||
model := []models.ProductTarget{
|
{
|
||||||
{
|
ID: "1",
|
||||||
ID: "1",
|
Factor: 50,
|
||||||
Factor: 50,
|
Overhelm: true,
|
||||||
Overhelm: true,
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "2",
|
||||||
ID: "2",
|
Factor: 20,
|
||||||
Factor: 20,
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "3",
|
||||||
ID: "3",
|
Factor: 10,
|
||||||
Factor: 10,
|
},
|
||||||
},
|
}
|
||||||
}
|
|
||||||
|
t.Run(testName, func(t *testing.T) {
|
||||||
t.Run(testName, func(t *testing.T) {
|
assert.Equal(t, proto, transfer.ProductTargetsModelToProto(model))
|
||||||
assert.Equal(t, proto, transfer.ProductTargetsModelToProto(model))
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
func TestProductTargetModelToProto(t *testing.T) {
|
||||||
func TestProductTargetModelToProto(t *testing.T) {
|
testCases := []struct {
|
||||||
testCases := []struct {
|
name string
|
||||||
name string
|
proto *discount.ProductTarget
|
||||||
proto *discount.ProductTarget
|
model models.ProductTarget
|
||||||
model models.ProductTarget
|
}{
|
||||||
}{
|
{
|
||||||
{
|
name: "correct transfer product tagret from model to proto",
|
||||||
name: "correct transfer product tagret from model to proto",
|
proto: &discount.ProductTarget{
|
||||||
proto: &discount.ProductTarget{
|
ID: "1",
|
||||||
ID: "1",
|
Factor: 20,
|
||||||
Factor: 20,
|
Overhelm: new(bool),
|
||||||
Overhelm: new(bool),
|
},
|
||||||
},
|
model: models.ProductTarget{
|
||||||
model: models.ProductTarget{
|
ID: "1",
|
||||||
ID: "1",
|
Factor: 20,
|
||||||
Factor: 20,
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "correct transfer nil product tagret from model to proto",
|
||||||
name: "correct transfer nil product tagret from model to proto",
|
proto: &discount.ProductTarget{
|
||||||
proto: &discount.ProductTarget{
|
Overhelm: new(bool),
|
||||||
Overhelm: new(bool),
|
},
|
||||||
},
|
model: models.ProductTarget{},
|
||||||
model: models.ProductTarget{},
|
},
|
||||||
},
|
}
|
||||||
}
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
for _, testCase := range testCases {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
assert.Equal(t, testCase.proto, transfer.ProductTargetModelToProto(testCase.model))
|
||||||
assert.Equal(t, testCase.proto, transfer.ProductTargetModelToProto(testCase.model))
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
func TestProductsProtoToCore(t *testing.T) {
|
||||||
func TestProductsProtoToCore(t *testing.T) {
|
group := "testGroup"
|
||||||
group := "testGroup"
|
|
||||||
|
testCases := []struct {
|
||||||
testCases := []struct {
|
name string
|
||||||
name string
|
proto []*discount.ProductInformation
|
||||||
proto []*discount.ProductInformation
|
core []core.Product
|
||||||
core []core.Product
|
}{
|
||||||
}{
|
{
|
||||||
{
|
name: "transfer product informations from proto to core",
|
||||||
name: "transfer product informations from proto to core",
|
proto: []*discount.ProductInformation{
|
||||||
proto: []*discount.ProductInformation{
|
{
|
||||||
{
|
ID: "1",
|
||||||
ID: "1",
|
Price: 20,
|
||||||
Price: 20,
|
Group: &group,
|
||||||
Group: &group,
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "2",
|
||||||
ID: "2",
|
Price: 30,
|
||||||
Price: 30,
|
},
|
||||||
},
|
},
|
||||||
},
|
core: []core.Product{
|
||||||
core: []core.Product{
|
{
|
||||||
{
|
ID: "1",
|
||||||
ID: "1",
|
Price: 20,
|
||||||
Price: 20,
|
Group: group,
|
||||||
Group: group,
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "2",
|
||||||
ID: "2",
|
Price: 30,
|
||||||
Price: 30,
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "transfer empty product informations from proto to core",
|
||||||
name: "transfer empty product informations from proto to core",
|
proto: []*discount.ProductInformation{},
|
||||||
proto: []*discount.ProductInformation{},
|
core: []core.Product{},
|
||||||
core: []core.Product{},
|
},
|
||||||
},
|
{
|
||||||
{
|
name: "transfer product informations from proto to core with nil proto",
|
||||||
name: "transfer product informations from proto to core with nil proto",
|
proto: []*discount.ProductInformation{
|
||||||
proto: []*discount.ProductInformation{
|
{
|
||||||
{
|
ID: "1",
|
||||||
ID: "1",
|
Price: 20,
|
||||||
Price: 20,
|
Group: &group,
|
||||||
Group: &group,
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "2",
|
||||||
ID: "2",
|
Price: 30,
|
||||||
Price: 30,
|
},
|
||||||
},
|
nil,
|
||||||
nil,
|
},
|
||||||
},
|
core: []core.Product{
|
||||||
core: []core.Product{
|
{
|
||||||
{
|
ID: "1",
|
||||||
ID: "1",
|
Price: 20,
|
||||||
Price: 20,
|
Group: group,
|
||||||
Group: group,
|
},
|
||||||
},
|
{
|
||||||
{
|
ID: "2",
|
||||||
ID: "2",
|
Price: 30,
|
||||||
Price: 30,
|
},
|
||||||
},
|
{},
|
||||||
{},
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
for _, testCase := range testCases {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
assert.Equal(t, testCase.core, transfer.ProductsProtoToCore(testCase.proto))
|
||||||
assert.Equal(t, testCase.core, transfer.ProductsProtoToCore(testCase.proto))
|
})
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -1 +1 @@
|
|||||||
[{ "delete": "discounts", "deletes": [{ "q": {} }] }]
|
[{ "delete": "discounts", "deletes": [{ "q": {} }] }]
|
||||||
|
@ -1,486 +1,486 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"insert": "discounts",
|
"insert": "discounts",
|
||||||
"ordered": true,
|
"ordered": true,
|
||||||
"documents": [
|
"documents": [
|
||||||
{
|
{
|
||||||
"layer": 4,
|
"layer": 4,
|
||||||
"name": "Лояльность 1",
|
"name": "Лояльность 1",
|
||||||
"description": "постоянная скидка для юзеров, внёсших на проект от 10 000 рублей. Применяется на итоговую сумму, после скидок за сумму в корзине",
|
"description": "постоянная скидка для юзеров, внёсших на проект от 10 000 рублей. Применяется на итоговую сумму, после скидок за сумму в корзине",
|
||||||
"condition": {
|
"condition": {
|
||||||
"purchasesAmount": 10000
|
"purchasesAmount": 10000
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"factor": 0.99
|
"factor": 0.99
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Лояльность 2",
|
"name": "Лояльность 2",
|
||||||
"description": "постоянная скидка для юзеров, внёсших на проект от 25 000 рублей. Применяется на итоговую сумму, после скидок за сумму в корзине",
|
"description": "постоянная скидка для юзеров, внёсших на проект от 25 000 рублей. Применяется на итоговую сумму, после скидок за сумму в корзине",
|
||||||
"layer": 4,
|
"layer": 4,
|
||||||
"condition": {
|
"condition": {
|
||||||
"purchasesAmount": 25000
|
"purchasesAmount": 25000
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"factor": 0.99
|
"factor": 0.99
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Лояльность 3",
|
"name": "Лояльность 3",
|
||||||
"description": "постоянная скидка для юзеров, внёсших на проект от 50 000 рублей. Применяется на итоговую сумму, после скидок за сумму в корзине",
|
"description": "постоянная скидка для юзеров, внёсших на проект от 50 000 рублей. Применяется на итоговую сумму, после скидок за сумму в корзине",
|
||||||
"layer": 4,
|
"layer": 4,
|
||||||
"condition": {
|
"condition": {
|
||||||
"purchasesAmount": 50000
|
"purchasesAmount": 50000
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"factor": 0.975
|
"factor": 0.975
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Корзина 1",
|
"name": "Корзина 1",
|
||||||
"description": "Скидка на размер корзины от 5 000 р. Применяется на итоговую сумму, после суммирования корзины",
|
"description": "Скидка на размер корзины от 5 000 р. Применяется на итоговую сумму, после суммирования корзины",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"cartPurchasesAmount": 5000
|
"cartPurchasesAmount": 5000
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "sum",
|
"scope": "sum",
|
||||||
"factor": 0.985
|
"factor": 0.985
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Корзина 2",
|
"name": "Корзина 2",
|
||||||
"description": "Скидка на размер корзины от 50 000 р. Применяется на итоговую сумму, после суммирования корзины",
|
"description": "Скидка на размер корзины от 50 000 р. Применяется на итоговую сумму, после суммирования корзины",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"cartPurchasesAmount": 50000
|
"cartPurchasesAmount": 50000
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "sum",
|
"scope": "sum",
|
||||||
"factor": 0.965
|
"factor": 0.965
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "НКО",
|
"name": "НКО",
|
||||||
"description": "Скидка всем подтвердившим статус НКО. Перекрывает ВСЕ остальные скидки. Если эта скидка срабатывает, остальные можно не вычислять. Т.е. если на уровне 0 находится какая-лидо скидка для выданных условий, просто суммируем корзину и применяем к сумме указанный множитель, после чего прекращаем процесс рассчёта",
|
"description": "Скидка всем подтвердившим статус НКО. Перекрывает ВСЕ остальные скидки. Если эта скидка срабатывает, остальные можно не вычислять. Т.е. если на уровне 0 находится какая-лидо скидка для выданных условий, просто суммируем корзину и применяем к сумме указанный множитель, после чего прекращаем процесс рассчёта",
|
||||||
"layer": 1,
|
"layer": 1,
|
||||||
"condition": {
|
"condition": {
|
||||||
"userType": "nko"
|
"userType": "nko"
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "sum",
|
"scope": "sum",
|
||||||
"factor": 0.2,
|
"factor": 0.2,
|
||||||
"overhelm": true
|
"overhelm": true
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Промокод На АБ тесты",
|
"name": "Промокод На АБ тесты",
|
||||||
"description": "Скидка, полученная конкретным юзером, после введения промокода. Заменяет собой не промокодовую",
|
"description": "Скидка, полученная конкретным юзером, после введения промокода. Заменяет собой не промокодовую",
|
||||||
"layer": 2,
|
"layer": 2,
|
||||||
"condition": {
|
"condition": {
|
||||||
"coupon": "coupon1",
|
"coupon": "coupon1",
|
||||||
"user": "buddy"
|
"user": "buddy"
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"overhelm": true,
|
"overhelm": true,
|
||||||
"scope": "each",
|
"scope": "each",
|
||||||
"products": [
|
"products": [
|
||||||
{
|
{
|
||||||
"productId": "p6",
|
"productId": "p6",
|
||||||
"factor": 0.5
|
"factor": 0.5
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Новогодняя скидка",
|
"name": "Новогодняя скидка",
|
||||||
"description": "",
|
"description": "",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"period": {
|
"period": {
|
||||||
"from": "2022-12-31T00:00:00.000Z",
|
"from": "2022-12-31T00:00:00.000Z",
|
||||||
"to": "2024-01-01T00:00:00.000Z"
|
"to": "2024-01-01T00:00:00.000Z"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "each",
|
"scope": "each",
|
||||||
"products": [
|
"products": [
|
||||||
{
|
{
|
||||||
"productId": "p1",
|
"productId": "p1",
|
||||||
"factor": 0.965
|
"factor": 0.965
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"productId": "p2",
|
"productId": "p2",
|
||||||
"factor": 0.5
|
"factor": 0.5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"productId": "p3",
|
"productId": "p3",
|
||||||
"factor": 0.8
|
"factor": 0.8
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"productId": "p4",
|
"productId": "p4",
|
||||||
"factor": 0.95
|
"factor": 0.95
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Скидка на определённого пользователя",
|
"name": "Скидка на определённого пользователя",
|
||||||
"description": "",
|
"description": "",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"user": "another_buddy"
|
"user": "another_buddy"
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "sum",
|
"scope": "sum",
|
||||||
"factor": 0.95
|
"factor": 0.95
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Анлим Шабло 1",
|
"name": "Анлим Шабло 1",
|
||||||
"description": "Скидка на количество безлимитных дней работы от 30 дней",
|
"description": "Скидка на количество безлимитных дней работы от 30 дней",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"term": 30,
|
"term": 30,
|
||||||
"product": "p1"
|
"product": "p1"
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "each",
|
"scope": "each",
|
||||||
"products": [
|
"products": [
|
||||||
{
|
{
|
||||||
"productId": "p1",
|
"productId": "p1",
|
||||||
"factor": 0.975
|
"factor": 0.975
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Анлим Шабло 2",
|
"name": "Анлим Шабло 2",
|
||||||
"description": "Скидка на количество безлимитных дней работы от 90 дней",
|
"description": "Скидка на количество безлимитных дней работы от 90 дней",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"term": 90,
|
"term": 90,
|
||||||
"product": "p1"
|
"product": "p1"
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "each",
|
"scope": "each",
|
||||||
"products": [
|
"products": [
|
||||||
{
|
{
|
||||||
"productId": "p1",
|
"productId": "p1",
|
||||||
"factor": 0.975
|
"factor": 0.975
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Анлим Шабло 3",
|
"name": "Анлим Шабло 3",
|
||||||
"description": "Скидка на количество безлимитных дней работы от 180 дней",
|
"description": "Скидка на количество безлимитных дней работы от 180 дней",
|
||||||
"layer": 1,
|
"layer": 1,
|
||||||
"condition": {
|
"condition": {
|
||||||
"term": 180,
|
"term": 180,
|
||||||
"product": "p1"
|
"product": "p1"
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "each",
|
"scope": "each",
|
||||||
"products": [
|
"products": [
|
||||||
{
|
{
|
||||||
"productId": "p1",
|
"productId": "p1",
|
||||||
"factor": 0.93
|
"factor": 0.93
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Генерации Шабло 1",
|
"name": "Генерации Шабло 1",
|
||||||
"description": "Скидка на количество генераций от 100 шт",
|
"description": "Скидка на количество генераций от 100 шт",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"usage": 100,
|
"usage": 100,
|
||||||
"product": "p2"
|
"product": "p2"
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "each",
|
"scope": "each",
|
||||||
"products": [
|
"products": [
|
||||||
{
|
{
|
||||||
"productId": "p2",
|
"productId": "p2",
|
||||||
"factor": 0.995
|
"factor": 0.995
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Генерации Шабло 2",
|
"name": "Генерации Шабло 2",
|
||||||
"description": "Скидка на количество генераций от 350 шт",
|
"description": "Скидка на количество генераций от 350 шт",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"usage": 350,
|
"usage": 350,
|
||||||
"product": "p2"
|
"product": "p2"
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "each",
|
"scope": "each",
|
||||||
"products": [
|
"products": [
|
||||||
{
|
{
|
||||||
"productId": "p2",
|
"productId": "p2",
|
||||||
"factor": 0.98
|
"factor": 0.98
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Генерации Шабло 3",
|
"name": "Генерации Шабло 3",
|
||||||
"description": "Скидка на количество генераций от 500 шт",
|
"description": "Скидка на количество генераций от 500 шт",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"usage": 500,
|
"usage": 500,
|
||||||
"product": "p2"
|
"product": "p2"
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "each",
|
"scope": "each",
|
||||||
"products": [
|
"products": [
|
||||||
{
|
{
|
||||||
"productId": "p2",
|
"productId": "p2",
|
||||||
"factor": 0.945
|
"factor": 0.945
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Шаблонизатор 1",
|
"name": "Шаблонизатор 1",
|
||||||
"description": "Скидка на сумму стоимостей товаров, принадлежащих сервису шаблонизации, от 1000 р",
|
"description": "Скидка на сумму стоимостей товаров, принадлежащих сервису шаблонизации, от 1000 р",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"group": "templategen",
|
"group": "templategen",
|
||||||
"priceFrom": 1000
|
"priceFrom": 1000
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "group",
|
"scope": "group",
|
||||||
"group": "templategen",
|
"group": "templategen",
|
||||||
"factor": 0.996
|
"factor": 0.996
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Шаблонизатор 2",
|
"name": "Шаблонизатор 2",
|
||||||
"description": "Скидка на сумму стоимостей товаров, принадлежащих сервису шаблонизации, от 5000 р",
|
"description": "Скидка на сумму стоимостей товаров, принадлежащих сервису шаблонизации, от 5000 р",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"group": "templategen",
|
"group": "templategen",
|
||||||
"priceFrom": 5000
|
"priceFrom": 5000
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "group",
|
"scope": "group",
|
||||||
"group": "templategen",
|
"group": "templategen",
|
||||||
"factor": 0.983
|
"factor": 0.983
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Опросник 1",
|
"name": "Опросник 1",
|
||||||
"description": "Скидка на сумму стоимостей товаров, принадлежащих сервису опросника, от 2000 р",
|
"description": "Скидка на сумму стоимостей товаров, принадлежащих сервису опросника, от 2000 р",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"group": "squiz",
|
"group": "squiz",
|
||||||
"priceFrom": 2000
|
"priceFrom": 2000
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "group",
|
"scope": "group",
|
||||||
"group": "squiz",
|
"group": "squiz",
|
||||||
"factor": 0.983
|
"factor": 0.983
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Опросник 2",
|
"name": "Опросник 2",
|
||||||
"description": "Скидка на сумму стоимостей товаров, принадлежащих сервису опросника, от 6000 р",
|
"description": "Скидка на сумму стоимостей товаров, принадлежащих сервису опросника, от 6000 р",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"group": "squiz",
|
"group": "squiz",
|
||||||
"priceFrom": 6000
|
"priceFrom": 6000
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "group",
|
"scope": "group",
|
||||||
"group": "squiz",
|
"group": "squiz",
|
||||||
"factor": 0.969
|
"factor": 0.969
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Сокращатель 1",
|
"name": "Сокращатель 1",
|
||||||
"description": "Скидка на сумму стоимостей товаров, принадлежащих сервису сокращателя, от 500 р",
|
"description": "Скидка на сумму стоимостей товаров, принадлежащих сервису сокращателя, от 500 р",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"group": "dwarfener",
|
"group": "dwarfener",
|
||||||
"priceFrom": 500
|
"priceFrom": 500
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "group",
|
"scope": "group",
|
||||||
"group": "dwarfener",
|
"group": "dwarfener",
|
||||||
"factor": 0.99
|
"factor": 0.99
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Сокращатель 2",
|
"name": "Сокращатель 2",
|
||||||
"description": "Скидка на сумму стоимостей товаров, принадлежащих сервису сокращателя, от 2500 р",
|
"description": "Скидка на сумму стоимостей товаров, принадлежащих сервису сокращателя, от 2500 р",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"group": "dwarfener",
|
"group": "dwarfener",
|
||||||
"priceFrom": 2500
|
"priceFrom": 2500
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "group",
|
"scope": "group",
|
||||||
"group": "dwarfener",
|
"group": "dwarfener",
|
||||||
"factor": 0.96
|
"factor": 0.96
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"_id": {
|
"_id": {
|
||||||
"$oid": "641b2d73e0e07a7e90b59616"
|
"$oid": "641b2d73e0e07a7e90b59616"
|
||||||
},
|
},
|
||||||
"name": "Анлим Квиз 1",
|
"name": "Анлим Квиз 1",
|
||||||
"description": "Скидка на количество дней безлимитного использования опросника, от 30 дней",
|
"description": "Скидка на количество дней безлимитного использования опросника, от 30 дней",
|
||||||
"layer": 3,
|
"layer": 3,
|
||||||
"condition": {
|
"condition": {
|
||||||
"term": 30,
|
"term": 30,
|
||||||
"product": "p3"
|
"product": "p3"
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"scope": "each",
|
"scope": "each",
|
||||||
"products": [
|
"products": [
|
||||||
{
|
{
|
||||||
"productId": "p3",
|
"productId": "p3",
|
||||||
"factor": 0.97
|
"factor": 0.97
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"deprecated": false,
|
"deprecated": false,
|
||||||
"audit": {
|
"audit": {
|
||||||
"createdAt": "2022-12-31T00:00:00.000Z",
|
"createdAt": "2022-12-31T00:00:00.000Z",
|
||||||
"updatedAt": "2022-12-31T00:00:00.000Z",
|
"updatedAt": "2022-12-31T00:00:00.000Z",
|
||||||
"deleted": false
|
"deleted": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package array
|
package array
|
||||||
|
|
||||||
func Contains[T any](array []T, callback func(T, int, []T) bool) bool {
|
func Contains[T any](array []T, callback func(T, int, []T) bool) bool {
|
||||||
isContains := false
|
isContains := false
|
||||||
|
|
||||||
for index, element := range array {
|
for index, element := range array {
|
||||||
if callback(element, index, array) {
|
if callback(element, index, array) {
|
||||||
isContains = true
|
isContains = true
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return isContains
|
return isContains
|
||||||
}
|
}
|
||||||
|
@ -1,153 +1,153 @@
|
|||||||
package array_test
|
package array_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/array"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/array"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestContains(t *testing.T) {
|
func TestContains(t *testing.T) {
|
||||||
testCasesWithPrimitives := []struct {
|
testCasesWithPrimitives := []struct {
|
||||||
name string
|
name string
|
||||||
inputArray []any
|
inputArray []any
|
||||||
inputCallback func(any, int, []any) bool
|
inputCallback func(any, int, []any) bool
|
||||||
expect bool
|
expect bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Проверка наличие строк по значению",
|
name: "Проверка наличие строк по значению",
|
||||||
inputArray: []any{"test1", "test2"},
|
inputArray: []any{"test1245", "test2"},
|
||||||
inputCallback: func(element any, index int, array []any) bool {
|
inputCallback: func(element any, index int, array []any) bool {
|
||||||
assert.Equal(t, array, []any{"test1", "test2"})
|
assert.Equal(t, array, []any{"test1245", "test2"})
|
||||||
|
|
||||||
return element == "test1"
|
return element == "test1245"
|
||||||
},
|
},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Проверка наличие строк по значению (неудачная)",
|
name: "Проверка наличие строк по значению (неудачная)",
|
||||||
inputArray: []any{"test1", "test2"},
|
inputArray: []any{"test1", "test2"},
|
||||||
inputCallback: func(element any, index int, array []any) bool {
|
inputCallback: func(element any, index int, array []any) bool {
|
||||||
assert.Equal(t, array, []any{"test1", "test2"})
|
assert.Equal(t, array, []any{"test1", "test2"})
|
||||||
|
|
||||||
return element == "tttt"
|
return element == "fdadadfadfadf"
|
||||||
},
|
},
|
||||||
expect: false,
|
expect: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Проверка наличие строк по индексу",
|
name: "Проверка наличие строк по индексу",
|
||||||
inputArray: []any{"test1", "test2"},
|
inputArray: []any{"test1", "test2"},
|
||||||
inputCallback: func(element any, index int, array []any) bool {
|
inputCallback: func(element any, index int, array []any) bool {
|
||||||
assert.Equal(t, array, []any{"test1", "test2"})
|
assert.Equal(t, array, []any{"test1", "test2"})
|
||||||
|
|
||||||
return index == 1
|
return index == 1
|
||||||
},
|
},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Проверка наличие чисел по значению",
|
name: "Проверка наличие чисел по значению",
|
||||||
inputArray: []any{1, 4},
|
inputArray: []any{1, 4},
|
||||||
inputCallback: func(element any, index int, array []any) bool {
|
inputCallback: func(element any, index int, array []any) bool {
|
||||||
assert.Equal(t, array, []any{1, 4})
|
assert.Equal(t, array, []any{1, 4})
|
||||||
|
|
||||||
return element == 1
|
return element == 1
|
||||||
},
|
},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Проверка наличие строк по значению с несколькими схожими значениями",
|
name: "Проверка наличие строк по значению с несколькими схожими значениями",
|
||||||
inputArray: []any{"test1", "test2"},
|
inputArray: []any{"test1", "test2"},
|
||||||
inputCallback: func(element any, index int, array []any) bool {
|
inputCallback: func(element any, index int, array []any) bool {
|
||||||
assert.Equal(t, array, []any{"test1", "test2"})
|
assert.Equal(t, array, []any{"test1", "test2"})
|
||||||
|
|
||||||
return strings.Contains(element.(string), "test")
|
return strings.Contains(element.(string), "test")
|
||||||
},
|
},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCasesWithObjects := []struct {
|
testCasesWithObjects := []struct {
|
||||||
name string
|
name string
|
||||||
inputArray []struct{ Name string }
|
inputArray []struct{ Name string }
|
||||||
inputCallback func(struct{ Name string }, int, []struct{ Name string }) bool
|
inputCallback func(struct{ Name string }, int, []struct{ Name string }) bool
|
||||||
expect bool
|
expect bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Проверка наличие объектов по индексу",
|
name: "Проверка наличие объектов по индексу",
|
||||||
inputArray: []struct{ Name string }{
|
inputArray: []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test1"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
},
|
},
|
||||||
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
||||||
assert.Equal(t, array, []struct{ Name string }{
|
assert.Equal(t, array, []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test1"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
})
|
})
|
||||||
|
|
||||||
return index == 1
|
return index == 1
|
||||||
},
|
},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Проверка наличие объектов по имени (неудачная)",
|
name: "Проверка наличие объектов по имени (неудачная)",
|
||||||
inputArray: []struct{ Name string }{
|
inputArray: []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test1"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
},
|
},
|
||||||
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
||||||
assert.Equal(t, array, []struct{ Name string }{
|
assert.Equal(t, array, []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test1"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
})
|
})
|
||||||
|
|
||||||
return element.Name == "tttt"
|
return element.Name == "tttt"
|
||||||
},
|
},
|
||||||
expect: false,
|
expect: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Проверка наличие объектов по значению поля",
|
name: "Проверка наличие объектов по значению поля",
|
||||||
inputArray: []struct{ Name string }{
|
inputArray: []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test19999"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
},
|
},
|
||||||
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
||||||
assert.Equal(t, array, []struct{ Name string }{
|
assert.Equal(t, array, []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test19999"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
})
|
})
|
||||||
|
|
||||||
return element.Name == "test1"
|
return element.Name == "test19999"
|
||||||
},
|
},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Проверка наличие объектов по совпадению значения поля",
|
name: "Проверка наличие объектов по совпадению значения поля",
|
||||||
inputArray: []struct{ Name string }{
|
inputArray: []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test1"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
},
|
},
|
||||||
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
||||||
assert.Equal(t, array, []struct{ Name string }{
|
assert.Equal(t, array, []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test1"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
})
|
})
|
||||||
|
|
||||||
return strings.Contains(element.Name, "test")
|
return strings.Contains(element.Name, "test")
|
||||||
},
|
},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCasesWithPrimitives {
|
for _, test := range testCasesWithPrimitives {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
assert.Equal(t, test.expect, array.Contains(test.inputArray, test.inputCallback))
|
assert.Equal(t, test.expect, array.Contains(test.inputArray, test.inputCallback))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCasesWithObjects {
|
for _, test := range testCasesWithObjects {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
assert.Equal(t, test.expect, array.Contains(test.inputArray, test.inputCallback))
|
assert.Equal(t, test.expect, array.Contains(test.inputArray, test.inputCallback))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,4 +11,3 @@ func Filter[T any](array []T, callback func(T, int, []T) bool) []T {
|
|||||||
|
|
||||||
return filteredArray
|
return filteredArray
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,134 +1,134 @@
|
|||||||
package array_test
|
package array_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/array"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/array"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFilter(t *testing.T) {
|
func TestFilter(t *testing.T) {
|
||||||
testCasesWithPrimitives := []struct {
|
testCasesWithPrimitives := []struct {
|
||||||
name string
|
name string
|
||||||
inputArray []any
|
inputArray []any
|
||||||
inputCallback func(any, int, []any) bool
|
inputCallback func(any, int, []any) bool
|
||||||
expect []any
|
expect []any
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Фильтрация массива строк по значению",
|
name: "Фильтрация массива строк по значению",
|
||||||
inputArray: []any{"test1", "test2"},
|
inputArray: []any{"test10130153", "test2"},
|
||||||
inputCallback: func(element any, index int, array []any) bool {
|
inputCallback: func(element any, index int, array []any) bool {
|
||||||
assert.Equal(t, array, []any{"test1", "test2"})
|
assert.Equal(t, array, []any{"test10130153", "test2"})
|
||||||
|
|
||||||
return element == "test1"
|
return element == "test10130153"
|
||||||
},
|
},
|
||||||
expect: []any{"test1"},
|
expect: []any{"test10130153"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Фильтрация массива строк по индексу",
|
name: "Фильтрация массива строк по индексу",
|
||||||
inputArray: []any{"test1", "test2"},
|
inputArray: []any{"test1", "test2"},
|
||||||
inputCallback: func(element any, index int, array []any) bool {
|
inputCallback: func(element any, index int, array []any) bool {
|
||||||
assert.Equal(t, array, []any{"test1", "test2"})
|
assert.Equal(t, array, []any{"test1", "test2"})
|
||||||
|
|
||||||
return index == 1
|
return index == 1
|
||||||
},
|
},
|
||||||
expect: []any{"test2"},
|
expect: []any{"test2"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Фильтрация массива чисел по значению",
|
name: "Фильтрация массива чисел по значению",
|
||||||
inputArray: []any{1, 4},
|
inputArray: []any{1, 4},
|
||||||
inputCallback: func(element any, index int, array []any) bool {
|
inputCallback: func(element any, index int, array []any) bool {
|
||||||
assert.Equal(t, array, []any{1, 4})
|
assert.Equal(t, array, []any{1, 4})
|
||||||
|
|
||||||
return element == 1
|
return element == 1
|
||||||
},
|
},
|
||||||
expect: []any{1},
|
expect: []any{1},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Фильтрация массива строк по значению с несколькими схожими значениями",
|
name: "Фильтрация массива строк по значению с несколькими схожими значениями",
|
||||||
inputArray: []any{"test1", "test2"},
|
inputArray: []any{"test1", "test2"},
|
||||||
inputCallback: func(element any, index int, array []any) bool {
|
inputCallback: func(element any, index int, array []any) bool {
|
||||||
assert.Equal(t, array, []any{"test1", "test2"})
|
assert.Equal(t, array, []any{"test1", "test2"})
|
||||||
|
|
||||||
return strings.Contains(element.(string), "test")
|
return strings.Contains(element.(string), "test")
|
||||||
},
|
},
|
||||||
expect: []any{"test1", "test2"},
|
expect: []any{"test1", "test2"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCasesWithObjects := []struct {
|
testCasesWithObjects := []struct {
|
||||||
name string
|
name string
|
||||||
inputArray []struct{ Name string }
|
inputArray []struct{ Name string }
|
||||||
inputCallback func(struct{ Name string }, int, []struct{ Name string }) bool
|
inputCallback func(struct{ Name string }, int, []struct{ Name string }) bool
|
||||||
expect []struct{ Name string }
|
expect []struct{ Name string }
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Фильтрация массива объектов по индексу",
|
name: "Фильтрация массива объектов по индексу",
|
||||||
inputArray: []struct{ Name string }{
|
inputArray: []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test1"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
},
|
},
|
||||||
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
||||||
assert.Equal(t, array, []struct{ Name string }{
|
assert.Equal(t, array, []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test1"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
})
|
})
|
||||||
|
|
||||||
return index == 1
|
return index == 1
|
||||||
},
|
},
|
||||||
expect: []struct{ Name string }{
|
expect: []struct{ Name string }{
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Фильтрация массива объектов по значению поля",
|
name: "Фильтрация массива объектов по значению поля",
|
||||||
inputArray: []struct{ Name string }{
|
inputArray: []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test5313131"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
},
|
},
|
||||||
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
||||||
assert.Equal(t, array, []struct{ Name string }{
|
assert.Equal(t, array, []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test5313131"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
})
|
})
|
||||||
|
|
||||||
return element.Name == "test1"
|
return element.Name == "test5313131"
|
||||||
},
|
},
|
||||||
expect: []struct{ Name string }{
|
expect: []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test5313131"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Фильтрация массива объектов по совпадению значения поля",
|
name: "Фильтрация массива объектов по совпадению значения поля",
|
||||||
inputArray: []struct{ Name string }{
|
inputArray: []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test1"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
},
|
},
|
||||||
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
inputCallback: func(element struct{ Name string }, index int, array []struct{ Name string }) bool {
|
||||||
assert.Equal(t, array, []struct{ Name string }{
|
assert.Equal(t, array, []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test1"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
})
|
})
|
||||||
|
|
||||||
return strings.Contains(element.Name, "test")
|
return strings.Contains(element.Name, "test")
|
||||||
},
|
},
|
||||||
expect: []struct{ Name string }{
|
expect: []struct{ Name string }{
|
||||||
{Name: "test1"},
|
{Name: "test1"},
|
||||||
{Name: "test2"},
|
{Name: "test2"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCasesWithPrimitives {
|
for _, test := range testCasesWithPrimitives {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
assert.Equal(t, test.expect, array.Filter(test.inputArray, test.inputCallback))
|
assert.Equal(t, test.expect, array.Filter(test.inputArray, test.inputCallback))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCasesWithObjects {
|
for _, test := range testCasesWithObjects {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
assert.ElementsMatch(t, test.expect, array.Filter(test.inputArray, test.inputCallback))
|
assert.ElementsMatch(t, test.expect, array.Filter(test.inputArray, test.inputCallback))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
pkg/array/find.go
Normal file
11
pkg/array/find.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package array
|
||||||
|
|
||||||
|
func Find[T any](array []T, callback func(T, int, []T) bool) *T {
|
||||||
|
for index, element := range array {
|
||||||
|
if callback(element, index, array) {
|
||||||
|
return &element
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
32
pkg/array/find_test.go
Normal file
32
pkg/array/find_test.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package array_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/array"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFind(t *testing.T) {
|
||||||
|
t.Run("Find element in array (success)", func(t *testing.T) {
|
||||||
|
result := "test1"
|
||||||
|
callback := func(element string, index int, array []string) bool {
|
||||||
|
assert.Equal(t, array, []string{"test1", "test2"})
|
||||||
|
|
||||||
|
return element == result
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, &result, array.Find([]string{"test1", "test2"}, callback))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Find element in array (failure)", func(t *testing.T) {
|
||||||
|
result := "test"
|
||||||
|
callback := func(element string, index int, array []string) bool {
|
||||||
|
assert.Equal(t, array, []string{"test1", "test2"})
|
||||||
|
|
||||||
|
return element == result
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Nil(t, array.Find([]string{"test1", "test2"}, callback))
|
||||||
|
})
|
||||||
|
}
|
50
pkg/closer/closer.go
Normal file
50
pkg/closer/closer.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package closer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Callback func(ctx context.Context) error
|
||||||
|
|
||||||
|
type Closer struct {
|
||||||
|
mutex sync.Mutex
|
||||||
|
callbacks []Callback
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *Closer {
|
||||||
|
return &Closer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *Closer) Add(callback Callback) {
|
||||||
|
receiver.mutex.Lock()
|
||||||
|
defer receiver.mutex.Unlock()
|
||||||
|
|
||||||
|
receiver.callbacks = append(receiver.callbacks, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *Closer) Close(ctx context.Context) error {
|
||||||
|
receiver.mutex.Lock()
|
||||||
|
defer receiver.mutex.Unlock()
|
||||||
|
|
||||||
|
complete := make(chan struct{}, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for index, callback := range receiver.callbacks {
|
||||||
|
if err := callback(ctx); err != nil {
|
||||||
|
log.Printf("[! (%d)] %v", index, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete <- struct{}{}
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-complete:
|
||||||
|
return nil
|
||||||
|
case <-ctx.Done():
|
||||||
|
return fmt.Errorf("shutdown cancelled: %v", ctx.Err())
|
||||||
|
}
|
||||||
|
}
|
@ -1,29 +1,29 @@
|
|||||||
package convert
|
package convert
|
||||||
|
|
||||||
import "strconv"
|
import "strconv"
|
||||||
|
|
||||||
func StringArrayToIntSlice(stringArray []string) []int {
|
func StringArrayToIntSlice(stringArray []string) []int {
|
||||||
intArray := make([]int, 0, len(stringArray))
|
intArray := make([]int, 0, len(stringArray))
|
||||||
|
|
||||||
for _, stringValue := range stringArray {
|
for _, stringValue := range stringArray {
|
||||||
intValue, err := strconv.Atoi(stringValue)
|
intValue, err := strconv.Atoi(stringValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
intArray = append(intArray, intValue)
|
intArray = append(intArray, intValue)
|
||||||
}
|
}
|
||||||
return intArray
|
return intArray
|
||||||
}
|
}
|
||||||
|
|
||||||
func MapToArray[T any, V comparable](currentMap map[V]T) []T {
|
func MapToArray[T any, V comparable](currentMap map[V]T) []T {
|
||||||
result := make([]T, len(currentMap))
|
result := make([]T, len(currentMap))
|
||||||
index := 0
|
index := 0
|
||||||
|
|
||||||
for _, element := range currentMap {
|
for _, element := range currentMap {
|
||||||
result[index] = element
|
result[index] = element
|
||||||
index++
|
index++
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
package convert
|
package convert
|
||||||
|
|
||||||
func ArrayToMap[T any, V comparable](array []T, key func(T) V) map[V]T {
|
func ArrayToMap[T any, V comparable](array []T, key func(T) V) map[V]T {
|
||||||
result := make(map[V]T, len(array))
|
result := make(map[V]T, len(array))
|
||||||
|
|
||||||
for _, element := range array {
|
for _, element := range array {
|
||||||
result[key(element)] = element
|
result[key(element)] = element
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func MapToMapArray[T any, V comparable](currentMap map[V]T, key func(T) V) map[V][]T {
|
func MapToMapArray[T any, V comparable](currentMap map[V]T, key func(T) V) map[V][]T {
|
||||||
result := make(map[V][]T)
|
result := make(map[V][]T)
|
||||||
|
|
||||||
for _, element := range currentMap {
|
for _, element := range currentMap {
|
||||||
currentKey := key(element)
|
currentKey := key(element)
|
||||||
result[currentKey] = append(result[currentKey], element)
|
result[currentKey] = append(result[currentKey], element)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
74
pkg/convert/map_test.go
Normal file
74
pkg/convert/map_test.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package convert_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/convert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestArrayToMap(t *testing.T) {
|
||||||
|
type Product struct {
|
||||||
|
ID string
|
||||||
|
Price float64
|
||||||
|
Group string
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Успешная конвертация массива в карту по ID", func(t *testing.T) {
|
||||||
|
products := []Product{
|
||||||
|
{ID: "p1", Price: 1500, Group: "templategen"},
|
||||||
|
{ID: "p2", Price: 300, Group: "templategen"},
|
||||||
|
{ID: "p5", Price: 30, Group: "dwarfener"},
|
||||||
|
{ID: "p6", Price: 70, Group: "dwarfener"},
|
||||||
|
{ID: "p7", Price: 800, Group: "dwarfener"},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t,
|
||||||
|
map[string]Product{
|
||||||
|
"p1": {ID: "p1", Price: 1500, Group: "templategen"},
|
||||||
|
"p2": {ID: "p2", Price: 300, Group: "templategen"},
|
||||||
|
"p5": {ID: "p5", Price: 30, Group: "dwarfener"},
|
||||||
|
"p6": {ID: "p6", Price: 70, Group: "dwarfener"},
|
||||||
|
"p7": {ID: "p7", Price: 800, Group: "dwarfener"},
|
||||||
|
},
|
||||||
|
convert.ArrayToMap(products, func(product Product) string {
|
||||||
|
return product.ID
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMapToMapArray(t *testing.T) {
|
||||||
|
type Product struct {
|
||||||
|
ID string
|
||||||
|
Price float64
|
||||||
|
Group string
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Успешная конвертация массива в карту из массивов", func(t *testing.T) {
|
||||||
|
productsMap := map[string]Product{
|
||||||
|
"p1": {ID: "p1", Price: 1500, Group: "templategen"},
|
||||||
|
"p2": {ID: "p2", Price: 300, Group: "templategen"},
|
||||||
|
"p5": {ID: "p5", Price: 30, Group: "dwarfener"},
|
||||||
|
"p6": {ID: "p6", Price: 70, Group: "dwarfener"},
|
||||||
|
"p7": {ID: "p7", Price: 800, Group: "dwarfener"},
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.EqualValues(t,
|
||||||
|
map[string][]Product{
|
||||||
|
"templategen": {
|
||||||
|
{ID: "p1", Price: 1500, Group: "templategen"},
|
||||||
|
{ID: "p2", Price: 300, Group: "templategen"},
|
||||||
|
},
|
||||||
|
"dwarfener": {
|
||||||
|
{ID: "p5", Price: 30, Group: "dwarfener"},
|
||||||
|
{ID: "p6", Price: 70, Group: "dwarfener"},
|
||||||
|
{ID: "p7", Price: 800, Group: "dwarfener"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
convert.MapToMapArray(productsMap, func(product Product) string {
|
||||||
|
return product.Group
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
@ -1,60 +1,58 @@
|
|||||||
package convert
|
package convert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ObjectToMap[T ~map[string]interface{}](object interface{}, tagName string) (T, error) {
|
func ObjectToMap[T ~map[string]interface{}](object interface{}, tagName string) (T, error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if recoveredError := recover(); recoveredError != nil {
|
if recoveredError := recover(); recoveredError != nil {
|
||||||
fmt.Println("recovered from ObjectToMap: ", recoveredError)
|
fmt.Println("recovered from ObjectToMap: ", recoveredError)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
values := reflect.ValueOf(object)
|
values := reflect.ValueOf(object)
|
||||||
if values.Kind() == reflect.Ptr {
|
if values.Kind() == reflect.Ptr {
|
||||||
values = values.Elem()
|
values = values.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
if values.Kind() != reflect.Struct {
|
if values.Kind() != reflect.Struct {
|
||||||
return nil, fmt.Errorf("ObjectToMap only accepts structs; got %T", values)
|
return nil, fmt.Errorf("ObjectToMap only accepts structs; got %T", values)
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsCount := values.NumField()
|
fieldsCount := values.NumField()
|
||||||
resultMap := make(T, fieldsCount)
|
resultMap := make(T, fieldsCount)
|
||||||
valueType := values.Type()
|
valueType := values.Type()
|
||||||
|
|
||||||
for index := 0; index < fieldsCount; index++ {
|
for index := 0; index < fieldsCount; index++ {
|
||||||
fieldType := valueType.Field(index)
|
fieldType := valueType.Field(index)
|
||||||
field := values.Field(index)
|
field := values.Field(index)
|
||||||
|
|
||||||
if field.IsZero() {
|
if field.IsZero() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if tagValue := fieldType.Tag.Get(tagName); tagValue != "" {
|
if tagValue := fieldType.Tag.Get(tagName); tagValue != "" {
|
||||||
resultMap[tagValue] = field.Interface()
|
resultMap[tagValue] = field.Interface()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultMap, nil
|
return resultMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ObjectToStringMap(object interface{}, tagName string) (map[string]string, error) {
|
func ObjectToStringMap(object interface{}, tagName string) (map[string]string, error) {
|
||||||
mapObject, err := ObjectToMap[map[string]interface{}](object, tagName)
|
mapObject, err := ObjectToMap[map[string]interface{}](object, tagName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mapString := make(map[string]string, len(mapObject))
|
mapString := make(map[string]string, len(mapObject))
|
||||||
|
|
||||||
for key, value := range mapObject {
|
for key, value := range mapObject {
|
||||||
strKey := fmt.Sprintf("%v", key)
|
strValue := fmt.Sprintf("%v", value)
|
||||||
strValue := fmt.Sprintf("%v", value)
|
mapString[key] = strValue
|
||||||
|
}
|
||||||
mapString[strKey] = strValue
|
|
||||||
}
|
return mapString, nil
|
||||||
|
}
|
||||||
return mapString, nil
|
|
||||||
}
|
|
||||||
|
11
pkg/convert/uint.go
Normal file
11
pkg/convert/uint.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package convert
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FloatToUint64[T constraints.Float](number T) uint64 {
|
||||||
|
return uint64(math.Floor(float64(number)))
|
||||||
|
}
|
22
pkg/convert/uint_test.go
Normal file
22
pkg/convert/uint_test.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package convert_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/convert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFloatToUint64(t *testing.T) {
|
||||||
|
t.Run("Успешная конвертация float32 в uint32", func(t *testing.T) {
|
||||||
|
assert.Equal(t, uint64(10), convert.FloatToUint64(float32(10.6)))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Успешная конвертация float64 в uint32", func(t *testing.T) {
|
||||||
|
assert.Equal(t, uint64(10), convert.FloatToUint64(float64(10.6)))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Успешная конвертация float64 в uint32 (2)", func(t *testing.T) {
|
||||||
|
assert.Equal(t, uint64(10), convert.FloatToUint64(float64(10)))
|
||||||
|
})
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
package defaults
|
package defaults
|
||||||
|
|
||||||
func GetDefaultValue[T any](value *T, defaultValue T) T {
|
func GetDefaultValue[T any](value *T, defaultValue T) T {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
return *value
|
return *value
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
package defaults_test
|
package defaults_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/defaults"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/defaults"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetDefaultValue(t *testing.T) {
|
func TestGetDefaultValue(t *testing.T) {
|
||||||
|
t.Run("Стандартное значение nil", func(t *testing.T) {
|
||||||
t.Run("Стандартное значение nil", func(t *testing.T) {
|
assert.Equal(t, 0, defaults.GetDefaultValue(nil, 0))
|
||||||
assert.Equal(t, 0, defaults.GetDefaultValue(nil, 0))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Стандартное значение float64", func(t *testing.T) {
|
||||||
t.Run("Стандартное значение float64", func(t *testing.T) {
|
assert.Equal(t, float64(0), defaults.GetDefaultValue(nil, float64(0)))
|
||||||
assert.Equal(t, float64(0), defaults.GetDefaultValue(nil, float64(0)))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Стандартное значение строки", func(t *testing.T) {
|
||||||
t.Run("Стандартное значение строки", func(t *testing.T) {
|
testString := "test"
|
||||||
testString := "test"
|
|
||||||
|
assert.Equal(t, "test", defaults.GetDefaultValue(&testString, ""))
|
||||||
assert.Equal(t, "test", defaults.GetDefaultValue(&testString, ""))
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
2
pkg/env/parse.go
vendored
2
pkg/env/parse.go
vendored
@ -9,7 +9,7 @@ import (
|
|||||||
envParser "github.com/sethvargo/go-envconfig"
|
envParser "github.com/sethvargo/go-envconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Parsing default env file or env context and returns struct pointer by generic
|
// Parse parsing default env file or env context and returns struct pointer by generic.
|
||||||
func Parse[T interface{}](envFilePath string) (*T, error) {
|
func Parse[T interface{}](envFilePath string) (*T, error) {
|
||||||
var configuration T
|
var configuration T
|
||||||
|
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
package mongo
|
package mongo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
"go.mongodb.org/mongo-driver/mongo/options"
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
Host string `env:"MONGO_HOST,default=localhost"`
|
Host string `env:"MONGO_HOST,default=localhost"`
|
||||||
Port string `env:"MONGO_PORT,default=27017"`
|
Port string `env:"MONGO_PORT,default=27017"`
|
||||||
User string `env:"MONGO_USER,required"`
|
User string `env:"MONGO_USER,required"`
|
||||||
Password string `env:"MONGO_PASSWORD,required"`
|
Password string `env:"MONGO_PASSWORD,required"`
|
||||||
Auth string `env:"MONGO_AUTH,required"`
|
Auth string `env:"MONGO_AUTH,required"`
|
||||||
DatabaseName string `env:"MONGO_DB_NAME,required"`
|
DatabaseName string `env:"MONGO_DB_NAME,required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RequestSettings struct {
|
type RequestSettings struct {
|
||||||
Driver *mongo.Collection
|
Driver *mongo.Collection
|
||||||
Options *options.FindOptions
|
Options *options.FindOptions
|
||||||
Filter primitive.M
|
Filter primitive.M
|
||||||
}
|
}
|
||||||
|
@ -1,71 +1,73 @@
|
|||||||
package mongo
|
package mongo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/event"
|
"go.mongodb.org/mongo-driver/event"
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
"go.mongodb.org/mongo-driver/mongo/options"
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConnectDeps struct {
|
type ConnectDeps struct {
|
||||||
Configuration *Configuration
|
Configuration *Configuration
|
||||||
Timeout time.Duration
|
Timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func Connect(ctx context.Context, deps *ConnectDeps) (*mongo.Database, error) {
|
func Connect(ctx context.Context, deps *ConnectDeps) (*mongo.Database, error) {
|
||||||
if deps == nil {
|
if deps == nil {
|
||||||
return nil, ErrEmptyArgs
|
return nil, ErrEmptyArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
mongoURI := &url.URL{
|
mongoURI := &url.URL{
|
||||||
Scheme: "mongodb",
|
Scheme: "mongodb",
|
||||||
Host: net.JoinHostPort(deps.Configuration.Host, deps.Configuration.Port),
|
Host: net.JoinHostPort(deps.Configuration.Host, deps.Configuration.Port),
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdMonitor := &event.CommandMonitor{
|
cmdMonitor := &event.CommandMonitor{
|
||||||
Started: func(_ context.Context, evt *event.CommandStartedEvent) {
|
Started: func(_ context.Context, evt *event.CommandStartedEvent) {
|
||||||
log.Println(evt.Command)
|
log.Println(evt.Command)
|
||||||
},
|
},
|
||||||
Succeeded: func(_ context.Context, evt *event.CommandSucceededEvent) {
|
Succeeded: func(_ context.Context, evt *event.CommandSucceededEvent) {
|
||||||
log.Println(evt.Reply)
|
log.Println(evt.Reply)
|
||||||
},
|
},
|
||||||
Failed: func(_ context.Context, evt *event.CommandFailedEvent) {
|
Failed: func(_ context.Context, evt *event.CommandFailedEvent) {
|
||||||
log.Println(evt.Failure)
|
log.Println(evt.Failure)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionOptions := options.Client().
|
connectionOptions := options.Client().
|
||||||
ApplyURI(mongoURI.String()).
|
ApplyURI(mongoURI.String()).
|
||||||
SetAuth(options.Credential{
|
SetAuth(options.Credential{
|
||||||
AuthMechanism: "SCRAM-SHA-1",
|
AuthMechanism: "SCRAM-SHA-1",
|
||||||
AuthSource: deps.Configuration.Auth,
|
AuthSource: deps.Configuration.Auth,
|
||||||
Username: deps.Configuration.User,
|
Username: deps.Configuration.User,
|
||||||
Password: deps.Configuration.Password,
|
Password: deps.Configuration.Password,
|
||||||
}).
|
}).
|
||||||
SetMonitor(cmdMonitor)
|
SetMonitor(cmdMonitor)
|
||||||
|
|
||||||
ticker := time.NewTicker(1 * time.Second)
|
ticker := time.NewTicker(1 * time.Second)
|
||||||
timeoutExceeded := time.After(deps.Timeout)
|
timeoutExceeded := time.After(deps.Timeout)
|
||||||
|
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
connection, err := mongo.Connect(ctx, connectionOptions)
|
connection, err := mongo.Connect(ctx, connectionOptions)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return connection.Database(deps.Configuration.DatabaseName), nil
|
return connection.Database(deps.Configuration.DatabaseName), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("failed to connect to db <%s>: %s", mongoURI.String(), err.Error())
|
log.Printf("failed to connect to db <%s>: %s", mongoURI.String(), err.Error())
|
||||||
case <-timeoutExceeded:
|
case <-timeoutExceeded:
|
||||||
return nil, fmt.Errorf("db connection <%s> failed after %d timeout", mongoURI, deps.Timeout)
|
return nil, fmt.Errorf("db connection <%s> failed after %d timeout", mongoURI.String(), deps.Timeout)
|
||||||
}
|
default:
|
||||||
}
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package mongo
|
package mongo
|
||||||
|
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrEmptyArgs = errors.New("arguments are empty")
|
ErrEmptyArgs = errors.New("arguments are empty")
|
||||||
)
|
)
|
||||||
|
@ -1,52 +1,55 @@
|
|||||||
package mongo
|
package mongo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
)
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Find[T any](ctx context.Context, settings *RequestSettings) ([]T, error) {
|
||||||
func Find[T any](ctx context.Context, settings *RequestSettings) ([]T, error) {
|
if settings == nil {
|
||||||
if settings == nil {
|
return []T{}, ErrEmptyArgs
|
||||||
return []T{}, ErrEmptyArgs
|
}
|
||||||
}
|
|
||||||
|
results := make([]T, 0)
|
||||||
results := make([]T, 0)
|
|
||||||
|
cursor, err := settings.Driver.Find(ctx, settings.Filter, settings.Options)
|
||||||
cursor, err := settings.Driver.Find(ctx, settings.Filter)
|
if err != nil {
|
||||||
if err != nil {
|
return []T{}, err
|
||||||
return []T{}, err
|
}
|
||||||
}
|
|
||||||
|
defer func() {
|
||||||
defer cursor.Close(ctx)
|
if err := cursor.Close(ctx); err != nil {
|
||||||
|
log.Printf("failed to close cursor: %v", err)
|
||||||
for cursor.Next(ctx) {
|
}
|
||||||
result := new(T)
|
}()
|
||||||
|
|
||||||
if err := cursor.Decode(result); err != nil {
|
for cursor.Next(ctx) {
|
||||||
return []T{}, err
|
result := new(T)
|
||||||
}
|
|
||||||
|
if err := cursor.Decode(result); err != nil {
|
||||||
results = append(results, *result)
|
return []T{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := cursor.Err(); err != nil {
|
results = append(results, *result)
|
||||||
return []T{}, err
|
}
|
||||||
}
|
|
||||||
|
if err := cursor.Err(); err != nil {
|
||||||
return results, nil
|
return []T{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindOne[T any](ctx context.Context, settings *RequestSettings) (*T, error) {
|
return results, nil
|
||||||
if settings == nil {
|
}
|
||||||
return nil, ErrEmptyArgs
|
|
||||||
}
|
func FindOne[T any](ctx context.Context, settings *RequestSettings) (*T, error) {
|
||||||
|
if settings == nil {
|
||||||
result := new(T)
|
return nil, ErrEmptyArgs
|
||||||
|
}
|
||||||
if err := settings.Driver.FindOne(ctx, settings.Filter).Decode(result); err != nil {
|
|
||||||
return nil, err
|
result := new(T)
|
||||||
}
|
|
||||||
|
if err := settings.Driver.FindOne(ctx, settings.Filter).Decode(result); err != nil {
|
||||||
return result, nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
@ -1,35 +1,35 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetFilledFieldsCount(object interface{}) int {
|
func GetFilledFieldsCount(object interface{}) int {
|
||||||
filledFieldsCount := int(0)
|
filledFieldsCount := int(0)
|
||||||
|
|
||||||
if object == nil {
|
if object == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
value := reflect.ValueOf(object)
|
value := reflect.ValueOf(object)
|
||||||
if value.Kind() == reflect.Ptr {
|
if value.Kind() == reflect.Ptr {
|
||||||
value = value.Elem()
|
value = value.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsCount := value.NumField()
|
fieldsCount := value.NumField()
|
||||||
if fieldsCount < 1 {
|
if fieldsCount < 1 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
for index := 0; index < fieldsCount; index++ {
|
for index := 0; index < fieldsCount; index++ {
|
||||||
field := value.Field(index)
|
field := value.Field(index)
|
||||||
|
|
||||||
if field.IsZero() {
|
if field.IsZero() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
filledFieldsCount++
|
filledFieldsCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
return filledFieldsCount
|
return filledFieldsCount
|
||||||
}
|
}
|
||||||
|
@ -1,65 +1,64 @@
|
|||||||
package utils_test
|
package utils_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/utils"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/utils"
|
)
|
||||||
)
|
|
||||||
|
func TestGetFilledFieldsCount(t *testing.T) {
|
||||||
func TestGetFilledFieldsCount(t *testing.T) {
|
name := "name"
|
||||||
name := "name"
|
age := uint(10)
|
||||||
age := uint(10)
|
|
||||||
|
t.Run("Получение количества заполненных полей структуры с пустой структурой", func(t *testing.T) {
|
||||||
t.Run("Получение количества заполненных полей структуры с пустой структурой", func(t *testing.T) {
|
assert.Equal(t, 0, utils.GetFilledFieldsCount(struct{}{}))
|
||||||
assert.Equal(t, 0, utils.GetFilledFieldsCount(struct{}{}))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Получение количества заполненных полей структуры с nil", func(t *testing.T) {
|
||||||
t.Run("Получение количества заполненных полей структуры с nil", func(t *testing.T) {
|
assert.Equal(t, 0, utils.GetFilledFieldsCount(nil))
|
||||||
assert.Equal(t, 0, utils.GetFilledFieldsCount(nil))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Получение количества заполненных полей структуры с указателем на пустую структуру", func(t *testing.T) {
|
||||||
t.Run("Получение количества заполненных полей структуры с указателем на пустую структуру", func(t *testing.T) {
|
assert.Equal(t, 0, utils.GetFilledFieldsCount(&struct{}{}))
|
||||||
assert.Equal(t, 0, utils.GetFilledFieldsCount(&struct{}{}))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Получение количества заполненных полей структуры с заполненной структурой", func(t *testing.T) {
|
||||||
t.Run("Получение количества заполненных полей структуры с заполненной структурой", func(t *testing.T) {
|
assert.Equal(t, 1, utils.GetFilledFieldsCount(struct {
|
||||||
assert.Equal(t, 1, utils.GetFilledFieldsCount(struct {
|
name *string
|
||||||
name *string
|
age *uint
|
||||||
age *uint
|
}{
|
||||||
}{
|
name: &name,
|
||||||
name: &name,
|
}))
|
||||||
}))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Получение количества заполненных полей структуры с указателем на заполненную структурой", func(t *testing.T) {
|
||||||
t.Run("Получение количества заполненных полей структуры с указателем на заполненную структурой", func(t *testing.T) {
|
assert.Equal(t, 2, utils.GetFilledFieldsCount(&struct {
|
||||||
assert.Equal(t, 2, utils.GetFilledFieldsCount(&struct {
|
name *string
|
||||||
name *string
|
age *uint
|
||||||
age *uint
|
}{
|
||||||
}{
|
name: &name,
|
||||||
name: &name,
|
age: &age,
|
||||||
age: &age,
|
}))
|
||||||
}))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Получение количества заполненных полей структуры с заполненную структурой не опциональных значений", func(t *testing.T) {
|
||||||
t.Run("Получение количества заполненных полей структуры с заполненную структурой не опциональных значений", func(t *testing.T) {
|
assert.Equal(t, 2, utils.GetFilledFieldsCount(&struct {
|
||||||
assert.Equal(t, 2, utils.GetFilledFieldsCount(&struct {
|
name *string
|
||||||
name *string
|
age uint
|
||||||
age uint
|
}{
|
||||||
}{
|
name: &name,
|
||||||
name: &name,
|
age: age,
|
||||||
age: age,
|
}))
|
||||||
}))
|
})
|
||||||
})
|
|
||||||
|
t.Run("Получение количества заполненных полей структуры с не заполненную структурой не опциональных значений", func(t *testing.T) {
|
||||||
t.Run("Получение количества заполненных полей структуры с не заполненную структурой не опциональных значений", func(t *testing.T) {
|
assert.Equal(t, 0, utils.GetFilledFieldsCount(&struct {
|
||||||
assert.Equal(t, 0, utils.GetFilledFieldsCount(&struct {
|
name string
|
||||||
name string
|
age uint
|
||||||
age uint
|
}{
|
||||||
}{
|
name: "",
|
||||||
name: "",
|
age: 0,
|
||||||
age: 0,
|
}))
|
||||||
}))
|
})
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
@ -1,50 +1,50 @@
|
|||||||
package utils_test
|
package utils_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/utils"
|
"penahub.gitlab.yandexcloud.net/pena-services/accruals-service/pkg/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMergeMaps(t *testing.T) {
|
func TestMergeMaps(t *testing.T) {
|
||||||
t.Run("Соединение двух пустых map", func(t *testing.T) {
|
t.Run("Соединение двух пустых map", func(t *testing.T) {
|
||||||
assert.Equal(t, map[string]interface{}{}, utils.MergeMaps(map[string]interface{}{}, map[string]interface{}{}))
|
assert.Equal(t, map[string]interface{}{}, utils.MergeMaps(map[string]interface{}{}, map[string]interface{}{}))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Соединение несколько пустых map", func(t *testing.T) {
|
t.Run("Соединение несколько пустых map", func(t *testing.T) {
|
||||||
assert.Equal(t, map[string]interface{}{}, utils.MergeMaps(map[string]interface{}{}, map[string]interface{}{}, map[string]interface{}{}))
|
assert.Equal(t, map[string]interface{}{}, utils.MergeMaps(map[string]interface{}{}, map[string]interface{}{}, map[string]interface{}{}))
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Соединение заполненных map", func(t *testing.T) {
|
t.Run("Соединение заполненных map", func(t *testing.T) {
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"test1": "1",
|
"test1": "1",
|
||||||
"test2": "1",
|
"test2": "1",
|
||||||
"test3": "1",
|
"test3": "1",
|
||||||
"test4": "1",
|
"test4": "1",
|
||||||
},
|
},
|
||||||
utils.MergeMaps(
|
utils.MergeMaps(
|
||||||
map[string]interface{}{"test1": "1"},
|
map[string]interface{}{"test1": "1"},
|
||||||
map[string]interface{}{"test2": "1"},
|
map[string]interface{}{"test2": "1"},
|
||||||
map[string]interface{}{"test3": "1", "test4": "1"},
|
map[string]interface{}{"test3": "1", "test4": "1"},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Соединение заполненных map с одинаковыми ключами", func(t *testing.T) {
|
t.Run("Соединение заполненных map с одинаковыми ключами", func(t *testing.T) {
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"test1": "1",
|
"test1": "1",
|
||||||
"test2": "1",
|
"test2": "1",
|
||||||
"test3": "1",
|
"test3": "1",
|
||||||
"test4": "1",
|
"test4": "1",
|
||||||
},
|
},
|
||||||
utils.MergeMaps(
|
utils.MergeMaps(
|
||||||
map[string]interface{}{"test1": "1"},
|
map[string]interface{}{"test1": "1"},
|
||||||
map[string]interface{}{"test2": "1", "test1": "1"},
|
map[string]interface{}{"test2": "1", "test1": "1"},
|
||||||
map[string]interface{}{"test3": "1", "test4": "1"},
|
map[string]interface{}{"test3": "1", "test4": "1"},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package discount;
|
package discount;
|
||||||
|
|
||||||
import "google/api/annotations.proto";
|
import "google/api/annotations.proto";
|
||||||
import "google/protobuf/timestamp.proto";
|
import "google/protobuf/timestamp.proto";
|
||||||
import "google/protobuf/empty.proto";
|
import "google/protobuf/empty.proto";
|
||||||
|
|
||||||
option go_package = "./discount";
|
option go_package = "./discount";
|
||||||
|
|
||||||
message Audit {
|
message Audit {
|
||||||
google.protobuf.Timestamp UpdatedAt = 1;
|
google.protobuf.Timestamp UpdatedAt = 1;
|
||||||
google.protobuf.Timestamp CreatedAt = 2;
|
google.protobuf.Timestamp CreatedAt = 2;
|
||||||
optional google.protobuf.Timestamp DeletedAt = 3;
|
optional google.protobuf.Timestamp DeletedAt = 3;
|
||||||
bool Deleted = 4;
|
bool Deleted = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user