blob: d22e400f4d4304001dec73430c0c288a841db61c [file] [log] [blame]
/*
* 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 com.epam.dlab.backendapi.dao;
import com.google.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import org.bson.conversions.Bson;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import static com.epam.dlab.backendapi.dao.MongoCollections.BILLING;
import static com.mongodb.client.model.Accumulators.sum;
import static com.mongodb.client.model.Aggregates.group;
import static com.mongodb.client.model.Aggregates.match;
import static com.mongodb.client.model.Filters.eq;
import static java.util.Collections.singletonList;
@Slf4j
public class BaseBillingDAO extends BaseDAO implements BillingDAO {
private static final String PROJECT = "project";
private static final int ONE_HUNDRED = 100;
private static final String TOTAL_FIELD_NAME = "total";
private static final String COST_FIELD = "$cost";
@Inject
protected SettingsDAO settings;
@Inject
private UserSettingsDAO userSettingsDAO;
@Inject
private ProjectDAO projectDAO;
@Override
public Double getTotalCost() {
return aggregateBillingData(singletonList(group(null, sum(TOTAL_FIELD_NAME, COST_FIELD))));
}
@Override
public Double getUserCost(String user) {
final List<Bson> pipeline = Arrays.asList(match(eq(USER, user)),
group(null, sum(TOTAL_FIELD_NAME, COST_FIELD)));
return aggregateBillingData(pipeline);
}
@Override
public Double getProjectCost(String project) {
final List<Bson> pipeline = Arrays.asList(match(eq(PROJECT, project)),
group(null, sum(TOTAL_FIELD_NAME, COST_FIELD)));
return aggregateBillingData(pipeline);
}
@Override
public int getBillingQuoteUsed() {
return toPercentage(() -> settings.getMaxBudget(), getTotalCost());
}
@Override
public int getBillingUserQuoteUsed(String user) {
return toPercentage(() -> userSettingsDAO.getAllowedBudget(user), getUserCost(user));
}
@Override
public boolean isBillingQuoteReached() {
return getBillingQuoteUsed() >= ONE_HUNDRED;
}
@Override
public boolean isUserQuoteReached(String user) {
final Double userCost = getUserCost(user);
return userSettingsDAO.getAllowedBudget(user)
.filter(allowedBudget -> userCost.intValue() != 0 && allowedBudget <= userCost)
.isPresent();
}
@Override
public boolean isProjectQuoteReached(String project) {
final Double projectCost = getProjectCost(project);
return projectDAO.getAllowedBudget(project)
.filter(allowedBudget -> projectCost.intValue() != 0 && allowedBudget <= projectCost)
.isPresent();
}
@Override
public int getBillingProjectQuoteUsed(String project) {
return toPercentage(() -> projectDAO.getAllowedBudget(project), getProjectCost(project));
}
private Integer toPercentage(Supplier<Optional<Integer>> allowedBudget, Double totalCost) {
return allowedBudget.get()
.map(userBudget -> (totalCost * ONE_HUNDRED) / userBudget)
.map(Double::intValue)
.orElse(BigDecimal.ZERO.intValue());
}
private Double aggregateBillingData(List<Bson> pipeline) {
return Optional.ofNullable(aggregate(BILLING, pipeline).first())
.map(d -> d.getDouble(TOTAL_FIELD_NAME))
.orElse(BigDecimal.ZERO.doubleValue());
}
}