diff --git a/internal/db/models/accounts/user_account_daily_stat_dao.go b/internal/db/models/accounts/user_account_daily_stat_dao.go deleted file mode 100644 index 311cb9f7..00000000 --- a/internal/db/models/accounts/user_account_daily_stat_dao.go +++ /dev/null @@ -1,80 +0,0 @@ -package accounts - -import ( - "github.com/TeaOSLab/EdgeCommon/pkg/userconfigs" - _ "github.com/go-sql-driver/mysql" - "github.com/iwind/TeaGo/Tea" - "github.com/iwind/TeaGo/dbs" - "github.com/iwind/TeaGo/maps" - timeutil "github.com/iwind/TeaGo/utils/time" -) - -type UserAccountDailyStatDAO dbs.DAO - -func NewUserAccountDailyStatDAO() *UserAccountDailyStatDAO { - return dbs.NewDAO(&UserAccountDailyStatDAO{ - DAOObject: dbs.DAOObject{ - DB: Tea.Env, - Table: "edgeUserAccountDailyStats", - Model: new(UserAccountDailyStat), - PkName: "id", - }, - }).(*UserAccountDailyStatDAO) -} - -var SharedUserAccountDailyStatDAO *UserAccountDailyStatDAO - -func init() { - dbs.OnReady(func() { - SharedUserAccountDailyStatDAO = NewUserAccountDailyStatDAO() - }) -} - -// UpdateDailyStat 更新当天统计数据 -func (this *UserAccountDailyStatDAO) UpdateDailyStat(tx *dbs.Tx) error { - var day = timeutil.Format("Ymd") - var month = timeutil.Format("Ym") - income, err := SharedUserAccountLogDAO.SumDailyEventTypes(tx, day, userconfigs.AccountIncomeEventTypes) - if err != nil { - return err - } - - expense, err := SharedUserAccountLogDAO.SumDailyEventTypes(tx, day, userconfigs.AccountExpenseEventTypes) - if err != nil { - return err - } - if expense < 0 { - expense = -expense - } - - return this.Query(tx). - InsertOrUpdateQuickly(maps.Map{ - "day": day, - "month": month, - "income": income, - "expense": expense, - }, maps.Map{ - "income": income, - "expense": expense, - }) -} - -// FindDailyStats 查看按天统计 -func (this *UserAccountDailyStatDAO) FindDailyStats(tx *dbs.Tx, dayFrom string, dayTo string) (result []*UserAccountDailyStat, err error) { - _, err = this.Query(tx). - Between("day", dayFrom, dayTo). - Slice(&result). - FindAll() - return -} - -// FindMonthlyStats 查看某月统计 -func (this *UserAccountDailyStatDAO) FindMonthlyStats(tx *dbs.Tx, dayFrom string, dayTo string) (result []*UserAccountDailyStat, err error) { - _, err = this.Query(tx). - Result("SUM(income) AS income", "SUM(expense) AS expense", "month"). - Between("day", dayFrom, dayTo). - Group("month"). - Slice(&result). - FindAll() - return -} diff --git a/internal/db/models/accounts/user_account_daily_stat_dao_test.go b/internal/db/models/accounts/user_account_daily_stat_dao_test.go deleted file mode 100644 index 76141d0c..00000000 --- a/internal/db/models/accounts/user_account_daily_stat_dao_test.go +++ /dev/null @@ -1,6 +0,0 @@ -package accounts - -import ( - _ "github.com/go-sql-driver/mysql" - _ "github.com/iwind/TeaGo/bootstrap" -) diff --git a/internal/db/models/accounts/user_account_dao.go b/internal/db/models/accounts/user_account_dao.go deleted file mode 100644 index 7124b689..00000000 --- a/internal/db/models/accounts/user_account_dao.go +++ /dev/null @@ -1,253 +0,0 @@ -package accounts - -import ( - "github.com/TeaOSLab/EdgeAPI/internal/db/models" - "github.com/TeaOSLab/EdgeAPI/internal/errors" - "github.com/TeaOSLab/EdgeAPI/internal/goman" - "github.com/TeaOSLab/EdgeAPI/internal/remotelogs" - "github.com/TeaOSLab/EdgeCommon/pkg/userconfigs" - _ "github.com/go-sql-driver/mysql" - "github.com/iwind/TeaGo/Tea" - "github.com/iwind/TeaGo/dbs" - "github.com/iwind/TeaGo/lists" - "github.com/iwind/TeaGo/maps" - "github.com/iwind/TeaGo/types" - "time" -) - -func init() { - dbs.OnReadyDone(func() { - goman.New(func() { - // 自动支付账单任务 - var ticker = time.NewTicker(12 * time.Hour) - for range ticker.C { - if SharedUserAccountDAO.Instance != nil { - err := SharedUserAccountDAO.Instance.RunTx(func(tx *dbs.Tx) error { - return SharedUserAccountDAO.PayBills(tx) - }) - if err != nil { - remotelogs.Error("USER_ACCOUNT_DAO", "pay bills task failed: "+err.Error()) - } - } - } - }) - }) -} - -type UserAccountDAO dbs.DAO - -func NewUserAccountDAO() *UserAccountDAO { - return dbs.NewDAO(&UserAccountDAO{ - DAOObject: dbs.DAOObject{ - DB: Tea.Env, - Table: "edgeUserAccounts", - Model: new(UserAccount), - PkName: "id", - }, - }).(*UserAccountDAO) -} - -var SharedUserAccountDAO *UserAccountDAO - -func init() { - dbs.OnReady(func() { - SharedUserAccountDAO = NewUserAccountDAO() - }) -} - -// FindUserAccountWithUserId 根据用户ID查找用户账户 -func (this *UserAccountDAO) FindUserAccountWithUserId(tx *dbs.Tx, userId int64) (*UserAccount, error) { - if userId <= 0 { - return nil, errors.New("invalid userId '" + types.String(userId) + "'") - } - - // 用户是否存在 - user, err := models.SharedUserDAO.FindEnabledUser(tx, userId, nil) - if err != nil { - return nil, err - } - if user == nil { - return nil, errors.New("invalid userId '" + types.String(userId) + "'") - } - - account, err := this.Query(tx). - Attr("userId", userId). - Find() - if err != nil { - return nil, err - } - if account != nil { - return account.(*UserAccount), nil - } - - var op = NewUserAccountOperator() - op.UserId = userId - _, err = this.SaveInt64(tx, op) - if err != nil { - return nil, err - } - return this.FindUserAccountWithUserId(tx, userId) -} - -// FindUserAccountWithAccountId 根据ID查找用户账户 -func (this *UserAccountDAO) FindUserAccountWithAccountId(tx *dbs.Tx, accountId int64) (*UserAccount, error) { - one, err := this.Query(tx). - Pk(accountId). - Find() - if one != nil { - return one.(*UserAccount), nil - } - return nil, err -} - -// UpdateUserAccount 操作用户账户 -func (this *UserAccountDAO) UpdateUserAccount(tx *dbs.Tx, accountId int64, delta float32, eventType userconfigs.AccountEventType, description string, params maps.Map) error { - account, err := this.FindUserAccountWithAccountId(tx, accountId) - if err != nil { - return err - } - if account == nil { - return errors.New("invalid account id '" + types.String(accountId) + "'") - } - var userId = int64(account.UserId) - var deltaFloat64 = float64(delta) - if deltaFloat64 < 0 && account.Total < -deltaFloat64 { - return errors.New("not enough account quota to decrease") - } - - // 操作账户 - err = this.Query(tx). - Pk(account.Id). - Set("total", dbs.SQL("total+:delta")). - Param("delta", delta). - UpdateQuickly() - if err != nil { - return err - } - - // 生成日志 - err = SharedUserAccountLogDAO.CreateAccountLog(tx, userId, accountId, delta, 0, eventType, description, params) - if err != nil { - return err - } - - return nil -} - -// UpdateUserAccountFrozen 操作用户账户冻结余额 -func (this *UserAccountDAO) UpdateUserAccountFrozen(tx *dbs.Tx, userId int64, delta float32, eventType userconfigs.AccountEventType, description string, params maps.Map) error { - account, err := this.FindUserAccountWithUserId(tx, userId) - if err != nil { - return err - } - var deltaFloat64 = float64(delta) - if deltaFloat64 < 0 && account.TotalFrozen < -deltaFloat64 { - return errors.New("not enough account frozen quota to decrease") - } - - // 操作账户 - err = this.Query(tx). - Pk(account.Id). - Set("totalFrozen", dbs.SQL("total+:delta")). - Param("delta", delta). - UpdateQuickly() - if err != nil { - return err - } - - // 生成日志 - err = SharedUserAccountLogDAO.CreateAccountLog(tx, userId, int64(account.Id), 0, delta, eventType, description, params) - if err != nil { - return err - } - - return nil -} - -// CountAllAccounts 计算所有账户数量 -func (this *UserAccountDAO) CountAllAccounts(tx *dbs.Tx, keyword string) (int64, error) { - var query = this.Query(tx) - if len(keyword) > 0 { - query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword))") - query.Param("keyword", keyword) - } else { - query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1)") - } - return query.Count() -} - -// ListAccounts 列出单页账户 -func (this *UserAccountDAO) ListAccounts(tx *dbs.Tx, keyword string, offset int64, size int64) (result []*UserAccount, err error) { - var query = this.Query(tx) - if len(keyword) > 0 { - query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword))") - query.Param("keyword", keyword) - } else { - query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1)") - } - _, err = query. - DescPk(). - Offset(offset). - Limit(size). - Slice(&result). - FindAll() - return -} - -// PayBills 尝试自动支付账单 -func (this *UserAccountDAO) PayBills(tx *dbs.Tx) error { - bills, err := models.SharedUserBillDAO.FindUnpaidBills(tx, 10000) - if err != nil { - return err - } - - // 先支付久远的 - lists.Reverse(bills) - - for _, bill := range bills { - if bill.Amount <= 0 { - err = models.SharedUserBillDAO.UpdateUserBillIsPaid(tx, int64(bill.Id), true) - if err != nil { - return err - } - continue - } - - account, err := SharedUserAccountDAO.FindUserAccountWithUserId(tx, int64(bill.UserId)) - if err != nil { - return err - } - if account == nil || account.Total < bill.Amount { - continue - } - - // 扣款 - err = SharedUserAccountDAO.UpdateUserAccount(tx, int64(account.Id), -float32(bill.Amount), userconfigs.AccountEventTypePayBill, "支付账单"+bill.Code, maps.Map{"billId": bill.Id}) - if err != nil { - return err - } - - // 改为已支付 - err = models.SharedUserBillDAO.UpdateUserBillIsPaid(tx, int64(bill.Id), true) - if err != nil { - return err - } - } - - return nil -} - -// CheckUserAccount 检查用户账户 -func (this *UserAccountDAO) CheckUserAccount(tx *dbs.Tx, userId int64, accountId int64) error { - exists, err := this.Query(tx). - Pk(accountId). - Attr("userId", userId). - Exist() - if err != nil { - return err - } - if !exists { - return models.ErrNotFound - } - return nil -} diff --git a/internal/db/models/accounts/user_account_dao_test.go b/internal/db/models/accounts/user_account_dao_test.go deleted file mode 100644 index f6160c01..00000000 --- a/internal/db/models/accounts/user_account_dao_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package accounts - -import ( - _ "github.com/go-sql-driver/mysql" - _ "github.com/iwind/TeaGo/bootstrap" - "github.com/iwind/TeaGo/dbs" - "testing" -) - -func TestUserAccountDAO_PayBills(t *testing.T) { - dbs.NotifyReady() - - err := NewUserAccountDAO().PayBills(nil) - if err != nil { - t.Fatal(err) - } - t.Log("ok") -} diff --git a/internal/db/models/accounts/user_account_log_dao.go b/internal/db/models/accounts/user_account_log_dao.go deleted file mode 100644 index ef259d7f..00000000 --- a/internal/db/models/accounts/user_account_log_dao.go +++ /dev/null @@ -1,129 +0,0 @@ -package accounts - -import ( - "github.com/TeaOSLab/EdgeAPI/internal/db/models" - dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils" - "github.com/TeaOSLab/EdgeAPI/internal/errors" - "github.com/TeaOSLab/EdgeCommon/pkg/userconfigs" - _ "github.com/go-sql-driver/mysql" - "github.com/iwind/TeaGo/Tea" - "github.com/iwind/TeaGo/dbs" - "github.com/iwind/TeaGo/maps" - "github.com/iwind/TeaGo/types" - timeutil "github.com/iwind/TeaGo/utils/time" -) - -type UserAccountLogDAO dbs.DAO - -func NewUserAccountLogDAO() *UserAccountLogDAO { - return dbs.NewDAO(&UserAccountLogDAO{ - DAOObject: dbs.DAOObject{ - DB: Tea.Env, - Table: "edgeUserAccountLogs", - Model: new(UserAccountLog), - PkName: "id", - }, - }).(*UserAccountLogDAO) -} - -var SharedUserAccountLogDAO *UserAccountLogDAO - -func init() { - dbs.OnReady(func() { - SharedUserAccountLogDAO = NewUserAccountLogDAO() - }) -} - -// CreateAccountLog 生成用户账户日志 -func (this *UserAccountLogDAO) CreateAccountLog(tx *dbs.Tx, userId int64, accountId int64, delta float32, deltaFrozen float32, eventType userconfigs.AccountEventType, description string, params maps.Map) error { - var op = NewUserAccountLogOperator() - op.UserId = userId - op.AccountId = accountId - op.Delta = delta - op.DeltaFrozen = deltaFrozen - - account, err := SharedUserAccountDAO.FindUserAccountWithAccountId(tx, accountId) - if err != nil { - return err - } - if account == nil { - return errors.New("invalid account id '" + types.String(accountId) + "'") - } - op.Total = account.Total - op.TotalFrozen = account.TotalFrozen - - op.EventType = eventType - op.Description = description - - if params == nil { - params = maps.Map{} - } - op.Params = params.AsJSON() - - op.Day = timeutil.Format("Ymd") - err = this.Save(tx, op) - if err != nil { - return err - } - - return SharedUserAccountDailyStatDAO.UpdateDailyStat(tx) -} - -// CountAccountLogs 计算日志数量 -func (this *UserAccountLogDAO) CountAccountLogs(tx *dbs.Tx, userId int64, accountId int64, keyword string, eventType string) (int64, error) { - var query = this.Query(tx) - if userId > 0 { - query.Attr("userId", userId) - } - if accountId > 0 { - query.Attr("accountId", accountId) - } - if len(keyword) > 0 { - query.Where("(userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword)) OR description LIKE :keyword)") - query.Param("keyword", dbutils.QuoteLike(keyword)) - } - if len(eventType) > 0 { - query.Attr("eventType", eventType) - } - return query.Count() -} - -// ListAccountLogs 列出单页日志 -func (this *UserAccountLogDAO) ListAccountLogs(tx *dbs.Tx, userId int64, accountId int64, keyword string, eventType string, offset int64, size int64) (result []*UserAccountLog, err error) { - var query = this.Query(tx) - if userId > 0 { - query.Attr("userId", userId) - } - if accountId > 0 { - query.Attr("accountId", accountId) - } - if len(keyword) > 0 { - query.Where("(userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword)) OR description LIKE :keyword)") - query.Param("keyword", dbutils.QuoteLike(keyword)) - } - if len(eventType) > 0 { - query.Attr("eventType", eventType) - } - _, err = query. - DescPk(). - Offset(offset). - Limit(size). - Slice(&result). - FindAll() - return -} - -// SumDailyEventTypes 统计某天数据总和 -func (this *UserAccountLogDAO) SumDailyEventTypes(tx *dbs.Tx, day string, eventTypes []userconfigs.AccountEventType) (float32, error) { - if len(eventTypes) == 0 { - return 0, nil - } - result, err := this.Query(tx). - Attr("day", day). - Attr("eventType", eventTypes). - Sum("delta", 0) - if err != nil { - return 0, err - } - return types.Float32(result), nil -} diff --git a/internal/db/models/accounts/user_account_log_dao_test.go b/internal/db/models/accounts/user_account_log_dao_test.go deleted file mode 100644 index 76141d0c..00000000 --- a/internal/db/models/accounts/user_account_log_dao_test.go +++ /dev/null @@ -1,6 +0,0 @@ -package accounts - -import ( - _ "github.com/go-sql-driver/mysql" - _ "github.com/iwind/TeaGo/bootstrap" -) diff --git a/internal/nodes/api_node_services.go b/internal/nodes/api_node_services.go index 3936dae3..c23d47cc 100644 --- a/internal/nodes/api_node_services.go +++ b/internal/nodes/api_node_services.go @@ -357,16 +357,6 @@ func (this *APINode) registerServices(server *grpc.Server) { pb.RegisterServerDailyStatServiceServer(server, instance) this.rest(instance) } - { - var instance = this.serviceInstance(&services.UserBillService{}).(*services.UserBillService) - pb.RegisterUserBillServiceServer(server, instance) - this.rest(instance) - } - { - var instance = this.serviceInstance(&services.ServerBillService{}).(*services.ServerBillService) - pb.RegisterServerBillServiceServer(server, instance) - this.rest(instance) - } { var instance = this.serviceInstance(&services.LoginService{}).(*services.LoginService) pb.RegisterLoginServiceServer(server, instance) diff --git a/internal/rpc/services/service_server_bill.go b/internal/rpc/services/service_server_bill.go deleted file mode 100644 index 6a9751d4..00000000 --- a/internal/rpc/services/service_server_bill.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. - -package services - -import ( - "context" - "github.com/TeaOSLab/EdgeAPI/internal/db/models" - "github.com/TeaOSLab/EdgeAPI/internal/utils" - "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" -) - -// ServerBillService 服务账单相关服务 -type ServerBillService struct { - BaseService -} - -// CountAllServerBills 查询服务账单数量 -func (this *ServerBillService) CountAllServerBills(ctx context.Context, req *pb.CountAllServerBillsRequest) (*pb.RPCCountResponse, error) { - _, userId, err := this.ValidateAdminAndUser(ctx, true) - if err != nil { - return nil, err - } - - if userId > 0 { - req.UserId = userId - } - - var tx = this.NullTx() - count, err := models.SharedServerBillDAO.CountServerBills(tx, req.UserId, req.Month) - if err != nil { - return nil, err - } - return this.SuccessCount(count) -} - -// ListServerBills 查询服务账单列表 -func (this *ServerBillService) ListServerBills(ctx context.Context, req *pb.ListServerBillsRequest) (*pb.ListServerBillsResponse, error) { - _, userId, err := this.ValidateAdminAndUser(ctx, true) - if err != nil { - return nil, err - } - - if userId > 0 { - req.UserId = userId - } - - var tx = this.NullTx() - serverBills, err := models.SharedServerBillDAO.ListServerBills(tx, req.UserId, req.Month, req.Offset, req.Size) - if err != nil { - return nil, err - } - - var pbServerBills = []*pb.ServerBill{} - var cacheMap = utils.NewCacheMap() - for _, bill := range serverBills { - // user - user, err := models.SharedUserDAO.FindBasicUserWithoutState(tx, int64(bill.UserId)) - if err != nil { - return nil, err - } - var pbUser = &pb.User{Id: int64(bill.UserId)} - if user != nil { - pbUser = &pb.User{ - Id: int64(bill.UserId), - Username: user.Username, - Fullname: user.Fullname, - } - } - - // plan - var pbPlan *pb.Plan - if bill.PlanId > 0 { - plan, err := models.SharedPlanDAO.FindEnabledPlan(tx, int64(bill.PlanId)) - if err != nil { - return nil, err - } - if plan != nil { - pbPlan = &pb.Plan{ - Id: int64(plan.Id), - Name: plan.Name, - PriceType: plan.PriceType, - } - } - } - - // user plan - var pbUserPlan *pb.UserPlan - if bill.UserPlanId > 0 { - userPlan, err := models.SharedUserPlanDAO.FindEnabledUserPlan(tx, int64(bill.UserPlanId), cacheMap) - if err != nil { - return nil, err - } - if userPlan != nil { - pbUserPlan = &pb.UserPlan{ - Id: int64(userPlan.Id), - } - } - } - - // server - var pbServer *pb.Server - if bill.ServerId > 0 { - server, err := models.SharedServerDAO.FindEnabledServerBasic(tx, int64(bill.ServerId)) - if err != nil { - return nil, err - } - if server != nil { - pbServer = &pb.Server{Id: int64(bill.ServerId), Name: server.Name} - } - } - - pbServerBills = append(pbServerBills, &pb.ServerBill{ - Id: int64(bill.Id), - UserId: int64(bill.UserId), - ServerId: int64(bill.ServerId), - Amount: float32(bill.Amount), - PriceType: bill.PriceType, - CreatedAt: int64(bill.CreatedAt), - UserPlanId: int64(bill.UserPlanId), - PlanId: int64(bill.PlanId), - TotalTrafficBytes: int64(bill.TotalTrafficBytes), - BandwidthPercentileBytes: int64(bill.BandwidthPercentileBytes), - BandwidthPercentile: int32(bill.BandwidthPercentile), - User: pbUser, - Plan: pbPlan, - UserPlan: pbUserPlan, - Server: pbServer, - }) - } - - return &pb.ListServerBillsResponse{ServerBills: pbServerBills}, nil -} diff --git a/internal/rpc/services/service_user_bill.go b/internal/rpc/services/service_user_bill.go deleted file mode 100644 index f0b60b84..00000000 --- a/internal/rpc/services/service_user_bill.go +++ /dev/null @@ -1,255 +0,0 @@ -package services - -import ( - "context" - "github.com/TeaOSLab/EdgeAPI/internal/db/models" - "github.com/TeaOSLab/EdgeAPI/internal/db/models/accounts" - "github.com/TeaOSLab/EdgeAPI/internal/errors" - "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" - "github.com/TeaOSLab/EdgeCommon/pkg/userconfigs" - "github.com/iwind/TeaGo/dbs" - "github.com/iwind/TeaGo/maps" - timeutil "github.com/iwind/TeaGo/utils/time" - "regexp" -) - -// UserBillService 账单相关服务 -type UserBillService struct { - BaseService -} - -// GenerateAllUserBills 手工生成订单 -func (this *UserBillService) GenerateAllUserBills(ctx context.Context, req *pb.GenerateAllUserBillsRequest) (*pb.RPCSuccess, error) { - _, err := this.ValidateAdmin(ctx) - if err != nil { - return nil, err - } - - // 校验Month - if !regexp.MustCompile(`^\d{6}$`).MatchString(req.Month) { - return nil, errors.New("invalid month '" + req.Month + "'") - } - if req.Month >= timeutil.Format("Ym") { - return nil, errors.New("invalid month '" + req.Month + "'") - } - - var tx = this.NullTx() - - err = models.SharedUserBillDAO.GenerateBills(tx, req.Month) - if err != nil { - return nil, err - } - - return this.Success() -} - -// CountAllUserBills 计算所有账单数量 -func (this *UserBillService) CountAllUserBills(ctx context.Context, req *pb.CountAllUserBillsRequest) (*pb.RPCCountResponse, error) { - _, userId, err := this.ValidateAdminAndUser(ctx, true) - if err != nil { - return nil, err - } - - var tx = this.NullTx() - if userId > 0 { - req.UserId = userId - } - - count, err := models.SharedUserBillDAO.CountAllUserBills(tx, req.PaidFlag, req.UserId, req.Month) - if err != nil { - return nil, err - } - return this.SuccessCount(count) -} - -// ListUserBills 列出单页账单 -func (this *UserBillService) ListUserBills(ctx context.Context, req *pb.ListUserBillsRequest) (*pb.ListUserBillsResponse, error) { - _, userId, err := this.ValidateAdminAndUser(ctx, true) - if err != nil { - return nil, err - } - - var tx = this.NullTx() - if userId > 0 { - req.UserId = userId - } - - bills, err := models.SharedUserBillDAO.ListUserBills(tx, req.PaidFlag, req.UserId, req.Month, req.Offset, req.Size) - if err != nil { - return nil, err - } - result := []*pb.UserBill{} - for _, bill := range bills { - user, err := models.SharedUserDAO.FindBasicUserWithoutState(tx, int64(bill.UserId)) - if err != nil { - return nil, err - } - if user == nil { - user = &models.User{Id: bill.UserId} - } - - result = append(result, &pb.UserBill{ - Id: int64(bill.Id), - User: &pb.User{ - Id: int64(bill.UserId), - Fullname: user.Fullname, - Username: user.Username, - IsDeleted: user.State == models.UserStateDisabled, - }, - Type: bill.Type, - TypeName: models.SharedUserBillDAO.BillTypeName(bill.Type), - Description: bill.Description, - Amount: float32(bill.Amount), - Month: bill.Month, - CanPay: bill.CanPay, - IsPaid: bill.IsPaid, - PaidAt: int64(bill.PaidAt), - Code: bill.Code, - }) - } - return &pb.ListUserBillsResponse{UserBills: result}, nil -} - -// FindUserBill 查找账单信息 -func (this *UserBillService) FindUserBill(ctx context.Context, req *pb.FindUserBillRequest) (*pb.FindUserBillResponse, error) { - _, userId, err := this.ValidateAdminAndUser(ctx, true) - if err != nil { - return nil, err - } - - var tx = this.NullTx() - - // 检查用户 - if userId > 0 { - err = models.SharedUserBillDAO.CheckUserBill(tx, userId, req.UserBillId) - if err != nil { - return nil, err - } - } - - bill, err := models.SharedUserBillDAO.FindUserBill(tx, req.UserBillId) - if err != nil { - return nil, err - } - - if bill == nil { - return &pb.FindUserBillResponse{UserBill: nil}, nil - } - - // 用户 - var pbUser = &pb.User{Id: int64(bill.UserId)} - user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(bill.UserId), nil) - if err != nil { - return nil, err - } - if user != nil { - pbUser = &pb.User{ - Id: int64(user.Id), - Username: user.Username, - Fullname: user.Fullname, - } - } - - return &pb.FindUserBillResponse{ - UserBill: &pb.UserBill{ - Id: int64(bill.Id), - User: pbUser, - Type: bill.Type, - TypeName: models.SharedUserBillDAO.BillTypeName(bill.Type), - Description: bill.Description, - Amount: float32(bill.Amount), - Month: bill.Month, - CanPay: bill.CanPay, - IsPaid: bill.IsPaid, - PaidAt: int64(bill.PaidAt), - Code: bill.Code, - }, - }, nil -} - -// PayUserBill 支付账单 -func (this *UserBillService) PayUserBill(ctx context.Context, req *pb.PayUserBillRequest) (*pb.RPCSuccess, error) { - _, userId, err := this.ValidateAdminAndUser(ctx, true) - if err != nil { - return nil, err - } - - err = this.RunTx(func(tx *dbs.Tx) error { - // 检查用户 - if userId > 0 { - err = models.SharedUserBillDAO.CheckUserBill(tx, userId, req.UserBillId) - if err != nil { - return err - } - } - - // 是否存在 - bill, err := models.SharedUserBillDAO.FindUserBill(tx, req.UserBillId) - if err != nil { - return err - } - if bill == nil { - return nil - } - userId = int64(bill.UserId) - - // 是否已支付 - if bill.IsPaid { - return nil - } - - if bill.Amount <= 0 { - // 直接修改为已支付 - return models.SharedUserBillDAO.UpdateUserBillIsPaid(tx, req.UserBillId, true) - } - - if !bill.CanPay { - return errors.New("can not pay now") - } - - // 余额是否足够 - account, err := accounts.SharedUserAccountDAO.FindUserAccountWithUserId(tx, userId) - if err != nil { - return err - } - if account == nil { - return errors.New("can not find user account") - } - - if account.Total < bill.Amount { - return errors.New("not enough balance to pay") - } - - err = accounts.SharedUserAccountDAO.UpdateUserAccount(tx, int64(account.Id), -float32(bill.Amount), userconfigs.AccountEventTypePayBill, "支付账单"+bill.Code, maps.Map{"billId": bill.Id}) - if err != nil { - return err - } - - // 修改为已支付 - return models.SharedUserBillDAO.UpdateUserBillIsPaid(tx, req.UserBillId, true) - }) - if err != nil { - return nil, err - } - - return this.Success() -} - -// SumUserUnpaidBills 计算用户所有未支付账单总额 -func (this *UserBillService) SumUserUnpaidBills(ctx context.Context, req *pb.SumUserUnpaidBillsRequest) (*pb.SumUserUnpaidBillsResponse, error) { - _, userId, err := this.ValidateAdminAndUser(ctx, true) - if err != nil { - return nil, err - } - - var tx = this.NullTx() - if userId > 0 { - req.UserId = userId - } - - sum, err := models.SharedUserBillDAO.SumUnpaidUserBill(tx, userId) - if err != nil { - return nil, err - } - return &pb.SumUserUnpaidBillsResponse{Amount: sum}, nil -}