generated from PenaSide/GolangTemplate
merge dev in ref intrf
This commit is contained in:
commit
d614710c80
@ -1,57 +1,16 @@
|
|||||||
|
include:
|
||||||
|
- project: "devops/pena-continuous-integration"
|
||||||
|
file: "/templates/docker/build-template.gitlab-ci.yml"
|
||||||
|
- project: "devops/pena-continuous-integration"
|
||||||
|
file: "/templates/docker/deploy-template.gitlab-ci.yml"
|
||||||
stages:
|
stages:
|
||||||
- lint
|
|
||||||
- test
|
|
||||||
- clean
|
|
||||||
- build
|
- build
|
||||||
- deploy
|
- deploy
|
||||||
|
|
||||||
lint:
|
|
||||||
image: golangci/golangci-lint:v1.55-alpine
|
|
||||||
stage: lint
|
|
||||||
before_script:
|
|
||||||
- go install github.com/vektra/mockery/v2@v2.26.0
|
|
||||||
- go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.12.4
|
|
||||||
script:
|
|
||||||
- go generate ./internal/...
|
|
||||||
- golangci-lint version
|
|
||||||
- golangci-lint run ./internal/...
|
|
||||||
|
|
||||||
test:
|
|
||||||
image: golang:1.21-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:
|
|
||||||
stage: clean
|
|
||||||
image:
|
|
||||||
name: docker/compose:1.28.0
|
|
||||||
entrypoint: [""]
|
|
||||||
allow_failure: true
|
|
||||||
variables:
|
|
||||||
PRODUCTION_BRANCH: main
|
|
||||||
STAGING_BRANCH: "staging"
|
|
||||||
DEPLOY_TO: "staging"
|
|
||||||
rules:
|
|
||||||
- if: $CI_COMMIT_BRANCH == $PRODUCTION_BRANCH || $CI_COMMIT_BRANCH == $STAGING_BRANCH
|
|
||||||
when: on_success
|
|
||||||
before_script:
|
|
||||||
- echo DEPLOY_TO = $DEPLOY_TO
|
|
||||||
script:
|
|
||||||
- docker-compose -f deployments/$DEPLOY_TO/docker-compose.yaml down --volumes --rmi local
|
|
||||||
|
|
||||||
build-app:
|
build-app:
|
||||||
stage: build
|
stage: build
|
||||||
image:
|
tags:
|
||||||
name: gcr.io/kaniko-project/executor:debug
|
- gobuild
|
||||||
entrypoint: [""]
|
|
||||||
variables:
|
variables:
|
||||||
DOCKER_BUILD_PATH: "./Dockerfile"
|
DOCKER_BUILD_PATH: "./Dockerfile"
|
||||||
STAGING_BRANCH: "staging"
|
STAGING_BRANCH: "staging"
|
||||||
@ -69,32 +28,22 @@ build-app:
|
|||||||
- echo CI_COMMIT_REF_SLUG = $CI_COMMIT_REF_SLUG
|
- echo CI_COMMIT_REF_SLUG = $CI_COMMIT_REF_SLUG
|
||||||
- echo DOCKER_BUILD_PATH = $DOCKER_BUILD_PATH
|
- echo DOCKER_BUILD_PATH = $DOCKER_BUILD_PATH
|
||||||
- echo CI_PIPELINE_ID = $CI_PIPELINE_ID
|
- echo CI_PIPELINE_ID = $CI_PIPELINE_ID
|
||||||
|
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||||
script:
|
script:
|
||||||
- mkdir -p /kaniko/.docker
|
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID --build-arg GITLAB_TOKEN=$GITLAB_TOKEN $CI_PROJECT_DIR
|
||||||
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
|
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
|
||||||
- |
|
|
||||||
/kaniko/executor --context $CI_PROJECT_DIR \
|
|
||||||
--cache=true --cache-repo=$CI_REGISTRY_IMAGE \
|
|
||||||
--dockerfile $CI_PROJECT_DIR/$DOCKER_BUILD_PATH --target production \
|
|
||||||
--destination $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID
|
|
||||||
|
|
||||||
deploy-to-staging:
|
deploy-to-staging:
|
||||||
stage: deploy
|
stage: deploy
|
||||||
image:
|
extends: .deploy_template
|
||||||
name: docker/compose:1.28.0
|
|
||||||
entrypoint: [""]
|
|
||||||
variables:
|
variables:
|
||||||
DEPLOY_TO: "staging"
|
DEPLOY_TO: "staging"
|
||||||
BRANCH: "staging"
|
BRANCH: "staging"
|
||||||
rules:
|
rules:
|
||||||
- if: $CI_COMMIT_BRANCH == $BRANCH
|
- if: "$CI_COMMIT_BRANCH == $BRANCH"
|
||||||
before_script:
|
after_script:
|
||||||
- echo CI_PROJECT_NAME = $CI_PROJECT_NAME
|
- ls
|
||||||
- echo CI_REGISTRY = $CI_REGISTRY
|
|
||||||
- echo REGISTRY_USER = $REGISTRY_USER
|
|
||||||
- echo REGISTRY_TOKEN = $REGISTRY_TOKEN
|
|
||||||
- echo DEPLOY_TO = $DEPLOY_TO
|
|
||||||
- echo BRANCH = $BRANCH
|
|
||||||
script:
|
|
||||||
- docker login -u $REGISTRY_USER -p $REGISTRY_TOKEN $CI_REGISTRY
|
|
||||||
- docker-compose -f deployments/$DEPLOY_TO/docker-compose.yaml up -d
|
|
||||||
|
@ -44,7 +44,7 @@ linters:
|
|||||||
- revive
|
- revive
|
||||||
- rowserrcheck
|
- rowserrcheck
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- stylecheck
|
# - stylecheck
|
||||||
- thelper
|
- thelper
|
||||||
- typecheck
|
- typecheck
|
||||||
- unconvert
|
- unconvert
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
FROM golang:1.20.3-alpine AS build
|
FROM golang:1.20.3-alpine AS build
|
||||||
|
|
||||||
# Update packages and clear cache
|
# Update packages and clear cache
|
||||||
RUN apk update && apk add --no-cache curl && rm -rf /var/cache/apk/*
|
RUN apk add --no-cache curl
|
||||||
# Set work directory
|
# Set work directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
# Create binary directory
|
# Create binary directory
|
||||||
@ -24,9 +24,7 @@ RUN GOOS=linux go build -o bin ./...
|
|||||||
FROM alpine:3.18.3 AS test
|
FROM alpine:3.18.3 AS test
|
||||||
|
|
||||||
# Install packages
|
# Install packages
|
||||||
RUN apk --no-cache add ca-certificates && rm -rf /var/cache/apk/*
|
RUN apk --no-cache add ca-certificates
|
||||||
# Set GO111MODULE env
|
|
||||||
ENV GO111MODULE=off
|
|
||||||
# Create home directory
|
# Create home directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
# Copy build file
|
# Copy build file
|
||||||
@ -44,7 +42,7 @@ CMD [ "./app" ]
|
|||||||
FROM alpine:3.18.3 AS production
|
FROM alpine:3.18.3 AS production
|
||||||
|
|
||||||
# Install packages
|
# Install packages
|
||||||
RUN apk --no-cache add ca-certificates && rm -rf /var/cache/apk/*
|
RUN apk --no-cache add ca-certificates
|
||||||
# Create home directory
|
# Create home directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
# Copy build file
|
# Copy build file
|
||||||
|
5
Makefile
5
Makefile
@ -25,15 +25,16 @@ test.unit: ## run unit tests
|
|||||||
go test ./...
|
go test ./...
|
||||||
|
|
||||||
test.integration: ## run integration tests
|
test.integration: ## run integration tests
|
||||||
|
go mod vendor
|
||||||
@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 up -d
|
docker-compose -f deployments/test/docker-compose.yaml up -d --remove-orphans
|
||||||
|
|
||||||
test.integration.down: ## shutting down integration environment
|
test.integration.down: ## shutting down integration environment
|
||||||
docker-compose -f deployments/test/docker-compose.yaml down --volumes --rmi local
|
docker-compose -f deployments/test/docker-compose.yaml down --volumes
|
||||||
|
|
||||||
test.integration.start: ## run integration test
|
test.integration.start: ## run integration test
|
||||||
go test -count=1 ./tests/integration/...
|
go test -count=1 ./tests/integration/...
|
||||||
|
@ -42,3 +42,4 @@ KAFKA_TOPIC_TARIFF - название топика для сообщений т
|
|||||||
## Полезные ссылки:
|
## Полезные ссылки:
|
||||||
|
|
||||||
- [**Диаграммы**](./docs/diagram/README.md)
|
- [**Диаграммы**](./docs/diagram/README.md)
|
||||||
|
- Для того чтобы создать новые endpoint, нужно прописать их в customer/api/openapi/v1/openapi.yaml, сделать его описание, с помощью инструкций в makefile сгенерировать файлы
|
||||||
|
@ -18,16 +18,6 @@ tags:
|
|||||||
description: история
|
description: история
|
||||||
|
|
||||||
paths:
|
paths:
|
||||||
/health:
|
|
||||||
get:
|
|
||||||
summary: Health Check
|
|
||||||
description: Check the health status of the API
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: OK
|
|
||||||
503:
|
|
||||||
description: Service Unavailable
|
|
||||||
|
|
||||||
/account:
|
/account:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
@ -536,7 +526,7 @@ paths:
|
|||||||
summary: Получение лога событий связанных с аккаунтом
|
summary: Получение лога событий связанных с аккаунтом
|
||||||
operationId: getHistory
|
operationId: getHistory
|
||||||
security:
|
security:
|
||||||
- Bearer: []
|
- Bearer: [ ]
|
||||||
parameters:
|
parameters:
|
||||||
- name: page
|
- name: page
|
||||||
in: query
|
in: query
|
||||||
@ -561,6 +551,13 @@ paths:
|
|||||||
explode: false
|
explode: false
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
- name: accountID
|
||||||
|
in: query
|
||||||
|
description: Идентификатор аккаунта. Если не указан, будет использоваться идентификатор из токена.
|
||||||
|
required: false
|
||||||
|
explode: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: Успешное получение событий
|
description: Успешное получение событий
|
||||||
@ -583,6 +580,140 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/Error"
|
$ref: "#/components/schemas/Error"
|
||||||
|
|
||||||
|
/recent:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- history
|
||||||
|
summary: Получение недавних тарифов
|
||||||
|
operationId: getRecentTariffs
|
||||||
|
description: Возвращает список уникальных тарифов из истории. Айди аккаунта получается из заголовка.
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Успешный запрос
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/TariffID"
|
||||||
|
'400':
|
||||||
|
description: Неверный запрос
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/Error"
|
||||||
|
'404':
|
||||||
|
description: Тарифы не найдены
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/Error"
|
||||||
|
'500':
|
||||||
|
description: Внутренняя ошибка сервера
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/Error"
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
required: [id]
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
example: "807f1f77bcf81cd799439011"
|
||||||
|
/sendReport:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- history
|
||||||
|
summary: отправить акт проделанных работ на почту
|
||||||
|
operationId: sendReport
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
description: Запрос на отправку акта проделанных работ
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
required: [id]
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
example: "807f1f77bcf81cd799439011"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: успешная отправка
|
||||||
|
"401":
|
||||||
|
description: Неавторизован
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/Error"
|
||||||
|
|
||||||
|
/history/ltv:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- history
|
||||||
|
summary: Расчет среднего времени жизни платящего клиента (LTV)
|
||||||
|
operationId: calculateLTV
|
||||||
|
security:
|
||||||
|
- Bearer: [ ]
|
||||||
|
requestBody:
|
||||||
|
description: Период для расчета LTV
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
from:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: Начальная дата в формате Unix timestamp. Если 0, устанавливает начало истории.
|
||||||
|
to:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: Конечная дата в формате Unix timestamp. Если 0, устанавливает текущее время.
|
||||||
|
required:
|
||||||
|
- from
|
||||||
|
- to
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Успешный расчет LTV
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ltv:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: Среднее количество дней между первым и последним платежом
|
||||||
|
'400':
|
||||||
|
description: Неверный запрос, если from больше, чем to
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Error'
|
||||||
|
'401':
|
||||||
|
description: Неавторизован
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/Error"
|
||||||
|
'500':
|
||||||
|
description: Внутренняя ошибка сервера
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/Error"
|
||||||
|
|
||||||
|
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
Account:
|
Account:
|
||||||
@ -748,6 +879,14 @@ components:
|
|||||||
"alfabank",
|
"alfabank",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
TariffID:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
ID:
|
||||||
|
type: string
|
||||||
|
example: "807f1f77bcf81cd799439011"
|
||||||
|
|
||||||
|
|
||||||
AccountStatus:
|
AccountStatus:
|
||||||
type: string
|
type: string
|
||||||
enum: ["no", "nko", "org"]
|
enum: ["no", "nko", "org"]
|
||||||
|
9
deployments/local/auth.env.test
Normal file
9
deployments/local/auth.env.test
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
DB_HOST=test-pena-auth-db
|
||||||
|
DB_PORT=27017
|
||||||
|
ENVIRONMENT=staging
|
||||||
|
HTTP_HOST=0.0.0.0
|
||||||
|
HTTP_PORT=8000
|
||||||
|
DB_USERNAME=test
|
||||||
|
DB_PASSWORD=test
|
||||||
|
DB_NAME=admin
|
||||||
|
DB_AUTH=admin
|
191
deployments/local/docker-compose.yaml
Normal file
191
deployments/local/docker-compose.yaml
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
redpanda: null
|
||||||
|
test-mongodb: null
|
||||||
|
test-mongoconfdb: null
|
||||||
|
|
||||||
|
services:
|
||||||
|
customer-service:
|
||||||
|
container_name: customer-service
|
||||||
|
build:
|
||||||
|
context: ../../.
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
target: test
|
||||||
|
env_file:
|
||||||
|
- .env.test
|
||||||
|
environment:
|
||||||
|
- HTTP_HOST=0.0.0.0
|
||||||
|
- HTTP_PORT=8000
|
||||||
|
|
||||||
|
- GRPC_HOST=0.0.0.0
|
||||||
|
- GRPC_PORT=9000
|
||||||
|
- GRPC_DOMEN=customer-service:9000
|
||||||
|
|
||||||
|
- MONGO_HOST=customer-db
|
||||||
|
- MONGO_PORT=27017
|
||||||
|
- MONGO_USER=test
|
||||||
|
- MONGO_PASSWORD=test
|
||||||
|
- MONGO_DB_NAME=admin
|
||||||
|
- MONGO_AUTH=admin
|
||||||
|
|
||||||
|
- KAFKA_BROKERS=customer-redpanda:9092
|
||||||
|
- KAFKA_TOPIC_TARIFF=tariffs
|
||||||
|
|
||||||
|
- AUTH_MICROSERVICE_USER_URL=http://pena-auth-service:8000/user
|
||||||
|
- HUBADMIN_MICROSERVICE_TARIFF_URL=http://hub-admin-backend-service:8000/tariff
|
||||||
|
- CURRENCY_MICROSERVICE_TRANSLATE_URL=http://cbrfworker-service:8000/change
|
||||||
|
- DISCOUNT_MICROSERVICE_GRPC_HOST=discount-service:9000
|
||||||
|
- PAYMENT_MICROSERVICE_GRPC_HOST=treasurer-service:9085
|
||||||
|
ports:
|
||||||
|
- 8082:8000
|
||||||
|
- 9092:9000
|
||||||
|
depends_on:
|
||||||
|
- customer-db
|
||||||
|
- customer-migration
|
||||||
|
- redpanda
|
||||||
|
networks:
|
||||||
|
- test
|
||||||
|
|
||||||
|
customer-migration:
|
||||||
|
container_name: customer-migration
|
||||||
|
build:
|
||||||
|
context: ../../.
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
target: test
|
||||||
|
command:
|
||||||
|
[
|
||||||
|
"sh",
|
||||||
|
"-c",
|
||||||
|
'migrate -source file://migrations -database "mongodb://test:test@customer-db:27017/admin?authSource=admin" up',
|
||||||
|
]
|
||||||
|
depends_on:
|
||||||
|
- customer-db
|
||||||
|
networks:
|
||||||
|
- test
|
||||||
|
|
||||||
|
customer-db:
|
||||||
|
container_name: customer-db
|
||||||
|
image: "mongo:6.0.3"
|
||||||
|
environment:
|
||||||
|
MONGO_INITDB_ROOT_USERNAME: test
|
||||||
|
MONGO_INITDB_ROOT_PASSWORD: test
|
||||||
|
ports:
|
||||||
|
- "27024:27017"
|
||||||
|
networks:
|
||||||
|
- test
|
||||||
|
|
||||||
|
redpanda:
|
||||||
|
container_name: customer-redpanda
|
||||||
|
tty: true
|
||||||
|
image: docker.redpanda.com/redpandadata/redpanda:v23.1.13
|
||||||
|
command:
|
||||||
|
- redpanda start
|
||||||
|
- --smp 1
|
||||||
|
- --overprovisioned
|
||||||
|
- --kafka-addr internal://0.0.0.0:9092,external://0.0.0.0:19092
|
||||||
|
# Address the broker advertises to clients that connect to the Kafka API.
|
||||||
|
# Use the internal addresses to connect to the Redpanda brokers
|
||||||
|
# from inside the same Docker network.
|
||||||
|
# Use the external addresses to connect to the Redpanda brokers
|
||||||
|
# from outside the Docker network.
|
||||||
|
- --advertise-kafka-addr internal://redpanda:9092,external://localhost:19092
|
||||||
|
- --pandaproxy-addr internal://0.0.0.0:8082,external://0.0.0.0:18082
|
||||||
|
# Address the broker advertises to clients that connect to the HTTP Proxy.
|
||||||
|
- --advertise-pandaproxy-addr internal://redpanda:8082,external://localhost:18082
|
||||||
|
- --schema-registry-addr internal://0.0.0.0:8081,external://0.0.0.0:18081
|
||||||
|
# Redpanda brokers use the RPC API to communicate with each other internally.
|
||||||
|
- --rpc-addr redpanda:33145
|
||||||
|
- --advertise-rpc-addr redpanda:33145
|
||||||
|
ports:
|
||||||
|
- 18081:18081
|
||||||
|
- 18082:18082
|
||||||
|
- 19092:19092
|
||||||
|
- 19644:9644
|
||||||
|
volumes:
|
||||||
|
- redpanda:/var/lib/redpanda/data
|
||||||
|
networks:
|
||||||
|
- test
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "rpk cluster health | grep -E 'Healthy:.+true' || exit 1"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 5
|
||||||
|
start_period: 5s
|
||||||
|
|
||||||
|
console:
|
||||||
|
tty: true
|
||||||
|
image: docker.redpanda.com/redpandadata/console:v2.2.4
|
||||||
|
entrypoint: /bin/sh
|
||||||
|
command: -c "echo \"$$CONSOLE_CONFIG_FILE\" > /tmp/config.yml; /app/console"
|
||||||
|
environment:
|
||||||
|
CONFIG_FILEPATH: /tmp/config.yml
|
||||||
|
CONSOLE_CONFIG_FILE: |
|
||||||
|
kafka:
|
||||||
|
brokers: ["redpanda:9092"]
|
||||||
|
schemaRegistry:
|
||||||
|
enabled: true
|
||||||
|
urls: ["http://redpanda:8081"]
|
||||||
|
redpanda:
|
||||||
|
adminApi:
|
||||||
|
enabled: true
|
||||||
|
urls: ["http://redpanda:9644"]
|
||||||
|
connect:
|
||||||
|
enabled: true
|
||||||
|
clusters:
|
||||||
|
- name: local-connect-cluster
|
||||||
|
url: http://connect:8083
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
networks:
|
||||||
|
- test
|
||||||
|
depends_on:
|
||||||
|
- redpanda
|
||||||
|
|
||||||
|
connect:
|
||||||
|
tty: true
|
||||||
|
image: docker.redpanda.com/redpandadata/connectors:latest
|
||||||
|
hostname: connect
|
||||||
|
container_name: connect
|
||||||
|
networks:
|
||||||
|
- test
|
||||||
|
# platform: 'linux/amd64'
|
||||||
|
depends_on:
|
||||||
|
- redpanda
|
||||||
|
ports:
|
||||||
|
- "8083:8083"
|
||||||
|
environment:
|
||||||
|
CONNECT_CONFIGURATION: |
|
||||||
|
key.converter=org.apache.kafka.connect.converters.ByteArrayConverter
|
||||||
|
value.converter=org.apache.kafka.connect.converters.ByteArrayConverter
|
||||||
|
group.id=connectors-cluster
|
||||||
|
offset.storage.topic=_internal_connectors_offsets
|
||||||
|
config.storage.topic=_internal_connectors_configs
|
||||||
|
status.storage.topic=_internal_connectors_status
|
||||||
|
config.storage.replication.factor=-1
|
||||||
|
offset.storage.replication.factor=-1
|
||||||
|
status.storage.replication.factor=-1
|
||||||
|
offset.flush.interval.ms=1000
|
||||||
|
producer.linger.ms=50
|
||||||
|
producer.batch.size=131072
|
||||||
|
CONNECT_BOOTSTRAP_SERVERS: redpanda:9092
|
||||||
|
CONNECT_GC_LOG_ENABLED: "false"
|
||||||
|
CONNECT_HEAP_OPTS: -Xms512M -Xmx512M
|
||||||
|
CONNECT_LOG_LEVEL: info
|
||||||
|
|
||||||
|
test-pena-auth-db:
|
||||||
|
container_name: test-pena-auth-db
|
||||||
|
init: true
|
||||||
|
image: "mongo:6.0.3"
|
||||||
|
command: mongod --quiet --logpath /dev/null
|
||||||
|
volumes:
|
||||||
|
- test-mongodb:/data/db
|
||||||
|
- test-mongoconfdb:/data/configdb
|
||||||
|
environment:
|
||||||
|
MONGO_INITDB_ROOT_USERNAME: test
|
||||||
|
MONGO_INITDB_ROOT_PASSWORD: test
|
||||||
|
networks:
|
||||||
|
- test
|
||||||
|
|
||||||
|
networks:
|
||||||
|
test:
|
@ -24,11 +24,13 @@ services:
|
|||||||
- KAFKA_BROKERS=10.6.0.11:9092
|
- KAFKA_BROKERS=10.6.0.11:9092
|
||||||
- KAFKA_TOPIC_TARIFF=tariffs
|
- KAFKA_TOPIC_TARIFF=tariffs
|
||||||
|
|
||||||
- AUTH_MICROSERVICE_USER_URL=https://admin.pena.digital/user
|
- AUTH_MICROSERVICE_USER_URL=http://10.6.0.11:59300/user
|
||||||
- HUBADMIN_MICROSERVICE_TARIFF_URL=https://admin.pena.digital/strator/tariff
|
- HUBADMIN_MICROSERVICE_TARIFF_URL=http://10.6.0.11:59303/tariff
|
||||||
- CURRENCY_MICROSERVICE_TRANSLATE_URL=http://10.6.0.11:3131/change
|
- CURRENCY_MICROSERVICE_TRANSLATE_URL=http://10.6.0.11:3131/change
|
||||||
- DISCOUNT_MICROSERVICE_GRPC_HOST=10.6.0.11:9001
|
- DISCOUNT_MICROSERVICE_GRPC_HOST=10.6.0.11:9001
|
||||||
- PAYMENT_MICROSERVICE_GRPC_HOST=10.6.0.11:9085
|
- PAYMENT_MICROSERVICE_GRPC_HOST=10.6.0.11:9085
|
||||||
|
- VERIFICATION_MICROSERVICE_USER_URL=http://10.6.0.17:7035/verification
|
||||||
|
- TEMPLATEGEN_MICROSERVICE_URL=10.6.0.17
|
||||||
|
|
||||||
- JWT_PUBLIC_KEY=$JWT_PUBLIC_KEY
|
- JWT_PUBLIC_KEY=$JWT_PUBLIC_KEY
|
||||||
- JWT_ISSUER=pena-auth-service
|
- JWT_ISSUER=pena-auth-service
|
||||||
@ -37,9 +39,4 @@ services:
|
|||||||
- 8065:8065
|
- 8065:8065
|
||||||
- 9065:9065
|
- 9065:9065
|
||||||
networks:
|
networks:
|
||||||
- marketplace_penahub_frontend
|
|
||||||
- default
|
- default
|
||||||
|
|
||||||
networks:
|
|
||||||
marketplace_penahub_frontend:
|
|
||||||
external: true
|
|
18
deployments/test/docker-compose.integration.yaml
Normal file
18
deployments/test/docker-compose.integration.yaml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
integration:
|
||||||
|
container_name: customer-integration
|
||||||
|
image: golang:1
|
||||||
|
volumes:
|
||||||
|
- ../..:/app:ro,z
|
||||||
|
working_dir: /app
|
||||||
|
command: go test ./tests/integration/...
|
||||||
|
environment:
|
||||||
|
- CUSTOMER_SERVICE=customer-service:8000
|
||||||
|
networks:
|
||||||
|
- test_test
|
||||||
|
|
||||||
|
networks:
|
||||||
|
test_test:
|
||||||
|
external: true
|
@ -7,7 +7,7 @@ services:
|
|||||||
customer-service:
|
customer-service:
|
||||||
container_name: customer-service
|
container_name: customer-service
|
||||||
build:
|
build:
|
||||||
context: ../../.
|
context: ../..
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
target: test
|
target: test
|
||||||
env_file:
|
env_file:
|
||||||
@ -40,17 +40,11 @@ services:
|
|||||||
- 9092:9000
|
- 9092:9000
|
||||||
depends_on:
|
depends_on:
|
||||||
customer-db:
|
customer-db:
|
||||||
condition: service_healthy
|
condition: service_started
|
||||||
customer-migration:
|
customer-migration:
|
||||||
condition: service_completed_successfully
|
condition: service_completed_successfully
|
||||||
redpanda:
|
redpanda:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
healthcheck:
|
|
||||||
test: wget -q --spider http://localhost:8000/health
|
|
||||||
interval: 2s
|
|
||||||
timeout: 2s
|
|
||||||
retries: 5
|
|
||||||
start_period: 5s
|
|
||||||
networks:
|
networks:
|
||||||
- test
|
- test
|
||||||
|
|
||||||
@ -75,12 +69,6 @@ services:
|
|||||||
MONGO_INITDB_ROOT_PASSWORD: test
|
MONGO_INITDB_ROOT_PASSWORD: test
|
||||||
ports:
|
ports:
|
||||||
- "27024:27017"
|
- "27024:27017"
|
||||||
healthcheck:
|
|
||||||
test: mongosh --quiet --eval "db.adminCommand('ping')" >/dev/null
|
|
||||||
interval: 2s
|
|
||||||
timeout: 2s
|
|
||||||
retries: 5
|
|
||||||
start_period: 5s
|
|
||||||
networks:
|
networks:
|
||||||
- test
|
- test
|
||||||
|
|
||||||
@ -150,38 +138,42 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- test
|
- test
|
||||||
depends_on:
|
depends_on:
|
||||||
- redpanda
|
connect:
|
||||||
|
condition: service_started
|
||||||
|
redpanda:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
connect:
|
connect:
|
||||||
tty: true
|
tty: true
|
||||||
image: docker.redpanda.com/redpandadata/connectors:latest
|
image: docker.redpanda.com/redpandadata/connectors:latest
|
||||||
hostname: connect
|
# hostname: connect
|
||||||
container_name: connect
|
container_name: customer-connect
|
||||||
networks:
|
|
||||||
- test
|
|
||||||
# platform: 'linux/amd64'
|
# platform: 'linux/amd64'
|
||||||
depends_on:
|
depends_on:
|
||||||
- redpanda
|
redpanda:
|
||||||
|
condition: service_healthy
|
||||||
ports:
|
ports:
|
||||||
- "8083:8083"
|
- "8083:8083"
|
||||||
environment:
|
environment:
|
||||||
CONNECT_CONFIGURATION: |
|
CONNECT_CONFIGURATION: |
|
||||||
key.converter=org.apache.kafka.connect.converters.ByteArrayConverter
|
key.converter=org.apache.kafka.connect.converters.ByteArrayConverter
|
||||||
value.converter=org.apache.kafka.connect.converters.ByteArrayConverter
|
value.converter=org.apache.kafka.connect.converters.ByteArrayConverter
|
||||||
group.id=connectors-cluster
|
group.id=connectors-cluster
|
||||||
offset.storage.topic=_internal_connectors_offsets
|
offset.storage.topic=_internal_connectors_offsets
|
||||||
config.storage.topic=_internal_connectors_configs
|
config.storage.topic=_internal_connectors_configs
|
||||||
status.storage.topic=_internal_connectors_status
|
status.storage.topic=_internal_connectors_status
|
||||||
config.storage.replication.factor=-1
|
config.storage.replication.factor=-1
|
||||||
offset.storage.replication.factor=-1
|
offset.storage.replication.factor=-1
|
||||||
status.storage.replication.factor=-1
|
status.storage.replication.factor=-1
|
||||||
offset.flush.interval.ms=1000
|
offset.flush.interval.ms=1000
|
||||||
producer.linger.ms=50
|
producer.linger.ms=50
|
||||||
producer.batch.size=131072
|
producer.batch.size=131072
|
||||||
CONNECT_BOOTSTRAP_SERVERS: redpanda:9092
|
CONNECT_BOOTSTRAP_SERVERS: redpanda:9092
|
||||||
CONNECT_GC_LOG_ENABLED: "false"
|
CONNECT_GC_LOG_ENABLED: "false"
|
||||||
CONNECT_HEAP_OPTS: -Xms512M -Xmx512M
|
CONNECT_HEAP_OPTS: -Xms512M -Xmx512M
|
||||||
CONNECT_LOG_LEVEL: info
|
CONNECT_LOG_LEVEL: info
|
||||||
|
networks:
|
||||||
|
- test
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
test:
|
test:
|
||||||
|
6
go.mod
6
go.mod
@ -16,7 +16,7 @@ require (
|
|||||||
github.com/twmb/franz-go v1.13.6
|
github.com/twmb/franz-go v1.13.6
|
||||||
github.com/twmb/franz-go/pkg/kadm v1.8.1
|
github.com/twmb/franz-go/pkg/kadm v1.8.1
|
||||||
go.mongodb.org/mongo-driver v1.11.4
|
go.mongodb.org/mongo-driver v1.11.4
|
||||||
go.uber.org/zap v1.24.0
|
go.uber.org/zap v1.26.0
|
||||||
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923
|
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923
|
||||||
google.golang.org/grpc v1.53.0
|
google.golang.org/grpc v1.53.0
|
||||||
google.golang.org/protobuf v1.31.0
|
google.golang.org/protobuf v1.31.0
|
||||||
@ -24,7 +24,6 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||||
github.com/benbjohnson/clock v1.3.3 // indirect
|
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||||
github.com/go-openapi/swag v0.22.3 // indirect
|
github.com/go-openapi/swag v0.22.3 // indirect
|
||||||
@ -55,11 +54,10 @@ require (
|
|||||||
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
|
||||||
go.uber.org/atomic v1.11.0 // indirect
|
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/crypto v0.12.0 // indirect
|
golang.org/x/crypto v0.12.0 // indirect
|
||||||
golang.org/x/net v0.14.0 // indirect
|
golang.org/x/net v0.14.0 // indirect
|
||||||
golang.org/x/sync v0.2.0 // indirect
|
golang.org/x/sync v0.5.0 // indirect
|
||||||
golang.org/x/sys v0.11.0 // indirect
|
golang.org/x/sys v0.11.0 // indirect
|
||||||
golang.org/x/text v0.12.0 // indirect
|
golang.org/x/text v0.12.0 // indirect
|
||||||
golang.org/x/time v0.3.0 // indirect
|
golang.org/x/time v0.3.0 // indirect
|
||||||
|
16
go.sum
16
go.sum
@ -4,8 +4,6 @@ github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMz
|
|||||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/benbjohnson/clock v1.3.3 h1:g+rSsSaAzhHJYcIQE78hJ3AhyjjtQvleKDjlhdBnIhc=
|
|
||||||
github.com/benbjohnson/clock v1.3.3/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
|
||||||
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
|
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
|
||||||
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/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
@ -149,6 +147,7 @@ github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
|
|||||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||||
|
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||||
@ -167,16 +166,15 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
|||||||
go.mongodb.org/mongo-driver v1.11.4 h1:4ayjakA013OdpGyL2K3ZqylTac/rMjrJOMZ1EHizXas=
|
go.mongodb.org/mongo-driver v1.11.4 h1:4ayjakA013OdpGyL2K3ZqylTac/rMjrJOMZ1EHizXas=
|
||||||
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
|
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
|
||||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
|
||||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||||
|
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
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/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
||||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||||
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=
|
||||||
@ -209,8 +207,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
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=
|
||||||
|
@ -13,14 +13,18 @@ type ClientsDeps struct {
|
|||||||
CurrencyURL *models.CurrencyMicroserviceURL
|
CurrencyURL *models.CurrencyMicroserviceURL
|
||||||
DiscountServiceConfiguration *models.DiscountMicroserviceConfiguration
|
DiscountServiceConfiguration *models.DiscountMicroserviceConfiguration
|
||||||
PaymentServiceConfiguration *models.PaymentMicroserviceConfiguration
|
PaymentServiceConfiguration *models.PaymentMicroserviceConfiguration
|
||||||
|
VerificationURL *models.VerificationMicroserviceURL
|
||||||
|
TemplategenURL *models.TemplategenMicroserviceURL
|
||||||
}
|
}
|
||||||
|
|
||||||
type Clients struct {
|
type Clients struct {
|
||||||
AuthClient *client.AuthClient
|
AuthClient *client.AuthClient
|
||||||
HubadminClient *client.HubadminClient
|
HubadminClient *client.HubadminClient
|
||||||
CurrencyClient *client.CurrencyClient
|
CurrencyClient *client.CurrencyClient
|
||||||
DiscountClient *client.DiscountClient
|
DiscountClient *client.DiscountClient
|
||||||
PaymentClient *client.PaymentClient
|
PaymentClient *client.PaymentClient
|
||||||
|
VerificationClient *client.VerificationClient
|
||||||
|
TemplateClient *client.TemplateClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClients(deps ClientsDeps) *Clients {
|
func NewClients(deps ClientsDeps) *Clients {
|
||||||
@ -45,5 +49,13 @@ func NewClients(deps ClientsDeps) *Clients {
|
|||||||
Logger: deps.Logger,
|
Logger: deps.Logger,
|
||||||
PaymentServiceHost: deps.PaymentServiceConfiguration.HostGRPC,
|
PaymentServiceHost: deps.PaymentServiceConfiguration.HostGRPC,
|
||||||
}),
|
}),
|
||||||
|
VerificationClient: client.NewVerificationClient(client.VerificationClientDeps{
|
||||||
|
Logger: deps.Logger,
|
||||||
|
URLs: deps.VerificationURL,
|
||||||
|
}),
|
||||||
|
TemplateClient: client.NewTemplateClient(client.TemplateClientDeps{
|
||||||
|
Logger: deps.Logger,
|
||||||
|
URLs: deps.TemplategenURL,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ func TestNewClients(t *testing.T) {
|
|||||||
CurrencyURL: &models.CurrencyMicroserviceURL{},
|
CurrencyURL: &models.CurrencyMicroserviceURL{},
|
||||||
DiscountServiceConfiguration: &models.DiscountMicroserviceConfiguration{HostGRPC: "host"},
|
DiscountServiceConfiguration: &models.DiscountMicroserviceConfiguration{HostGRPC: "host"},
|
||||||
PaymentServiceConfiguration: &models.PaymentMicroserviceConfiguration{HostGRPC: "host"},
|
PaymentServiceConfiguration: &models.PaymentMicroserviceConfiguration{HostGRPC: "host"},
|
||||||
|
VerificationURL: &models.VerificationMicroserviceURL{Verification: ""},
|
||||||
|
TemplategenURL: &models.TemplategenMicroserviceURL{Templategen: ""},
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.NotNil(t, clients)
|
assert.NotNil(t, clients)
|
||||||
|
@ -90,6 +90,16 @@ func setDefaultTestingENV(t *testing.T) *models.Config {
|
|||||||
PaymentMicroservice: models.PaymentMicroserviceConfiguration{
|
PaymentMicroservice: models.PaymentMicroserviceConfiguration{
|
||||||
HostGRPC: "domen",
|
HostGRPC: "domen",
|
||||||
},
|
},
|
||||||
|
VerificationMicroservice: models.VerificationMicroserviceConfiguration{
|
||||||
|
URL: models.VerificationMicroserviceURL{
|
||||||
|
Verification: "domen",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TemplategenMicroserviceURL: models.TemplategenMicroserviceConfiguration{
|
||||||
|
URL: models.TemplategenMicroserviceURL{
|
||||||
|
Templategen: "domen",
|
||||||
|
},
|
||||||
|
},
|
||||||
JWT: models.JWTConfiguration{
|
JWT: models.JWTConfiguration{
|
||||||
PrivateKey: "jwt private key",
|
PrivateKey: "jwt private key",
|
||||||
PublicKey: "jwt public key",
|
PublicKey: "jwt public key",
|
||||||
@ -126,6 +136,8 @@ func setDefaultTestingENV(t *testing.T) *models.Config {
|
|||||||
t.Setenv("CURRENCY_MICROSERVICE_TRANSLATE_URL", defaultConfiguration.Service.CurrencyMicroservice.URL.Translate)
|
t.Setenv("CURRENCY_MICROSERVICE_TRANSLATE_URL", defaultConfiguration.Service.CurrencyMicroservice.URL.Translate)
|
||||||
t.Setenv("DISCOUNT_MICROSERVICE_GRPC_HOST", defaultConfiguration.Service.DiscountMicroservice.HostGRPC)
|
t.Setenv("DISCOUNT_MICROSERVICE_GRPC_HOST", defaultConfiguration.Service.DiscountMicroservice.HostGRPC)
|
||||||
t.Setenv("PAYMENT_MICROSERVICE_GRPC_HOST", defaultConfiguration.Service.PaymentMicroservice.HostGRPC)
|
t.Setenv("PAYMENT_MICROSERVICE_GRPC_HOST", defaultConfiguration.Service.PaymentMicroservice.HostGRPC)
|
||||||
|
t.Setenv("VERIFICATION_MICROSERVICE_USER_URL", defaultConfiguration.Service.VerificationMicroservice.URL.Verification)
|
||||||
|
t.Setenv("TEMPLATEGEN_MICROSERVICE_URL", defaultConfiguration.Service.TemplategenMicroserviceURL.URL.Templategen)
|
||||||
|
|
||||||
t.Setenv("MONGO_HOST", defaultConfiguration.Database.Host)
|
t.Setenv("MONGO_HOST", defaultConfiguration.Database.Host)
|
||||||
t.Setenv("MONGO_PORT", defaultConfiguration.Database.Port)
|
t.Setenv("MONGO_PORT", defaultConfiguration.Database.Port)
|
||||||
|
@ -25,6 +25,8 @@ func TestNewControllers(t *testing.T) {
|
|||||||
CurrencyURL: &models.CurrencyMicroserviceURL{},
|
CurrencyURL: &models.CurrencyMicroserviceURL{},
|
||||||
DiscountServiceConfiguration: &models.DiscountMicroserviceConfiguration{HostGRPC: "host"},
|
DiscountServiceConfiguration: &models.DiscountMicroserviceConfiguration{HostGRPC: "host"},
|
||||||
PaymentServiceConfiguration: &models.PaymentMicroserviceConfiguration{HostGRPC: "host"},
|
PaymentServiceConfiguration: &models.PaymentMicroserviceConfiguration{HostGRPC: "host"},
|
||||||
|
VerificationURL: &models.VerificationMicroserviceURL{Verification: ""},
|
||||||
|
TemplategenURL: &models.TemplategenMicroserviceURL{Templategen: ""},
|
||||||
})
|
})
|
||||||
|
|
||||||
repositories := initialize.NewRepositories(initialize.RepositoriesDeps{
|
repositories := initialize.NewRepositories(initialize.RepositoriesDeps{
|
||||||
|
@ -36,6 +36,7 @@ func NewServices(deps ServicesDeps) *Services {
|
|||||||
historyService := history.New(history.Deps{
|
historyService := history.New(history.Deps{
|
||||||
Logger: deps.Logger,
|
Logger: deps.Logger,
|
||||||
Repository: deps.Repositories.HistoryRepository,
|
Repository: deps.Repositories.HistoryRepository,
|
||||||
|
AuthClient: deps.Clients.AuthClient,
|
||||||
})
|
})
|
||||||
|
|
||||||
walletService := wallet.New(wallet.Deps{
|
walletService := wallet.New(wallet.Deps{
|
||||||
|
@ -25,6 +25,8 @@ func TestNewServices(t *testing.T) {
|
|||||||
CurrencyURL: &models.CurrencyMicroserviceURL{},
|
CurrencyURL: &models.CurrencyMicroserviceURL{},
|
||||||
DiscountServiceConfiguration: &models.DiscountMicroserviceConfiguration{HostGRPC: "host"},
|
DiscountServiceConfiguration: &models.DiscountMicroserviceConfiguration{HostGRPC: "host"},
|
||||||
PaymentServiceConfiguration: &models.PaymentMicroserviceConfiguration{HostGRPC: "host"},
|
PaymentServiceConfiguration: &models.PaymentMicroserviceConfiguration{HostGRPC: "host"},
|
||||||
|
VerificationURL: &models.VerificationMicroserviceURL{Verification: ""},
|
||||||
|
TemplategenURL: &models.TemplategenMicroserviceURL{Templategen: ""},
|
||||||
})
|
})
|
||||||
|
|
||||||
brokers := initialize.NewBrokers(initialize.BrokersDeps{
|
brokers := initialize.NewBrokers(initialize.BrokersDeps{
|
||||||
|
88
internal/interface/client/templategen.go
Normal file
88
internal/interface/client/templategen.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TemplateClientDeps struct {
|
||||||
|
Logger *zap.Logger
|
||||||
|
URLs *models.TemplategenMicroserviceURL
|
||||||
|
}
|
||||||
|
|
||||||
|
type TemplateClient struct {
|
||||||
|
logger *zap.Logger
|
||||||
|
urls *models.TemplategenMicroserviceURL
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTemplateClient(deps TemplateClientDeps) *TemplateClient {
|
||||||
|
if deps.Logger == nil {
|
||||||
|
log.Panicln("logger is nil on <NewTemplateClient>")
|
||||||
|
}
|
||||||
|
|
||||||
|
if deps.URLs == nil {
|
||||||
|
log.Panicln("urls is nil on <NewTemplateClient>")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &TemplateClient{
|
||||||
|
logger: deps.Logger,
|
||||||
|
urls: deps.URLs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *TemplateClient) SendData(ctx context.Context, data models.RespGeneratorService, fileContents []byte, email string) errors.Error {
|
||||||
|
tmplURL := receiver.urls.Templategen
|
||||||
|
|
||||||
|
body := &bytes.Buffer{}
|
||||||
|
writer := multipart.NewWriter(body)
|
||||||
|
|
||||||
|
err := writer.WriteField("email", email)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(err, errors.ErrInternalError)
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonData, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(err, errors.ErrInternalError)
|
||||||
|
}
|
||||||
|
err = writer.WriteField("data", string(jsonData))
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(err, errors.ErrInternalError)
|
||||||
|
}
|
||||||
|
|
||||||
|
fileWriter, err := writer.CreateFormFile("file", "report.docx")
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(err, errors.ErrInternalError)
|
||||||
|
}
|
||||||
|
_, err = fileWriter.Write(fileContents)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(err, errors.ErrInternalError)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = writer.Close()
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(err, errors.ErrInternalError)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, tmplURL, body)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(err, errors.ErrInternalError)
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(err, errors.ErrInternalError)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
58
internal/interface/client/verification.go
Normal file
58
internal/interface/client/verification.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VerificationClientDeps struct {
|
||||||
|
Logger *zap.Logger
|
||||||
|
URLs *models.VerificationMicroserviceURL
|
||||||
|
}
|
||||||
|
|
||||||
|
type VerificationClient struct {
|
||||||
|
logger *zap.Logger
|
||||||
|
urls *models.VerificationMicroserviceURL
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVerificationClient(deps VerificationClientDeps) *VerificationClient {
|
||||||
|
if deps.Logger == nil {
|
||||||
|
log.Panicln("logger is nil on <NewVerificationClient>")
|
||||||
|
}
|
||||||
|
|
||||||
|
if deps.URLs == nil {
|
||||||
|
log.Panicln("urls is nil on <NewVerificationClient>")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &VerificationClient{
|
||||||
|
logger: deps.Logger,
|
||||||
|
urls: deps.URLs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *VerificationClient) GetVerification(ctx context.Context, userID string) (*models.Verification, errors.Error) {
|
||||||
|
verifURL, err := url.JoinPath(receiver.urls.Verification, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New(
|
||||||
|
fmt.Errorf("failed to join path on <GetVerification> of <VerificationClient>: %w", err),
|
||||||
|
errors.ErrInternalError,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := client.Get[models.Verification, models.FastifyError](ctx, &client.RequestSettings{
|
||||||
|
URL: verifURL,
|
||||||
|
Headers: map[string]string{"Content-Type": "application/json"},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New(err, errors.ErrInternalError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Body, nil
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package history
|
package history
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
@ -38,8 +39,17 @@ func New(deps Deps) *Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (receiver *Controller) GetHistoryList(ctx echo.Context, params swagger.GetHistoryParams) error {
|
func (receiver *Controller) GetHistoryList(ctx echo.Context, params swagger.GetHistoryParams) error {
|
||||||
|
var userID string
|
||||||
|
|
||||||
|
if params.AccountID != nil && *params.AccountID != "" {
|
||||||
|
userID = *params.AccountID
|
||||||
|
} else {
|
||||||
|
userID, _ = ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||||
|
}
|
||||||
|
|
||||||
histories, err := receiver.historyService.GetHistoryList(ctx.Request().Context(), &history.GetHistories{
|
histories, err := receiver.historyService.GetHistoryList(ctx.Request().Context(), &history.GetHistories{
|
||||||
Type: params.Type,
|
Type: params.Type,
|
||||||
|
UserID: userID,
|
||||||
Pagination: &models.Pagination{
|
Pagination: &models.Pagination{
|
||||||
Page: int64(*params.Page),
|
Page: int64(*params.Page),
|
||||||
Limit: int64(*params.Limit),
|
Limit: int64(*params.Limit),
|
||||||
@ -52,3 +62,74 @@ func (receiver *Controller) GetHistoryList(ctx echo.Context, params swagger.GetH
|
|||||||
|
|
||||||
return ctx.JSON(http.StatusOK, histories)
|
return ctx.JSON(http.StatusOK, histories)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO:tests.
|
||||||
|
func (receiver *Controller) GetRecentTariffs(ctx echo.Context) error {
|
||||||
|
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||||
|
if !ok {
|
||||||
|
receiver.logger.Error("failed to convert jwt payload to string on <GetRecentTariffs> of <HistoryController>")
|
||||||
|
return errors.HTTP(ctx, errors.New(
|
||||||
|
fmt.Errorf("failed to convert jwt payload to string: %s", userID),
|
||||||
|
errors.ErrInvalidArgs,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
tariffs, err := receiver.historyService.GetRecentTariffs(ctx.Request().Context(), userID)
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error("failed to get recent tariffs on <GetRecentTariffs> of <HistoryController>",
|
||||||
|
zap.String("userId", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return errors.HTTP(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.JSON(http.StatusOK, tariffs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:tests.
|
||||||
|
func (receiver *Controller) SendReport(ctx echo.Context) error {
|
||||||
|
historyID := ctx.Param("id")
|
||||||
|
|
||||||
|
err := receiver.historyService.GetHistoryByID(ctx.Request().Context(), historyID)
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error("failed to send report on <SendReport> of <HistoryController>", zap.Error(err))
|
||||||
|
return errors.HTTP(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.NoContent(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:tests.
|
||||||
|
func (receiver *Controller) CalculateLTV(ctx echo.Context) error {
|
||||||
|
var req swagger.CalculateLTVJSONBody
|
||||||
|
|
||||||
|
if err := ctx.Bind(&req); err != nil {
|
||||||
|
receiver.logger.Error("failed to bind request", zap.Error(err))
|
||||||
|
return errors.HTTP(ctx, errors.New(
|
||||||
|
fmt.Errorf("failed to bind request: %s", err),
|
||||||
|
errors.ErrInvalidArgs,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.From > req.To && req.To != 0 {
|
||||||
|
receiver.logger.Error("From timestamp must be less than To timestamp unless To is 0")
|
||||||
|
return errors.HTTP(ctx, errors.New(
|
||||||
|
fmt.Errorf("From timestamp must be less than To timestamp unless To is 0"),
|
||||||
|
errors.ErrInvalidArgs,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
ltv, err := receiver.historyService.CalculateCustomerLTV(ctx.Request().Context(), req.From, req.To)
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error("failed to calculate LTV", zap.Error(err))
|
||||||
|
return errors.HTTP(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
response := struct {
|
||||||
|
LTV int64 `json:"LTV"`
|
||||||
|
}{
|
||||||
|
LTV: ltv,
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
@ -4,12 +4,15 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"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"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/fields"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/service/history"
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/service/history"
|
||||||
mongoWrapper "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/mongo"
|
mongoWrapper "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/mongo"
|
||||||
@ -80,6 +83,9 @@ func (receiver *HistoryRepository) FindMany(ctx context.Context, dto *history.Ge
|
|||||||
|
|
||||||
findOptions.SetSkip((dto.Pagination.Page - 1) * dto.Pagination.Limit)
|
findOptions.SetSkip((dto.Pagination.Page - 1) * dto.Pagination.Limit)
|
||||||
findOptions.SetLimit(dto.Pagination.Limit)
|
findOptions.SetLimit(dto.Pagination.Limit)
|
||||||
|
findOptions.SetSort(bson.D{{
|
||||||
|
Key: "createdAt", Value: -1,
|
||||||
|
}})
|
||||||
|
|
||||||
histories, err := mongoWrapper.Find[models.History](ctx, &mongoWrapper.RequestSettings{
|
histories, err := mongoWrapper.Find[models.History](ctx, &mongoWrapper.RequestSettings{
|
||||||
Driver: receiver.mongoDB,
|
Driver: receiver.mongoDB,
|
||||||
@ -118,3 +124,218 @@ func (receiver *HistoryRepository) CountAll(ctx context.Context, dto *history.Ge
|
|||||||
|
|
||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO:tests
|
||||||
|
// GetRecentTariffs method for processing a user request with data aggregation with a limit of 100 sorted in descending order.
|
||||||
|
func (receiver *HistoryRepository) GetRecentTariffs(ctx context.Context, userID string) ([]models.TariffID, errors.Error) {
|
||||||
|
matchStage := bson.D{
|
||||||
|
{Key: "$match", Value: bson.D{
|
||||||
|
{Key: fields.History.UserID, Value: userID},
|
||||||
|
{Key: fields.History.IsDeleted, Value: false},
|
||||||
|
{Key: fields.History.Type, Value: models.CustomerHistoryKeyPayCart},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
unwindStage := bson.D{
|
||||||
|
{Key: "$unwind", Value: bson.D{
|
||||||
|
{Key: "path", Value: "$rawDetails.tariffs"},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
groupStage := bson.D{
|
||||||
|
{Key: "$group", Value: bson.D{
|
||||||
|
{Key: "_id", Value: "$rawDetails.tariffs.id"},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
sortStage := bson.D{
|
||||||
|
{Key: "$sort", Value: bson.D{
|
||||||
|
{Key: "createdAt", Value: -1},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
limitStage := bson.D{
|
||||||
|
{Key: "$limit", Value: 100},
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor, err := receiver.mongoDB.Aggregate(ctx, mongo.Pipeline{matchStage, unwindStage, sortStage, groupStage, limitStage})
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error("failed to get recent tariffs on <GetRecentTariffs> of <HistoryRepository>",
|
||||||
|
zap.String("userId", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, errors.New(
|
||||||
|
fmt.Errorf("failed to get recent tariffs on <GetRecentTariffs> of <HistoryRepository>: %w", err),
|
||||||
|
errors.ErrInternalError,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []models.TariffID
|
||||||
|
if err := cursor.All(ctx, &result); err != nil {
|
||||||
|
receiver.logger.Error("failed to decode recent tariffs on <GetRecentTariffs> of <HistoryRepository>",
|
||||||
|
zap.String("userId", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, errors.New(
|
||||||
|
fmt.Errorf("failed to decode recent tariffs on <GetRecentTariffs> of <HistoryRepository>: %w", err),
|
||||||
|
errors.ErrInternalError,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:tests.
|
||||||
|
func (receiver *HistoryRepository) GetHistoryByID(ctx context.Context, historyID string) (*models.ReportHistory, errors.Error) {
|
||||||
|
history := &models.ReportHistory{}
|
||||||
|
err := receiver.mongoDB.FindOne(ctx, bson.M{"_id": historyID}).Decode(history)
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error(
|
||||||
|
"failed to find by id in <GetHistoryById> of <HistoryRepository>",
|
||||||
|
zap.String("historyID", historyID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
|
||||||
|
if err == mongo.ErrNoDocuments {
|
||||||
|
return nil, errors.New(
|
||||||
|
fmt.Errorf("history not found with ID: %s", historyID),
|
||||||
|
errors.ErrNotFound,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New(
|
||||||
|
fmt.Errorf("failed to find by id: %w", err),
|
||||||
|
errors.ErrInternalError,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return history, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO:tests.
|
||||||
|
func (receiver *HistoryRepository) GetDocNumber(ctx context.Context, userID string) (map[string]int, errors.Error) {
|
||||||
|
findOptions := options.Find()
|
||||||
|
findOptions.SetSort(bson.D{{Key: "createdAt", Value: 1}})
|
||||||
|
|
||||||
|
filter := bson.M{
|
||||||
|
fields.History.UserID: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor, err := receiver.mongoDB.Find(ctx, filter, findOptions)
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error("failed to get DocNumber list on <GetDocNumber> of <HistoryRepository>",
|
||||||
|
zap.String("userId", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, errors.New(
|
||||||
|
fmt.Errorf("failed to get DocNumber list on <GetDocNumber> of <HistoryRepository>: %w", err),
|
||||||
|
errors.ErrInternalError,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := cursor.Close(ctx); err != nil {
|
||||||
|
receiver.logger.Error("failed to close cursor on <GetDocNumber> of <HistoryRepository>",
|
||||||
|
zap.String("userId", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
result := make(map[string]int)
|
||||||
|
var count int
|
||||||
|
for cursor.Next(ctx) {
|
||||||
|
var history models.History
|
||||||
|
if err := cursor.Decode(&history); err != nil {
|
||||||
|
receiver.logger.Error("failed to decode history on <GetDocNumber> of <HistoryRepository>",
|
||||||
|
zap.String("userId", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, errors.New(
|
||||||
|
fmt.Errorf("failed to decode history on <GetDocNumber> of <HistoryRepository>: %w", err),
|
||||||
|
errors.ErrInternalError,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
result[history.ID] = count
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cursor.Err(); err != nil {
|
||||||
|
receiver.logger.Error("cursor error on <GetDocNumber> of <HistoryRepository>",
|
||||||
|
zap.String("userId", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, errors.New(
|
||||||
|
fmt.Errorf("cursor error on <GetDocNumber> of <HistoryRepository>: %w", err),
|
||||||
|
errors.ErrInternalError,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *HistoryRepository) CalculateCustomerLTV(ctx context.Context, from, to int64) (int64, errors.Error) {
|
||||||
|
timeFilter := bson.M{}
|
||||||
|
if from != 0 || to != 0 {
|
||||||
|
timeRange := bson.M{}
|
||||||
|
if from != 0 {
|
||||||
|
timeRange["$gte"] = time.Unix(from, 0).UTC().Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
|
if to != 0 {
|
||||||
|
timeRange["$lte"] = time.Unix(to, 0).UTC().Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
|
timeFilter["createdAt"] = timeRange
|
||||||
|
}
|
||||||
|
pipeline := mongo.Pipeline{
|
||||||
|
{{Key: "$match", Value: bson.M{"key": models.CustomerHistoryKeyPayCart, "isDeleted": false}}},
|
||||||
|
{{Key: "$match", Value: timeFilter}},
|
||||||
|
{{Key: "$group", Value: bson.M{
|
||||||
|
"_id": "$userId",
|
||||||
|
"firstPayment": bson.M{"$min": "$createdAt"},
|
||||||
|
"lastPayment": bson.M{"$max": "$createdAt"},
|
||||||
|
}}},
|
||||||
|
{{Key: "$project", Value: bson.M{
|
||||||
|
"lifeTimeInDays": bson.M{"$divide": []interface{}{
|
||||||
|
bson.M{"$subtract": []interface{}{bson.M{"$toDate": "$lastPayment"}, bson.M{"$toDate": "$firstPayment"}}},
|
||||||
|
86400000,
|
||||||
|
}},
|
||||||
|
}}},
|
||||||
|
{{Key: "$group", Value: bson.M{
|
||||||
|
"_id": nil,
|
||||||
|
"averageLTV": bson.M{"$avg": "$lifeTimeInDays"},
|
||||||
|
}}},
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor, err := receiver.mongoDB.Aggregate(ctx, pipeline)
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error("failed to calculate customer LTV <CalculateCustomerLTV> of <HistoryRepository>",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return 0, errors.New(
|
||||||
|
fmt.Errorf("failed to calculate customer LTV <CalculateCustomerLTV> of <HistoryRepository>: %w", err),
|
||||||
|
errors.ErrInternalError,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := cursor.Close(ctx); err != nil {
|
||||||
|
receiver.logger.Error("failed to close cursor", zap.Error(err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var results []struct{ AverageLTV float64 }
|
||||||
|
if err := cursor.All(ctx, &results); err != nil {
|
||||||
|
receiver.logger.Error("failed to getting result LTV <CalculateCustomerLTV> of <HistoryRepository>",
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return 0, errors.New(
|
||||||
|
fmt.Errorf("failed to getting result LTV <CalculateCustomerLTV> of <HistoryRepository>: %w", err),
|
||||||
|
errors.ErrInternalError,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if len(results) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
averageLTV := int64(results[0].AverageLTV)
|
||||||
|
return averageLTV, nil
|
||||||
|
}
|
||||||
|
@ -207,8 +207,9 @@ func (api *API2) PaginationAccounts(ctx echo.Context, params PaginationAccountsP
|
|||||||
return api.error(ctx, http.StatusInternalServerError, "default values missing for PaginationAccounts")
|
return api.error(ctx, http.StatusInternalServerError, "default values missing for PaginationAccounts")
|
||||||
}
|
}
|
||||||
|
|
||||||
page := int64(max(*params.Page, 1))
|
page := int64(math.Max(float64(*params.Page), 1))
|
||||||
limit := min(int64(max(*params.Limit, 1)), models.DefaultLimit)
|
limit := int64(math.Max(float64(*params.Limit), 1))
|
||||||
|
limit = int64(math.Min(float64(limit), float64(models.DefaultLimit)))
|
||||||
|
|
||||||
count, err := api.account.CountAll(ctx.Request().Context())
|
count, err := api.account.CountAll(ctx.Request().Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -592,3 +593,18 @@ func (api *API2) ChangeCurrency(ctx echo.Context) error {
|
|||||||
|
|
||||||
return ctx.JSON(http.StatusOK, updatedAccount)
|
return ctx.JSON(http.StatusOK, updatedAccount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *API2) CalculateLTV(ctx echo.Context) error {
|
||||||
|
//TODO implement me
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API2) GetRecentTariffs(ctx echo.Context) error {
|
||||||
|
//TODO implement me
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API2) SendReport(ctx echo.Context) error {
|
||||||
|
//TODO implement me
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
@ -59,12 +59,18 @@ type ServerInterface interface {
|
|||||||
// обновляет список одобренных валют
|
// обновляет список одобренных валют
|
||||||
// (PUT /currencies)
|
// (PUT /currencies)
|
||||||
UpdateCurrencies(ctx echo.Context) error
|
UpdateCurrencies(ctx echo.Context) error
|
||||||
// Health Check
|
|
||||||
// (GET /health)
|
|
||||||
GetHealth(ctx echo.Context) error
|
|
||||||
// Получение лога событий связанных с аккаунтом
|
// Получение лога событий связанных с аккаунтом
|
||||||
// (GET /history)
|
// (GET /history)
|
||||||
GetHistory(ctx echo.Context, params GetHistoryParams) error
|
GetHistory(ctx echo.Context, params GetHistoryParams) error
|
||||||
|
// Расчет среднего времени жизни платящего клиента (LTV)
|
||||||
|
// (POST /history/ltv)
|
||||||
|
CalculateLTV(ctx echo.Context) error
|
||||||
|
// Получение недавних тарифов
|
||||||
|
// (GET /recent)
|
||||||
|
GetRecentTariffs(ctx echo.Context) error
|
||||||
|
// отправить акт проделанных работ на почту
|
||||||
|
// (POST /sendReport)
|
||||||
|
SendReport(ctx echo.Context) error
|
||||||
// Изменить валюту кошелька
|
// Изменить валюту кошелька
|
||||||
// (PATCH /wallet)
|
// (PATCH /wallet)
|
||||||
ChangeCurrency(ctx echo.Context) error
|
ChangeCurrency(ctx echo.Context) error
|
||||||
@ -272,15 +278,6 @@ func (w *ServerInterfaceWrapper) UpdateCurrencies(ctx echo.Context) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHealth converts echo context to params.
|
|
||||||
func (w *ServerInterfaceWrapper) GetHealth(ctx echo.Context) error {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// Invoke the callback with all the unmarshaled arguments
|
|
||||||
err = w.Handler.GetHealth(ctx)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHistory converts echo context to params.
|
// GetHistory converts echo context to params.
|
||||||
func (w *ServerInterfaceWrapper) GetHistory(ctx echo.Context) error {
|
func (w *ServerInterfaceWrapper) GetHistory(ctx echo.Context) error {
|
||||||
var err error
|
var err error
|
||||||
@ -310,11 +307,51 @@ func (w *ServerInterfaceWrapper) GetHistory(ctx echo.Context) error {
|
|||||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter type: %s", err))
|
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter type: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------- Optional query parameter "accountID" -------------
|
||||||
|
|
||||||
|
err = runtime.BindQueryParameter("form", false, false, "accountID", ctx.QueryParams(), ¶ms.AccountID)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter accountID: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
// Invoke the callback with all the unmarshaled arguments
|
// Invoke the callback with all the unmarshaled arguments
|
||||||
err = w.Handler.GetHistory(ctx, params)
|
err = w.Handler.GetHistory(ctx, params)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CalculateLTV converts echo context to params.
|
||||||
|
func (w *ServerInterfaceWrapper) CalculateLTV(ctx echo.Context) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx.Set(BearerScopes, []string{})
|
||||||
|
|
||||||
|
// Invoke the callback with all the unmarshaled arguments
|
||||||
|
err = w.Handler.CalculateLTV(ctx)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRecentTariffs converts echo context to params.
|
||||||
|
func (w *ServerInterfaceWrapper) GetRecentTariffs(ctx echo.Context) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx.Set(BearerScopes, []string{})
|
||||||
|
|
||||||
|
// Invoke the callback with all the unmarshaled arguments
|
||||||
|
err = w.Handler.GetRecentTariffs(ctx)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendReport converts echo context to params.
|
||||||
|
func (w *ServerInterfaceWrapper) SendReport(ctx echo.Context) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
ctx.Set(BearerScopes, []string{})
|
||||||
|
|
||||||
|
// Invoke the callback with all the unmarshaled arguments
|
||||||
|
err = w.Handler.SendReport(ctx)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// ChangeCurrency converts echo context to params.
|
// ChangeCurrency converts echo context to params.
|
||||||
func (w *ServerInterfaceWrapper) ChangeCurrency(ctx echo.Context) error {
|
func (w *ServerInterfaceWrapper) ChangeCurrency(ctx echo.Context) error {
|
||||||
var err error
|
var err error
|
||||||
@ -378,8 +415,10 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
|||||||
router.POST(baseURL+"/cart/pay", wrapper.PayCart)
|
router.POST(baseURL+"/cart/pay", wrapper.PayCart)
|
||||||
router.GET(baseURL+"/currencies", wrapper.GetCurrencies)
|
router.GET(baseURL+"/currencies", wrapper.GetCurrencies)
|
||||||
router.PUT(baseURL+"/currencies", wrapper.UpdateCurrencies)
|
router.PUT(baseURL+"/currencies", wrapper.UpdateCurrencies)
|
||||||
router.GET(baseURL+"/health", wrapper.GetHealth)
|
|
||||||
router.GET(baseURL+"/history", wrapper.GetHistory)
|
router.GET(baseURL+"/history", wrapper.GetHistory)
|
||||||
|
router.POST(baseURL+"/history/ltv", wrapper.CalculateLTV)
|
||||||
|
router.GET(baseURL+"/recent", wrapper.GetRecentTariffs)
|
||||||
|
router.POST(baseURL+"/sendReport", wrapper.SendReport)
|
||||||
router.PATCH(baseURL+"/wallet", wrapper.ChangeCurrency)
|
router.PATCH(baseURL+"/wallet", wrapper.ChangeCurrency)
|
||||||
router.POST(baseURL+"/wallet", wrapper.RequestMoney)
|
router.POST(baseURL+"/wallet", wrapper.RequestMoney)
|
||||||
|
|
||||||
@ -388,72 +427,81 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
|||||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||||
var swaggerSpec = []string{
|
var swaggerSpec = []string{
|
||||||
|
|
||||||
"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",
|
||||||
|
"WKMkDmpVAAA=",
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSwagger returns the content of the embedded swagger specification file
|
// GetSwagger returns the content of the embedded swagger specification file
|
||||||
|
173
internal/interface/swagger/api.go
Normal file
173
internal/interface/swagger/api.go
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
package swagger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
type accountController interface {
|
||||||
|
RemoveAccount(ctx echo.Context) error
|
||||||
|
GetAccount(ctx echo.Context) error
|
||||||
|
CreateAccount(ctx echo.Context) error
|
||||||
|
RemoveDirectAccount(ctx echo.Context, userID string) error
|
||||||
|
GetDirectAccount(ctx echo.Context, userID string) error
|
||||||
|
GetAccounts(echo.Context, PaginationAccountsParams) error
|
||||||
|
SetVerificationStatus(ctx echo.Context, userID string) error
|
||||||
|
UpdateAccountName(ctx echo.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type currencyController interface {
|
||||||
|
GetCurrencies(ctx echo.Context) error
|
||||||
|
PutCurrencies(ctx echo.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type cartController interface {
|
||||||
|
Remove(echo.Context, RemoveFromCartParams) error
|
||||||
|
Add(echo.Context, Add2cartParams) error
|
||||||
|
Pay(echo.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type walletController interface {
|
||||||
|
ChangeCurrency(ctx echo.Context) error
|
||||||
|
GetPaymentLink(ctx echo.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type historyController interface {
|
||||||
|
GetHistoryList(ctx echo.Context, params GetHistoryParams) error
|
||||||
|
GetRecentTariffs(ctx echo.Context) error
|
||||||
|
SendReport(ctx echo.Context) error
|
||||||
|
CalculateLTV(ctx echo.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Deps struct {
|
||||||
|
AccountController accountController
|
||||||
|
CurrencyController currencyController
|
||||||
|
CartController cartController
|
||||||
|
WalletController walletController
|
||||||
|
HistoryController historyController
|
||||||
|
}
|
||||||
|
|
||||||
|
type API struct {
|
||||||
|
accountController accountController
|
||||||
|
currencyController currencyController
|
||||||
|
cartController cartController
|
||||||
|
walletController walletController
|
||||||
|
historyController historyController
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(deps Deps) *API {
|
||||||
|
if deps.AccountController == nil {
|
||||||
|
log.Panicln("AccountController is nil on <New (API)>")
|
||||||
|
}
|
||||||
|
|
||||||
|
if deps.CurrencyController == nil {
|
||||||
|
log.Panicln("currencyController is nil on <New (API)>")
|
||||||
|
}
|
||||||
|
|
||||||
|
if deps.CartController == nil {
|
||||||
|
log.Panicln("cartController is nil on <New (API)>")
|
||||||
|
}
|
||||||
|
|
||||||
|
if deps.WalletController == nil {
|
||||||
|
log.Panicln("walletController is nil on <New (API)>")
|
||||||
|
}
|
||||||
|
|
||||||
|
if deps.HistoryController == nil {
|
||||||
|
log.Panicln("historyController is nil on <New (API)>")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &API{
|
||||||
|
accountController: deps.AccountController,
|
||||||
|
currencyController: deps.CurrencyController,
|
||||||
|
cartController: deps.CartController,
|
||||||
|
walletController: deps.WalletController,
|
||||||
|
historyController: deps.HistoryController,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account
|
||||||
|
|
||||||
|
func (receiver *API) DeleteAccount(ctx echo.Context) error {
|
||||||
|
return receiver.accountController.RemoveAccount(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) ChangeAccount(ctx echo.Context) error {
|
||||||
|
return receiver.accountController.UpdateAccountName(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) SetAccountVerificationStatus(ctx echo.Context, userID string) error {
|
||||||
|
return receiver.accountController.SetVerificationStatus(ctx, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) GetAccount(ctx echo.Context) error {
|
||||||
|
return receiver.accountController.GetAccount(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) AddAccount(ctx echo.Context) error {
|
||||||
|
return receiver.accountController.CreateAccount(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) DeleteDirectAccount(ctx echo.Context, userID string) error {
|
||||||
|
return receiver.accountController.RemoveDirectAccount(ctx, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) GetDirectAccount(ctx echo.Context, userID string) error {
|
||||||
|
return receiver.accountController.GetDirectAccount(ctx, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) PaginationAccounts(ctx echo.Context, params PaginationAccountsParams) error {
|
||||||
|
return receiver.accountController.GetAccounts(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cart
|
||||||
|
|
||||||
|
func (receiver *API) RemoveFromCart(ctx echo.Context, params RemoveFromCartParams) error {
|
||||||
|
return receiver.cartController.Remove(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) Add2cart(ctx echo.Context, params Add2cartParams) error {
|
||||||
|
return receiver.cartController.Add(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) PayCart(ctx echo.Context) error {
|
||||||
|
return receiver.cartController.Pay(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Currency
|
||||||
|
|
||||||
|
func (receiver *API) GetCurrencies(ctx echo.Context) error {
|
||||||
|
return receiver.currencyController.GetCurrencies(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) UpdateCurrencies(ctx echo.Context) error {
|
||||||
|
return receiver.currencyController.PutCurrencies(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// History
|
||||||
|
|
||||||
|
func (receiver *API) GetHistory(ctx echo.Context, params GetHistoryParams) error {
|
||||||
|
return receiver.historyController.GetHistoryList(ctx, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) GetRecentTariffs(ctx echo.Context) error {
|
||||||
|
return receiver.historyController.GetRecentTariffs(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) SendReport(ctx echo.Context) error {
|
||||||
|
return receiver.historyController.SendReport(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) CalculateLTV(ctx echo.Context) error {
|
||||||
|
return receiver.historyController.CalculateLTV(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wallet
|
||||||
|
|
||||||
|
func (receiver *API) RequestMoney(ctx echo.Context) error {
|
||||||
|
return receiver.walletController.GetPaymentLink(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *API) ChangeCurrency(ctx echo.Context) error {
|
||||||
|
return receiver.walletController.ChangeCurrency(ctx)
|
||||||
|
}
|
@ -100,6 +100,11 @@ type Name struct {
|
|||||||
// PaymentType defines model for PaymentType.
|
// PaymentType defines model for PaymentType.
|
||||||
type PaymentType string
|
type PaymentType string
|
||||||
|
|
||||||
|
// TariffID defines model for TariffID.
|
||||||
|
type TariffID struct {
|
||||||
|
ID *string `json:"ID,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Wallet defines model for Wallet.
|
// Wallet defines model for Wallet.
|
||||||
type Wallet struct {
|
type Wallet struct {
|
||||||
// Cash Сумма money переведённая на текущий курс
|
// Cash Сумма money переведённая на текущий курс
|
||||||
@ -155,6 +160,28 @@ type GetHistoryParams struct {
|
|||||||
|
|
||||||
// Type Тип события
|
// Type Тип события
|
||||||
Type *string `form:"type,omitempty" json:"type,omitempty"`
|
Type *string `form:"type,omitempty" json:"type,omitempty"`
|
||||||
|
|
||||||
|
// AccountID Идентификатор аккаунта. Если не указан, будет использоваться идентификатор из токена.
|
||||||
|
AccountID *string `form:"accountID,omitempty" json:"accountID,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CalculateLTVJSONBody defines parameters for CalculateLTV.
|
||||||
|
type CalculateLTVJSONBody struct {
|
||||||
|
// From Начальная дата в формате Unix timestamp. Если 0, устанавливает начало истории.
|
||||||
|
From int64 `json:"from"`
|
||||||
|
|
||||||
|
// To Конечная дата в формате Unix timestamp. Если 0, устанавливает текущее время.
|
||||||
|
To int64 `json:"to"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRecentTariffsJSONBody defines parameters for GetRecentTariffs.
|
||||||
|
type GetRecentTariffsJSONBody struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendReportJSONBody defines parameters for SendReport.
|
||||||
|
type SendReportJSONBody struct {
|
||||||
|
Id string `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChangeCurrencyJSONBody defines parameters for ChangeCurrency.
|
// ChangeCurrencyJSONBody defines parameters for ChangeCurrency.
|
||||||
@ -184,6 +211,15 @@ type SetAccountVerificationStatusJSONRequestBody SetAccountVerificationStatusJSO
|
|||||||
// UpdateCurrenciesJSONRequestBody defines body for UpdateCurrencies for application/json ContentType.
|
// UpdateCurrenciesJSONRequestBody defines body for UpdateCurrencies for application/json ContentType.
|
||||||
type UpdateCurrenciesJSONRequestBody = UpdateCurrenciesJSONBody
|
type UpdateCurrenciesJSONRequestBody = UpdateCurrenciesJSONBody
|
||||||
|
|
||||||
|
// CalculateLTVJSONRequestBody defines body for CalculateLTV for application/json ContentType.
|
||||||
|
type CalculateLTVJSONRequestBody CalculateLTVJSONBody
|
||||||
|
|
||||||
|
// GetRecentTariffsJSONRequestBody defines body for GetRecentTariffs for application/json ContentType.
|
||||||
|
type GetRecentTariffsJSONRequestBody GetRecentTariffsJSONBody
|
||||||
|
|
||||||
|
// SendReportJSONRequestBody defines body for SendReport for application/json ContentType.
|
||||||
|
type SendReportJSONRequestBody SendReportJSONBody
|
||||||
|
|
||||||
// ChangeCurrencyJSONRequestBody defines body for ChangeCurrency for application/json ContentType.
|
// ChangeCurrencyJSONRequestBody defines body for ChangeCurrency for application/json ContentType.
|
||||||
type ChangeCurrencyJSONRequestBody ChangeCurrencyJSONBody
|
type ChangeCurrencyJSONRequestBody ChangeCurrencyJSONBody
|
||||||
|
|
||||||
|
@ -26,13 +26,15 @@ type ConfigurationGRPC struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ServiceConfiguration struct {
|
type ServiceConfiguration struct {
|
||||||
AuthMicroservice AuthMicroserviceConfiguration
|
AuthMicroservice AuthMicroserviceConfiguration
|
||||||
HubadminMicroservice HubadminMicroserviceConfiguration
|
HubadminMicroservice HubadminMicroserviceConfiguration
|
||||||
CurrencyMicroservice CurrencyMicroserviceConfiguration
|
CurrencyMicroservice CurrencyMicroserviceConfiguration
|
||||||
DiscountMicroservice DiscountMicroserviceConfiguration
|
DiscountMicroservice DiscountMicroserviceConfiguration
|
||||||
PaymentMicroservice PaymentMicroserviceConfiguration
|
PaymentMicroservice PaymentMicroserviceConfiguration
|
||||||
JWT JWTConfiguration
|
VerificationMicroservice VerificationMicroserviceConfiguration
|
||||||
Kafka KafkaConfiguration
|
TemplategenMicroserviceURL TemplategenMicroserviceConfiguration
|
||||||
|
JWT JWTConfiguration
|
||||||
|
Kafka KafkaConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
type KafkaConfiguration struct {
|
type KafkaConfiguration struct {
|
||||||
@ -65,6 +67,14 @@ type CurrencyMicroserviceConfiguration struct {
|
|||||||
URL CurrencyMicroserviceURL
|
URL CurrencyMicroserviceURL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type VerificationMicroserviceConfiguration struct {
|
||||||
|
URL VerificationMicroserviceURL
|
||||||
|
}
|
||||||
|
|
||||||
|
type TemplategenMicroserviceConfiguration struct {
|
||||||
|
URL TemplategenMicroserviceURL
|
||||||
|
}
|
||||||
|
|
||||||
type PaymentMicroserviceConfiguration struct {
|
type PaymentMicroserviceConfiguration struct {
|
||||||
HostGRPC string `env:"PAYMENT_MICROSERVICE_GRPC_HOST,required"`
|
HostGRPC string `env:"PAYMENT_MICROSERVICE_GRPC_HOST,required"`
|
||||||
}
|
}
|
||||||
@ -84,3 +94,11 @@ type HubadminMicroserviceURL struct {
|
|||||||
type CurrencyMicroserviceURL struct {
|
type CurrencyMicroserviceURL struct {
|
||||||
Translate string `env:"CURRENCY_MICROSERVICE_TRANSLATE_URL,required"`
|
Translate string `env:"CURRENCY_MICROSERVICE_TRANSLATE_URL,required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type VerificationMicroserviceURL struct {
|
||||||
|
Verification string `env:"VERIFICATION_MICROSERVICE_USER_URL,required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TemplategenMicroserviceURL struct {
|
||||||
|
Templategen string `env:"TEMPLATEGEN_MICROSERVICE_URL,required"`
|
||||||
|
}
|
||||||
|
@ -14,6 +14,27 @@ type History struct {
|
|||||||
DeletedAt *time.Time `json:"deletedAt,omitempty" bson:"deletedAt,omitempty"`
|
DeletedAt *time.Time `json:"deletedAt,omitempty" bson:"deletedAt,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TariffID struct {
|
||||||
|
ID string `json:"id" bson:"_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ReportHistory struct {
|
||||||
|
ID string `json:"id" bson:"_id,omitempty"`
|
||||||
|
UserID string `json:"userId" bson:"userId"`
|
||||||
|
Comment string `json:"comment" bson:"comment"`
|
||||||
|
Key string `json:"key" bson:"key"`
|
||||||
|
RawDetails RawDetails `json:"rawDetails" bson:"rawDetails"`
|
||||||
|
Deleted bool `json:"isDeleted" bson:"isDeleted"`
|
||||||
|
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
|
||||||
|
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`
|
||||||
|
DeletedAt *time.Time `json:"deletedAt,omitempty" bson:"deletedAt,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RawDetails struct {
|
||||||
|
Tariffs []Tariff `json:"tariffs" bson:"tariffs"`
|
||||||
|
Price int64 `json:"price" bson:"price"`
|
||||||
|
}
|
||||||
|
|
||||||
func (receiver *History) Sanitize() *History {
|
func (receiver *History) Sanitize() *History {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
|
12
internal/models/templategen.go
Normal file
12
internal/models/templategen.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
type RespGeneratorService struct {
|
||||||
|
DocNumber int `json:"docnumber"`
|
||||||
|
Date string `json:"date"`
|
||||||
|
OrgTaxNum string `json:"orgtaxnum"`
|
||||||
|
OrgName Name `json:"orgname"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Amount uint64 `json:"amount"`
|
||||||
|
Price int64 `json:"price"`
|
||||||
|
Sum int64 `json:"sum"`
|
||||||
|
}
|
19
internal/models/verification.go
Normal file
19
internal/models/verification.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type Verification struct {
|
||||||
|
ID string `json:"_id" bson:"_id,omitempty"`
|
||||||
|
UserID string `json:"userID" bson:"user_id,omitempty"`
|
||||||
|
Accepted bool `json:"accepted" bson:"accepted"`
|
||||||
|
Status string `json:"status" bson:"status,omitempty"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
|
||||||
|
Comment string `json:"comment" bson:"comment,omitempty"`
|
||||||
|
Files []VerificationFile `json:"files" bson:"files,omitempty"`
|
||||||
|
TaxNumber string `json:"taxnumber" bson:"taxnumber,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type VerificationFile struct {
|
||||||
|
Name string `json:"name" bson:"name"`
|
||||||
|
URL string `json:"url" bson:"url"`
|
||||||
|
}
|
@ -165,7 +165,7 @@ func (receiver *Service) Pay(ctx context.Context, accessToken string, userID str
|
|||||||
UserInformation: &discount.UserInformation{
|
UserInformation: &discount.UserInformation{
|
||||||
ID: account.UserID,
|
ID: account.UserID,
|
||||||
Type: string(account.Status),
|
Type: string(account.Status),
|
||||||
PurchasesAmount: uint64(account.Wallet.PurchasesAmount),
|
PurchasesAmount: uint64(account.Wallet.Spent),
|
||||||
CartPurchasesAmount: tariffsAmount,
|
CartPurchasesAmount: tariffsAmount,
|
||||||
},
|
},
|
||||||
Products: transfer.TariffsToProductInformations(tariffs),
|
Products: transfer.TariffsToProductInformations(tariffs),
|
||||||
@ -180,7 +180,7 @@ func (receiver *Service) Pay(ctx context.Context, accessToken string, userID str
|
|||||||
UserInformation: &discount.UserInformation{
|
UserInformation: &discount.UserInformation{
|
||||||
ID: account.UserID,
|
ID: account.UserID,
|
||||||
Type: string(account.Status),
|
Type: string(account.Status),
|
||||||
PurchasesAmount: uint64(account.Wallet.PurchasesAmount),
|
PurchasesAmount: uint64(account.Wallet.Spent),
|
||||||
CartPurchasesAmount: tariffsAmount,
|
CartPurchasesAmount: tariffsAmount,
|
||||||
},
|
},
|
||||||
Products: transfer.TariffsToProductInformations(tariffs),
|
Products: transfer.TariffsToProductInformations(tariffs),
|
||||||
@ -203,10 +203,13 @@ func (receiver *Service) Pay(ctx context.Context, accessToken string, userID str
|
|||||||
|
|
||||||
go func(tariffs []models.Tariff) {
|
go func(tariffs []models.Tariff) {
|
||||||
if _, historyErr := receiver.historyService.CreateHistory(ctx, &models.History{
|
if _, historyErr := receiver.historyService.CreateHistory(ctx, &models.History{
|
||||||
Key: models.CustomerHistoryKeyPayCart,
|
Key: models.CustomerHistoryKeyPayCart,
|
||||||
UserID: account.UserID,
|
UserID: account.UserID,
|
||||||
Comment: "Успешная оплата корзины",
|
Comment: "Успешная оплата корзины",
|
||||||
RawDetails: tariffs,
|
RawDetails: map[string]any{
|
||||||
|
"tariffs": tariffs,
|
||||||
|
"price": discountResponse.Price,
|
||||||
|
},
|
||||||
}); historyErr != nil {
|
}); historyErr != nil {
|
||||||
receiver.logger.Error("failed to insert history on <Pay> of <CartService>", zap.Error(historyErr))
|
receiver.logger.Error("failed to insert history on <Pay> of <CartService>", zap.Error(historyErr))
|
||||||
}
|
}
|
||||||
@ -214,6 +217,8 @@ func (receiver *Service) Pay(ctx context.Context, accessToken string, userID str
|
|||||||
|
|
||||||
// TODO: обработать ошибки при отправке сообщений
|
// TODO: обработать ошибки при отправке сообщений
|
||||||
|
|
||||||
|
receiver.logger.Error("send to redpanda", zap.String("userID", account.UserID), zap.Any("bought tariffs", tariffs))
|
||||||
|
|
||||||
if sendErrors := receiver.tariffBrokerService.SendMany(ctx, account.UserID, tariffs); len(sendErrors) > 0 {
|
if sendErrors := receiver.tariffBrokerService.SendMany(ctx, account.UserID, tariffs); len(sendErrors) > 0 {
|
||||||
for _, err := range sendErrors {
|
for _, err := range sendErrors {
|
||||||
receiver.logger.Error("failed to send tariffs to broker on <Pay> of <CartService>", zap.Error(err))
|
receiver.logger.Error("failed to send tariffs to broker on <Pay> of <CartService>", zap.Error(err))
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -16,12 +18,14 @@ import (
|
|||||||
type GetHistories struct {
|
type GetHistories struct {
|
||||||
Pagination *models.Pagination
|
Pagination *models.Pagination
|
||||||
Type *string
|
Type *string
|
||||||
|
UserID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (receiver *GetHistories) BSON() bson.M {
|
func (receiver *GetHistories) BSON() bson.M {
|
||||||
query := bson.M{
|
query := bson.M{
|
||||||
fields.History.IsDeleted: false,
|
fields.History.IsDeleted: false,
|
||||||
fields.History.Type: *receiver.Type,
|
fields.History.Type: *receiver.Type,
|
||||||
|
fields.History.UserID: receiver.UserID,
|
||||||
}
|
}
|
||||||
|
|
||||||
return query
|
return query
|
||||||
@ -31,16 +35,38 @@ type historyRepository interface {
|
|||||||
CountAll(context.Context, *GetHistories) (int64, errors.Error)
|
CountAll(context.Context, *GetHistories) (int64, errors.Error)
|
||||||
FindMany(context.Context, *GetHistories) ([]models.History, errors.Error)
|
FindMany(context.Context, *GetHistories) ([]models.History, errors.Error)
|
||||||
Insert(context.Context, *models.History) (*models.History, errors.Error)
|
Insert(context.Context, *models.History) (*models.History, errors.Error)
|
||||||
|
GetRecentTariffs(context.Context, string) ([]models.TariffID, errors.Error) // new
|
||||||
|
GetHistoryByID(context.Context, string) (*models.ReportHistory, errors.Error)
|
||||||
|
GetDocNumber(context.Context, string) (map[string]int, errors.Error)
|
||||||
|
CalculateCustomerLTV(ctx context.Context, from, to int64) (int64, errors.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type authClient interface {
|
||||||
|
GetUser(ctx context.Context, userID string) (*models.User, errors.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type verificationClient interface {
|
||||||
|
GetUser(ctx context.Context, userID string) (*models.Verification, errors.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type temlategenClient interface {
|
||||||
|
SendData(ctx context.Context, data models.RespGeneratorService, fileContents []byte, email string) errors.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Deps struct {
|
type Deps struct {
|
||||||
Logger *zap.Logger
|
Logger *zap.Logger
|
||||||
Repository historyRepository
|
Repository historyRepository
|
||||||
|
AuthClient authClient
|
||||||
|
VerificationClient verificationClient
|
||||||
|
TemlategenClient temlategenClient
|
||||||
}
|
}
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
repository historyRepository
|
repository historyRepository
|
||||||
|
AuthClient authClient
|
||||||
|
VerificationClient verificationClient
|
||||||
|
TemlategenClient temlategenClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(deps Deps) *Service {
|
func New(deps Deps) *Service {
|
||||||
@ -52,9 +78,14 @@ func New(deps Deps) *Service {
|
|||||||
log.Panicln("repository is nil on <New (history service)>")
|
log.Panicln("repository is nil on <New (history service)>")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if deps.AuthClient == nil {
|
||||||
|
log.Panicln("auth client is nil on <New (account service)>")
|
||||||
|
}
|
||||||
|
|
||||||
return &Service{
|
return &Service{
|
||||||
logger: deps.Logger,
|
logger: deps.Logger,
|
||||||
repository: deps.Repository,
|
repository: deps.Repository,
|
||||||
|
AuthClient: deps.AuthClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,3 +136,138 @@ func (receiver *Service) CreateHistory(ctx context.Context, history *models.Hist
|
|||||||
|
|
||||||
return createdHistory, nil
|
return createdHistory, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO:tests.
|
||||||
|
func (receiver *Service) GetRecentTariffs(ctx context.Context, userID string) ([]models.TariffID, errors.Error) {
|
||||||
|
if userID == "" {
|
||||||
|
receiver.logger.Error("user id is missing in <GetRecentTariffs> of <HistoryService>")
|
||||||
|
return nil, errors.New(
|
||||||
|
fmt.Errorf("user id is missing: %w", errors.ErrInvalidArgs),
|
||||||
|
errors.ErrInvalidArgs,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
tariffs, err := receiver.repository.GetRecentTariffs(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error(
|
||||||
|
"failed to get recent tariffs in <GetRecentTariffs> of <HistoryService>",
|
||||||
|
zap.String("userId", userID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tariffs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *Service) GetHistoryByID(ctx context.Context, historyID string) errors.Error {
|
||||||
|
if historyID == "" {
|
||||||
|
receiver.logger.Error("history id is missing in <GetHistoryById> of <HistoryService>")
|
||||||
|
return errors.New(
|
||||||
|
fmt.Errorf("history id is missing: %w", errors.ErrInvalidArgs),
|
||||||
|
errors.ErrInvalidArgs,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
tariffs, err := receiver.repository.GetHistoryByID(ctx, historyID)
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error(
|
||||||
|
"failed to get history by id in <GetHistoryById> of <HistoryService>",
|
||||||
|
zap.String("historyID", historyID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if tariffs.Key != models.CustomerHistoryKeyPayCart {
|
||||||
|
receiver.logger.Error(
|
||||||
|
"invalid history record key",
|
||||||
|
zap.String("historyID", historyID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
historyMap, err := receiver.repository.GetDocNumber(ctx, tariffs.UserID)
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error(
|
||||||
|
"failed to get history of sorting by date created in <GetDocNumber> of <HistoryService>",
|
||||||
|
zap.String("historyID", historyID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
verifuser, err := receiver.VerificationClient.GetUser(ctx, tariffs.UserID)
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error("failed to get user verification on <GetHistoryById> of <HistoryService>",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.String("userID", tariffs.UserID),
|
||||||
|
)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !verifuser.Accepted {
|
||||||
|
receiver.logger.Error(
|
||||||
|
"verification not accepted",
|
||||||
|
zap.String("userID", tariffs.UserID),
|
||||||
|
zap.Error(err),
|
||||||
|
)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
authuser, err := receiver.AuthClient.GetUser(ctx, tariffs.UserID)
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error("failed to get user on <GetHistoryById> of <HistoryService>",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.String("userID", tariffs.UserID),
|
||||||
|
)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fileContents, readerr := os.ReadFile("./report.docx")
|
||||||
|
if readerr != nil {
|
||||||
|
return errors.New(
|
||||||
|
fmt.Errorf("failed to read file: %w", errors.ErrInternalError),
|
||||||
|
errors.ErrInternalError,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tariff := range tariffs.RawDetails.Tariffs {
|
||||||
|
totalAmount := uint64(0)
|
||||||
|
for _, privilege := range tariff.Privileges {
|
||||||
|
totalAmount += privilege.Amount
|
||||||
|
}
|
||||||
|
data := models.RespGeneratorService{
|
||||||
|
DocNumber: historyMap[historyID] + 1,
|
||||||
|
Date: time.Now().Format("2006-01-02"),
|
||||||
|
OrgTaxNum: verifuser.TaxNumber,
|
||||||
|
OrgName: models.Name{Orgname: "Orgname"},
|
||||||
|
Name: tariff.Name,
|
||||||
|
Amount: totalAmount,
|
||||||
|
Price: tariffs.RawDetails.Price,
|
||||||
|
Sum: tariffs.RawDetails.Price,
|
||||||
|
}
|
||||||
|
err = receiver.TemlategenClient.SendData(ctx, data, fileContents, authuser.Email)
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error("failed to send report to user on <GetHistoryById> of <HistoryService>",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.String("userID", tariffs.UserID),
|
||||||
|
)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (receiver *Service) CalculateCustomerLTV(ctx context.Context, from, to int64) (int64, errors.Error) {
|
||||||
|
ltv, err := receiver.repository.CalculateCustomerLTV(ctx, from, to)
|
||||||
|
if err != nil {
|
||||||
|
receiver.logger.Error("failed to calculate LTV", zap.Error(err))
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ltv, nil
|
||||||
|
}
|
||||||
|
@ -10,7 +10,7 @@ func CalculateCartPurchasesAmount(tariffs []models.Tariff) uint64 {
|
|||||||
privilegesSum := uint64(0)
|
privilegesSum := uint64(0)
|
||||||
|
|
||||||
for _, privilege := range tariff.Privileges {
|
for _, privilege := range tariff.Privileges {
|
||||||
privilegesSum += privilege.Price
|
privilegesSum += privilege.Price*privilege.Amount
|
||||||
}
|
}
|
||||||
|
|
||||||
sum += privilegesSum
|
sum += privilegesSum
|
||||||
|
@ -13,6 +13,12 @@ func TariffsToProductInformations(tarrifs []models.Tariff) []*discount.ProductIn
|
|||||||
for _, privilege := range tariff.Privileges {
|
for _, privilege := range tariff.Privileges {
|
||||||
productInformations = append(productInformations, PrivilegeToProductInformation(privilege))
|
productInformations = append(productInformations, PrivilegeToProductInformation(privilege))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tariff.Price != 0 {
|
||||||
|
for i := range productInformations {
|
||||||
|
productInformations[i].Price = tariff.Price
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return productInformations
|
return productInformations
|
||||||
|
BIN
main
Executable file
BIN
main
Executable file
Binary file not shown.
@ -45,4 +45,4 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
BIN
report.docx
Normal file
BIN
report.docx
Normal file
Binary file not shown.
54
tests/integration/calculate_LTV_test.go
Normal file
54
tests/integration/calculate_LTV_test.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package integration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/swagger"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCalculateLTV(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
jwtUtil := helpers.InitializeJWT()
|
||||||
|
token, err := jwtUtil.Create("807f1f77bcf81cd799439077")
|
||||||
|
|
||||||
|
if ok := assert.NoError(t, err); !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
layout := "2006-01-02T15:04:05.000Z"
|
||||||
|
fromString := "2023-11-08T22:29:48.719Z"
|
||||||
|
toString := "2023-12-27T15:00:00.000Z"
|
||||||
|
fromTime, err := time.Parse(layout, fromString)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("error:", err)
|
||||||
|
}
|
||||||
|
toTime, err := time.Parse(layout, toString)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("error:", err)
|
||||||
|
}
|
||||||
|
from := fromTime.Unix()
|
||||||
|
to := toTime.Unix()
|
||||||
|
fmt.Println(from, to)
|
||||||
|
|
||||||
|
response, err := client.Post[struct{}, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||||
|
URL: "http://" + "localhost:8000" + "/history/ltv",
|
||||||
|
Body: swagger.CalculateLTVJSONBody{From: from, To: to},
|
||||||
|
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||||
|
})
|
||||||
|
if ok := assert.NoError(t, err); !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ok := assert.Nil(t, response.Error); !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 200, response.StatusCode)
|
||||||
|
|
||||||
|
fmt.Println(response.Body)
|
||||||
|
}
|
37
tests/integration/history_report_test.go
Normal file
37
tests/integration/history_report_test.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package integration_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/swagger"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client"
|
||||||
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHistoryReport(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
jwtUtil := helpers.InitializeJWT()
|
||||||
|
token, err := jwtUtil.Create("807f1f77bcf81cd799439077")
|
||||||
|
|
||||||
|
if ok := assert.NoError(t, err); !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := client.Post[struct{}, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||||
|
URL: "http://" + customerServiceBase + "/sendReport",
|
||||||
|
Body: swagger.SendReportJSONBody{Id: "10002"},
|
||||||
|
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||||
|
})
|
||||||
|
if ok := assert.NoError(t, err); !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ok := assert.Nil(t, response.Error); !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 200, response.StatusCode)
|
||||||
|
}
|
@ -3,6 +3,7 @@ package integration_test
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -11,6 +12,8 @@ import (
|
|||||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers"
|
"penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var customerServiceBase = os.Getenv("CUSTOMER_SERVICE")
|
||||||
|
|
||||||
func TestSetAccountVerificationStatusNO(t *testing.T) {
|
func TestSetAccountVerificationStatusNO(t *testing.T) {
|
||||||
jwtUtil := helpers.InitializeJWT()
|
jwtUtil := helpers.InitializeJWT()
|
||||||
|
|
||||||
@ -25,7 +28,7 @@ func TestSetAccountVerificationStatusNO(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
response, getAccountErr := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
response, getAccountErr := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||||
URL: "http://localhost:8082/account/807f1f77bcf81cd799439077",
|
URL: "http://" + customerServiceBase + "/account/807f1f77bcf81cd799439077",
|
||||||
Body: models.SetAccountStatus{Status: models.AccountStatusNo},
|
Body: models.SetAccountStatus{Status: models.AccountStatusNo},
|
||||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||||
})
|
})
|
||||||
@ -56,7 +59,7 @@ func TestSetAccountVerificationStatusORG(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
response, getAccountErr := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
response, getAccountErr := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||||
URL: "http://localhost:8082/account/807f1f77bcf81cd799439077",
|
URL: "http://" + customerServiceBase + "/account/807f1f77bcf81cd799439077",
|
||||||
Body: models.SetAccountStatus{Status: models.AccountStatusOrg},
|
Body: models.SetAccountStatus{Status: models.AccountStatusOrg},
|
||||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||||
})
|
})
|
||||||
@ -87,7 +90,7 @@ func TestSetAccountVerificationStatusNKO(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
response, getAccountErr := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
response, getAccountErr := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||||
URL: "http://localhost:8082/account/807f1f77bcf81cd799439077",
|
URL: "http://" + customerServiceBase + "/account/807f1f77bcf81cd799439077",
|
||||||
Body: models.SetAccountStatus{Status: models.AccountStatusNko},
|
Body: models.SetAccountStatus{Status: models.AccountStatusNko},
|
||||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||||
})
|
})
|
||||||
@ -118,7 +121,7 @@ func TestSetAccountVerificationStatusFailure(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
response, getAccountErr := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
response, getAccountErr := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||||
URL: "http://localhost:8082/account/807f1f77bcf81cd799439077",
|
URL: "http://" + customerServiceBase + "/account/807f1f77bcf81cd799439077",
|
||||||
Body: models.SetAccountStatus{Status: "radnom-status"},
|
Body: models.SetAccountStatus{Status: "radnom-status"},
|
||||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||||
})
|
})
|
||||||
|
@ -25,7 +25,7 @@ func TestUpdateAccountName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
response, getAccountErr := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
response, getAccountErr := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||||
URL: "http://localhost:8082/account",
|
URL: "http://" + customerServiceBase + "/account",
|
||||||
Body: models.Name{
|
Body: models.Name{
|
||||||
FirstName: "Ivan",
|
FirstName: "Ivan",
|
||||||
Secondname: "Ivanov",
|
Secondname: "Ivanov",
|
||||||
|
Loading…
Reference in New Issue
Block a user