2323import java .util .Comparator ;
2424import java .util .Date ;
2525import java .util .HashMap ;
26+ import java .util .LinkedHashMap ;
2627import java .util .LinkedHashSet ;
2728import java .util .List ;
2829import java .util .Map ;
4344import org .apache .cloudstack .quota .dao .QuotaAccountDao ;
4445import org .apache .cloudstack .quota .dao .QuotaBalanceDao ;
4546import org .apache .cloudstack .quota .dao .QuotaTariffDao ;
47+ import org .apache .cloudstack .quota .dao .QuotaTariffUsageDao ;
4648import org .apache .cloudstack .quota .dao .QuotaUsageDao ;
4749import org .apache .cloudstack .quota .vo .QuotaAccountVO ;
4850import org .apache .cloudstack .quota .vo .QuotaBalanceVO ;
51+ import org .apache .cloudstack .quota .vo .QuotaTariffUsageVO ;
4952import org .apache .cloudstack .quota .vo .QuotaTariffVO ;
5053import org .apache .cloudstack .quota .vo .QuotaUsageVO ;
5154import org .apache .cloudstack .usage .UsageUnitTypes ;
@@ -86,7 +89,8 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager {
8689 private QuotaBalanceDao _quotaBalanceDao ;
8790 @ Inject
8891 private ConfigurationDao _configDao ;
89-
92+ @ Inject
93+ private QuotaTariffUsageDao quotaTariffUsageDao ;
9094 @ Inject
9195 protected PresetVariableHelper presetVariableHelper ;
9296
@@ -310,33 +314,46 @@ protected List<QuotaUsageVO> createQuotaUsagesAccordingToQuotaTariffs(AccountVO
310314 String accountToString = account .reflectionToString ();
311315 logger .info ("Calculating quota usage of [{}] usage records for account [{}]." , usageRecords .size (), accountToString );
312316
313- List < Pair < UsageVO , QuotaUsageVO >> pairsUsageAndQuotaUsage = new ArrayList <>();
317+ Map < UsageVO , Pair < QuotaUsageVO , List < QuotaTariffUsageVO >>> mapUsageAndQuotaUsage = new LinkedHashMap <>();
314318
315319 try (JsInterpreter jsInterpreter = new JsInterpreter (QuotaConfig .QuotaActivationRuleTimeout .value ())) {
316320 for (UsageVO usageRecord : usageRecords ) {
317321 int usageType = usageRecord .getUsageType ();
318322
319323 if (!shouldCalculateUsageRecord (account , usageRecord )) {
320- pairsUsageAndQuotaUsage . add ( new Pair <>( usageRecord , null ) );
324+ mapUsageAndQuotaUsage . put ( usageRecord , null );
321325 continue ;
322326 }
323327
324328 Pair <List <QuotaTariffVO >, Boolean > pairQuotaTariffsPerUsageTypeAndHasActivationRule = mapQuotaTariffsPerUsageType .get (usageType );
325329 List <QuotaTariffVO > quotaTariffs = pairQuotaTariffsPerUsageTypeAndHasActivationRule .first ();
326330 boolean hasAnyQuotaTariffWithActivationRule = pairQuotaTariffsPerUsageTypeAndHasActivationRule .second ();
327331
328- BigDecimal aggregatedQuotaTariffsValue = aggregateQuotaTariffsValues (usageRecord , quotaTariffs , hasAnyQuotaTariffWithActivationRule , jsInterpreter , accountToString );
332+ Map <QuotaTariffVO , BigDecimal > aggregatedQuotaTariffsAndValues = aggregateQuotaTariffsValues (usageRecord ,
333+ quotaTariffs , hasAnyQuotaTariffWithActivationRule , jsInterpreter , accountToString );
334+ BigDecimal aggregatedQuotaTariffsValue = aggregatedQuotaTariffsAndValues .values ().stream ().reduce (BigDecimal .ZERO , BigDecimal ::add );
335+ logger .debug ("The aggregation of the quota tariffs of account [{}] resulted in [{}] for the usage record [{}]." ,
336+ account , aggregatedQuotaTariffsValue , usageRecord );
329337
330338 QuotaUsageVO quotaUsage = createQuotaUsageAccordingToUsageUnit (usageRecord , aggregatedQuotaTariffsValue , accountToString );
339+ if (quotaUsage == null ) {
340+ mapUsageAndQuotaUsage .put (usageRecord , null );
341+ continue ;
342+ }
331343
332- pairsUsageAndQuotaUsage .add (new Pair <>(usageRecord , quotaUsage ));
344+ List <QuotaTariffUsageVO > quotaTariffUsages = new ArrayList <>();
345+ for (Map .Entry <QuotaTariffVO , BigDecimal > entry : aggregatedQuotaTariffsAndValues .entrySet ()) {
346+ QuotaTariffUsageVO quotaTariffUsage = createQuotaTariffUsage (usageRecord , entry .getKey (), entry .getValue ());
347+ quotaTariffUsages .add (quotaTariffUsage );
348+ }
349+ mapUsageAndQuotaUsage .put (usageRecord , new Pair <>(quotaUsage , quotaTariffUsages ));
333350 }
334351 } catch (Exception e ) {
335352 logger .error (String .format ("Failed to calculate the quota usage for account [%s] due to [%s]." , accountToString , e .getMessage ()), e );
336353 return new ArrayList <>();
337354 }
338355
339- return persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsages (pairsUsageAndQuotaUsage );
356+ return persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsages (mapUsageAndQuotaUsage );
340357 }
341358
342359 protected boolean shouldCalculateUsageRecord (AccountVO accountVO , UsageVO usageRecord ) {
@@ -348,31 +365,41 @@ protected boolean shouldCalculateUsageRecord(AccountVO accountVO, UsageVO usageR
348365 return true ;
349366 }
350367
351- protected List <QuotaUsageVO > persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsages (List < Pair < UsageVO , QuotaUsageVO >> pairsUsageAndQuotaUsage ) {
352- List <QuotaUsageVO > quotaUsages = new ArrayList <>();
368+ protected List <QuotaUsageVO > persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsages (Map < UsageVO , Pair < QuotaUsageVO , List < QuotaTariffUsageVO >>> mapUsageAndQuotaTariffUsage ) {
369+ List <QuotaUsageVO > quotaUsages = new ArrayList <>(); // TODO: isso tem que ser em uma transação
353370
354- for (Pair <UsageVO , QuotaUsageVO > pairUsageAndQuotaUsage : pairsUsageAndQuotaUsage ) {
355- UsageVO usageVo = pairUsageAndQuotaUsage . first ();
371+ for (Map . Entry <UsageVO , Pair < QuotaUsageVO , List < QuotaTariffUsageVO >>> usageAndTariffUsage : mapUsageAndQuotaTariffUsage . entrySet () ) {
372+ UsageVO usageVo = usageAndTariffUsage . getKey ();
356373 usageVo .setQuotaCalculated (1 );
357374 _usageDao .persistUsage (usageVo );
358375
359- QuotaUsageVO quotaUsageVo = pairUsageAndQuotaUsage .second ();
360- if (quotaUsageVo != null ) {
361- _quotaUsageDao .persistQuotaUsage (quotaUsageVo );
362- quotaUsages .add (quotaUsageVo );
376+ Pair <QuotaUsageVO , List <QuotaTariffUsageVO >> pairUsageAndTariffUsages = usageAndTariffUsage .getValue ();
377+ if (pairUsageAndTariffUsages != null ) {
378+ QuotaUsageVO quotaUsage = pairUsageAndTariffUsages .first ();
379+ _quotaUsageDao .persistQuotaUsage (quotaUsage );
380+ quotaUsages .add (quotaUsage );
381+
382+ persistQuotaTariffUsages (pairUsageAndTariffUsages .second (), quotaUsage .getId ());
363383 }
364384 }
365385
366386 return quotaUsages ;
367387 }
368388
369- protected BigDecimal aggregateQuotaTariffsValues (UsageVO usageRecord , List <QuotaTariffVO > quotaTariffs , boolean hasAnyQuotaTariffWithActivationRule ,
370- JsInterpreter jsInterpreter , String accountToString ) {
389+ protected void persistQuotaTariffUsages (List <QuotaTariffUsageVO > quotaTariffUsages , Long quotaUsageId ) {
390+ for (QuotaTariffUsageVO quotaTariffUsage : quotaTariffUsages ) {
391+ quotaTariffUsage .setQuotaUsageId (quotaUsageId );
392+ quotaTariffUsageDao .persistQuotaTariffUsage (quotaTariffUsage );
393+ }
394+ }
395+
396+ protected Map <QuotaTariffVO , BigDecimal > aggregateQuotaTariffsValues (UsageVO usageRecord , List <QuotaTariffVO > quotaTariffs , boolean hasAnyQuotaTariffWithActivationRule ,
397+ JsInterpreter jsInterpreter , String accountToString ) {
371398 String usageRecordToString = usageRecord .toString (usageAggregationTimeZone );
372399 logger .debug ("Validating usage record [{}] for account [{}] against [{}] quota tariffs." , usageRecordToString , accountToString , quotaTariffs .size ());
373400
374401 PresetVariables presetVariables = getPresetVariables (hasAnyQuotaTariffWithActivationRule , usageRecord );
375- BigDecimal aggregatedQuotaTariffsValue = BigDecimal . ZERO ;
402+ Map < QuotaTariffVO , BigDecimal > aggregatedQuotaTariffsAndValues = new HashMap <>() ;
376403
377404 quotaTariffs .sort (Comparator .comparing (QuotaTariffVO ::getPosition ));
378405
@@ -381,10 +408,9 @@ protected BigDecimal aggregateQuotaTariffsValues(UsageVO usageRecord, List<Quota
381408
382409 for (QuotaTariffVO quotaTariff : quotaTariffs ) {
383410 if (isQuotaTariffInPeriodToBeApplied (usageRecord , quotaTariff , accountToString )) {
384-
385411 BigDecimal tariffValue = getQuotaTariffValueToBeApplied (quotaTariff , jsInterpreter , presetVariables , lastTariffs );
386412
387- aggregatedQuotaTariffsValue = aggregatedQuotaTariffsValue . add ( tariffValue );
413+ aggregatedQuotaTariffsAndValues . put ( quotaTariff , tariffValue );
388414
389415 Tariff tariffPresetVariable = new Tariff ();
390416 tariffPresetVariable .setId (quotaTariff .getUuid ());
@@ -393,10 +419,10 @@ protected BigDecimal aggregateQuotaTariffsValues(UsageVO usageRecord, List<Quota
393419 }
394420 }
395421
396- logger .debug (String . format ( "The aggregation of the quota tariffs resulted in the value [%s] for the usage record [%s ]. We will use this value to calculate the final "
397- + " usage value." , aggregatedQuotaTariffsValue , usageRecordToString ) );
422+ logger .debug ("The aggregation of the quota tariffs resulted in [{}] quota tariffs for the usage record [{} ]. The values of the quota tariffs will be used "
423+ + " to calculate the final usage value." , aggregatedQuotaTariffsAndValues . size () , usageRecordToString );
398424
399- return aggregatedQuotaTariffsValue ;
425+ return aggregatedQuotaTariffsAndValues ;
400426 }
401427
402428 protected PresetVariables getPresetVariables (boolean hasAnyQuotaTariffWithActivationRule , UsageVO usageRecord ) {
@@ -407,6 +433,26 @@ protected PresetVariables getPresetVariables(boolean hasAnyQuotaTariffWithActiva
407433 return null ;
408434 }
409435
436+ protected QuotaTariffUsageVO createQuotaTariffUsage (UsageVO usageRecord , QuotaTariffVO quotaTariff , BigDecimal quotaTariffValue ) {
437+ BigDecimal quotaUsageValue = BigDecimal .ZERO ;
438+
439+ if (!quotaTariffValue .equals (BigDecimal .ZERO )) {
440+ String quotaUnit = QuotaTypes .getQuotaType (usageRecord .getUsageType ()).getQuotaUnit ();
441+ logger .trace ("Calculating the value of the quota tariff [{}] according to its value [{}] and its quota unit [{}]." , quotaTariff , quotaTariffValue , quotaUnit );
442+ quotaUsageValue = getUsageValueAccordingToUsageUnitType (usageRecord , quotaTariffValue , quotaUnit );
443+ logger .debug ("The calculation of the value of the quota tariff [{}] according to its value [{}] and its usage unit [{}] resulted in the value [{}]." ,
444+ quotaTariff , quotaTariffValue , quotaUnit , quotaUsageValue );
445+ } else {
446+ logger .debug ("Quota tariff [{}] has no value to be calculated; therefore, it will be marked as value zero." , quotaTariff );
447+ }
448+
449+ QuotaTariffUsageVO quotaTariffUsage = new QuotaTariffUsageVO ();
450+ quotaTariffUsage .setTariffId (quotaTariff .getId ());
451+ quotaTariffUsage .setQuotaUsed (quotaUsageValue );
452+
453+ return quotaTariffUsage ;
454+ }
455+
410456 /**
411457 * Returns the quota tariff value according to the result of the activation rule.<br/>
412458 * <ul>
0 commit comments