| 122 | } |
| 123 | |
| 124 | func (t *RecordTransaction) ValidateRecordTransaction() error { |
| 125 | return validation.ValidateStruct(t, |
| 126 | validation.Field(&t.Amount, validation.By(func(value interface{}) error { |
| 127 | if t.Amount != 0 && t.PreciseAmount != nil { |
| 128 | return errors.New("either amount or precise_amount should be provided, not both") |
| 129 | } |
| 130 | if t.Amount == 0 && t.PreciseAmount == nil { |
| 131 | return errors.New("either amount or precise_amount is required") |
| 132 | } |
| 133 | |
| 134 | // Check for high precision amounts that might lead to rounding errors |
| 135 | if t.Amount != 0 { |
| 136 | // Convert to string to check significant digits |
| 137 | amountStr := strconv.FormatFloat(t.Amount, 'f', -1, 64) |
| 138 | |
| 139 | // Remove decimal point for counting significant digits |
| 140 | amountStr = strings.Replace(amountStr, ".", "", 1) |
| 141 | |
| 142 | // Remove leading zeros which aren't significant |
| 143 | amountStr = strings.TrimLeft(amountStr, "0") |
| 144 | |
| 145 | // Count significant digits |
| 146 | significantDigits := len(amountStr) |
| 147 | |
| 148 | // If more than 15 significant digits, warn about potential rounding errors |
| 149 | if significantDigits > 15 { |
| 150 | return errors.New("amount has more than 15 significant digits which may cause rounding errors; use precise_amount instead") |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | return nil |
| 155 | })), |
| 156 | validation.Field(&t.Precision, validation.By(validatePrecisionIsInteger)), |
| 157 | validation.Field(&t.Currency, validation.Required), |
| 158 | validation.Field(&t.Reference, validation.Required), |
| 159 | validation.Field(&t.Description, validation.Required), |
| 160 | validation.Field(&t.Source, validation.By(sourceOrSourcesValidation(t))), |
| 161 | validation.Field(&t.Destination, validation.By(destinationOrDestinationsValidation(t))), |
| 162 | validation.Field(&t.ScheduledFor, validation.When(t.ScheduledFor != "", validation.By(func(value interface{}) error { |
| 163 | dateStr, ok := value.(string) |
| 164 | if !ok { |
| 165 | return errors.New("invalid type for scheduled date") |
| 166 | } |
| 167 | return validateDateFormat("2006-01-02T15:04:05Z07:00", dateStr) |
| 168 | })), |
| 169 | ), |
| 170 | validation.Field(&t.InflightExpiryDate, validation.When(t.InflightExpiryDate != "", validation.By(func(value interface{}) error { |
| 171 | dateStr, ok := value.(string) |
| 172 | if !ok { |
| 173 | return errors.New("invalid type for scheduled date") |
| 174 | } |
| 175 | return validateDateFormat("2006-01-02T15:04:05Z07:00", dateStr) |
| 176 | })), |
| 177 | ), |
| 178 | validation.Field(&t.InflightCommitDate, validation.When(t.InflightCommitDate != "", validation.By(func(value interface{}) error { |
| 179 | dateStr, ok := value.(string) |
| 180 | if !ok { |
| 181 | return errors.New("invalid type for scheduled date") |