github.com/condensat/bank-core@v0.1.0/database/model/accountoperation.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 model 6 7 import ( 8 "math" 9 "time" 10 ) 11 12 type AccountOperationID ID 13 14 // AccountOperation model 15 type AccountOperation struct { 16 ID AccountOperationID `gorm:"primary_key;unique_index:idx_id_previd;"` // [PK] AccountOperation 17 AccountID AccountID `gorm:"index;not null"` // [FK] Reference to Account table 18 19 SynchroneousType SynchroneousType `gorm:"index;not null;type:varchar(16)"` // [enum] Operation synchroneous type (sync, async-start, async-end) 20 OperationType OperationType `gorm:"index;not null;type:varchar(16)"` // [enum] Determine table for ReferenceID (deposit, withdraw, transfer, adjustment, none, other) 21 ReferenceID RefID `gorm:"index;not null"` // [optional - FK] Reference to related table with OperationType 22 23 Timestamp time.Time `gorm:"index;not null;type:timestamp"` // Operation timestamp 24 Amount ZeroFloat `gorm:"default:0;not null"` // Operation amount (can be negative) 25 Balance ZeroFloat `gorm:"default:0;not null"` // Account balance (strictly positive or zero) 26 27 LockAmount ZeroFloat `gorm:"default:0;not null"` // Operation amount (can be negative) 28 TotalLocked ZeroFloat `gorm:"default:0;not null"` // Total locked (strictly positive or zero and less or equal than Balance) 29 } 30 31 func NewAccountOperation(ID AccountOperationID, accountID AccountID, synchroneousType SynchroneousType, operationType OperationType, referenceID RefID, timestamp time.Time, amount, balance, lockAmount, totalLocked Float) AccountOperation { 32 return AccountOperation{ 33 ID: ID, 34 AccountID: accountID, 35 36 SynchroneousType: synchroneousType, 37 OperationType: operationType, 38 ReferenceID: referenceID, 39 40 Timestamp: timestamp.UTC().Truncate(time.Second), 41 Amount: &amount, 42 Balance: &balance, 43 44 LockAmount: &lockAmount, 45 TotalLocked: &totalLocked, 46 } 47 } 48 49 func NewInitOperation(accountID AccountID, referenceID RefID) AccountOperation { 50 return NewAccountOperation(0, 51 accountID, 52 SynchroneousTypeSync, 53 OperationTypeInit, 54 referenceID, 55 time.Now(), 56 0.0, 0.0, 57 0.0, 0.0, 58 ) 59 } 60 61 func (p *AccountOperation) IsValid() bool { 62 return p.ID > 0 && 63 p.AccountID > 0 && 64 65 // check enums 66 p.OperationType.Valid() && 67 p.SynchroneousType.Valid() && 68 69 // check pointers 70 p.Amount != nil && p.Balance != nil && 71 p.LockAmount != nil && p.TotalLocked != nil && 72 73 // check positive balance and TotalLocked 74 *p.Balance >= 0 && 75 *p.TotalLocked >= 0 && 76 // check for max total locked 77 *p.TotalLocked <= *p.Balance && 78 79 // check amount less or equals than balance 80 *p.Amount <= *p.Balance && 81 // check lockAmount less or equals than totalLocked 82 *p.LockAmount <= *p.TotalLocked && 83 84 // Check for zero operation 85 // allow zero operation for OperationTypeInit 86 (p.OperationType == OperationTypeInit || (math.Abs(float64(*p.Amount)) > 0.0 || math.Abs(float64(*p.LockAmount)) > 0.0)) 87 } 88 89 func (p *AccountOperation) PreCheck() bool { 90 // deepcopy 91 operation := *p 92 // overwite operation IDs 93 operation.ID = 1 94 95 // operation should be valid 96 return operation.IsValid() 97 }