Skip to content

Commit

Permalink
SWATCH-2897 Internal api to provide remittance response based on tall…
Browse files Browse the repository at this point in the history
…y_id

Add unit test for API endpoint

Signed-off-by: Kartik Shah <karshah@redhat.com>
  • Loading branch information
kartikshahc committed Sep 17, 2024
1 parent a06ba8f commit 77be0ce
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 1 deletion.
2 changes: 2 additions & 0 deletions swatch-billable-usage/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ dependencies {
implementation project(":swatch-model-billable-usage")
annotationProcessor enforcedPlatform(libraries["quarkus-bom"])
annotationProcessor "org.hibernate.orm:hibernate-jpamodelgen"
implementation libraries["mapstruct"]
annotationProcessor libraries["mapstruct-processor"]
testImplementation libraries["junit-jupiter"]
testImplementation "org.apache.kafka:kafka-streams-test-utils"
testImplementation 'io.smallrye.reactive:smallrye-reactive-messaging-in-memory'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@
import com.redhat.swatch.billable.usage.data.BillableUsageRemittanceRepository;
import com.redhat.swatch.billable.usage.data.RemittanceErrorCode;
import com.redhat.swatch.billable.usage.data.RemittanceSummaryProjection;
import com.redhat.swatch.billable.usage.model.RemittanceMapper;
import com.redhat.swatch.billable.usage.openapi.model.MonthlyRemittance;
import com.redhat.swatch.billable.usage.openapi.model.TallyRemittance;
import com.redhat.swatch.billable.usage.services.BillingProducer;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import java.time.OffsetDateTime;
import java.util.ArrayList;
Expand All @@ -47,6 +50,7 @@
public class InternalBillableUsageController {
private final BillableUsageRemittanceRepository remittanceRepository;
private final BillingProducer billingProducer;
@Inject protected RemittanceMapper remittanceMapper;

public List<MonthlyRemittance> getRemittances(BillableUsageRemittanceFilter filter) {
if (filter.getOrgId() == null) {
Expand All @@ -71,6 +75,10 @@ public List<MonthlyRemittance> getRemittances(BillableUsageRemittanceFilter filt
return accountRemittanceList;
}

public List<TallyRemittance> getRemittancesByTally(BillableUsageRemittanceFilter filter) {
return remittanceMapper.map(remittanceRepository.find(filter));
}

@Transactional
public int resetBillableUsageRemittance(
String productId, OffsetDateTime start, OffsetDateTime end, Set<String> orgIds) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.redhat.swatch.billable.usage.kafka.streams.FlushTopicService;
import com.redhat.swatch.billable.usage.openapi.model.DefaultResponse;
import com.redhat.swatch.billable.usage.openapi.model.MonthlyRemittance;
import com.redhat.swatch.billable.usage.openapi.model.TallyRemittance;
import com.redhat.swatch.billable.usage.openapi.resource.DefaultApi;
import com.redhat.swatch.billable.usage.services.EnabledOrgsProducer;
import jakarta.enterprise.context.ApplicationScoped;
Expand All @@ -35,6 +36,7 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.candlepin.clock.ApplicationClock;
Expand Down Expand Up @@ -84,6 +86,18 @@ public List<MonthlyRemittance> getRemittances(
return billingController.getRemittances(filter);
}

@Override
public List<TallyRemittance> getRemittancesByTally(String tallyId) throws ProcessingException {

BillableUsageRemittanceFilter filter =
BillableUsageRemittanceFilter.builder().tallyId(UUID.fromString(tallyId)).build();
List<TallyRemittance> tallyRemittances = billingController.getRemittancesByTally(filter);
if (tallyRemittances.isEmpty()) {
throw new BadRequestException("Tally id not found in billable usage remittance" + tallyId);
}
return tallyRemittances;
}

@Override
public DefaultResponse resetBillableUsageRemittance(
Set<String> orgIds, String productId, OffsetDateTime start, OffsetDateTime end) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import com.redhat.swatch.configuration.registry.MetricId;
import java.time.OffsetDateTime;
import java.util.UUID;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
Expand Down Expand Up @@ -50,6 +51,7 @@ public class BillableUsageRemittanceFilter {
private OffsetDateTime ending;
private String accumulationPeriod;
private boolean excludeFailures;
private UUID tallyId;

public static BillableUsageRemittanceFilter fromUsage(BillableUsage usage) {
return BillableUsageRemittanceFilter.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ private Specification<BillableUsageRemittanceEntity> buildSearchSpecification(
if (filter.isExcludeFailures()) {
searchCriteria = searchCriteria.and(excludesFailures());
}
if (Objects.nonNull(filter.getTallyId())) {
searchCriteria = searchCriteria.and(matchingTallyId(filter.getTallyId()));
}

return searchCriteria;
}
Expand Down Expand Up @@ -241,4 +244,9 @@ private static Specification<BillableUsageRemittanceEntity> matchingSla(String s
return (root, query, builder) ->
builder.equal(root.get(BillableUsageRemittanceEntity_.sla), sla);
}

private static Specification<BillableUsageRemittanceEntity> matchingTallyId(UUID tallyId) {
return (root, query, builder) ->
builder.equal(root.get(BillableUsageRemittanceEntity_.tallyId), tallyId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright Red Hat, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* Red Hat trademarks are not licensed under GPLv3. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package com.redhat.swatch.billable.usage.model;

import com.redhat.swatch.billable.usage.data.BillableUsageRemittanceEntity;
import com.redhat.swatch.billable.usage.openapi.model.TallyRemittance;
import java.util.List;
import org.mapstruct.Builder;
import org.mapstruct.CollectionMappingStrategy;
import org.mapstruct.Mapper;

@Mapper(
componentModel = "cdi",
collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
builder = @Builder(disableBuilder = true))
public interface RemittanceMapper {

TallyRemittance mapBillableUsageEntityToTallyRemittance(
BillableUsageRemittanceEntity billableUsageRemittanceEntity);

List<TallyRemittance> map(List<BillableUsageRemittanceEntity> billableUsageRemittanceEntities);
}
55 changes: 55 additions & 0 deletions swatch-billable-usage/src/main/resources/META-INF/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,30 @@ info:
name: SWATCH Dev
url: https://github.com/RedHatInsights/rhsm-subscriptions
paths:
/api/swatch-billable-usage/internal/remittance/accountRemittances/{tally_id}:
get:
operationId: getRemittancesByTally
summary: Get Account Remittance by Tally ID
description: Returns a single account remittance by tally ID.
parameters:
- name: tally_id
in: path
required: true
schema:
type: string
responses:
'200':
description: "Remittance records by tally id."
content:
application/json:
schema:
$ref: "#/components/schemas/TallyRemittances"
'400':
$ref: "../../../../../spec/error-responses.yaml#/$defs/BadRequest"
'403':
$ref: "../../../../../spec/error-responses.yaml#/$defs/Forbidden"
'500':
$ref: "../../../../../spec/error-responses.yaml#/$defs/InternalServerError"
/api/swatch-billable-usage/internal/remittance/accountRemittances:
description: 'Operations to get specific account remittances'
parameters:
Expand Down Expand Up @@ -219,6 +243,37 @@ components:
type: string
remittanceErrorCode:
type: string
TallyRemittances:
type: array
items:
$ref: "#/components/schemas/TallyRemittance"
TallyRemittance:
description: Encapsulates all Monthly remittance
properties:
orgId:
type: string
productId:
type: string
metricId:
type: string
billingProvider:
type: string
billingAccountId:
type: string
remittedPendingValue:
type: number
format: double
accumulationPeriod:
type: string
remittancePendingDate:
type: string
format: date-time
status:
type: string
errorCode:
type: string
tallyId:
type: string
OrgIds:
type: string
properties:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.redhat.swatch.billable.usage.kafka.InMemoryMessageBrokerKafkaResource;
import com.redhat.swatch.billable.usage.model.EnabledOrgsRequest;
import com.redhat.swatch.billable.usage.openapi.model.MonthlyRemittance;
import com.redhat.swatch.billable.usage.openapi.model.TallyRemittance;
import io.quarkus.test.InjectMock;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
Expand All @@ -47,6 +48,7 @@
import jakarta.transaction.Transactional;
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.UUID;
import org.apache.http.HttpStatus;
import org.awaitility.Awaitility;
import org.candlepin.subscriptions.billable.usage.BillableUsage;
Expand Down Expand Up @@ -123,6 +125,28 @@ void testGetRemittances() {
assertEquals(RemittanceErrorCode.UNKNOWN.getValue(), remittances[0].getRemittanceErrorCode());
}

@Test
void testGetRemittancesReturnsBadRequestWhenWrongTallyId() {
String tallyId = "e404074d-626f-4272-aa05-b6d69d6de16c";
given()
.get("/api/swatch-billable-usage/internal/remittance/accountRemittances/" + tallyId)
.then()
.statusCode(HttpStatus.SC_BAD_REQUEST);
}

@Test
void testGetRemittancesByTallyId() {
String tallyId = "c204074d-626f-4272-aa05-b6d69d6de16a";
givenRemittanceForTallyId(tallyId);
TallyRemittance[] remittances =
given()
.get("/api/swatch-billable-usage/internal/remittance/accountRemittances/" + tallyId)
.as(TallyRemittance[].class);
assertEquals(1, remittances.length);
assertEquals(ORG_ID, remittances[0].getOrgId());
assertEquals(RemittanceStatus.FAILED.name(), remittances[0].getStatus());
}

@Test
void testResetBillableUsageRemittance() {
givenRemittanceForOrgId(ORG_ID);
Expand All @@ -143,7 +167,7 @@ void testProcessRetries() {
.post("/api/swatch-billable-usage/internal/rpc/remittance/processRetries")
.then()
.statusCode(HttpStatus.SC_OK);
Awaitility.await().untilAsserted(() -> assertEquals(2, billableUsageSink.received().size()));
Awaitility.await().untilAsserted(() -> assertEquals(3, billableUsageSink.received().size()));
assertNull(remittanceRepository.findById(entity.getUuid()).getRetryAfter());
}

Expand Down Expand Up @@ -187,11 +211,34 @@ BillableUsageRemittanceEntity givenRemittanceForOrgId(String orgId) {
.status(RemittanceStatus.FAILED)
.errorCode(RemittanceErrorCode.UNKNOWN)
.retryAfter(OffsetDateTime.now().minusDays(1))
.tallyId(UUID.fromString("c204074d-626f-4272-aa05-b6d69d6de16a"))
.build();
remittanceRepository.persist(entity);
return entity;
}

@Transactional
void givenRemittanceForTallyId(String tallyId) {
var entity =
BillableUsageRemittanceEntity.builder()
.usage(BillableUsage.Usage.PRODUCTION.value())
.orgId(ORG_ID)
.billingProvider(BillableUsage.BillingProvider.AZURE.value())
.billingAccountId(String.format("%s_%s_ba", ORG_ID, PRODUCT_ID))
.productId(PRODUCT_ID)
.accumulationPeriod("mm-DD")
.sla(BillableUsage.Sla.PREMIUM.value())
.metricId("Cores")
.remittancePendingDate(OffsetDateTime.now())
.remittedPendingValue(2.0)
.status(RemittanceStatus.FAILED)
.errorCode(RemittanceErrorCode.UNKNOWN)
.retryAfter(OffsetDateTime.now().minusDays(1))
.tallyId(UUID.fromString(tallyId))
.build();
remittanceRepository.persist(entity);
}

private static void whenPurgeRemittances() {
given()
.post("/api/swatch-billable-usage/internal/rpc/remittance/purge")
Expand Down

0 comments on commit 77be0ce

Please sign in to comment.