common/repository/statistics/click_statistics.go

275 lines
6.8 KiB
Go
Raw Normal View History

2024-06-13 12:39:18 +00:00
package statistics
2024-06-13 15:37:58 +00:00
import (
"context"
"database/sql"
"fmt"
"time"
2024-06-13 15:37:58 +00:00
)
2024-06-13 12:39:18 +00:00
type DepsClick struct {
Conn *sql.DB
}
type StatisticClick struct {
conn *sql.DB
}
2024-07-02 08:18:00 +00:00
func NewClickStatistic(deps DepsClick) *StatisticClick {
return &StatisticClick{
2024-06-13 12:39:18 +00:00
conn: deps.Conn,
}
2024-06-13 15:37:58 +00:00
}
type PipelineAndFormStatistic struct {
PipelineStatistic PipeLineStatsResp
ContactFormStatistic map[int64]int
}
2024-06-13 19:03:41 +00:00
type Statistic struct {
2024-06-13 15:37:58 +00:00
Count int64
QuestionID int64
}
2024-06-19 14:51:34 +00:00
type PipeLineStatsResp map[int64][]Statistic
2024-06-13 19:03:41 +00:00
func (s *StatisticClick) GetPipelinesStatistics(ctx context.Context, quizID int64, from uint64, to uint64) (*PipelineAndFormStatistic, error) {
2024-06-30 08:42:21 +00:00
pipelines := make(PipeLineStatsResp)
2024-06-19 14:29:20 +00:00
query := `
2024-06-30 08:42:21 +00:00
select last_quesion, questions, count() from (select last_quesion, questions, target_quiz
from (select last_quesion, questions, target_quiz from view_pipelines_signs
join view_respondent_paths on long_sess = session array join questions)
as pipelines join mv_answers on questions=questionid and quizid=target_quiz
where target_quiz = ? AND event_time BETWEEN ? AND ? ) group by last_quesion, questions;
`
rows, err := s.conn.QueryContext(ctx, query, quizID, from, to)
2024-06-13 15:37:58 +00:00
if err != nil {
return nil, err
}
defer rows.Close()
2024-06-14 18:06:01 +00:00
for rows.Next() {
2024-06-30 08:42:21 +00:00
var lastQuestionID int64
var questionID int64
var count int64
2024-06-30 08:42:21 +00:00
if err := rows.Scan(&lastQuestionID, &questionID, &count); err != nil {
2024-06-19 14:51:34 +00:00
return nil, err
}
2024-06-14 13:51:47 +00:00
2024-06-30 08:42:21 +00:00
stat := Statistic{
Count: count,
QuestionID: questionID,
2024-06-14 13:51:47 +00:00
}
2024-06-30 08:42:21 +00:00
pipelines[lastQuestionID] = append(pipelines[lastQuestionID], stat)
}
2024-06-14 13:51:47 +00:00
if err := rows.Err(); err != nil {
return nil, err
2024-06-14 13:51:47 +00:00
}
contactQuery := `
SELECT questionid, count() FROM mv_quiz_open WHERE quizid = ? AND event_time BETWEEN ? AND ?
GROUP BY questionid;
`
contactRows, err := s.conn.QueryContext(ctx, contactQuery, quizID, from, to)
if err != nil {
return nil, err
}
defer contactRows.Close()
contactForms := make(map[int64]int)
for contactRows.Next() {
var questionID int64
var count int
if err := contactRows.Scan(&questionID, &count); err != nil {
return nil, err
}
contactForms[questionID] = count
}
if err := contactRows.Err(); err != nil {
return nil, err
}
return &PipelineAndFormStatistic{
PipelineStatistic: pipelines,
ContactFormStatistic: contactForms,
}, nil
}
func (s *StatisticClick) CalculateCustomerLTV(ctx context.Context, req ChStatDeps) (int64, error) {
timeFilter := ""
if req.From != 0 {
fromTime := time.Unix(req.From, 0).UTC().Format("2006-01-02 15:04:05")
timeFilter += fmt.Sprintf(" AND create_time >= '%s'", fromTime)
}
if req.To != 0 {
toTime := time.Unix(req.To, 0).UTC().Format("2006-01-02 15:04:05")
timeFilter += fmt.Sprintf(" AND create_time <= '%s'", toTime)
}
query := fmt.Sprintf(`
SELECT avg(lifeTimeInDays) AS averageLTV
FROM (
SELECT
(dateDiff('day', min(create_time), max(create_time))) AS lifeTimeInDays
FROM ltv_view WHERE 1 = 1 %s GROUP BY ctxuserid)
`, timeFilter)
var result struct{ AverageLTV float64 }
if err := s.conn.QueryRowContext(ctx, query).Scan(&result.AverageLTV); err != nil {
return 0, err
}
return int64(result.AverageLTV), nil
}
type ChStatDeps struct {
From int64
To int64
}
type QuizLogoStats struct {
ID string
Regs int
Money int64
Quizes []Quiz
}
type Quiz struct {
QuizID string
Regs uint64
Money int64
}
func (s *StatisticClick) QuizLogoStat(ctx context.Context, req ChStatDeps) ([]QuizLogoStats, error) {
timeFilter := ""
if req.From != 0 && req.To != 0 {
timeFilter = fmt.Sprintf("AND lv.create_time >= toDate(%d) AND lv.create_time <= toDate(%d)", req.From, req.To)
}
query := fmt.Sprintf(`
SELECT
sub.partner AS partner,
count() AS regs,
sum(sub.rowPrice) AS money,
groupArray((sub.fromID, sub.regCount, sub.sumPrice)) AS quizes
FROM (
SELECT
uv.keyfrompartner AS partner,
uv.keyfromid AS fromID,
count() AS regCount,
sum(lv.ctxprice) AS sumPrice,
sum(lv.ctxprice) AS rowPrice
FROM ltv_view lv
JOIN user_regs_view uv ON lv.ctxuserid = uv.ctxuserid
WHERE uv.keyfrompartner != '' AND uv.keyfromid != ''
%s
GROUP BY uv.keyfrompartner, uv.keyfromid
) AS sub
GROUP BY sub.partner;
`, timeFilter)
var results []QuizLogoStats
rows, err := s.conn.QueryContext(ctx, query)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
var stats QuizLogoStats
var quizesData [][]interface{}
err := rows.Scan(&stats.ID, &stats.Regs, &stats.Money, &quizesData)
if err != nil {
return nil, err
}
var quizes []Quiz
for _, q := range quizesData {
quiz := Quiz{
QuizID: q[0].(string),
Regs: q[1].(uint64),
Money: q[2].(int64),
}
quizes = append(quizes, quiz)
}
stats.Quizes = quizes
results = append(results, stats)
}
if err := rows.Err(); err != nil {
return nil, err
}
return results, nil
}
type PromoLtvResp struct {
Regs int
Money int
}
func (s *StatisticClick) PromocodeLTV(ctx context.Context, req ChStatDeps) (map[string]PromoLtvResp, error) {
timeFilterFirstPromo := ""
timeFilterFirstData := ""
timeFilterMainQuery := ""
if req.From != 0 && req.To != 0 {
timeFilterFirstPromo = fmt.Sprintf("AND create_time BETWEEN toDateTime(%d) AND toDateTime(%d)", req.From, req.To)
timeFilterFirstData = fmt.Sprintf("AND promo.create_time BETWEEN toDateTime(%d) AND toDateTime(%d)", req.From, req.To)
timeFilterMainQuery = fmt.Sprintf("AND ltv.create_time BETWEEN toDateTime(%d) AND toDateTime(%d)", req.From, req.To)
}
query := fmt.Sprintf(`
WITH first_promo AS (
SELECT
ctxuserid, min(create_time) AS first_promo_time
FROM promo_view
WHERE 1=1 %s
GROUP BY ctxuserid
),
first_data AS (
SELECT
promo.ctxid, promo.ctxuserid, promo.create_time AS first_time
FROM
promo_view AS promo JOIN first_promo AS first
ON promo.ctxuserid = first.ctxuserid AND promo.create_time = first.first_promo_time
WHERE 1=1 %s
)
SELECT
promo_data.ctxid AS promoID,
count(DISTINCT promo_data.ctxuserid) AS regs,
sum(if(ltv.create_time > promo_data.first_time %s, ltv.ctxprice, 0)) AS totalSpent
FROM
first_data AS promo_data LEFT JOIN ltv_view AS ltv
ON promo_data.ctxuserid = ltv.ctxuserid
GROUP BY promo_data.ctxid;
`, timeFilterFirstPromo, timeFilterFirstData, timeFilterMainQuery)
rows, err := s.conn.QueryContext(ctx, query)
if err != nil {
return nil, err
}
defer rows.Close()
results := make(map[string]PromoLtvResp)
for rows.Next() {
var promoID string
var resp PromoLtvResp
if err := rows.Scan(&promoID, &resp.Regs, &resp.Money); err != nil {
return nil, err
}
results[promoID] = resp
}
if err := rows.Err(); err != nil {
return nil, err
}
return results, nil
2024-06-13 12:39:18 +00:00
}