|
22 | 22 | import java.util.Arrays; |
23 | 23 | import java.util.Date; |
24 | 24 | import java.util.HashMap; |
| 25 | +import java.util.LinkedHashSet; |
25 | 26 | import java.util.List; |
26 | 27 | import java.util.Map; |
27 | 28 | import java.util.TimeZone; |
|
54 | 55 | import org.apache.commons.lang3.ObjectUtils; |
55 | 56 | import org.apache.commons.lang3.StringUtils; |
56 | 57 | import org.apache.commons.lang3.math.NumberUtils; |
| 58 | +import org.apache.commons.lang3.time.DateUtils; |
57 | 59 | import org.springframework.stereotype.Component; |
58 | 60 |
|
59 | 61 | import com.cloud.usage.UsageVO; |
@@ -145,79 +147,81 @@ protected void processQuotaBalanceForAccount(AccountVO accountVo, List<QuotaUsag |
145 | 147 | return; |
146 | 148 | } |
147 | 149 |
|
148 | | - QuotaUsageVO firstQuotaUsage = accountQuotaUsages.get(0); |
149 | | - Date startDate = firstQuotaUsage.getStartDate(); |
150 | | - Date endDate = firstQuotaUsage.getStartDate(); |
| 150 | + Date startDate = accountQuotaUsages.get(0).getStartDate(); |
| 151 | + Date endDate = accountQuotaUsages.get(0).getEndDate(); |
| 152 | + Date lastQuotaUsageEndDate = accountQuotaUsages.get(accountQuotaUsages.size() - 1).getEndDate(); |
151 | 153 |
|
152 | | - logger.info("Processing quota balance for account [{}] between [{}] and [{}].", accountToString, |
153 | | - DateUtil.displayDateInTimezone(usageAggregationTimeZone, startDate), |
154 | | - DateUtil.displayDateInTimezone(usageAggregationTimeZone, accountQuotaUsages.get(accountQuotaUsages.size() - 1).getEndDate())); |
| 154 | + LinkedHashSet<Pair<Date, Date>> periods = accountQuotaUsages.stream() |
| 155 | + .map(quotaUsageVO -> new Pair<>(quotaUsageVO.getStartDate(), quotaUsageVO.getEndDate())) |
| 156 | + .collect(Collectors.toCollection(LinkedHashSet::new)); |
| 157 | + |
| 158 | + logger.info(String.format("Processing quota balance for account[%s] between [%s] and [%s].", accountToString, startDate, lastQuotaUsageEndDate)); |
155 | 159 |
|
156 | | - BigDecimal aggregatedUsage = BigDecimal.ZERO; |
157 | 160 | long accountId = accountVo.getAccountId(); |
158 | 161 | long domainId = accountVo.getDomainId(); |
| 162 | + BigDecimal accountBalance = retrieveBalanceForUsageCalculation(accountId, domainId, startDate, accountToString); |
159 | 163 |
|
160 | | - aggregatedUsage = getUsageValueAccordingToLastQuotaUsageEntryAndLastQuotaBalance(accountId, domainId, startDate, endDate, aggregatedUsage, accountToString); |
161 | | - |
162 | | - for (QuotaUsageVO quotaUsage : accountQuotaUsages) { |
163 | | - Date quotaUsageStartDate = quotaUsage.getStartDate(); |
164 | | - Date quotaUsageEndDate = quotaUsage.getEndDate(); |
165 | | - BigDecimal quotaUsed = quotaUsage.getQuotaUsed(); |
166 | | - |
167 | | - if (quotaUsed.equals(BigDecimal.ZERO)) { |
168 | | - aggregatedUsage = aggregatedUsage.add(aggregateCreditBetweenDates(accountId, domainId, quotaUsageStartDate, quotaUsageEndDate, accountToString)); |
169 | | - continue; |
170 | | - } |
171 | | - |
172 | | - if (startDate.compareTo(quotaUsageStartDate) == 0) { |
173 | | - aggregatedUsage = aggregatedUsage.subtract(quotaUsed); |
174 | | - continue; |
175 | | - } |
176 | | - |
177 | | - _quotaBalanceDao.saveQuotaBalance(new QuotaBalanceVO(accountId, domainId, aggregatedUsage, endDate)); |
| 164 | + for (Pair<Date, Date> period : periods) { |
| 165 | + startDate = period.first(); |
| 166 | + endDate = period.second(); |
178 | 167 |
|
179 | | - aggregatedUsage = BigDecimal.ZERO; |
180 | | - startDate = quotaUsageStartDate; |
181 | | - endDate = quotaUsageEndDate; |
| 168 | + accountBalance = calculateBalanceConsideringCreditsAddedAndQuotaUsed(accountBalance, accountQuotaUsages, accountId, domainId, startDate, endDate, accountToString); |
| 169 | + _quotaBalanceDao.saveQuotaBalance(new QuotaBalanceVO(accountId, domainId, accountBalance, endDate)); |
| 170 | + } |
| 171 | + saveQuotaAccount(accountId, accountBalance, endDate); |
| 172 | + } |
182 | 173 |
|
183 | | - QuotaBalanceVO lastRealBalanceEntry = _quotaBalanceDao.findLastBalanceEntry(accountId, domainId, endDate); |
184 | | - Date lastBalanceDate = new Date(0); |
| 174 | + /** |
| 175 | + * Calculates the balance for the given account considering the specified period. The balance is calculated as follows: |
| 176 | + * <ol> |
| 177 | + * <li>The credits added in this period are added to the balance.</li> |
| 178 | + * <li>All quota consumed in this period are subtracted from the account balance.</li> |
| 179 | + * </ol> |
| 180 | + */ |
| 181 | + protected BigDecimal calculateBalanceConsideringCreditsAddedAndQuotaUsed(BigDecimal accountBalance, List<QuotaUsageVO> accountQuotaUsages, long accountId, long domainId, |
| 182 | + Date startDate, Date endDate, String accountToString) { |
| 183 | + accountBalance = accountBalance.add(aggregateCreditBetweenDates(accountId, domainId, startDate, endDate, accountToString)); |
185 | 184 |
|
186 | | - if (lastRealBalanceEntry != null) { |
187 | | - lastBalanceDate = lastRealBalanceEntry.getUpdatedOn(); |
188 | | - aggregatedUsage = aggregatedUsage.add(lastRealBalanceEntry.getCreditBalance()); |
| 185 | + for (QuotaUsageVO quotaUsageVO : accountQuotaUsages) { |
| 186 | + if (DateUtils.isSameInstant(quotaUsageVO.getStartDate(), startDate)) { |
| 187 | + accountBalance = accountBalance.subtract(quotaUsageVO.getQuotaUsed()); |
189 | 188 | } |
190 | | - |
191 | | - aggregatedUsage = aggregatedUsage.add(aggregateCreditBetweenDates(accountId, domainId, lastBalanceDate, endDate, accountToString)); |
192 | | - aggregatedUsage = aggregatedUsage.subtract(quotaUsed); |
193 | 189 | } |
194 | | - |
195 | | - _quotaBalanceDao.saveQuotaBalance(new QuotaBalanceVO(accountId, domainId, aggregatedUsage, endDate)); |
196 | | - saveQuotaAccount(accountId, aggregatedUsage, endDate); |
| 190 | + return accountBalance; |
197 | 191 | } |
198 | 192 |
|
199 | | - protected BigDecimal getUsageValueAccordingToLastQuotaUsageEntryAndLastQuotaBalance(long accountId, long domainId, Date startDate, Date endDate, BigDecimal aggregatedUsage, |
200 | | - String accountToString) { |
| 193 | + /** |
| 194 | + * Retrieves the initial balance prior to the period of the quota processing. |
| 195 | + * <ul> |
| 196 | + * <li> |
| 197 | + * If it is the first time of processing for the account, the credits prior to the quota processing are added, and the first balance is persisted in the DB. |
| 198 | + * </li> |
| 199 | + * <li> |
| 200 | + * Otherwise, the last real balance of the account is retrieved. |
| 201 | + * </li> |
| 202 | + * </ul> |
| 203 | + */ |
| 204 | + protected BigDecimal retrieveBalanceForUsageCalculation(long accountId, long domainId, Date startDate, String accountToString) { |
| 205 | + BigDecimal accountBalance = BigDecimal.ZERO; |
201 | 206 | QuotaUsageVO lastQuotaUsage = _quotaUsageDao.findLastQuotaUsageEntry(accountId, domainId, startDate); |
202 | 207 |
|
203 | 208 | if (lastQuotaUsage == null) { |
204 | | - aggregatedUsage = aggregatedUsage.add(aggregateCreditBetweenDates(accountId, domainId, new Date(0), startDate, accountToString)); |
205 | | - QuotaBalanceVO firstBalance = new QuotaBalanceVO(accountId, domainId, aggregatedUsage, startDate); |
| 209 | + accountBalance = accountBalance.add(aggregateCreditBetweenDates(accountId, domainId, new Date(0), startDate, accountToString)); |
| 210 | + QuotaBalanceVO firstBalance = new QuotaBalanceVO(accountId, domainId, accountBalance, startDate); |
206 | 211 |
|
207 | 212 | logger.debug(String.format("Persisting the first quota balance [%s] for account [%s].", firstBalance, accountToString)); |
208 | 213 | _quotaBalanceDao.saveQuotaBalance(firstBalance); |
209 | 214 | } else { |
210 | | - QuotaBalanceVO lastRealBalance = _quotaBalanceDao.findLastBalanceEntry(accountId, domainId, endDate); |
| 215 | + QuotaBalanceVO lastRealBalance = _quotaBalanceDao.findLastBalanceEntry(accountId, domainId, startDate); |
211 | 216 |
|
212 | | - if (lastRealBalance != null) { |
213 | | - aggregatedUsage = aggregatedUsage.add(lastRealBalance.getCreditBalance()); |
214 | | - aggregatedUsage = aggregatedUsage.add(aggregateCreditBetweenDates(accountId, domainId, lastRealBalance.getUpdatedOn(), endDate, accountToString)); |
215 | | - } else { |
| 217 | + if (lastRealBalance == null) { |
216 | 218 | logger.warn(String.format("Account [%s] has quota usage entries, however it does not have a quota balance.", accountToString)); |
| 219 | + } else { |
| 220 | + accountBalance = accountBalance.add(lastRealBalance.getCreditBalance()); |
217 | 221 | } |
218 | 222 | } |
219 | 223 |
|
220 | | - return aggregatedUsage; |
| 224 | + return accountBalance; |
221 | 225 | } |
222 | 226 |
|
223 | 227 | protected void saveQuotaAccount(long accountId, BigDecimal aggregatedUsage, Date endDate) { |
|
0 commit comments