github.com/condensat/bank-core@v0.1.0/database/query/withdraw.go (about)

     1  // Copyright 2020 Condensat Tech. All rights reserved.
     2  // Use of this source code is governed by a MIT
     3  // license that can be found in the LICENSE file.
     4  
     5  package query
     6  
     7  import (
     8  	"errors"
     9  	"time"
    10  
    11  	"github.com/condensat/bank-core/database"
    12  	"github.com/condensat/bank-core/database/model"
    13  
    14  	"github.com/jinzhu/gorm"
    15  )
    16  
    17  var (
    18  	ErrInvalidWithdrawID              = errors.New("Invalid WithdrawID")
    19  	ErrInvalidWithdrawAmount          = errors.New("Invalid Amount")
    20  	ErrInvalidWithdrawAccount         = errors.New("Invalid Withdraw Account")
    21  	ErrInvalidWithdrawAccountCurrency = errors.New("Invalid Withdraw Account Currency")
    22  	ErrInvalidBatchMode               = errors.New("Invalid BatchMode")
    23  )
    24  
    25  func AddWithdraw(db database.Context, from, to model.AccountID, amount model.Float, batch model.BatchMode, data model.WithdrawData) (model.Withdraw, error) {
    26  	gdb := db.DB().(*gorm.DB)
    27  	if db == nil {
    28  		return model.Withdraw{}, database.ErrInvalidDatabase
    29  	}
    30  
    31  	if from == 0 {
    32  		return model.Withdraw{}, ErrInvalidAccountID
    33  	}
    34  	if to == 0 {
    35  		return model.Withdraw{}, ErrInvalidAccountID
    36  	}
    37  	if from == to {
    38  		return model.Withdraw{}, ErrInvalidAccountID
    39  	}
    40  	accountFrom, err := GetAccountByID(db, from)
    41  	if err != nil {
    42  		return model.Withdraw{}, ErrInvalidWithdrawAccount
    43  	}
    44  	accountTo, err := GetAccountByID(db, to)
    45  	if err != nil {
    46  		return model.Withdraw{}, ErrInvalidWithdrawAccount
    47  	}
    48  	if accountFrom.CurrencyName != accountTo.CurrencyName {
    49  		return model.Withdraw{}, ErrInvalidWithdrawAccountCurrency
    50  	}
    51  
    52  	if amount <= 0.0 {
    53  		return model.Withdraw{}, ErrInvalidWithdrawAmount
    54  	}
    55  	if len(batch) == 0 {
    56  		return model.Withdraw{}, ErrInvalidBatchMode
    57  	}
    58  
    59  	timestamp := time.Now().UTC().Truncate(time.Second)
    60  	result := model.Withdraw{
    61  		Timestamp: timestamp,
    62  		From:      from,
    63  		To:        to,
    64  		Amount:    &amount,
    65  		Batch:     batch,
    66  		Data:      data,
    67  	}
    68  	err = gdb.Create(&result).Error
    69  	if err != nil {
    70  		return model.Withdraw{}, err
    71  	}
    72  
    73  	return result, nil
    74  }
    75  
    76  func GetWithdraw(db database.Context, ID model.WithdrawID) (model.Withdraw, error) {
    77  	gdb := db.DB().(*gorm.DB)
    78  	if db == nil {
    79  		return model.Withdraw{}, database.ErrInvalidDatabase
    80  	}
    81  
    82  	if ID == 0 {
    83  		return model.Withdraw{}, ErrInvalidWithdrawID
    84  	}
    85  
    86  	var result model.Withdraw
    87  	err := gdb.
    88  		Where(&model.Withdraw{ID: ID}).
    89  		First(&result).Error
    90  	if err != nil {
    91  		return model.Withdraw{}, err
    92  	}
    93  
    94  	return result, nil
    95  }
    96  
    97  func FindWithdrawByCurrencyNameAndStatus(db database.Context, currency model.CurrencyName, status model.WithdrawStatus) ([]model.Withdraw, error) {
    98  	gdb := db.DB().(*gorm.DB)
    99  
   100  	subQueryAccount := gdb.Model(&model.Account{}).
   101  		Select("id").
   102  		Where("currency_name = ?", currency).
   103  		SubQuery()
   104  
   105  	subQueryInfo := gdb.Model(&model.WithdrawInfo{}).
   106  		Select("withdraw_id").
   107  		Where("status = ?", status).
   108  		SubQuery()
   109  
   110  	var list []*model.Withdraw
   111  	err := gdb.Model(&model.Withdraw{}).
   112  		Joins("JOIN (?) AS a ON withdraw.from = a.id", subQueryAccount).
   113  		Joins("JOIN (?) AS i ON withdraw.id = i.withdraw_id", subQueryInfo).
   114  		Order("id ASC").
   115  		Find(&list).Error
   116  
   117  	if err != nil && err != gorm.ErrRecordNotFound {
   118  		return nil, err
   119  	}
   120  
   121  	return convertWithdraws(list), nil
   122  }
   123  
   124  func FindWithdrawByUser(db database.Context, userID model.UserID) ([]model.Withdraw, error) {
   125  	gdb := db.DB().(*gorm.DB)
   126  
   127  	if userID == 0 {
   128  		return nil, ErrInvalidUserID
   129  	}
   130  
   131  	subQueryAccount := gdb.Model(&model.Account{}).
   132  		Select("id").
   133  		Where("user_id = ?", userID).
   134  		SubQuery()
   135  
   136  	var list []*model.Withdraw
   137  	err := gdb.Model(&model.Withdraw{}).
   138  		Joins("JOIN (?) AS a ON withdraw.from = a.id", subQueryAccount).
   139  		Order("id ASC").
   140  		Find(&list).Error
   141  
   142  	if err != nil && err != gorm.ErrRecordNotFound {
   143  		return nil, err
   144  	}
   145  
   146  	return convertWithdraws(list), nil
   147  }
   148  
   149  type WithdrawInfos struct {
   150  	Count  int
   151  	Active int
   152  }
   153  
   154  func WithdrawsInfos(db database.Context) (WithdrawInfos, error) {
   155  	gdb := db.DB().(*gorm.DB)
   156  	if gdb == nil {
   157  		return WithdrawInfos{}, database.ErrInvalidDatabase
   158  	}
   159  
   160  	var totalWithdraws int64
   161  	err := gdb.Model(&model.Withdraw{}).
   162  		Count(&totalWithdraws).Error
   163  	if err != nil {
   164  		return WithdrawInfos{}, err
   165  	}
   166  
   167  	subQueryLast := gdb.Model(&model.WithdrawInfo{}).
   168  		Select("MAX(id)").
   169  		Group("withdraw_id").
   170  		SubQuery()
   171  
   172  	var activeWithdraws int64
   173  	err = gdb.Model(&model.WithdrawInfo{}).
   174  		Where("id IN (?)", subQueryLast).
   175  		Where("status <> ?", model.WithdrawStatusSettled).
   176  		Count(&activeWithdraws).Error
   177  	if err != nil {
   178  		return WithdrawInfos{}, err
   179  	}
   180  
   181  	return WithdrawInfos{
   182  		Count:  int(totalWithdraws),
   183  		Active: int(activeWithdraws),
   184  	}, nil
   185  }
   186  
   187  func convertWithdraws(list []*model.Withdraw) []model.Withdraw {
   188  	var result []model.Withdraw
   189  	for _, curr := range list {
   190  		if curr != nil {
   191  			result = append(result, *curr)
   192  		}
   193  	}
   194  
   195  	return result[:]
   196  }