@@ -0,0 +1,190 @@
|
||||
package txnmod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/common/pageopt"
|
||||
"91porn-server/common/ysinterface/disc"
|
||||
"91porn-server/models/commod"
|
||||
)
|
||||
|
||||
type DiscSeqe = commod.DiscSeqe
|
||||
|
||||
type DistrictStatKey struct {
|
||||
DiscSeqe `bson:",inline"` //商区码
|
||||
SysType string `bson:"sysType"` //系统类型 iOS Android
|
||||
}
|
||||
|
||||
func (d DistrictStatKey) GetDiscCode() string {
|
||||
return strings.ToUpper(d.DistrictCode)
|
||||
}
|
||||
|
||||
func (d DistrictStatKey) GetPromSeqe() string {
|
||||
return d.PromSeqe
|
||||
}
|
||||
|
||||
func (d DistrictStatKey) GetSysType() string {
|
||||
return d.SysType
|
||||
}
|
||||
|
||||
func (d DistrictStatKey) String() string {
|
||||
if d.DiscSeqe.String() == "" {
|
||||
return ""
|
||||
}
|
||||
return strings.ToUpper(strings.Join([]string{d.DiscSeqe.String(), d.SysType}, "-"))
|
||||
}
|
||||
|
||||
type DistrictStater = disc.DistrictStater
|
||||
|
||||
// DiscSeqeTransCount
|
||||
func DiscSeqeTransCount(start, end time.Time, mats ...Matcher) (map[DistrictStater]int64, error) {
|
||||
mats = append(mats, (&CreatedAtGTEAndLTMatch{GTE: &start, LT: &end}).New())
|
||||
filter := pageopt.MergeM(mats)
|
||||
list := []DistrictStatKey{}
|
||||
if err := coll(nil).Find(&list, filter); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "DiscSeqeTransCount", table, "Find", err))
|
||||
return nil, err
|
||||
}
|
||||
m := make(map[DistrictStater]int64)
|
||||
for _, v := range list {
|
||||
if v.String() != "" {
|
||||
m[v] += 1
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// DiscSeqeTransAmount
|
||||
func DiscSeqeTransAmount(start, end time.Time, mats ...Matcher) (map[DistrictStater]int64, error) {
|
||||
mats = append(mats, (&CreatedAtGTEAndLTMatch{GTE: &start, LT: &end}).New())
|
||||
filter := pageopt.MergeM(mats)
|
||||
list := []struct {
|
||||
DistrictStatKey `bson:",inline"` //商区码
|
||||
Amount int64 `bson:"amount"`
|
||||
}{}
|
||||
if err := coll(nil).Find(&list, filter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := make(map[DistrictStater]int64, len(list))
|
||||
for _, v := range list {
|
||||
if v.String() != "" {
|
||||
m[v.DistrictStatKey] += v.Amount
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// DiscTransUIDSMap
|
||||
func DiscTransUIDSMap(start, end time.Time, mats ...Matcher) (map[DistrictStater][]uint64, error) {
|
||||
mats = append(mats, (&CreatedAtGTEAndLTMatch{GTE: &start, LT: &end}).New())
|
||||
filter := pageopt.MergeM(mats)
|
||||
list := []struct {
|
||||
DistrictCode string `json:"districtCode" bson:"districtCode"` //商区码
|
||||
UID uint64 `bson:"uid"`
|
||||
}{}
|
||||
if err := coll(nil).Find(&list, filter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := make(map[DistrictStater][]uint64, len(list))
|
||||
for _, v := range list {
|
||||
key := DistrictStatKey{
|
||||
DiscSeqe: DiscSeqe{DistrictCode: v.DistrictCode},
|
||||
}
|
||||
if key.String() != "" {
|
||||
m[key] = append(m[key], v.UID)
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// DiscSeqeTransUIDSMap
|
||||
func DiscSeqeTransUIDSMap(start, end time.Time, mats ...Matcher) (map[DistrictStater][]uint64, error) {
|
||||
mats = append(mats, (&CreatedAtGTEAndLTMatch{GTE: &start, LT: &end}).New())
|
||||
filter := pageopt.MergeM(mats)
|
||||
list := []struct {
|
||||
DistrictStatKey `bson:",inline"` //商区码
|
||||
UID uint64 `bson:"uid"`
|
||||
}{}
|
||||
if err := coll(nil).Find(&list, filter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := make(map[DistrictStater][]uint64, len(list))
|
||||
for _, v := range list {
|
||||
if v.String() != "" {
|
||||
m[v.DistrictStatKey] = append(m[v.DistrictStatKey], v.UID)
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// DiscSeqeTransTaxAmount
|
||||
func DiscSeqeTransTaxAmount(start, end time.Time, mats ...Matcher) (map[DistrictStater]float64, error) {
|
||||
mats = append(mats, (&CreatedAtGTEAndLTMatch{GTE: &start, LT: &end}).New())
|
||||
filter := pageopt.MergeM(mats)
|
||||
list := []struct {
|
||||
DistrictStatKey `bson:",inline"` //商区码
|
||||
TaxAmount float64 `bson:"taxAmount"` //税额
|
||||
}{}
|
||||
if err := coll(nil).Find(&list, filter); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := make(map[DistrictStater]float64, len(list))
|
||||
for _, v := range list {
|
||||
if v.String() != "" {
|
||||
m[v.DistrictStatKey] += v.TaxAmount
|
||||
}
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// DiscSeqeBuyVipCount 时间内购买VIP次数
|
||||
func DiscSeqeBuyVipCount(start, end time.Time, mats ...Matcher) (map[DistrictStater]int64, error) {
|
||||
payVIP := PayVIP.Key()
|
||||
mats = append(mats, (&TranTypeMatch{&payVIP}).New())
|
||||
return DiscSeqeTransCount(start, end, mats...)
|
||||
}
|
||||
|
||||
// DiscSeqeBuyVipCount 时间内购买VIP金额
|
||||
func DiscSeqeBuyVipAmount(start, end time.Time, mats ...Matcher) (map[DistrictStater]int64, error) {
|
||||
payVIP := PayVIP.Key()
|
||||
mats = append(mats, (&TranTypeMatch{&payVIP}).New())
|
||||
return DiscSeqeTransAmount(start, end, mats...)
|
||||
}
|
||||
|
||||
// DiscBuyVipUIDSMap 时间内购买用户列表
|
||||
func DiscBuyVipUIDSMap(start, end time.Time, mats ...Matcher) (map[DistrictStater][]uint64, error) {
|
||||
payVIP := PayVIP.Key()
|
||||
mats = append(mats, (&TranTypeMatch{&payVIP}).New())
|
||||
return DiscTransUIDSMap(start, end, mats...)
|
||||
}
|
||||
|
||||
// DiscSeqeBuyVipUIDSMap 时间内购买用户列表
|
||||
func DiscSeqeBuyVipUIDSMap(start, end time.Time, mats ...Matcher) (map[DistrictStater][]uint64, error) {
|
||||
payVIP := PayVIP.Key()
|
||||
mats = append(mats, (&TranTypeMatch{&payVIP}).New())
|
||||
return DiscSeqeTransUIDSMap(start, end, mats...)
|
||||
}
|
||||
|
||||
// DiscSeqeBuyVidCount 时间内购买VID次数
|
||||
func DiscSeqeBuyVidCount(start, end time.Time, mats ...Matcher) (map[DistrictStater]int64, error) {
|
||||
payVID := PayVID.Key()
|
||||
mats = append(mats, (&TranTypeMatch{&payVID}).New())
|
||||
return DiscSeqeTransCount(start, end, mats...)
|
||||
}
|
||||
|
||||
// DiscSeqeBuyVidAmount 时间内购买VID金额
|
||||
func DiscSeqeBuyVidAmount(start, end time.Time, mats ...Matcher) (map[DistrictStater]int64, error) {
|
||||
payVID := PayVID.Key()
|
||||
mats = append(mats, (&TranTypeMatch{&payVID}).New())
|
||||
return DiscSeqeTransAmount(start, end, mats...)
|
||||
}
|
||||
|
||||
// DiscSeqeWorksIncomeTaxAmount 时间内购买VID税额
|
||||
func DiscSeqeWorksIncomeTaxAmount(start, end time.Time, mats ...Matcher) (map[DistrictStater]float64, error) {
|
||||
worksIncome := WorksIncome.Key()
|
||||
mats = append(mats, (&TranTypeMatch{&worksIncome}).New())
|
||||
return DiscSeqeTransTaxAmount(start, end, mats...)
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package txnmod
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"91porn-server/models"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
const ledgerQueryTimeout = 5 * time.Second
|
||||
const maxLedgerWindow int64 = 100000
|
||||
|
||||
var ledgerSort = bson.D{{Key: "createdAt", Value: -1}, {Key: "_id", Value: -1}}
|
||||
|
||||
// Fund records have no global time index. Only a concrete user's ledger can
|
||||
// include them without introducing a collection scan into the admin listing.
|
||||
func hasLedgerUID(filter bson.M) bool {
|
||||
switch uid := filter["uid"].(type) {
|
||||
case uint64:
|
||||
return uid > 0
|
||||
case int64:
|
||||
return uid > 0
|
||||
case int:
|
||||
return uid > 0
|
||||
case int32:
|
||||
return uid > 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Normalize at read time: no historical transaction or wallet is rewritten.
|
||||
// The indexable user/time match precedes projection and derived-field filters.
|
||||
func fundLedgerPipeline(filter bson.M, ordered bool) []bson.M {
|
||||
if !hasLedgerUID(filter) {
|
||||
return nil
|
||||
}
|
||||
if kind, ok := filter["tranType"].(string); ok && kind != AiGirlfriendTransferIn.Key() && kind != AiGirlfriendTransferOut.Key() {
|
||||
return nil
|
||||
}
|
||||
match := bson.M{"uid": filter["uid"], "category": 0, "fundType": bson.M{"$in": []int{1, 2}}}
|
||||
if period, ok := filter["createdAt"]; ok {
|
||||
match["createdAt"] = period
|
||||
}
|
||||
in := bson.M{"$eq": bson.A{"$fundType", 1}}
|
||||
amount := bson.M{"$cond": bson.A{in, bson.M{"$multiply": bson.A{"$amount", -1}}, "$amount"}}
|
||||
kind := bson.M{"$cond": bson.A{in, AiGirlfriendTransferIn.Key(), AiGirlfriendTransferOut.Key()}}
|
||||
pipeline := []bson.M{{"$match": match}}
|
||||
if ordered {
|
||||
pipeline = append(pipeline, bson.M{"$sort": ledgerSort})
|
||||
}
|
||||
pipeline = append(pipeline,
|
||||
bson.M{"$project": bson.M{
|
||||
"_id": 1, "uid": 1, "createdAt": 1,
|
||||
"purchaseOrder": "$_id", "amount": amount,
|
||||
"actualAmount": bson.M{"$toDouble": amount},
|
||||
"integral": bson.M{"$literal": 0},
|
||||
"tranType": kind,
|
||||
"tranTypeInt": bson.M{"$cond": bson.A{in, AiGirlfriendTransferIn, AiGirlfriendTransferOut}},
|
||||
"desc": bson.M{"$ifNull": bson.A{"$desc", kind}},
|
||||
"realAmount": bson.M{"$toDecimal": "$balance"},
|
||||
}},
|
||||
bson.M{"$match": filter},
|
||||
)
|
||||
return pipeline
|
||||
}
|
||||
|
||||
func mergeLedgerRows(ordinary, transfers []*TransactionLog, skip, limit int64) []*TransactionLog {
|
||||
rows := append(ordinary, transfers...)
|
||||
sort.SliceStable(rows, func(i, j int) bool {
|
||||
if !rows[i].CreatedAt.Equal(rows[j].CreatedAt) {
|
||||
return rows[i].CreatedAt.After(rows[j].CreatedAt)
|
||||
}
|
||||
return bytes.Compare(rows[i].ID[:], rows[j].ID[:]) > 0
|
||||
})
|
||||
if skip >= int64(len(rows)) {
|
||||
return []*TransactionLog{}
|
||||
}
|
||||
end := int64(len(rows))
|
||||
if limit > 0 && skip+limit < end {
|
||||
end = skip + limit
|
||||
}
|
||||
return rows[skip:end]
|
||||
}
|
||||
|
||||
// Read only the prefix needed from each source, then paginate the merged order.
|
||||
// An explicit window and server timeout bound old monthly and export requests.
|
||||
func findLedgerRows(filter bson.M, skip, limit int64) ([]*TransactionLog, error) {
|
||||
if skip < 0 || limit < 0 || skip > maxLedgerWindow || limit > maxLedgerWindow || (limit > 0 && skip > maxLedgerWindow-limit) {
|
||||
return nil, errors.New("ledger query window is too large; narrow the time range")
|
||||
}
|
||||
window := skip + limit
|
||||
if limit == 0 {
|
||||
window = maxLedgerWindow + 1
|
||||
}
|
||||
rows := []*TransactionLog{}
|
||||
pipeline := fundLedgerPipeline(filter, true)
|
||||
opt := options.Find().SetSort(ledgerSort).SetMaxTime(ledgerQueryTimeout)
|
||||
if !hasLedgerUID(filter) {
|
||||
opt.SetSort(bson.D{{Key: "createdAt", Value: -1}})
|
||||
}
|
||||
if pipeline == nil && limit > 0 {
|
||||
opt.SetSkip(skip).SetLimit(limit)
|
||||
} else {
|
||||
opt.SetLimit(window)
|
||||
}
|
||||
if err := coll(nil).Find(&rows, filter, opt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pipeline == nil && limit > 0 {
|
||||
return rows, nil
|
||||
}
|
||||
transfers := []*TransactionLog{}
|
||||
if pipeline != nil {
|
||||
pipeline = append(pipeline, bson.M{"$limit": window})
|
||||
if err := mdb.Coll(models.FundTransferLog).Aggregate(&transfers, pipeline, options.Aggregate().SetMaxTime(ledgerQueryTimeout)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if limit == 0 && int64(len(rows)+len(transfers)) > maxLedgerWindow {
|
||||
return nil, errors.New("ledger query window is too large; narrow the time range")
|
||||
}
|
||||
return mergeLedgerRows(rows, transfers, skip, limit), nil
|
||||
}
|
||||
|
||||
func countLedgerRows(filter bson.M) (int64, error) {
|
||||
count, err := coll(nil).Count(filter, options.Count().SetMaxTime(ledgerQueryTimeout))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
pipeline := fundLedgerPipeline(filter, false)
|
||||
if pipeline == nil {
|
||||
return count, nil
|
||||
}
|
||||
var result []struct {
|
||||
Count int64 `bson:"count"`
|
||||
}
|
||||
pipeline = append(pipeline, bson.M{"$count": "count"})
|
||||
if err := mdb.Coll(models.FundTransferLog).Aggregate(&result, pipeline, options.Aggregate().SetMaxTime(ledgerQueryTimeout)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(result) > 0 {
|
||||
count += result[0].Count
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func getLedgerCoinLogs(page, size uint64, filter bson.M) ([]*TransactionLog, uint64, int64, error) {
|
||||
if size == 0 || size > uint64(maxLedgerWindow) {
|
||||
return nil, 0, 0, errors.New("invalid ledger page size")
|
||||
}
|
||||
total, err := countLedgerRows(filter)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
pages := (uint64(total) + size - 1) / size
|
||||
if pages == 0 {
|
||||
return []*TransactionLog{}, 0, 0, nil
|
||||
}
|
||||
if page == 0 {
|
||||
page = 1
|
||||
}
|
||||
if page > pages {
|
||||
page = pages
|
||||
}
|
||||
if page-1 > uint64(maxLedgerWindow)/size {
|
||||
return nil, pages, total, errors.New("ledger query window is too large; narrow the time range")
|
||||
}
|
||||
rows, err := findLedgerRows(filter, int64((page-1)*size), int64(size))
|
||||
return rows, pages, total, err
|
||||
}
|
||||
|
||||
func FindLedgerByTime(uid uint64, start, end time.Time) ([]*TransactionLog, error) {
|
||||
return findLedgerRows(bson.M{"uid": uid, "createdAt": bson.M{"$gte": start, "$lt": end}}, 0, 0)
|
||||
}
|
||||
|
||||
func LastLedgerTime(uid uint64, end time.Time) (TransactionLog, error) {
|
||||
rows, err := findLedgerRows(bson.M{"uid": uid, "createdAt": bson.M{"$lt": end}}, 0, 1)
|
||||
if err != nil || len(rows) == 0 {
|
||||
return TransactionLog{}, err
|
||||
}
|
||||
return *rows[0], nil
|
||||
}
|
||||
|
||||
// These are wallet inflow/outflow totals, not recharge, creator or agent revenue.
|
||||
func sumLedgerAmount(uid uint64, start, end time.Time, income bool) (float64, error) {
|
||||
op := "$lt"
|
||||
if income {
|
||||
op = "$gt"
|
||||
}
|
||||
filter := bson.M{"uid": uid, "createdAt": bson.M{"$gte": start, "$lt": end}, "actualAmount": bson.M{op: 0}}
|
||||
group := bson.M{"$group": bson.M{"_id": nil, "total": bson.M{"$sum": "$actualAmount"}}}
|
||||
pipelines := [][]bson.M{{{"$match": filter}, group}, append(fundLedgerPipeline(filter, false), group)}
|
||||
var total float64
|
||||
for i, name := range []string{table, models.FundTransferLog} {
|
||||
var result []struct {
|
||||
Total float64 `bson:"total"`
|
||||
}
|
||||
if i == 1 && !hasLedgerUID(filter) {
|
||||
continue
|
||||
}
|
||||
if err := mdb.Coll(name).Aggregate(&result, pipelines[i], options.Aggregate().SetMaxTime(ledgerQueryTimeout)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(result) > 0 {
|
||||
total += result[0].Total
|
||||
}
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package txnmod
|
||||
|
||||
import (
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/common/pageopt"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
type Matcher = pageopt.Matcher
|
||||
|
||||
// TranTypeMatch
|
||||
type TranTypeMatch struct {
|
||||
TransType *string
|
||||
}
|
||||
|
||||
func (s *TranTypeMatch) New() Matcher {
|
||||
return pageopt.NewAssignMatch("tranType", s.TransType)
|
||||
}
|
||||
|
||||
// DistrictCodeMatch
|
||||
type DistrictCodeMatch struct {
|
||||
DistrictCode *string
|
||||
}
|
||||
|
||||
func (s *DistrictCodeMatch) New() Matcher {
|
||||
return pageopt.NewAssignMatch("districtCode", s.DistrictCode)
|
||||
}
|
||||
|
||||
// DistrictCodeINMatch
|
||||
type DistrictCodeINMatch struct {
|
||||
DistrictCodeList []string
|
||||
}
|
||||
|
||||
func (d *DistrictCodeINMatch) New() Matcher {
|
||||
return pageopt.NewInMatch("districtCode", d.DistrictCodeList)
|
||||
}
|
||||
|
||||
// PromSeqeMatch
|
||||
type PromSeqeMatch struct {
|
||||
Seqe *string
|
||||
}
|
||||
|
||||
func (d *PromSeqeMatch) New() Matcher {
|
||||
return pageopt.NewAssignMatch("promSeqe", d.Seqe)
|
||||
}
|
||||
|
||||
// SysTypeMatch
|
||||
type SysTypeMatch struct {
|
||||
SysType *string
|
||||
}
|
||||
|
||||
func (d *SysTypeMatch) New() Matcher {
|
||||
return pageopt.NewAssignMatch("sysType", d.SysType)
|
||||
}
|
||||
|
||||
// IsDirectMatch
|
||||
type IsDirectMatch struct {
|
||||
IsDirect *bool
|
||||
}
|
||||
|
||||
func (b *IsDirectMatch) New() Matcher {
|
||||
return pageopt.NewAssignMatch("isDirect", b.IsDirect)
|
||||
}
|
||||
|
||||
// CreatedAtGTEAndLTMatch
|
||||
type CreatedAtGTEAndLTMatch = pageopt.CreatedAtGTEAndLTMatch
|
||||
|
||||
// UIDMatch
|
||||
type UIDMatch = pageopt.UIDMatch
|
||||
|
||||
// UIDInMatch
|
||||
type UIDInMatch = pageopt.UIDInMatch
|
||||
|
||||
// IDMatch
|
||||
type IDMatch = pageopt.IDMatch
|
||||
|
||||
type Sort = bson.D
|
||||
|
||||
var Sort_CreatedAt_n1 = Sort{{Key: "createdAt", Value: -1}}
|
||||
|
||||
func List(sort Sort, skip, limit *int64, matchers ...Matcher) ([]TransactionLog, error) {
|
||||
filter := pageopt.MergeM(matchers)
|
||||
opt := (&options.FindOptions{})
|
||||
if len(sort) != 0 {
|
||||
opt.SetSort(sort)
|
||||
}
|
||||
if skip != nil {
|
||||
opt.SetSkip(*skip)
|
||||
}
|
||||
if limit != nil {
|
||||
opt.SetLimit(*limit)
|
||||
}
|
||||
list := []TransactionLog{}
|
||||
if err := coll(nil).Find(&list, filter, opt); err != nil {
|
||||
log.Error("txnmod List error", log.E(err))
|
||||
return nil, err
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func Count(matchers ...Matcher) (int64, error) {
|
||||
filter := pageopt.MergeM(matchers)
|
||||
count, err := coll(nil).Count(filter)
|
||||
if err != nil {
|
||||
log.Error("txnmod Count error", log.E(err))
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func AmountSum(matchers ...Matcher) (int64, error) {
|
||||
filter := pageopt.MergeM(matchers)
|
||||
pipeline := []M{}
|
||||
pipeline = append(pipeline, M{"$match": filter})
|
||||
pipeline = append(pipeline, M{"$group": M{"_id": nil,
|
||||
"amount": M{"$sum": "$amount"},
|
||||
}})
|
||||
var amount struct {
|
||||
Amount int64 `bson:"amount"` //金币
|
||||
}
|
||||
if err := coll(nil).AggregateDecode(&amount, pipeline); err != nil {
|
||||
log.Error("txnmod Sum error", log.E(err))
|
||||
return 0, err
|
||||
}
|
||||
return amount.Amount, nil
|
||||
}
|
||||
@@ -0,0 +1,654 @@
|
||||
/*
|
||||
* @Description: In User Settings Edit
|
||||
* @Author: your name
|
||||
* @Date: 2019-08-29 19:55:45
|
||||
* @LastEditTime: 2019-08-30 19:39:56
|
||||
* @LastEditors: Please set LastEditors
|
||||
*/
|
||||
package txnmod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"91porn-server/common/db"
|
||||
"91porn-server/common/log"
|
||||
"91porn-server/common/pageopt"
|
||||
"91porn-server/common/timeutil"
|
||||
"91porn-server/models"
|
||||
"91porn-server/models/commod"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
const table = models.Transaction
|
||||
|
||||
// InitIndex 设置index
|
||||
func initIndex() {
|
||||
coll := coll(nil)
|
||||
many := []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.D{{Key: "uid", Value: 1}},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "purchaseOrder", Value: 1}},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "uid", Value: 1}, {Key: "createdAt", Value: -1}},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "amount", Value: 1}},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "actualAmount", Value: 1}},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "createdAt", Value: 1}},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "uniqueOrder", Value: 1}},
|
||||
Options: options.Index().SetSparse(true).SetUnique(true),
|
||||
},
|
||||
|
||||
{
|
||||
Keys: bson.D{{Key: "tranType", Value: 1}, {Key: "createdAt", Value: -1}},
|
||||
// Options: options.Index().SetUnique(true).SetSparse(true),
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "tranType", Value: 1}, {Key: "districtCode", Value: 1}, {Key: "promSeqe", Value: 1}, {Key: "createdAt", Value: -1}},
|
||||
Options: options.Index().SetSparse(true),
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "tranType", Value: 1}, {Key: "districtCode", Value: 1}, {Key: "promSeqe", Value: 1}, {Key: "sysType", Value: 1}, {Key: "createdAt", Value: -1}},
|
||||
Options: options.Index().SetSparse(true),
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "tranTypeInt", Value: 1}, {Key: "createdAt", Value: -1}},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "tranTypeInt", Value: 1}, {Key: "districtCode", Value: 1}, {Key: "promSeqe", Value: 1}, {Key: "createdAt", Value: -1}},
|
||||
Options: options.Index().SetSparse(true),
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "tranTypeInt", Value: 1}, {Key: "districtCode", Value: 1}, {Key: "promSeqe", Value: 1}, {Key: "sysType", Value: 1}, {Key: "createdAt", Value: -1}},
|
||||
Options: options.Index().SetSparse(true),
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "isDirect", Value: 1}, {Key: "createdAt", Value: -1}},
|
||||
Options: options.Index().SetSparse(true),
|
||||
},
|
||||
|
||||
{
|
||||
Keys: bson.D{{Key: "uid", Value: 1}, {Key: "tranTypeInt", Value: 1}, {Key: "money", Value: 1}, {Key: "fruitCoin", Value: 1}, {Key: "createdAt", Value: -1}},
|
||||
Options: options.Index().SetSparse(true),
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "deductType", Value: 1}, {Key: "createdAt", Value: -1}},
|
||||
Options: options.Index().SetSparse(true),
|
||||
},
|
||||
}
|
||||
if _, err := coll.CreateIndex(many); err != nil {
|
||||
panic(fmt.Sprintf("%s model set index err ==>[%+v]", table, err))
|
||||
}
|
||||
}
|
||||
|
||||
func coll(t *db.MongoTool) *db.MongoTool {
|
||||
if t == nil {
|
||||
return mdb.Coll(table)
|
||||
}
|
||||
return t.Coll(table)
|
||||
}
|
||||
|
||||
// Insert 新增
|
||||
func InsertTransactionLog(mt *db.MongoTool, t *TransactionLog) error {
|
||||
//Insert 插入一条交易流水
|
||||
t.CreatedAt = time.Now()
|
||||
if _, err := coll(mt).InsertOne(t); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "InsertTransactionLog", table, "InsertOne", err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func InsertManyTransactionLog(mt *db.MongoTool, trans []TransactionLog) error {
|
||||
ops := options.InsertMany().SetOrdered(false)
|
||||
if _, err := coll(mt).InsertMany(trans, ops); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "InsertTransactionLog", table, "InsertOne", err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindMany 查询所有
|
||||
func FindTransactionLogs(filter bson.M, opts *options.FindOptions) (total int64, data []*TransactionLog, err error) {
|
||||
data = make([]*TransactionLog, 0)
|
||||
if err = coll(nil).Find(&data, filter, opts); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindTransactionLogs", table, "Find", err),
|
||||
log.Any("filter", filter),
|
||||
)
|
||||
return
|
||||
}
|
||||
total, err = coll(nil).Count(filter)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindTransactionLogs", table, "Count", err),
|
||||
log.Any("filter", filter),
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getTotalCnt 获取标签视频总数
|
||||
func getTotalCnt(cond bson.M) (int64, error) {
|
||||
total, err := coll(nil).Count(cond)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "getTotalCnt", table, "Count", err),
|
||||
log.Any("cond", cond),
|
||||
)
|
||||
return 0, err
|
||||
}
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// GetSkipSize 计算跳转
|
||||
func getSkipSize(page, size uint64, cond bson.M) (uint64, uint64, int64, error) {
|
||||
total, err := getTotalCnt(cond)
|
||||
if err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
totalpages := uint64(math.Ceil(float64(total) / float64(size)))
|
||||
if page > totalpages {
|
||||
page = totalpages
|
||||
}
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
return (page - 1) * size, totalpages, total, nil
|
||||
}
|
||||
|
||||
// GetCoinLogs 条件获取金币日志(时间倒序)
|
||||
func GetCoinLogs(page, size uint64, cond map[string]interface{}) ([]*TransactionLog, uint64, int64, error) {
|
||||
if !hasLedgerUID(bson.M(cond)) {
|
||||
// Preserve the existing global listing and export path until the fund
|
||||
// collection has an approved index for cross-user time queries.
|
||||
skip, totalPages, total, err := getSkipSize(page, size, bson.M(cond))
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
opts := options.Find().SetSort(bson.D{{Key: "createdAt", Value: -1}}).
|
||||
SetSkip(int64(skip)).SetLimit(int64(size))
|
||||
var rows []*TransactionLog
|
||||
err = coll(nil).Find(&rows, bson.M(cond), opts)
|
||||
return rows, totalPages, total, err
|
||||
}
|
||||
return getLedgerCoinLogs(page, size, bson.M(cond))
|
||||
}
|
||||
|
||||
func GetTranTypes() (data []interface{}, err error) {
|
||||
data, err = coll(nil).Distinct("tranType", bson.M{})
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetTranTypes", table, "Distinct", err))
|
||||
return nil, err
|
||||
}
|
||||
for _, kind := range []string{AiGirlfriendTransferIn.Key(), AiGirlfriendTransferOut.Key()} {
|
||||
found := false
|
||||
for _, existing := range data {
|
||||
if existing == kind {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
data = append(data, kind)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// FindManyByTime 查询所有
|
||||
func FindManyByTime(uid uint64, start time.Time, end time.Time) (data []*TransactionLog, err error) {
|
||||
data = make([]*TransactionLog, 0)
|
||||
opts := options.FindOptions{
|
||||
Sort: bson.D{{Key: "createdAt", Value: -1}},
|
||||
}
|
||||
if err = coll(nil).Find(&data, bson.M{"uid": uid, "createdAt": bson.M{"$gte": start, "$lt": end}}, &opts); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindManyByTime", table, "Find", err),
|
||||
log.Any("uid", uid),
|
||||
log.Any("start", start),
|
||||
log.Any("end", end),
|
||||
)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// HasNext 查询所有
|
||||
func HasNext(uid uint64, start time.Time) (hasNext bool, err error) {
|
||||
var data TransactionLog
|
||||
if err = coll(nil).FindOne(&data, bson.M{"uid": uid, "createdAt": bson.M{"$lt": start}}); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "HasNext", table, "FindOne", err),
|
||||
log.Any("uid", uid),
|
||||
log.Any("start", start),
|
||||
)
|
||||
return
|
||||
}
|
||||
return !data.ID.IsZero(), err
|
||||
}
|
||||
|
||||
// LastTime 查询所有
|
||||
func LastTime(uid uint64, end time.Time) (data TransactionLog, err error) {
|
||||
opt := options.FindOneOptions{
|
||||
Sort: bson.D{{Key: "createdAt", Value: -1}},
|
||||
}
|
||||
if err = coll(nil).FindOne(&data, bson.M{"uid": uid, "createdAt": bson.M{"$lt": end}}, &opt); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "LastTime", table, "FindOne", err),
|
||||
log.Any("uid", uid),
|
||||
log.Any("end", end),
|
||||
)
|
||||
return
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func GetBuyVipCountMapByHour(discCode string, start, end time.Time, mats ...Matcher) ([]int, map[int]int64, int64, error) {
|
||||
payVIP := PayVIP.Key()
|
||||
mats = append(mats,
|
||||
(&TranTypeMatch{&payVIP}).New(),
|
||||
(&DistrictCodeMatch{&discCode}).New(),
|
||||
(&CreatedAtGTEAndLTMatch{GTE: &start, LT: &end}).New())
|
||||
filter := pageopt.MergeM(mats)
|
||||
opt := (&options.FindOptions{}).SetProjection(M{
|
||||
"createdAt": 1,
|
||||
})
|
||||
var list []struct {
|
||||
CreatedAt time.Time `bson:"createdAt"` //创建时间
|
||||
}
|
||||
if err := coll(nil).Find(&list, filter, opt); err != nil {
|
||||
log.Error("txnmod GetBuyVipCountMap error", log.E(err))
|
||||
return nil, nil, 0, err
|
||||
}
|
||||
m := make(map[int]int64)
|
||||
startH := start.Hour()
|
||||
lastH := end.Hour() + (end.Day()-start.Day())*24
|
||||
hs := make([]int, lastH-startH+1)
|
||||
for i, j := startH, 0; i <= lastH; i++ {
|
||||
hs[j] = i
|
||||
m[i] = 0
|
||||
j++
|
||||
}
|
||||
var total int64
|
||||
for _, v := range list {
|
||||
hour := v.CreatedAt.Hour() + (v.CreatedAt.Day()-start.Day())*24
|
||||
m[hour] += 1
|
||||
total++
|
||||
}
|
||||
return hs, m, total, nil
|
||||
}
|
||||
|
||||
// FindIncome 查询所有
|
||||
func FindIncome(uid uint64, pageNumebr, pageSize uint64) (data []*TransactionLog, hasNext bool, err error) {
|
||||
data = make([]*TransactionLog, 0)
|
||||
f := bson.M{"uid": uid, "actualAmount": bson.M{"$gt": 0}}
|
||||
skip := int64(pageSize * (pageNumebr - 1))
|
||||
limit := int64(pageSize + 1)
|
||||
opts := options.FindOptions{
|
||||
Skip: &skip,
|
||||
Limit: &limit,
|
||||
Sort: bson.D{{Key: "createdAt", Value: -1}},
|
||||
}
|
||||
if err = coll(nil).Find(&data, f, &opts); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindTransactionLogs", table, "Find", err),
|
||||
log.Any("filter", f),
|
||||
)
|
||||
return
|
||||
}
|
||||
if len(data) > int(pageSize) {
|
||||
hasNext = true
|
||||
data = data[:pageSize]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// FindPoxyIncomeOfMonth 查询每月收益
|
||||
func FindPoxyIncomeOfMonth(uid uint64) (totalMoney int64, totalPerfomance int64, err error) {
|
||||
firstDay, lastDay := timeutil.MonthStartEndTime(time.Now())
|
||||
pipelines := []bson.M{
|
||||
{"$match": bson.M{"uid": uid, "tranTypeInt": ProxyIncome, "createdAt": bson.M{"$gte": firstDay, "$lt": lastDay}}},
|
||||
{"$group": bson.M{"_id": nil, "totalMoney": bson.M{"$sum": "$actualAmount"}, "totalPerformance": bson.M{"$sum": "$performance"}}},
|
||||
{"$project": bson.M{"totalMoney": 1, "totalPerformance": 1}},
|
||||
}
|
||||
type res struct {
|
||||
TotalMoney int64 `bson:"totalMoney"`
|
||||
TotalPerformance int64 `bson:"totalPerformance"`
|
||||
}
|
||||
data := make([]res, 0)
|
||||
if err = coll(nil).Aggregate(&data, pipelines); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindIncomeOfMonth", table, "Aggregate", err), log.Any("uid", uid))
|
||||
return
|
||||
}
|
||||
if len(data) > 0 {
|
||||
totalMoney = data[0].TotalMoney
|
||||
totalPerfomance = data[0].TotalPerformance
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// FindTransactionLogsByTransType 查询所有
|
||||
func FindTransactionLogsByTransType(uid uint64, pageNumber int64, pageSize int64, tranType TransType) (data []*TransactionLog, hasNext bool, err error) {
|
||||
data = make([]*TransactionLog, 0)
|
||||
skip := (pageNumber - 1) * pageSize
|
||||
limit := pageSize + 1
|
||||
opts := options.FindOptions{
|
||||
Skip: &skip,
|
||||
Limit: &limit,
|
||||
Sort: bson.D{{Key: "createdAt", Value: -1}},
|
||||
}
|
||||
if err = coll(nil).Find(&data, bson.M{"uid": uid, "tranTypeInt": tranType}, &opts); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindTransactionLogsByTransType", table, "Find", err), log.Any("uid", uid))
|
||||
return
|
||||
}
|
||||
if len(data) > int(pageSize) {
|
||||
hasNext = true
|
||||
data = data[:pageSize]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetProxyIncomeForToday 查询所有
|
||||
func GetProxyIncomeForToday(uid uint64, start time.Time, end time.Time) (data []AgentIncomeRes, err error) {
|
||||
pipelines := []bson.M{
|
||||
{"$match": bson.M{"uid": uid, "tranTypeInt": ProxyIncome, "createdAt": bson.M{"$gte": start, "$lt": end}}},
|
||||
{"$group": bson.M{"_id": "$agentLevel", "totalAmount": bson.M{"$sum": "$actualAmount"}, "totalPerformance": bson.M{"$sum": "$performance"}}},
|
||||
{"$project": bson.M{"totalAmount": 1, "totalPerformance": 1}},
|
||||
}
|
||||
data = make([]AgentIncomeRes, 0)
|
||||
if err = coll(nil).Aggregate(&data, pipelines); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetProxyIncomeOfDay", table, "Find", err), log.Any("uid", uid))
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetIncomeByType 查询所有
|
||||
func GetIncomeByType(uid uint64, tp TransType, start time.Time, end time.Time) (totalAmount float64, totalPer int64, err error) {
|
||||
match := bson.M{"uid": uid, "tranTypeInt": tp, "createdAt": bson.M{"$gte": start, "$lt": end}}
|
||||
log.Info(fmt.Sprintf("%v", match))
|
||||
pipelines := []bson.M{
|
||||
{"$match": match},
|
||||
{"$group": bson.M{"_id": nil, "totalAmount": bson.M{"$sum": "$actualAmount"}, "totalPerformance": bson.M{"$sum": "$performance"}}},
|
||||
{"$project": bson.M{"totalAmount": 1, "totalPerformance": 1}},
|
||||
}
|
||||
var res struct {
|
||||
TotalAmount float64 `bson:"totalAmount"`
|
||||
TotalPerformance int64 `bson:"totalPerformance"`
|
||||
}
|
||||
if err = coll(nil).AggregateDecode(&res, pipelines); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "GetProxyIncomeOfDay", table, "Find", err), log.Any("uid", uid))
|
||||
return
|
||||
}
|
||||
totalAmount = res.TotalAmount
|
||||
totalPer = res.TotalPerformance
|
||||
return
|
||||
}
|
||||
|
||||
// IsProxyExist 代理分成是否存在
|
||||
func IsProxyExist(uid uint64, objId primitive.ObjectID) bool {
|
||||
filter := bson.M{"uid": uid, "purchaseOrder": objId, "tranType": ProxyIncome.Key()}
|
||||
count, err := coll(nil).Count(filter)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "IsProxyExist", table, "Count", count), log.Any("uid", uid), log.Any("objId", objId))
|
||||
//查询异常的时候, 默认不分成, 用户找来可以人工修复, 项目不能亏
|
||||
return true
|
||||
}
|
||||
if count > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Income 收益
|
||||
func Income(uid uint64, start time.Time, end time.Time) (totalAmount float64, err error) {
|
||||
return sumLedgerAmount(uid, start, end, true)
|
||||
}
|
||||
|
||||
// Expenditure 支出
|
||||
func Expenditure(uid uint64, start time.Time, end time.Time) (totalAmount float64, err error) {
|
||||
return sumLedgerAmount(uid, start, end, false)
|
||||
}
|
||||
|
||||
// Ibills 账单
|
||||
func Ibills(uid uint64, pageNumebr, pageSize uint64, start time.Time, end time.Time) (data []TransactionLog, hasNext bool, err error) {
|
||||
data = make([]TransactionLog, 0)
|
||||
f := bson.M{
|
||||
"uid": uid,
|
||||
"createdAt": bson.M{"$gte": start, "$lt": end},
|
||||
"tranTypeInt": bson.M{"$in": []TransType{
|
||||
AiGirlfriendTransferIn, AiGirlfriendTransferOut, Rchg, PayVID, WithdrawTransfer, PayVIP, WithdrawRefund, AdminCreaditAmount, AdminDebitAmount, OfficialRech, MeetingCard,
|
||||
GameCoin, ChaseScore, PayReward, Other, LouFeng, AudioBook, LouFengRefund, LouFengDiscount, GameRewards, VipCardGive,
|
||||
LouFengMianFei, LuckyDraw, PayAvVID, TranType_WLSysGive, SignBoon, JewelBoxBoon, LouFengConsumerRebate, ChessRechargePolite,
|
||||
JiuGongGeDraw, CurrencyGive, GoldCouplePayVID, BookLoufeng, Active2023Cost, Active2023Reward, RaffleDeduction, PrizeRecord,
|
||||
DailyTaskAdsClick, DailyTaskUserInvite, OnceTaskBuyVIP, OnceTaskBindMobile, ReceiveIntegral, BuyVIP, IntegralExchangeVip,
|
||||
ReceiveIntegral, ProxyIncome, WorksIncome, SendMsgDebitIncomeGold, SendMsgDebitIncomeGoldReturn, SendMsgDebitAmountGold,
|
||||
SendMsgDebitAmountGoldReturn, AiChangefaceDebitGold, AiChangefaceDebitGoldReturn, AiChangefaceDebitInComeGold, AiChangefaceDebitIncomeGoldReturn,
|
||||
AiChangeFaceImgDebitGold, AiChangeFaceImgReturnGold, AiUndressDebitFreeTimes, AiUndressDebitFreeTimesReturn, AiUndressDebitIncomeGold,
|
||||
AiUndressDebitIncomeGoldReturn, AiChangeFaceImgDebitIncomeGold, AiChangeFaceImgReturnIncomeGold, AiChangeFaceImgDebitFreeTimes,
|
||||
AiChangeFaceImgDebitFreeTimesReturn, AiUndress, AiUndressRefund, AiUndressInc, AiUndressIncBackend, AiUndressDebitGold, AiUndressDebitGoldReturn,
|
||||
VipCardGiveAiUndressFreeCount, AdminAddDownloadCount, AdminDebitDownloadCount, BuyAdvanceVIP, BuyBalanceVIP, BuyGameAdvanceVIP,
|
||||
BuyWhoringCard, ReSignDebitAmount, SuccessSignReturnAmount, GodCommentAward, IntegralExchangeAICount, AiMateCurrencyExchange,
|
||||
AiImageToVideoDebitGold, AiImageToVideoDebitGoldReturn, AiImageToVideoDebitInComeGold, AiImageToVideoDebitIncomeGoldReturn,
|
||||
AiTextToImageDebitGold, AiTextToImageDebitGoldReturn, AiTextToImageDebitInComeGold, AiTextToImageDebitIncomeGoldReturn, BuyAcg,
|
||||
AiTextToNovelDebitGold, AiTextToNovelDebitGoldReturn, AiTextToNovelDebitInComeGold, AiTextToNovelDebitIncomeGoldReturn,
|
||||
}},
|
||||
//"amount": bson.M{"$ne": 0},
|
||||
"$or": []bson.M{
|
||||
bson.M{"amount": bson.M{"$ne": 0}},
|
||||
bson.M{"integral": bson.M{"$ne": 0}},
|
||||
bson.M{"tranTypeInt": bson.M{"$in": []TransType{AiGirlfriendTransferIn, AiGirlfriendTransferOut}}},
|
||||
},
|
||||
}
|
||||
if pageSize == 0 || pageSize >= uint64(maxLedgerWindow) {
|
||||
return nil, false, fmt.Errorf("invalid ledger page size")
|
||||
}
|
||||
if pageNumebr == 0 {
|
||||
pageNumebr = 1
|
||||
}
|
||||
if pageNumebr-1 > uint64(maxLedgerWindow)/pageSize {
|
||||
return nil, false, fmt.Errorf("ledger query window is too large; narrow the time range")
|
||||
}
|
||||
rows, err := findLedgerRows(f, int64(pageSize*(pageNumebr-1)), int64(pageSize+1))
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
hasNext = len(rows) > int(pageSize)
|
||||
if hasNext {
|
||||
rows = rows[:pageSize]
|
||||
}
|
||||
for _, row := range rows {
|
||||
data = append(data, *row)
|
||||
}
|
||||
return data, hasNext, nil
|
||||
}
|
||||
|
||||
// HasNextMonth 查询当前月之前的最迟数据的的时间
|
||||
func HasNextMonth(uid uint64, start time.Time) (data TransactionLog, err error) {
|
||||
opt := options.FindOne()
|
||||
opt.Sort = bson.D{{Key: "createdAt", Value: -1}}
|
||||
err = coll(nil).FindOne(&data, bson.M{"uid": uid, "createdAt": bson.M{"$lt": start}})
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "HasNext", table, "FindOne", err),
|
||||
log.Any("uid", uid),
|
||||
log.Any("start", start),
|
||||
)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func BuyLoufengCount(uid uint64) (int64, error) {
|
||||
return coll(nil).Count(bson.M{"uid": uid, "tranTypeInt": bson.M{"$in": []TransType{LouFeng, BookLoufeng}}})
|
||||
}
|
||||
|
||||
// 时间内购买VIP次数
|
||||
func BuyVipCount(start, end time.Time, mats ...Matcher) (int64, error) {
|
||||
payVIP := PayVIP.Key()
|
||||
mats = append(mats, (&TranTypeMatch{&payVIP}).New(), (&CreatedAtGTEAndLTMatch{GTE: &start, LT: &end}).New())
|
||||
filter := pageopt.MergeM(mats)
|
||||
count, err := coll(nil).Count(filter)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "BuyVipCount", table, "Count", err))
|
||||
}
|
||||
return count, err
|
||||
}
|
||||
|
||||
// //产品购买记录
|
||||
func BuyProductLog(uid uint64, tranTypeInt TransType, pids []primitive.ObjectID) (data []TransactionLog, err error) {
|
||||
objIDs := make([]string, len(pids))
|
||||
for i := range pids {
|
||||
objIDs[i] = pids[i].Hex()
|
||||
}
|
||||
data = make([]TransactionLog, 0)
|
||||
opt := options.FindOptions{
|
||||
Sort: bson.D{{Key: "createdAt", Value: -1}},
|
||||
}
|
||||
f := bson.M{"uid": uid, "tranTypeInt": tranTypeInt, "productID": bson.M{"$in": objIDs}}
|
||||
if err = coll(nil).Find(&data, f, &opt); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "BuyProductLog", table, "Find", err))
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 产品购买记录 单个
|
||||
func BuyProductLogSingle(uid uint64, tranTypeInt TransType, pid string) (data TransactionLog, err error) {
|
||||
f := bson.M{"uid": uid, "tranTypeInt": tranTypeInt, "productID": pid}
|
||||
if err = coll(nil).FindOne(&data, f); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "BuyProductLogSingle", table, "Find", err))
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 产品购买记录
|
||||
func BuyProductLogWithPage(uid uint64, tranTypeInt TransType, page commod.Page) (data []TransactionLog, hasNext bool, err error) {
|
||||
data = make([]TransactionLog, 0)
|
||||
skip := int64(page.Skip())
|
||||
limit := int64(page.Limit() + 1)
|
||||
opts := options.FindOptions{
|
||||
Skip: &skip,
|
||||
Limit: &limit,
|
||||
Sort: bson.D{{Key: "createdAt", Value: -1}},
|
||||
}
|
||||
f := bson.M{"uid": uid, "tranTypeInt": tranTypeInt}
|
||||
if tranTypeInt == PayAvVID {
|
||||
f["productID"] = bson.M{"$exists": true}
|
||||
}
|
||||
if err = coll(nil).Find(&data, f, &opts); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "BuyProductLog", table, "Find", err))
|
||||
return
|
||||
}
|
||||
if uint64(len(data)) > page.PageSize {
|
||||
hasNext = true
|
||||
data = data[:page.PageSize]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Income 账单
|
||||
func WorksIncomebills(uid uint64, pageNumebr, pageSize uint64) (data []TransactionLog, hasNext bool, err error) {
|
||||
data = make([]TransactionLog, 0)
|
||||
f := bson.M{"uid": uid, "tranTypeInt": WorksIncome}
|
||||
skip := int64(pageSize * (pageNumebr - 1))
|
||||
limit := int64(pageSize + 1)
|
||||
opts := options.FindOptions{
|
||||
Skip: &skip,
|
||||
Limit: &limit,
|
||||
Sort: bson.D{{Key: "createdAt", Value: -1}},
|
||||
}
|
||||
if err = coll(nil).Find(&data, f, &opts); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "FindTransactionLogs", table, "Find", err),
|
||||
log.Any("filter", f),
|
||||
)
|
||||
return
|
||||
}
|
||||
if len(data) > int(pageSize) {
|
||||
hasNext = true
|
||||
data = data[:pageSize]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 是否购买了某个产品
|
||||
func IsBuyProduct(uid uint64, id primitive.ObjectID, tranTypeInt TransType) (bool, error) {
|
||||
f := bson.M{"uid": uid, "productID": id.Hex(), "tranTypeInt": tranTypeInt}
|
||||
count, err := coll(nil).Count(f)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "BuyVipCount", table, "Count", count))
|
||||
return false, err
|
||||
}
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
// QueryAll 条件查询列表
|
||||
func QueryAll(filter bson.M, opts ...*options.FindOptions) ([]TransactionLog, error) {
|
||||
var items []TransactionLog
|
||||
return items, coll(nil).Find(&items, filter, opts...)
|
||||
}
|
||||
|
||||
// TransStat 交易统计
|
||||
func TransStat(start, end time.Time) ([]TransactionR, error) {
|
||||
var items []TransactionR
|
||||
f := bson.M{"createdAt": bson.M{"$gt": start, "$lte": end}, "tranTypeInt": LouFeng}
|
||||
return items, coll(nil).Find(&items, f)
|
||||
}
|
||||
|
||||
// IncomeLeaderboard 收益榜单
|
||||
func IncomeLeaderboard(bind interface{}, filter bson.M, limit int) error {
|
||||
pip := []bson.M{
|
||||
{"$match": filter},
|
||||
{"$group": bson.M{"_id": "$uid", "income": bson.M{"$sum": "$actualAmount"}}},
|
||||
{"$sort": bson.M{"income": -1}},
|
||||
{"$limit": limit},
|
||||
}
|
||||
if err := coll(nil).Aggregate(bind, pip); err != nil {
|
||||
log.Info(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "IncomeLeaderboard", table, "Aggregate", err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindByCond 根据条件查询
|
||||
func FindByCond(filter primitive.M) (TransactionLog, error) {
|
||||
opt := options.FindOneOptions{
|
||||
Sort: bson.D{{Key: "createdAt", Value: -1}},
|
||||
}
|
||||
var data TransactionLog
|
||||
if err := coll(nil).FindOne(&data, filter, &opt); err != nil {
|
||||
log.Warn(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "LastTime", table, "FindByCond", err),
|
||||
log.Any("filter", filter),
|
||||
)
|
||||
return data, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// CheckRepurchaseByTransTypes 判断是否购买过,返回yes/no
|
||||
func CheckRepurchaseByTransTypes(uid uint64, types []TransType) (isRepurchase string, err error) {
|
||||
if len(types) == 0 {
|
||||
return "no", nil
|
||||
}
|
||||
has, err := coll(nil).Exists(bson.M{"uid": uid, "tranTypeInt": bson.M{"$in": types}})
|
||||
if err != nil {
|
||||
log.Error(fmt.Sprintf("[METHOD-%s]==> Model %s %s fail error:%+v:", "CheckRepurchaseByTransTypes", table, "Exists", err),
|
||||
log.Any("uid", uid),
|
||||
log.Any("types", types),
|
||||
)
|
||||
return "no", err
|
||||
}
|
||||
if has {
|
||||
return "yes", nil
|
||||
}
|
||||
return "no", nil
|
||||
}
|
||||
@@ -0,0 +1,462 @@
|
||||
package txnmod
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"91porn-server/common/db"
|
||||
"91porn-server/models/commod"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
var tranMap = map[TransType]string{
|
||||
AiGirlfriendTransferIn: "AI女友上分",
|
||||
AiGirlfriendTransferOut: "AI女友下分",
|
||||
Rchg: "充值",
|
||||
PayVID: "购买视频",
|
||||
WithdrawTransfer: "提现转账",
|
||||
PayVIP: "VIP购买",
|
||||
WithdrawRefund: "提现失败退款",
|
||||
WorksIncome: "作品收益",
|
||||
ActIncome: "活动收益",
|
||||
ProxyIncome: "代理收益",
|
||||
AdminCreaditAmount: "官方增加金币",
|
||||
AdminDebitAmount: "官方减去金币",
|
||||
NengModel: "购买嫩模",
|
||||
OfficialRech: "官方充值",
|
||||
MeetingCard: "购买约会卡",
|
||||
GameCoin: "购买游戏币",
|
||||
ChaseScore: "官方追分",
|
||||
RewardIncome: "打赏收益",
|
||||
PayReward: "打赏",
|
||||
CoinMonthCard: "金币月卡",
|
||||
Other: "购买特殊卡",
|
||||
LouFeng: "购买楼凤",
|
||||
AudioBook: "购买有声小说",
|
||||
LouFengRefund: "楼凤退款",
|
||||
LouFengDiscount: "楼凤优惠卡",
|
||||
GameRewards: "游戏奖励",
|
||||
VipCardGive: "购买会员卡赠送金币",
|
||||
LouFengMianFei: "楼凤全免卡",
|
||||
LuckyDraw: "幸运抽奖",
|
||||
PayAvVID: "购买AV解说视频",
|
||||
AvCommentVideoIncome: "AV解说视频收益",
|
||||
TranType_WLSysGive: "棋牌游戏活动赠送",
|
||||
VipCardGiveGameCoin: "购买会员卡赠送游戏金币",
|
||||
WaLiProxyIncome: "瓦力推广收益",
|
||||
AppStoreRewardIncome: "应用中心下载奖励",
|
||||
SignBoon: "签到福利",
|
||||
JewelBoxBoon: "宝箱福利",
|
||||
LouFengConsumerRebate: "消费返利(楼凤)",
|
||||
ChessRechargePolite: "充值有礼(棋牌)",
|
||||
JiuGongGeDraw: "九宫格抽奖",
|
||||
NudeChatConsumption: "裸聊消费",
|
||||
FruitCoinRecharge: "果币充值",
|
||||
BuyNudeChatService: "购买裸聊服务",
|
||||
NudeChatIncome: "裸聊收益",
|
||||
CurrencyGive: "货币赠送",
|
||||
BuyVIP: "充值购买会员卡",
|
||||
NudeChatRefund: "裸聊退款",
|
||||
AdminCreditFruitCoin: "官方增加果币",
|
||||
AdminDebitFruitCoin: "官方减去果币",
|
||||
VideoDiscount: "视频折扣卡",
|
||||
GoldCouplePayVID: "金币抵用券购买视频",
|
||||
VideoFreeCard: "视频免费卡",
|
||||
Active2023Cost: "2023春节活动消耗金币",
|
||||
Active2023Reward: "2023春节抽奖活动获得金币",
|
||||
Active2023VIP: "2023春节抽奖活动获得VIP卡",
|
||||
RaffleDeduction: "抽奖扣款记录",
|
||||
PrizeRecord: "抽奖记录",
|
||||
DailyTaskAdsClick: "每日广告下载任务",
|
||||
DailyTaskUserInvite: "每日邀请任务",
|
||||
OnceTaskBuyVIP: "新手任务: 购买VIP/金币",
|
||||
OnceTaskBindMobile: "新手任务: 绑定手机",
|
||||
AiUndress: "AI脱衣",
|
||||
AiUndressRefund: "AI脱衣返还次数(后台未通过时返还次数)",
|
||||
AiUndressInc: "AI脱衣新增次数",
|
||||
AiUndressIncBackend: "AI脱衣后台赠送次数",
|
||||
AiUndressDebitGold: "AI脱衣扣款金币记录",
|
||||
AiUndressDebitGoldReturn: "AI脱衣扣款金币记录返还",
|
||||
IntegralExchangeVip: "VIP",
|
||||
DailyComment: "每日评论记录",
|
||||
ReceiveIntegral: "领取积分",
|
||||
GiveDownload: "赠送下载次数",
|
||||
AiChangefaceDebitGold: "AI换脸扣款金币记录",
|
||||
AiChangefaceDebitGoldReturn: "AI换脸扣款金币记录返还",
|
||||
AiChangefaceDebitInComeGold: "AI换脸扣款收益金币记录",
|
||||
AiChangefaceDebitIncomeGoldReturn: "AI换脸扣款收益金币记录返还",
|
||||
SendMsgDebitIncomeGold: "用户发送私信扣除收益金币",
|
||||
SendMsgDebitIncomeGoldReturn: "用户发送私信收益金币返还",
|
||||
SendMsgDebitAmountGold: "用户发送私信扣除金币",
|
||||
SendMsgDebitAmountGoldReturn: "用户发送私信扣除金币返还",
|
||||
AdminAddAiUndressFreeTimes: "官方增加AI脱衣免费次数",
|
||||
AdminDebitAiUndressFreeTimes: "官方减去AI脱衣免费次数",
|
||||
AiChangeFaceImgDebitGold: "AI图片换脸金币扣款记录",
|
||||
AiChangeFaceImgReturnGold: "AI图片换脸金币返还",
|
||||
AiUndressDebitFreeTimes: "AI脱衣扣款免费次数记录",
|
||||
AiUndressDebitFreeTimesReturn: "AI脱衣免费次数返回",
|
||||
AiUndressDebitIncomeGold: "AI脱衣扣款收益金币记录",
|
||||
AiUndressDebitIncomeGoldReturn: "AI脱衣收益金币返还",
|
||||
AiChangeFaceImgDebitIncomeGold: "AI图片换脸收益金币扣款记录",
|
||||
AiChangeFaceImgReturnIncomeGold: "AI图片换脸收益金币返还",
|
||||
AiChangeFaceImgDebitFreeTimes: "AI图片换脸免费次数扣款记录",
|
||||
AiChangeFaceImgDebitFreeTimesReturn: "AI图片换脸免费次数返回",
|
||||
VipCardGiveAiUndressFreeCount: "购买会员卡赠送AI脱衣免费次数",
|
||||
AdminAddVIP: "官方新增VIP",
|
||||
AdminAddDownloadCount: "官方增加下载次数",
|
||||
AdminDebitDownloadCount: "官方扣除加下载次数",
|
||||
BuyAdvanceVIP: "充值购买预售卡",
|
||||
BuyBalanceVIP: "充值购买预售尾卡",
|
||||
BuyGameAdvanceVIP: "充值购买游戏预售卡",
|
||||
AdminAddLotteryTimesCount: "官方增加抽奖次数",
|
||||
AdminDebitLotteryTimesCount: "官方扣除加抽奖次数",
|
||||
GiveLotteryTimesCount: "充值赠送抽奖次数",
|
||||
IntegralExchangeInKind: "实物",
|
||||
IntegralExchangeAICount: "AI黑科技券",
|
||||
IntegralExchangeFreeCount: "幸运抽奖次数",
|
||||
IntegralExchangeGoldCoinBonus: "金币加赠券",
|
||||
IntegralExchangeGoldWatch: "金币观影券",
|
||||
GodCommentAward: "神评奖励",
|
||||
BuyWhoringCard: "购买白嫖卡",
|
||||
ReSignDebitAmount: "补签打卡扣除金币",
|
||||
SuccessSignReturnAmount: "完成打卡返回金币",
|
||||
AiImageToVideoDebitGold: "AI图生视频金币扣款记录",
|
||||
AiImageToVideoDebitGoldReturn: "AI图生视频金币返还",
|
||||
AiImageToVideoDebitInComeGold: "AI图生视频收益金币扣款记录",
|
||||
AiImageToVideoDebitIncomeGoldReturn: "AI图生视频收益金币返还",
|
||||
AiTextToImageDebitGold: "AI绘图金币扣款记录",
|
||||
AiTextToImageDebitGoldReturn: "AI绘图金币返还",
|
||||
AiTextToImageDebitInComeGold: "AI绘图收益金币扣款记录",
|
||||
AiTextToImageDebitIncomeGoldReturn: "AI绘图收益金币返还",
|
||||
AiMateChat: "AI女友聊天花费积分",
|
||||
AiMateCurrencyExchange: "AI伴侣货币兑换",
|
||||
AdminAiMateSet: "官方设置AI伴侣货币值",
|
||||
AiTextToNovelDebitGold: "AI小说金币扣款记录",
|
||||
AiTextToNovelDebitGoldReturn: "AI小说金币返还",
|
||||
AiTextToNovelDebitInComeGold: "AI小说收益金币扣款记录",
|
||||
AiTextToNovelDebitIncomeGoldReturn: "AI小说收益金币返还",
|
||||
AdminCreaditIntegral: "官方增加积分",
|
||||
AdminDebitIntegral: "官方减去积分",
|
||||
|
||||
StoreBuyGoods: "商城购买普通商品",
|
||||
StoreBuyNudeChat: "商城购买裸聊",
|
||||
StorePublishWish: "商城发布许愿单",
|
||||
StoreGoodsOrderRefund: "商城普通商品订单退款",
|
||||
StoreNudeChatOrderRefund: "商城裸聊订单退款",
|
||||
StoreWishRefund: "商城许愿单退款",
|
||||
StoreWishEdit: "商城许愿单修改价格扣款",
|
||||
BuyAcg: "购买ACG动漫",
|
||||
JoinGroup: "加入群组",
|
||||
BuyNakedChat: "购买裸聊",
|
||||
|
||||
OrderRefund: "官方充值订单退款",
|
||||
OrderRefundVip: "官方充值VIP订单退款",
|
||||
RefundVipCardGive: "官方充值VIP赠送金币退款",
|
||||
|
||||
ActivityRewardGold: "活动发放金币",
|
||||
ActivityRewardVIP: "活动发放VIP",
|
||||
ActivityRewardGoldBonusCoupon: "活动发放金币加赠券",
|
||||
ActivityRewardGoldVideoCoupon: "活动发放金币观影券",
|
||||
ActivityRewardAiChangeFaceFree: "活动发放AI换脸免费次数",
|
||||
ActivityRewardAiUndressFree: "活动发放AI脱衣免费次数",
|
||||
ActivityRewardIntegral: "活动发放积分",
|
||||
ActivityRewardPhysical: "活动发放实物奖品",
|
||||
ActivityDeductGold: "活动扣除金币",
|
||||
ActivityDeductIntegral: "活动扣除积分",
|
||||
ActivityDeductLotteryTimes: "活动扣除抽奖免费次数",
|
||||
}
|
||||
|
||||
// TranType2ProductType 交易类型到产品类型映射
|
||||
var TranType2ProductType = map[TransType]commod.ProductType{
|
||||
PayVIP: commod.VIP,
|
||||
MeetingCard: commod.MeetingCard,
|
||||
Other: commod.OTHER,
|
||||
BuyVIP: commod.VIP,
|
||||
VideoDiscount: commod.VideoDiscount,
|
||||
VideoFreeCard: commod.VideoFreeCard,
|
||||
}
|
||||
|
||||
const (
|
||||
Rchg TransType = iota + 1 // 充值
|
||||
PayVID TransType = 2 // 购买视频
|
||||
WithdrawTransfer TransType = 3 // 提现转账
|
||||
PayVIP TransType = 4 // VIP购买(金币)
|
||||
WithdrawRefund TransType = 5 // 提现失败退款
|
||||
WorksIncome TransType = 6 // 作品收益
|
||||
ActIncome TransType = 7 // 活动收益
|
||||
ProxyIncome TransType = 8 // 代理收益
|
||||
AdminCreaditAmount TransType = 9 // 官方增加金币
|
||||
AdminDebitAmount TransType = 10 // 官方减去金币
|
||||
NengModel TransType = 11 // 购买嫩模 弃用
|
||||
OfficialRech TransType = 12 // 官方充值
|
||||
MeetingCard TransType = 13 // 购买约会卡
|
||||
GameCoin TransType = 14 // 购买游戏币
|
||||
ChaseScore TransType = 15 // 从用户处追分,扣减用户金币
|
||||
RewardIncome TransType = 16 // 打赏收益
|
||||
PayReward TransType = 17 // 打赏
|
||||
CoinMonthCard TransType = 18 // 金币月卡
|
||||
Other TransType = 20 // 购买约会卡
|
||||
LouFeng TransType = 21 // 购买楼凤联系方式
|
||||
AudioBook TransType = 22 // 购买有声小说
|
||||
LouFengRefund TransType = 23 // 楼凤退款(包含预约)
|
||||
LouFengDiscount TransType = 24 // 楼凤优惠卡
|
||||
GameRewards TransType = 25 // 游戏奖励
|
||||
VipCardGive TransType = 26 // 购买会员卡赠送金币
|
||||
LouFengMianFei TransType = 27 // 楼凤全免卡
|
||||
LuckyDraw TransType = 28 // 幸运抽奖
|
||||
PayAvVID TransType = 36 // 购买AV解说视频
|
||||
AvCommentVideoIncome TransType = 37 // AV解说视频收益
|
||||
TranType_WLSysGive TransType = 38 // 棋牌游戏活动赠送金币
|
||||
VipCardGiveGameCoin TransType = 39 // 购买会员卡赠送棋牌金币
|
||||
WaLiProxyIncome TransType = 40 // 瓦力代理收益
|
||||
AppStoreRewardIncome TransType = 41 // 应用中心下载奖励
|
||||
SignBoon TransType = 42 // 签到福利
|
||||
JewelBoxBoon TransType = 43 // 宝箱福利
|
||||
LouFengConsumerRebate TransType = 44 // 消费返利(楼凤)
|
||||
ChessRechargePolite TransType = 45 // 充值有礼(棋牌)
|
||||
JiuGongGeDraw TransType = 46 // 九宫格抽奖
|
||||
NudeChatConsumption TransType = 47 // 裸聊消费
|
||||
FruitCoinRecharge TransType = 48 // 果币充值
|
||||
BuyNudeChatService TransType = 49 // 购买裸聊服务
|
||||
NudeChatIncome TransType = 50 // 裸聊收益
|
||||
CurrencyGive TransType = 51 // 货币赠送
|
||||
BuyVIP TransType = 52 // 充值购买会员卡
|
||||
NudeChatRefund TransType = 53 // 裸聊退款
|
||||
AdminCreditFruitCoin TransType = 54 // 官方增加果币
|
||||
AdminDebitFruitCoin TransType = 55 // 官方减去果币
|
||||
VideoDiscount TransType = 56 // 视频折扣卡
|
||||
VideoFreeCard TransType = 57 // 视频免费卡
|
||||
GoldCouplePayVID TransType = 58 // 金币抵用券购买视频
|
||||
BookLoufeng TransType = 59 // 预约
|
||||
Active2023Cost TransType = 61 // 2023春节活动抽奖扣除金币
|
||||
Active2023Reward TransType = 62 // 2023春节活动获得金币
|
||||
Active2023VIP TransType = 63 // 2023新春抽奖获得VIP卡
|
||||
RaffleDeduction TransType = 64 //抽奖扣款记录
|
||||
PrizeRecord TransType = 65 //抽奖记录
|
||||
AiUndressDebitGoldReturn TransType = 66 // AI脱衣金币返回
|
||||
DailyTaskAdsClick TransType = 70 // 每日活动: 下载广告app
|
||||
DailyTaskUserInvite TransType = 71 // 每日活动: 用户邀请
|
||||
OnceTaskBuyVIP TransType = 80 // 一次性任务: 购买VIP
|
||||
OnceTaskBindMobile TransType = 81 // 一次性任务: 绑定手机号
|
||||
AiUndress TransType = 82 // AI脱衣
|
||||
AiUndressRefund TransType = 83 // AI脱衣返还次数(后台未通过时返还次数)
|
||||
AiUndressInc TransType = 84 // AI脱衣新增次数
|
||||
AiUndressIncBackend TransType = 85 // AI脱衣后台赠送
|
||||
AiUndressDebitGold TransType = 86 // AI脱衣金币扣款记录
|
||||
IntegralExchangeVip TransType = 87 // 积分兑换VIP
|
||||
DailyComment TransType = 88 // 每日评论记录
|
||||
ReceiveIntegral TransType = 89 // 领取积分
|
||||
GiveDownload TransType = 90 // 赠送下载次数
|
||||
AiChangefaceDebitGold TransType = 91 // AI换脸金币扣款记录
|
||||
AiChangefaceDebitGoldReturn TransType = 92 // AI换脸金币返还
|
||||
AiChangefaceDebitInComeGold TransType = 93 // AI换脸收益金币扣款记录
|
||||
AiChangefaceDebitIncomeGoldReturn TransType = 94 // AI换脸收益金币返还
|
||||
SendMsgDebitIncomeGold TransType = 95 // 用户发送私信扣除收益金币
|
||||
SendMsgDebitIncomeGoldReturn TransType = 96 // 用户发送私信收益金币返还
|
||||
SendMsgDebitAmountGold TransType = 97 // 用户发送私信扣除金币
|
||||
SendMsgDebitAmountGoldReturn TransType = 98 // 用户发送私信扣除金币返还
|
||||
AdminAddAiUndressFreeTimes TransType = 99 // 官方增加AI脱衣免费次数
|
||||
AdminDebitAiUndressFreeTimes TransType = 100 // 官方减去AI脱衣免费次数
|
||||
AiChangeFaceImgDebitGold TransType = 101 // AI图片换脸金币扣款记录
|
||||
AiChangeFaceImgReturnGold TransType = 102 // AI图片换脸金币返还
|
||||
AiUndressDebitFreeTimes TransType = 103 // AI脱衣免费次数扣款记录
|
||||
AiUndressDebitFreeTimesReturn TransType = 104 // AI脱衣免费次数返回
|
||||
AiUndressDebitIncomeGold TransType = 105 // AI脱衣收益金币扣款记录
|
||||
AiUndressDebitIncomeGoldReturn TransType = 106 // AI脱衣收益金币返回
|
||||
AiChangeFaceImgDebitIncomeGold TransType = 107 // AI图片换脸收益金币扣款记录
|
||||
AiChangeFaceImgReturnIncomeGold TransType = 108 // AI图片换脸收益金币返还
|
||||
AiChangeFaceImgDebitFreeTimes TransType = 109 // AI图片换脸免费次数扣款记录
|
||||
AiChangeFaceImgDebitFreeTimesReturn TransType = 110 // AI图片换脸免费次数返回
|
||||
VipCardGiveAiUndressFreeCount TransType = 111 // 购买会员卡赠送AI脱衣免费次数
|
||||
AdminAddVIP TransType = 112 // 官方新增VIP
|
||||
AdminAddDownloadCount TransType = 113 // 官方增加下载次数
|
||||
AdminDebitDownloadCount TransType = 114 // 官方扣除加下载次数
|
||||
BuyAdvanceVIP TransType = 115 // 充值购买预售卡
|
||||
BuyBalanceVIP TransType = 117 // 充值购买预售尾卡
|
||||
BuyGameAdvanceVIP TransType = 116 // 充值购买游戏预售卡
|
||||
AdminAddLotteryTimesCount TransType = 120 // 官方增加抽奖次数
|
||||
AdminDebitLotteryTimesCount TransType = 121 // 官方扣除加抽奖次数
|
||||
GiveLotteryTimesCount TransType = 122 // 赠送抽奖次数
|
||||
BuyWhoringCard TransType = 123 // 充值购买白嫖卡
|
||||
ReSignDebitAmount TransType = 124 // 补签打卡扣除金币
|
||||
SuccessSignReturnAmount TransType = 125 // 完成打卡返回金币
|
||||
IntegralExchangeInKind TransType = 126 // 积分兑换实物
|
||||
IntegralExchangeAICount TransType = 127 // 积分兑换AI黑科技券
|
||||
IntegralExchangeFreeCount TransType = 128 // 积分兑换幸运抽奖次数
|
||||
IntegralExchangeGoldCoinBonus TransType = 129 // 积分兑换金币加赠券
|
||||
IntegralExchangeGoldWatch TransType = 130 // 积分兑换金币观影券
|
||||
GodCommentAward TransType = 131 // 神评奖励
|
||||
OnceTaskTypeUserBuyCoin TransType = 132 // 一次性任务: 购买金币
|
||||
|
||||
AiMateCurrencyExchange TransType = 137 // AI伴侣货币兑换
|
||||
AiMateChat TransType = 138 // AI女友聊天花费积分
|
||||
AdminAiMateSet TransType = 139 // 官方设置AI伴侣货币值
|
||||
AdminCreaditIntegral TransType = 143 // 官方增加积分
|
||||
AdminDebitIntegral TransType = 144 // 官方减去积分
|
||||
AiImageToVideoDebitGold TransType = 202 // AI图生视频金币扣款记录
|
||||
AiImageToVideoDebitGoldReturn TransType = 203 // AI图生视频金币返还
|
||||
AiImageToVideoDebitInComeGold TransType = 204 // AI图生视频收益金币扣款记录
|
||||
AiImageToVideoDebitIncomeGoldReturn TransType = 205 // AI图生视频收益金币返还
|
||||
AiTextToImageDebitGold TransType = 206 // AI绘图金币扣款记录
|
||||
AiTextToImageDebitGoldReturn TransType = 207 // AI绘图金币返还
|
||||
AiTextToImageDebitInComeGold TransType = 208 // AI绘图收益金币扣款记录
|
||||
AiTextToImageDebitIncomeGoldReturn TransType = 209 // AI绘图收益金币返还
|
||||
AiTextToNovelDebitGold TransType = 210 // AI小说金币扣款记录
|
||||
AiTextToNovelDebitGoldReturn TransType = 211 // AI小说金币返还
|
||||
AiTextToNovelDebitInComeGold TransType = 212 // AI小说收益金币扣款记录
|
||||
AiTextToNovelDebitIncomeGoldReturn TransType = 213 // AI小说收益金币返还
|
||||
|
||||
BuyAcg TransType = 166 // 购买acg动漫
|
||||
|
||||
OrderRefund TransType = 301 // 官方充值退款
|
||||
OrderRefundVip TransType = 302 // 官方充值VIP退款
|
||||
RefundVipCardGive TransType = 303 // 官方充值VIP赠送金币退款
|
||||
|
||||
StoreBuyGoods TransType = 10001 // 商城购买普通商品
|
||||
StoreBuyNudeChat TransType = 10002 // 商城购买裸聊
|
||||
StorePublishWish TransType = 10003 // 商城发布许愿单
|
||||
StoreGoodsOrderRefund TransType = 10004 // 商城普通商品订单退款
|
||||
StoreNudeChatOrderRefund TransType = 10005 // 商城裸聊订单退款
|
||||
StoreWishRefund TransType = 10006 // 商城许愿单退款
|
||||
StoreWishEdit TransType = 10007 // 商城许愿单修改价格扣款
|
||||
|
||||
JoinGroup TransType = 10101 // 加入群组
|
||||
BuyNakedChat TransType = 10201 // 购买裸聊
|
||||
|
||||
ActivityRewardGold TransType = 20001 // 活动发放金币
|
||||
ActivityRewardVIP TransType = 20002 // 活动发放VIP
|
||||
ActivityRewardGoldBonusCoupon TransType = 20003 // 活动发放金币加赠券
|
||||
ActivityRewardGoldVideoCoupon TransType = 20004 // 活动发放金币观影券
|
||||
ActivityRewardAiChangeFaceFree TransType = 20005 // 活动发放AI换脸免费次数
|
||||
ActivityRewardAiUndressFree TransType = 20006 // 活动发放AI脱衣免费次数
|
||||
ActivityRewardIntegral TransType = 20007 // 活动发放积分
|
||||
ActivityRewardPhysical TransType = 20008 // 活动发放实物奖品
|
||||
ActivityDeductGold TransType = 20101 // 活动扣除金币
|
||||
ActivityDeductIntegral TransType = 20102 // 活动扣除积分
|
||||
ActivityDeductLotteryTimes TransType = 20103 // 活动扣除抽奖免费次数
|
||||
)
|
||||
|
||||
const (
|
||||
CurrencyTypeGold = iota //金币
|
||||
CurrencyTypeCash //现金
|
||||
)
|
||||
|
||||
const (
|
||||
AiGirlfriendTransferIn TransType = 145
|
||||
AiGirlfriendTransferOut TransType = 146
|
||||
)
|
||||
|
||||
type TransType int64
|
||||
|
||||
func (t TransType) Key() string {
|
||||
if key, ok := tranMap[t]; ok {
|
||||
return key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type M = bson.M
|
||||
|
||||
type DiscDoc = commod.DiscDoc
|
||||
|
||||
// TransactionLog 账户交易流水表,
|
||||
type TransactionLog struct {
|
||||
//流水id
|
||||
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
|
||||
//出金方 UID
|
||||
UID uint64 `json:"uid" bson:"uid"`
|
||||
//交易订单号
|
||||
TransNo primitive.ObjectID `json:"purchaseOrder" bson:"purchaseOrder"`
|
||||
//产品id 传购买某些物品或者卖出某些物品的id
|
||||
ProductID *string `json:"productID" bson:"productID,omitempty"`
|
||||
//金币
|
||||
Amount int64 `json:"amount" bson:"amount"`
|
||||
//积分
|
||||
Integral int64 `json:"integral" bson:"integral"`
|
||||
//用户实时余额
|
||||
RealIntegral decimal.Decimal `json:"realIntegral" bson:"realIntegral"`
|
||||
//实际收入/支出的积分
|
||||
ActualIntegral float64 `json:"actualIntegral" bson:"actualIntegral"`
|
||||
//实际收入/支出的金币
|
||||
ActualAmount float64 `json:"actualAmount" bson:"actualAmount"`
|
||||
//税率
|
||||
Tax int64 `json:"tax" bson:"tax"`
|
||||
//系统收取的税额 税率*定价
|
||||
TaxAmount float64 `json:"taxAmount" bson:"taxAmount"`
|
||||
//充值/提现渠道类型
|
||||
ChannelType string `json:"channelType" bson:"channelType"`
|
||||
//交易类型
|
||||
TranType string `json:"tranType" bson:"tranType"`
|
||||
//交易类型的数字值
|
||||
TranTypeInt int64 `json:"tranTypeInt" bson:"tranTypeInt"`
|
||||
//推广绩效
|
||||
Performance int64 `form:"performance" json:"performance" bson:"performance"`
|
||||
//充值用户
|
||||
RechargeId uint64 `form:"rechargeId" json:"rechargeId" bson:"rechargeId"`
|
||||
RechargeUser RechargeUserInfo `json:"rechargeUser" bson:"rechargeUser"` // 购买用户信息
|
||||
//记录描述
|
||||
Desc string `json:"desc" bson:"desc"`
|
||||
//创建时间
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
|
||||
//设备系统类型 ios pc android
|
||||
SysType string `json:"sysType" bson:"sysType"`
|
||||
//代理等级
|
||||
AgentLevel int `form:"agentLevel" json:"agentLevel" bson:"agentLevel"`
|
||||
//会员等级
|
||||
VipLevel int `json:"vipLevel" bson:"vipLevel"`
|
||||
//用户实时余额
|
||||
RealAmount decimal.Decimal `json:"realAmount" bson:"realAmount"`
|
||||
//棋牌充值/提现的金额 单位元
|
||||
Money decimal.Decimal `json:"money" bson:"money"`
|
||||
//用户瓦力棋牌游戏实时余额
|
||||
WaLIRealAmount decimal.Decimal `json:"wlRealAmount" bson:"wlRealAmount"`
|
||||
//唯一订单号
|
||||
UniqueOrder string `json:"uniqueOrder,omitempty" bson:"uniqueOrder,omitempty"`
|
||||
//交易类型(0 金币 1 现金)
|
||||
CurrencyType int `json:"currencyType,omitempty" bson:"currencyType,omitempty"`
|
||||
//果币
|
||||
FruitCoin int64 `json:"fruitCoin" bson:"fruitCoin,omitempty"`
|
||||
//下载次数
|
||||
DownloadCount int64 `json:"downloadCount" bson:"downloadCount,omitempty"`
|
||||
//抽奖次数
|
||||
LotteryTimes int64 `json:"lotteryTimes" bson:"lotteryTimes,omitempty"`
|
||||
//果币余额
|
||||
FruitCoinBalance int64 `json:"fruitCoinBalance" bson:"fruitCoinBalance,omitempty"`
|
||||
AiMatePoint float64 `json:"aiMatePoint" bson:"aiMatePoint,omitempty"` // AI女友积分
|
||||
RealAiMatePoint float64 `json:"realAiMatePoint" bson:"realAiMatePoint,omitempty"` // 剩余AI女友积分
|
||||
IsRepurchase string `json:"isRepurchase" bson:"isRepurchase"` // 是否复购,yes、no
|
||||
DiscDoc `bson:",inline"`
|
||||
}
|
||||
|
||||
type RechargeUserInfo struct {
|
||||
UID uint64 `json:"uid" bson:"uid"` // 用户ID
|
||||
Name string `json:"name" bson:"name"` // 用户姓名
|
||||
Portrait string `json:"portrait" bson:"portrait"` // 用户头像
|
||||
}
|
||||
|
||||
type AgentIncomeRes struct {
|
||||
AgentLevel int `bson:"_id"`
|
||||
TotalMoney float64 `bson:"totalAmount"`
|
||||
TotalPerformance int64 `bson:"totalPerformance"`
|
||||
}
|
||||
|
||||
type LoufengTemp struct {
|
||||
ProductID string `json:"productID" bson:"productID,omitempty"` //产品id 传购买某些物品或者卖出某些物品的id
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` //创建时间
|
||||
|
||||
}
|
||||
|
||||
type TransactionR struct {
|
||||
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"` //流水id
|
||||
ActualAmount float64 `json:"actualAmount" bson:"actualAmount"` //实际收入/支出的金币
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` //创建时间
|
||||
}
|
||||
|
||||
var mdb *db.MongoDB
|
||||
|
||||
func Init() {
|
||||
mdb = db.Init(table)
|
||||
initIndex()
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package txnmod
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"91porn-server/models/commod"
|
||||
)
|
||||
|
||||
// CoinLogReq 金币流水请求
|
||||
type CoinLogReq struct {
|
||||
UID uint64 `form:"uid" json:"uid"`
|
||||
Balance int `form:"balance" json:"balance"` //0所有 1收入 2支出
|
||||
TranType string `form:"tranType" json:"tranType"`
|
||||
DistrictCode string `form:"districtCode" json:"districtCode"`
|
||||
Start time.Time `form:"start" json:"start"`
|
||||
End time.Time `form:"end" json:"end"`
|
||||
commod.Page
|
||||
}
|
||||
|
||||
// CoinLogResp 金币流水返回
|
||||
type CoinLogResp struct {
|
||||
Logs []*TransactionLog `json:"logs"`
|
||||
Total int64 `json:"total"`
|
||||
}
|
||||
|
||||
// TransactionQueryReq 账户交易流水表,
|
||||
type TransactionQueryReq struct {
|
||||
ID *string `json:"id,omitempty" bson:"_id,omitempty"` //流水id
|
||||
UID *uint64 ` json:"uid,omitempty" bson:"uid,omitempty"` //出金方 UID
|
||||
TransNo *string ` json:"transNo,omitempty" bson:"transNo,omitempty"` //交易订单号
|
||||
Amount *int64 ` json:"amount,omitempty" bson:"amount,omitempty"` //金币
|
||||
TransType *string ` json:"transType,omitempty" bson:"transType,omitempty"` //交易类型
|
||||
Desc *string ` json:"desc,omitempty" bson:"desc,omitempty"` //记录描述
|
||||
}
|
||||
|
||||
type BillsRes struct {
|
||||
Month string `json:"month"`
|
||||
Income int64 `json:"income"`
|
||||
Withdraw int64 `json:"withdraw"`
|
||||
IncomeStr string `json:"incomeStr"` //收益
|
||||
WithdrawStr string `json:"withdrawStr"` //提现
|
||||
List []*TransactionLog `json:"list"`
|
||||
}
|
||||
|
||||
type Bills1Res struct {
|
||||
//收益
|
||||
Income string `json:"income"`
|
||||
//支出
|
||||
Expenditure string `json:"expenditure"`
|
||||
HasNext bool `json:"hasNext"`
|
||||
//列表
|
||||
List []TransactionLog `json:"list"`
|
||||
//当前焦点月之前是否有数据
|
||||
HasNextMonth bool `json:"haxNextMonth"`
|
||||
//当前焦点月有数据的最迟月份
|
||||
Month int `json:"month"`
|
||||
//当前焦点月有数据的最迟月份的年
|
||||
Year int `json:"year"`
|
||||
}
|
||||
Reference in New Issue
Block a user