Skip to content

Commit

Permalink
feat: implementing gated top down allocation table subsidy service ap…
Browse files Browse the repository at this point in the history
…i usage
  • Loading branch information
alex-sheehan-edx committed Nov 7, 2023
1 parent d518a4d commit c524738
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,22 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';

import LearnerCreditAllocationTable from './LearnerCreditAllocationTable';
import { useBudgetId, useOfferRedemptions } from './data';
import { useBudgetId, useOfferRedemptions, useSubsidyAccessPolicy } from './data';

const BudgetDetailRedemptions = ({ enterpriseUUID }) => {
const BudgetDetailRedemptions = ({ enterpriseFeatures, enterpriseUUID }) => {
const { enterpriseOfferId, subsidyAccessPolicyId } = useBudgetId();
const { data: subsidyAccessPolicy } = useSubsidyAccessPolicy(subsidyAccessPolicyId);
const {
isLoading,
offerRedemptions,
fetchOfferRedemptions,
} = useOfferRedemptions(enterpriseUUID, enterpriseOfferId, subsidyAccessPolicyId);

} = useOfferRedemptions(
enterpriseUUID,
enterpriseOfferId,
subsidyAccessPolicyId,
enterpriseFeatures.topDownAssignmentRealTimeLcm,
subsidyAccessPolicy.subsidyUuid,
);
return (
<section>
<h3 className="mb-3">Spent</h3>
Expand All @@ -30,11 +36,15 @@ const BudgetDetailRedemptions = ({ enterpriseUUID }) => {
};

const mapStateToProps = state => ({
enterpriseFeatures: state.portalConfiguration.enterpriseFeatures,
enterpriseUUID: state.portalConfiguration.enterpriseId,
});

BudgetDetailRedemptions.propTypes = {
enterpriseUUID: PropTypes.string.isRequired,
enterpriseFeatures: PropTypes.shape({
topDownAssignmentRealTimeLcm: PropTypes.bool,
}).isRequired,
};

export default connect(mapStateToProps)(BudgetDetailRedemptions);
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils';
import debounce from 'lodash.debounce';

import EnterpriseDataApiService from '../../../../data/services/EnterpriseDataApiService';
import SubsidyApiService from '../../../../data/services/EnterpriseSubsidyApiService';
import { API_FIELDS_BY_TABLE_COLUMN_ACCESSOR } from '../constants';
import { transformUtilizationTableResults } from '../utils';
import { transformUtilizationTableResults, transformUtilizationTableTransactionResults } from '../utils';

const applySortByToOptions = (sortBy, options) => {
const orderingStrings = sortBy.map(({ id, desc }) => {
Expand All @@ -29,19 +30,27 @@ const applySortByToOptions = (sortBy, options) => {
});
};

const applyFiltersToOptions = (filters, options) => {
const applyFiltersToOptions = (filters, options, fetchTransactions = null) => {
const courseProductLineSearchQuery = filters?.find(filter => filter.id === 'courseProductLine')?.value;
const searchQuery = filters?.find(filter => filter.id.toLowerCase() === 'enrollment details')?.value;
const searchQuery = filters?.find(filter => filter.id.toLowerCase() === 'enrollmentdetails')?.value;

if (courseProductLineSearchQuery) {
Object.assign(options, { courseProductLine: courseProductLineSearchQuery });
}
if (searchQuery) {
Object.assign(options, { searchAll: searchQuery });
const optionsObject = {};
optionsObject[fetchTransactions ? 'search' : 'searchAll'] = searchQuery;
Object.assign(options, optionsObject);
}
};

const useOfferRedemptions = (enterpriseUUID, offerId = null, budgetId = null) => {
const useOfferRedemptions = (
enterpriseUUID,
offerId = null,
budgetId = null,
fetchTransactions = null,
subsidyUuid = null,
) => {
const shouldTrackFetchEvents = useRef(false);
const [isLoading, setIsLoading] = useState(true);
const [offerRedemptions, setOfferRedemptions] = useState({
Expand Down Expand Up @@ -69,14 +78,27 @@ const useOfferRedemptions = (enterpriseUUID, offerId = null, budgetId = null) =>
applySortByToOptions(args.sortBy, options);
}
if (args.filters?.length > 0) {
applyFiltersToOptions(args.filters, options);
applyFiltersToOptions(args.filters, options, fetchTransactions);
}
const response = await EnterpriseDataApiService.fetchCourseEnrollments(
enterpriseUUID,
options,
);
const data = camelCaseObject(response.data);
const transformedTableResults = transformUtilizationTableResults(data.results);
let data;
let transformedTableResults;
if (offerId === null && fetchTransactions) { // and do the feature flag check here
const response = await SubsidyApiService.fetchCustomerTransactions(
enterpriseUUID,
subsidyUuid,
options,
);
data = camelCaseObject(response.data);
transformedTableResults = transformUtilizationTableTransactionResults(data.results);
} else {
const response = await EnterpriseDataApiService.fetchCourseEnrollments(
enterpriseUUID,
options,
);
data = camelCaseObject(response.data);
transformedTableResults = transformUtilizationTableResults(data.results);
}

setOfferRedemptions({
itemCount: data.count,
pageCount: data.numPages,
Expand Down Expand Up @@ -104,7 +126,7 @@ const useOfferRedemptions = (enterpriseUUID, offerId = null, budgetId = null) =>
if (offerId || budgetId) {
fetch();
}
}, [enterpriseUUID, offerId, budgetId, shouldTrackFetchEvents]);
}, [enterpriseUUID, offerId, budgetId, shouldTrackFetchEvents, fetchTransactions, subsidyUuid]);

const debouncedFetchOfferRedemptions = useMemo(() => debounce(fetchOfferRedemptions, 300), [fetchOfferRedemptions]);

Expand Down
10 changes: 10 additions & 0 deletions src/components/learner-credit-management/data/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ export const transformUtilizationTableResults = results => results.map(result =>
courseKey: result.courseKey,
}));

export const transformUtilizationTableTransactionResults = results => results.map(result => ({
created: result.created,
enterpriseEnrollmentId: result.fulfillmentIdentifier,
userEmail: result.lmsUserEmail,
courseTitle: result.contentTitle,
courseListPrice: result.unit === 'usd_cents' ? -1 * (result.quantity / 100) : -1 * results.quantity,
uuid: uuidv4(),
courseKey: result.contentKey,
}));

/**
* Gets appropriate color variant for the annotated progress bar.
*
Expand Down
12 changes: 12 additions & 0 deletions src/data/services/EnterpriseSubsidyApiService.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,20 @@ import { configuration } from '../../config';
class SubsidyApiService {
static baseUrl = `${configuration.ENTERPRISE_SUBSIDY_BASE_URL}/api/v1`;

static subsidyV2Url = `${configuration.ENTERPRISE_SUBSIDY_BASE_URL}/api/v2/subsidies`;

static apiClient = getAuthenticatedHttpClient;

static fetchCustomerTransactions(customerUuid, subsidyUuid, options = {}) {
const queryParams = new URLSearchParams({
...snakeCaseObject(options),
});
const url = `${SubsidyApiService.subsidyV2Url}/${subsidyUuid}/transactions/?${queryParams.toString()}`;
return SubsidyApiService.apiClient({
useCache: configuration.USE_API_CACHE,
}).get(url, { clearCacheEntry: true });
}

static getSubsidyByCustomerUUID(uuid, options = {}) {
const queryParams = new URLSearchParams({
enterprise_customer_uuid: uuid,
Expand Down

0 comments on commit c524738

Please sign in to comment.