Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quota tariff order #8347

Merged
merged 19 commits into from
Jul 14, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
aecfb2f
quota tariff positions
JoaoJandre Dec 5, 2023
0104ded
Merge remote-tracking branch 'origin/main' into quota-tariff-order
JoaoJandre Dec 19, 2023
72f0cc2
Create integration test
JoaoJandre Dec 26, 2023
418f78a
Merge remote-tracking branch 'origin/main' into quota-tariff-order
JoaoJandre Feb 5, 2024
c388bea
change sql file
JoaoJandre Feb 5, 2024
2860a2d
Merge remote-tracking branch 'origin/main' into quota-tariff-order
JoaoJandre Feb 8, 2024
779e79f
Address reviews
JoaoJandre Feb 16, 2024
74b6baf
Merge remote-tracking branch 'origin/main' into quota-tariff-order
JoaoJandre Feb 20, 2024
732ee93
Merge remote-tracking branch 'origin/main' into quota-tariff-order
JoaoJandre Feb 27, 2024
b6557b4
Merge remote-tracking branch 'origin/main' into quota-tariff-order
JoaoJandre Mar 8, 2024
b33fd20
Merge remote-tracking branch 'origin/main' into quota-tariff-order
JoaoJandre Mar 14, 2024
fe519bb
Merge remote-tracking branch 'origin/main' into quota-tariff-order
JoaoJandre Mar 20, 2024
38b1f00
Address reviews
JoaoJandre Mar 20, 2024
ff7fa7c
use idempotent_add_column
JoaoJandre Apr 16, 2024
06eca87
Merge remote-tracking branch 'origin/main' into quota-tariff-order
JoaoJandre May 29, 2024
b1b3b2a
Merge remote-tracking branch 'origin/main' into quota-tariff-order
JoaoJandre May 31, 2024
1b1fa6b
Merge remote-tracking branch 'origin/main' into quota-tariff-order
JoaoJandre Jun 11, 2024
f0923dd
Merge remote-tracking branch 'origin/main' into quota-tariff-order
JoaoJandre Jun 14, 2024
9d31172
Merge remote-tracking branch 'origin/main' into quota-tariff-order
JoaoJandre Jul 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,7 @@ CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_email_configuration`(
PRIMARY KEY (`account_id`, `email_template_id`),
CONSTRAINT `FK_quota_email_configuration_account_id` FOREIGN KEY (`account_id`) REFERENCES `cloud_usage`.`quota_account`(`account_id`),
CONSTRAINT `FK_quota_email_configuration_email_template_id` FOREIGN KEY (`email_template_id`) REFERENCES `cloud_usage`.`quota_email_templates`(`id`));


-- Quota inject tariff result into subsequent ones
CALL `cloud_usage`.`IDEMPOTENT_ADD_COLUMN`('cloud_usage.quota_tariff', 'position', 'bigint(20) NOT NULL DEFAULT 1 COMMENT "Position in the execution sequence for tariffs of the same type"');
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
Expand All @@ -35,6 +36,7 @@
import org.apache.cloudstack.quota.activationrule.presetvariables.GenericPresetVariable;
import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariableHelper;
import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariables;
import org.apache.cloudstack.quota.activationrule.presetvariables.Tariff;
import org.apache.cloudstack.quota.constant.QuotaConfig;
import org.apache.cloudstack.quota.constant.QuotaTypes;
import org.apache.cloudstack.quota.dao.QuotaAccountDao;
Expand Down Expand Up @@ -367,9 +369,22 @@ protected BigDecimal aggregateQuotaTariffsValues(UsageVO usageRecord, List<Quota
PresetVariables presetVariables = getPresetVariables(hasAnyQuotaTariffWithActivationRule, usageRecord);
BigDecimal aggregatedQuotaTariffsValue = BigDecimal.ZERO;

quotaTariffs.sort(Comparator.comparing(QuotaTariffVO::getPosition));

List<Tariff> lastTariffs = new ArrayList<>();


for (QuotaTariffVO quotaTariff : quotaTariffs) {
if (isQuotaTariffInPeriodToBeApplied(usageRecord, quotaTariff, accountToString)) {
aggregatedQuotaTariffsValue = aggregatedQuotaTariffsValue.add(getQuotaTariffValueToBeApplied(quotaTariff, jsInterpreter, presetVariables));

BigDecimal tariffValue = getQuotaTariffValueToBeApplied(quotaTariff, jsInterpreter, presetVariables, lastTariffs);

aggregatedQuotaTariffsValue = aggregatedQuotaTariffsValue.add(tariffValue);

Tariff tariffPresetVariable = new Tariff();
tariffPresetVariable.setId(quotaTariff.getUuid());
tariffPresetVariable.setValue(tariffValue);
lastTariffs.add(tariffPresetVariable);
JoaoJandre marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down Expand Up @@ -397,7 +412,7 @@ protected PresetVariables getPresetVariables(boolean hasAnyQuotaTariffWithActiva
* <li>If the activation rule result in something else, returns {@link BigDecimal#ZERO}.</li>
* </ul>
*/
protected BigDecimal getQuotaTariffValueToBeApplied(QuotaTariffVO quotaTariff, JsInterpreter jsInterpreter, PresetVariables presetVariables) {
protected BigDecimal getQuotaTariffValueToBeApplied(QuotaTariffVO quotaTariff, JsInterpreter jsInterpreter, PresetVariables presetVariables, List<Tariff> lastAppliedTariffsList) {
String activationRule = quotaTariff.getActivationRule();
BigDecimal quotaTariffValue = quotaTariff.getCurrencyValue();
String quotaTariffToString = quotaTariff.toString(usageAggregationTimeZone);
Expand All @@ -409,6 +424,7 @@ protected BigDecimal getQuotaTariffValueToBeApplied(QuotaTariffVO quotaTariff, J
}

injectPresetVariablesIntoJsInterpreter(jsInterpreter, presetVariables);
jsInterpreter.injectVariable("lastTariffs", lastAppliedTariffsList.toString());

String scriptResult = jsInterpreter.executeScript(activationRule).toString();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package org.apache.cloudstack.quota.activationrule.presetvariables;

import java.math.BigDecimal;

public class Tariff extends GenericPresetVariable {
private BigDecimal value;

public BigDecimal getValue() {
return value;
}

Check warning on line 27 in framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Tariff.java

View check run for this annotation

Codecov / codecov/patch

framework/quota/src/main/java/org/apache/cloudstack/quota/activationrule/presetvariables/Tariff.java#L25-L27

Added lines #L25 - L27 were not covered by tests

public void setValue(BigDecimal value) {
this.value = value;
fieldNamesToIncludeInToString.add("value");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@
@Temporal(value = TemporalType.TIMESTAMP)
private Date endDate;

@Column(name = "position")
protected Integer position;


public QuotaTariffVO() {
}

Expand Down Expand Up @@ -120,6 +124,7 @@
this.setDescription(that.getDescription());
this.setActivationRule(that.getActivationRule());
this.setEndDate(that.getEndDate());
this.setPosition(that.getPosition());

Check warning on line 127 in framework/quota/src/main/java/org/apache/cloudstack/quota/vo/QuotaTariffVO.java

View check run for this annotation

Codecov / codecov/patch

framework/quota/src/main/java/org/apache/cloudstack/quota/vo/QuotaTariffVO.java#L127

Added line #L127 was not covered by tests
}

public void setId(Long id) {
Expand Down Expand Up @@ -263,6 +268,15 @@
return true;
}

public Integer getPosition() {
return position;
}

public void setPosition(Integer position) {
this.position = position;
}


@Override
public String toString() {
return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "uuid", "name", "usageName");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.apache.cloudstack.quota.activationrule.presetvariables.GenericPresetVariable;
import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariableHelper;
import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariables;
import org.apache.cloudstack.quota.activationrule.presetvariables.Tariff;
import org.apache.cloudstack.quota.activationrule.presetvariables.Value;
import org.apache.cloudstack.quota.constant.QuotaTypes;
import org.apache.cloudstack.quota.dao.QuotaTariffDao;
Expand Down Expand Up @@ -395,7 +396,7 @@ public void getQuotaTariffValueToBeAppliedTestActivationRuleIsNullReturnTariffVa
Mockito.doReturn(null).when(quotaTariffVoMock).getActivationRule();
Mockito.doReturn(BigDecimal.ONE).when(quotaTariffVoMock).getCurrencyValue();

BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, null, null);
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, null, null, null);

Assert.assertEquals(BigDecimal.ONE, result);
}
Expand All @@ -405,59 +406,66 @@ public void getQuotaTariffValueToBeAppliedTestActivationRuleIsEmptyReturnTariffV
Mockito.doReturn("").when(quotaTariffVoMock).getActivationRule();
Mockito.doReturn(BigDecimal.TEN).when(quotaTariffVoMock).getCurrencyValue();

BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, null, null);
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, null, null, null);

Assert.assertEquals(BigDecimal.TEN, result);
}

@Test
public void getQuotaTariffValueToBeAppliedTestScriptResultIsNumberReturnIt() {
BigDecimal expected = new BigDecimal(50.1);
List<Tariff> lastTariffs = createLastAppliedTariffsPresetVariableList(0);


Mockito.doReturn(" ").when(quotaTariffVoMock).getActivationRule();
Mockito.doReturn(BigDecimal.TEN).when(quotaTariffVoMock).getCurrencyValue();
Mockito.doNothing().when(quotaManagerImplSpy).injectPresetVariablesIntoJsInterpreter(Mockito.any(), Mockito.any());
Mockito.doReturn(expected).when(jsInterpreterMock).executeScript(Mockito.anyString());

BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock);
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock, lastTariffs);

Assert.assertEquals(expected, result);
}

@Test
public void getQuotaTariffValueToBeAppliedTestScriptResultIsTrueReturnTariffValue() {
BigDecimal expected = new BigDecimal(236.84);
List<Tariff> lastTariffs = createLastAppliedTariffsPresetVariableList(0);

Mockito.doReturn(" ").when(quotaTariffVoMock).getActivationRule();
Mockito.doReturn(expected).when(quotaTariffVoMock).getCurrencyValue();
Mockito.doNothing().when(quotaManagerImplSpy).injectPresetVariablesIntoJsInterpreter(Mockito.any(), Mockito.any());
Mockito.doReturn(true).when(jsInterpreterMock).executeScript(Mockito.anyString());

BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock);
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock, lastTariffs);

Assert.assertEquals(expected, result);
}

@Test
public void getQuotaTariffValueToBeAppliedTestScriptResultIsFalseReturnZero() {
List<Tariff> lastTariffs = createLastAppliedTariffsPresetVariableList(0);

Mockito.doReturn(" ").when(quotaTariffVoMock).getActivationRule();
Mockito.doReturn(BigDecimal.TEN).when(quotaTariffVoMock).getCurrencyValue();
Mockito.doNothing().when(quotaManagerImplSpy).injectPresetVariablesIntoJsInterpreter(Mockito.any(), Mockito.any());
Mockito.doReturn(false).when(jsInterpreterMock).executeScript(Mockito.anyString());

BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock);
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock, lastTariffs);

Assert.assertEquals(BigDecimal.ZERO, result);
}

@Test
public void getQuotaTariffValueToBeAppliedTestScriptResultIsNotBooleanNorNumericReturnZero() {
List<Tariff> lastTariffs = createLastAppliedTariffsPresetVariableList(0);

Mockito.doReturn(" ").when(quotaTariffVoMock).getActivationRule();
Mockito.doReturn(BigDecimal.TEN).when(quotaTariffVoMock).getCurrencyValue();
Mockito.doNothing().when(quotaManagerImplSpy).injectPresetVariablesIntoJsInterpreter(Mockito.any(), Mockito.any());
Mockito.doReturn("test").when(jsInterpreterMock).executeScript(Mockito.anyString());

BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock);
BigDecimal result = quotaManagerImplSpy.getQuotaTariffValueToBeApplied(quotaTariffVoMock, jsInterpreterMock, presetVariablesMock, lastTariffs);

Assert.assertEquals(BigDecimal.ZERO, result);
}
Expand All @@ -477,10 +485,7 @@ public void getPresetVariablesTestHasTariffsWithActivationRuleReturnPresetVariab

@Test
public void aggregateQuotaTariffsValuesTestTariffsWereNotInPeriodToBeAppliedReturnZero() {
List<QuotaTariffVO> tariffs = new ArrayList<>();
tariffs.add(new QuotaTariffVO());
tariffs.add(new QuotaTariffVO());
tariffs.add(new QuotaTariffVO());
List<QuotaTariffVO> tariffs = createTariffList();

Mockito.doReturn(false).when(quotaManagerImplSpy).isQuotaTariffInPeriodToBeApplied(Mockito.any(), Mockito.any(), Mockito.anyString());
BigDecimal result = quotaManagerImplSpy.aggregateQuotaTariffsValues(usageVoMock, tariffs, false, jsInterpreterMock, "");
Expand All @@ -497,13 +502,10 @@ public void aggregateQuotaTariffsValuesTestTariffsIsEmptyReturnZero() {

@Test
public void aggregateQuotaTariffsValuesTestTariffsAreInPeriodToBeAppliedReturnAggregation() {
List<QuotaTariffVO> tariffs = new ArrayList<>();
tariffs.add(new QuotaTariffVO());
tariffs.add(new QuotaTariffVO());
tariffs.add(new QuotaTariffVO());
List<QuotaTariffVO> tariffs = createTariffList();

Mockito.doReturn(true, false, true).when(quotaManagerImplSpy).isQuotaTariffInPeriodToBeApplied(Mockito.any(), Mockito.any(), Mockito.anyString());
Mockito.doReturn(BigDecimal.TEN).when(quotaManagerImplSpy).getQuotaTariffValueToBeApplied(Mockito.any(), Mockito.any(), Mockito.any());
Mockito.doReturn(BigDecimal.TEN).when(quotaManagerImplSpy).getQuotaTariffValueToBeApplied(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
BigDecimal result = quotaManagerImplSpy.aggregateQuotaTariffsValues(usageVoMock, tariffs, false, jsInterpreterMock, "");

Assert.assertEquals(BigDecimal.TEN.multiply(new BigDecimal(2)), result);
Expand All @@ -528,4 +530,25 @@ public void persistUsagesAndQuotaUsagesAndRetrievePersistedQuotaUsagesTestReturn
Assert.assertEquals(quotaUsageVoMock1, result.get(0));
Assert.assertEquals(quotaUsageVoMock2, result.get(1));
}

private static List<QuotaTariffVO> createTariffList() {
List<QuotaTariffVO> tariffs = new ArrayList<>();
tariffs.add(new QuotaTariffVO());
tariffs.add(new QuotaTariffVO());
tariffs.add(new QuotaTariffVO());
tariffs.forEach(quotaTariffVO -> quotaTariffVO.setPosition(1));
return tariffs;
}

private static List<Tariff> createLastAppliedTariffsPresetVariableList(int numberOfTariffs) {
List<Tariff> lastTariffs = new ArrayList<>();
for (int i = 0; i < numberOfTariffs; i++) {
Tariff tariff = new Tariff();
tariff.setId(String.valueOf(i));
tariff.setValue(BigDecimal.valueOf(i));
lastTariffs.add(tariff);
}
return lastTariffs;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
+ " endDate=2009-06-03.")
private Date endDate;

@Parameter(name = ApiConstants.POSITION, type = CommandType.INTEGER, description = "Position in the execution sequence for tariffs of the same type", since = "4.20.0.0")
JoaoJandre marked this conversation as resolved.
Show resolved Hide resolved
private Integer position;

@Override
public void execute() {
CallContext.current().setEventDetails(String.format("Tariff: %s, description: %s, value: %s", getName(), getDescription(), getValue()));
Expand Down Expand Up @@ -139,4 +142,13 @@
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.QuotaTariff;
}
public Integer getPosition() {
return position;
}

Check warning on line 147 in plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffCreateCmd.java

View check run for this annotation

Codecov / codecov/patch

plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffCreateCmd.java#L145-L147

Added lines #L145 - L147 were not covered by tests

public void setPosition(Integer position) {
this.position = position;
}

Check warning on line 151 in plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffCreateCmd.java

View check run for this annotation

Codecov / codecov/patch

plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffCreateCmd.java#L149-L151

Added lines #L149 - L151 were not covered by tests


}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@
"value will be applied. Inform empty to remove the activation rule.", length = 65535, since = "4.18.0.0")
private String activationRule;

@Parameter(name = ApiConstants.POSITION, type = CommandType.INTEGER, description = "Position in the execution sequence for tariffs of the same type", since = "4.20.0.0")
JoaoJandre marked this conversation as resolved.
Show resolved Hide resolved
private Integer position;

public Integer getUsageType() {
return usageType;
}
Expand Down Expand Up @@ -130,4 +133,13 @@
public ApiCommandResourceType getApiResourceType() {
return ApiCommandResourceType.QuotaTariff;
}

public Integer getPosition() {
return position;
}

Check warning on line 139 in plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java

View check run for this annotation

Codecov / codecov/patch

plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java#L137-L139

Added lines #L137 - L139 were not covered by tests

public void setPosition(Integer position) {
this.position = position;
}

Check warning on line 143 in plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java

View check run for this annotation

Codecov / codecov/patch

plugins/database/quota/src/main/java/org/apache/cloudstack/api/command/QuotaTariffUpdateCmd.java#L141-L143

Added lines #L141 - L143 were not covered by tests

}
Loading
Loading