generated from PenaSide/GolangTemplate
Merge branch 'LTV' into 'dev'
Ltv See merge request pena-services/customer!31
This commit is contained in:
commit
75dc9314f5
@ -655,6 +655,65 @@ paths:
|
||||
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:
|
||||
schemas:
|
||||
Account:
|
||||
|
@ -98,3 +98,38 @@ func (receiver *Controller) SendReport(ctx echo.Context) error {
|
||||
|
||||
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,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
@ -273,3 +274,68 @@ func (receiver *HistoryRepository) GetDocNumber(ctx context.Context, userID stri
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -92,3 +92,7 @@ func (api *API2) ChangeCurrency(_ echo.Context) error {
|
||||
func (api *API2) RequestMoney(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
}
|
||||
|
||||
func (api *API2) CalculateLTV(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
}
|
||||
|
@ -62,6 +62,9 @@ type ServerInterface interface {
|
||||
// Получение лога событий связанных с аккаунтом
|
||||
// (GET /history)
|
||||
GetHistory(ctx echo.Context, params GetHistoryParams) error
|
||||
// Расчет среднего времени жизни платящего клиента (LTV)
|
||||
// (POST /history/ltv)
|
||||
CalculateLTV(ctx echo.Context) error
|
||||
// Получение недавних тарифов
|
||||
// (GET /recent)
|
||||
GetRecentTariffs(ctx echo.Context) error
|
||||
@ -316,6 +319,17 @@ func (w *ServerInterfaceWrapper) GetHistory(ctx echo.Context) error {
|
||||
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
|
||||
@ -402,6 +416,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
||||
router.GET(baseURL+"/currencies", wrapper.GetCurrencies)
|
||||
router.PUT(baseURL+"/currencies", wrapper.UpdateCurrencies)
|
||||
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)
|
||||
@ -412,76 +427,80 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||
var swaggerSpec = []string{
|
||||
|
||||
"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",
|
||||
"aC42/y8AAP//Dabnb25UAAA=",
|
||||
}
|
||||
|
||||
// GetSwagger returns the content of the embedded swagger specification file
|
||||
|
@ -37,6 +37,7 @@ 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 {
|
||||
@ -157,6 +158,10 @@ 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 {
|
||||
|
@ -170,6 +170,20 @@ type GetRecentTariffsJSONBody struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
@ -202,6 +216,9 @@ type SetAccountVerificationStatusJSONRequestBody SetAccountVerificationStatusJSO
|
||||
// UpdateCurrenciesJSONRequestBody defines body for UpdateCurrencies for application/json ContentType.
|
||||
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
|
||||
|
||||
|
@ -37,6 +37,7 @@ type historyRepository interface {
|
||||
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 {
|
||||
@ -259,3 +260,13 @@ func (receiver *Service) GetHistoryByID(ctx context.Context, historyID string) e
|
||||
}
|
||||
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
|
||||
}
|
||||
|
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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user