diff --git a/pom.xml b/pom.xml index f5f0ce6..c9d7b51 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ - 6.5.200-SNAPSHOT + 6.5.317-SNAPSHOT 2.6 9.8.0 diff --git a/src/main/java/org.wso2.apim.monetization/impl/StripeMonetizationImpl.java b/src/main/java/org.wso2.apim.monetization/impl/StripeMonetizationImpl.java index 01f34d4..69b383b 100644 --- a/src/main/java/org.wso2.apim.monetization/impl/StripeMonetizationImpl.java +++ b/src/main/java/org.wso2.apim.monetization/impl/StripeMonetizationImpl.java @@ -41,6 +41,8 @@ import org.wso2.carbon.apimgt.api.MonetizationException; import org.wso2.carbon.apimgt.api.model.API; import org.wso2.carbon.apimgt.api.model.APIIdentifier; +import org.wso2.carbon.apimgt.api.model.APIProduct; +import org.wso2.carbon.apimgt.api.model.APIProductIdentifier; import org.wso2.carbon.apimgt.api.model.Monetization; import org.wso2.carbon.apimgt.api.model.MonetizationUsagePublishInfo; import org.wso2.carbon.apimgt.api.model.SubscribedAPI; @@ -400,7 +402,7 @@ public boolean enableMonetization(String tenantDomain, API api, Map getMonetizedPoliciesToPlanMapping(API api) throws Mon //throw MonetizationException as it will be logged and handled by the caller throw new MonetizationException(errorMessage, e); } catch (APIManagementException e) { - String errorMessage = "Failed to get API ID from database for : " + api.getId().getApiName() + + String errorMessage = "Failed to get ID from database for : " + api.getId().getApiName() + " when getting tier to billing engine plan mapping."; //throw MonetizationException as it will be logged and handled by the caller throw new MonetizationException(errorMessage, e); @@ -628,11 +630,11 @@ public boolean publishMonetizationUsageRecords(MonetizationUsagePublishInfo last jsonObj = apiUsageStatisticsRestClient.getUsageCountForMonetization(lastPublishInfo.getLastPublishTime(), currentTimestamp); } catch (APIMgtUsageQueryServiceClientException e) { - String errorMessage = "Failed to get the API Usage count for Monetization"; + String errorMessage = "Failed to get the usage count for monetization."; //throw MonetizationException as it will be logged and handled by the caller throw new MonetizationException(errorMessage, e); } - log.info("Usage record publisher is running"); + log.info("Usage record publisher is running."); SubscriptionItem subscriptionItem = null; try { if (jsonObj != null) { @@ -660,7 +662,7 @@ public boolean publishMonetizationUsageRecords(MonetizationUsagePublishInfo last Stripe.apiKey = getStripePlatformAccountKey(tenantDomain); } catch (StripeMonetizationException e) { String errorMessage = "Failed to get Stripe platform account key for tenant : " + - tenantDomain + " when disabling monetization for API : " + apiName; + tenantDomain + " when disabling monetization for : " + apiName; //throw MonetizationException as it will be logged and handled by the caller throw new MonetizationException(errorMessage, e); } finally { @@ -685,7 +687,7 @@ public boolean publishMonetizationUsageRecords(MonetizationUsagePublishInfo last connectedAccountKey = monetizationProperties.get (StripeMonetizationConstants.BILLING_ENGINE_CONNECTED_ACCOUNT_KEY); if (StringUtils.isBlank(connectedAccountKey)) { - String errorMessage = "Connected account stripe key was not found for API : " + String errorMessage = "Connected account stripe key was not found for : " + api.getId().getApiName(); //throw MonetizationException as it will be logged and handled by the caller throw new MonetizationException(errorMessage); @@ -697,7 +699,7 @@ public boolean publishMonetizationUsageRecords(MonetizationUsagePublishInfo last } } catch (APIManagementException e) { String errorMessage = "Failed to get the Stripe key of the connected account from " - + "the API : " + apiName; + + "the : " + apiName; //throw MonetizationException as it will be logged and handled by the caller throw new MonetizationException(errorMessage, e); } finally { @@ -791,18 +793,42 @@ public Map getCurrentUsageForSubscription(String subscriptionUUI try { SubscribedAPI subscribedAPI = ApiMgtDAO.getInstance().getSubscriptionByUUID(subscriptionUUID); APIIdentifier apiIdentifier = subscribedAPI.getApiId(); - API api = apiProvider.getAPI(apiIdentifier); - apiName = apiIdentifier.getApiName(); - if (api.getMonetizationProperties() == null) { - String errorMessage = "Monetization properties are empty for API : " + apiName; - //throw MonetizationException as it will be logged and handled by the caller - throw new MonetizationException(errorMessage); - } - HashMap monetizationDataMap = new Gson().fromJson(api.getMonetizationProperties().toString(), HashMap.class); - if (MapUtils.isEmpty(monetizationDataMap)) { - String errorMessage = "Monetization data map is empty for API : " + apiName; - //throw MonetizationException as it will be logged and handled by the caller - throw new MonetizationException(errorMessage); + APIProductIdentifier apiProductIdentifier; + API api; + APIProduct apiProduct; + HashMap monetizationDataMap; + int apiId; + if (apiIdentifier != null) { + api = apiProvider.getAPI(apiIdentifier); + apiName = apiIdentifier.getApiName(); + if (api.getMonetizationProperties() == null) { + String errorMessage = "Monetization properties are empty for : " + apiName; + //throw MonetizationException as it will be logged and handled by the caller + throw new MonetizationException(errorMessage); + } + monetizationDataMap = new Gson().fromJson(api.getMonetizationProperties().toString(), HashMap.class); + if (MapUtils.isEmpty(monetizationDataMap)) { + String errorMessage = "Monetization data map is empty for : " + apiName; + //throw MonetizationException as it will be logged and handled by the caller + throw new MonetizationException(errorMessage); + } + apiId = ApiMgtDAO.getInstance().getAPIID(apiIdentifier, null); + } else { + apiProductIdentifier = subscribedAPI.getProductId(); + apiProduct = apiProvider.getAPIProduct(apiProductIdentifier); + apiName = apiProductIdentifier.getName(); + if (apiProduct.getMonetizationProperties() == null) { + String errorMessage = "Monetization properties are empty for : " + apiName; + //throw MonetizationException as it will be logged and handled by the caller + throw new MonetizationException(errorMessage); + } + monetizationDataMap = new Gson().fromJson(apiProduct.getMonetizationProperties().toString(), HashMap.class); + if (MapUtils.isEmpty(monetizationDataMap)) { + String errorMessage = "Monetization data map is empty for : " + apiName; + //throw MonetizationException as it will be logged and handled by the caller + throw new MonetizationException(errorMessage); + } + apiId = ApiMgtDAO.getInstance().getAPIProductId(apiProductIdentifier); } String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain(); //get billing engine platform account key @@ -811,19 +837,18 @@ public Map getCurrentUsageForSubscription(String subscriptionUUI String connectedAccountKey = monetizationDataMap.get (StripeMonetizationConstants.BILLING_ENGINE_CONNECTED_ACCOUNT_KEY).toString(); if (StringUtils.isBlank(connectedAccountKey)) { - String errorMessage = "Connected account stripe key was not found for API : " + apiName; + String errorMessage = "Connected account stripe key was not found for : " + apiName; //throw MonetizationException as it will be logged and handled by the caller throw new MonetizationException(errorMessage); } Stripe.apiKey = platformAccountKey; //create request options to link with the connected account RequestOptions requestOptions = RequestOptions.builder().setStripeAccount(connectedAccountKey).build(); - int apiId = ApiMgtDAO.getInstance().getAPIID(apiIdentifier, null); int applicationId = subscribedAPI.getApplication().getId(); String billingPlanSubscriptionId = stripeMonetizationDAO.getBillingEngineSubscriptionId(apiId, applicationId); Subscription billingEngineSubscription = Subscription.retrieve(billingPlanSubscriptionId, requestOptions); if (billingEngineSubscription == null) { - String errorMessage = "No billing engine subscription was found for API : " + apiName; + String errorMessage = "No billing engine subscription was found for : " + apiName; //throw MonetizationException as it will be logged and handled by the caller throw new MonetizationException(errorMessage); } @@ -946,11 +971,11 @@ public Map getTotalRevenue(API api, APIProvider apiProvider) thr billingEngineUsageData.get("amount_due")); } } catch (APIManagementException e) { - String errorMessage = "Failed to get subscriptions of API : " + apiIdentifier.getApiName(); + String errorMessage = "Failed to get subscriptions of : " + apiIdentifier.getApiName(); //throw MonetizationException as it will be logged and handled by the caller throw new MonetizationException(errorMessage, e); } catch (StripeMonetizationException e) { - String errorMessage = "Failed to get subscription UUID of API : " + apiIdentifier.getApiName(); + String errorMessage = "Failed to get subscription UUID of : " + apiIdentifier.getApiName(); //throw MonetizationException as it will be logged and handled by the caller throw new MonetizationException(errorMessage, e); } diff --git a/src/main/java/org.wso2.apim.monetization/impl/workflow/StripeSubscriptionCreationWorkflowExecutor.java b/src/main/java/org.wso2.apim.monetization/impl/workflow/StripeSubscriptionCreationWorkflowExecutor.java index aca7d56..fb93034 100644 --- a/src/main/java/org.wso2.apim.monetization/impl/workflow/StripeSubscriptionCreationWorkflowExecutor.java +++ b/src/main/java/org.wso2.apim.monetization/impl/workflow/StripeSubscriptionCreationWorkflowExecutor.java @@ -40,6 +40,7 @@ import org.wso2.carbon.apimgt.api.WorkflowResponse; import org.wso2.carbon.apimgt.api.model.API; import org.wso2.carbon.apimgt.api.model.APIIdentifier; +import org.wso2.carbon.apimgt.api.model.APIProduct; import org.wso2.carbon.apimgt.api.model.Subscriber; import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO; @@ -175,6 +176,77 @@ public WorkflowResponse monetizeSubscription(WorkflowDTO workflowDTO, API api) t return execute(workflowDTO); } + @Override + public WorkflowResponse monetizeSubscription(WorkflowDTO workflowDTO, APIProduct apiProduct) + throws WorkflowException { + + boolean isMonetizationEnabled = false; + SubscriptionWorkflowDTO subWorkFlowDTO = null; + String stripePlatformAccountKey = null; + Subscriber subscriber = null; + Customer customer = null; + Customer sharedCustomerBE = null; + MonetizationPlatformCustomer monetizationPlatformCustomer; + MonetizationSharedCustomer monetizationSharedCustomer; + ApiMgtDAO apiMgtDAO = ApiMgtDAO.getInstance(); + subWorkFlowDTO = (SubscriptionWorkflowDTO) workflowDTO; + //read the platform account key of Stripe + Stripe.apiKey = getPlatformAccountKey(subWorkFlowDTO.getTenantId()); + String connectedAccountKey = StringUtils.EMPTY; + Map monetizationProperties = new Gson().fromJson(apiProduct.getMonetizationProperties().toString(), + HashMap.class); + if (MapUtils.isNotEmpty(monetizationProperties) && + monetizationProperties.containsKey(StripeMonetizationConstants.BILLING_ENGINE_CONNECTED_ACCOUNT_KEY)) { + connectedAccountKey = monetizationProperties.get + (StripeMonetizationConstants.BILLING_ENGINE_CONNECTED_ACCOUNT_KEY); + if (StringUtils.isBlank(connectedAccountKey)) { + String errorMessage = "Connected account stripe key was not found for : " + + apiProduct.getId().getName(); + log.error(errorMessage); + throw new WorkflowException(errorMessage); + } + } else { + String errorMessage = "Stripe key of the connected account is empty."; + log.error(errorMessage); + throw new WorkflowException(errorMessage); + } + //needed to create artifacts in the stripe connected account + RequestOptions requestOptions = RequestOptions.builder().setStripeAccount(connectedAccountKey).build(); + try { + subscriber = apiMgtDAO.getSubscriber(subWorkFlowDTO.getSubscriber()); + // check whether the application is already registered as a customer under the particular + // APIprovider/Connected Account in Stripe + monetizationSharedCustomer = stripeMonetizationDAO.getSharedCustomer(subWorkFlowDTO.getApplicationId(), + subWorkFlowDTO.getApiProvider(), subWorkFlowDTO.getTenantId()); + if (monetizationSharedCustomer.getSharedCustomerId() == null) { + // checks whether the subscriber is already registered as a customer Under the + // tenant/Platform account in Stripe + monetizationPlatformCustomer = stripeMonetizationDAO.getPlatformCustomer(subscriber.getId(), + subscriber.getTenantId()); + if (monetizationPlatformCustomer.getCustomerId() == null) { + monetizationPlatformCustomer = createMonetizationPlatformCutomer(subscriber); + } + monetizationSharedCustomer = createSharedCustomer(subscriber.getEmail(), monetizationPlatformCustomer, + requestOptions, subWorkFlowDTO); + } + //creating Subscriptions + int apiId = ApiMgtDAO.getInstance().getAPIProductId(apiProduct.getId()); + String planId = stripeMonetizationDAO.getBillingEnginePlanIdForTier(apiId, subWorkFlowDTO.getTierName()); + createMonetizedSubscriptions(planId, monetizationSharedCustomer, requestOptions, subWorkFlowDTO); + } catch (APIManagementException e) { + String errorMessage = "Could not monetize subscription for : " + subWorkFlowDTO.getApiName() + + " by application : " + subWorkFlowDTO.getApplicationName(); + log.error(errorMessage); + throw new WorkflowException(errorMessage, e); + } catch (StripeMonetizationException e) { + String errorMessage = "Could not monetize subscription for : " + subWorkFlowDTO.getApiName() + + " by application " + subWorkFlowDTO.getApplicationName(); + log.error(errorMessage); + throw new WorkflowException(errorMessage, e); + } + return execute(workflowDTO); + } + /** * Returns the stripe key of the platform/tenant * diff --git a/src/main/java/org.wso2.apim.monetization/impl/workflow/StripeSubscriptionDeletionWorkflowExecutor.java b/src/main/java/org.wso2.apim.monetization/impl/workflow/StripeSubscriptionDeletionWorkflowExecutor.java index 1535718..5bfe95d 100644 --- a/src/main/java/org.wso2.apim.monetization/impl/workflow/StripeSubscriptionDeletionWorkflowExecutor.java +++ b/src/main/java/org.wso2.apim.monetization/impl/workflow/StripeSubscriptionDeletionWorkflowExecutor.java @@ -35,6 +35,7 @@ import org.wso2.carbon.apimgt.api.WorkflowResponse; import org.wso2.carbon.apimgt.api.model.API; import org.wso2.carbon.apimgt.api.model.APIIdentifier; +import org.wso2.carbon.apimgt.api.model.APIProduct; import org.wso2.carbon.apimgt.impl.APIConstants; import org.wso2.carbon.apimgt.impl.dao.ApiMgtDAO; import org.wso2.carbon.apimgt.impl.dto.SubscriptionWorkflowDTO; @@ -114,7 +115,7 @@ public WorkflowResponse deleteMonetizedSubscription(WorkflowDTO workflowDTO, API connectedAccountKey = monetizationProperties.get (StripeMonetizationConstants.BILLING_ENGINE_CONNECTED_ACCOUNT_KEY); if (StringUtils.isBlank(connectedAccountKey)) { - String errorMessage = "Connected account stripe key was not found for API : " + String errorMessage = "Connected account stripe key was not found for : " + api.getId().getApiName(); log.error(errorMessage); throw new WorkflowException(errorMessage); @@ -132,7 +133,7 @@ public WorkflowResponse deleteMonetizedSubscription(WorkflowDTO workflowDTO, API subWorkflowDTO.getApiVersion(), subWorkflowDTO.getApiProvider(), subWorkflowDTO.getApplicationId(), subWorkflowDTO.getTenantDomain()); } catch (StripeMonetizationException ex) { - String errorMessage = "Could not retrieve monetized subscription info for API : " + String errorMessage = "Could not retrieve monetized subscription info for : " + subWorkflowDTO.getApplicationName() + " by Application : " + subWorkflowDTO.getApplicationName(); throw new WorkflowException(errorMessage, ex); } @@ -148,17 +149,88 @@ public WorkflowResponse deleteMonetizedSubscription(WorkflowDTO workflowDTO, API stripeMonetizationDAO.removeMonetizedSubscription(monetizedSubscription.getId()); } if (log.isDebugEnabled()) { - String msg = "Monetized subscriprion for API : " + subWorkflowDTO.getApiName() + String msg = "Monetized subscriprion for : " + subWorkflowDTO.getApiName() + " by Application : " + subWorkflowDTO.getApplicationName() + " is removed successfully "; log.debug(msg); } } catch (StripeException ex) { - String errorMessage = "Failed to remove subcription in billing engine for API : " + String errorMessage = "Failed to remove subcription in billing engine for : " + subWorkflowDTO.getApiName() + " by Application : " + subWorkflowDTO.getApplicationName(); log.error(errorMessage); throw new WorkflowException(errorMessage, ex); } catch (StripeMonetizationException ex) { - String errorMessage = "Failed to remove monetization subcription info from DB of API : " + String errorMessage = "Failed to remove monetization subcription info from DB of : " + + subWorkflowDTO.getApiName() + " by Application : " + subWorkflowDTO.getApplicationName(); + log.error(errorMessage); + throw new WorkflowException(errorMessage, ex); + } + } + return execute(workflowDTO); + } + + @Override + public WorkflowResponse deleteMonetizedSubscription(WorkflowDTO workflowDTO, APIProduct apiProduct) + throws WorkflowException { + + SubscriptionWorkflowDTO subWorkflowDTO; + MonetizedSubscription monetizedSubscription; + StripeMonetizationDAO stripeMonetizationDAO = new StripeMonetizationDAO(); + subWorkflowDTO = (SubscriptionWorkflowDTO) workflowDTO; + //read the platform key of Stripe + Stripe.apiKey = getPlatformAccountKey(subWorkflowDTO.getTenantId()); + String connectedAccountKey = StringUtils.EMPTY; + Map monetizationProperties = new Gson().fromJson(apiProduct.getMonetizationProperties().toString(), + HashMap.class); + if (MapUtils.isNotEmpty(monetizationProperties) && + monetizationProperties.containsKey(StripeMonetizationConstants.BILLING_ENGINE_CONNECTED_ACCOUNT_KEY)) { + // get the key of the connected account + connectedAccountKey = monetizationProperties.get + (StripeMonetizationConstants.BILLING_ENGINE_CONNECTED_ACCOUNT_KEY); + if (StringUtils.isBlank(connectedAccountKey)) { + String errorMessage = "Connected account stripe key was not found for : " + apiProduct.getId().getName(); + log.error(errorMessage); + throw new WorkflowException(errorMessage); + } + } else { + String errorMessage = "Stripe key of the connected account is empty."; + log.error(errorMessage); + throw new WorkflowException(errorMessage); + } + //needed to add,remove artifacts in connected account + RequestOptions requestOptions = RequestOptions.builder().setStripeAccount(connectedAccountKey).build(); + try { + //get the stripe subscription id + monetizedSubscription = stripeMonetizationDAO.getMonetizedSubscription(subWorkflowDTO.getApiName(), + subWorkflowDTO.getApiVersion(), subWorkflowDTO.getApiProvider(), subWorkflowDTO.getApplicationId(), + subWorkflowDTO.getTenantDomain()); + } catch (StripeMonetizationException ex) { + String errorMessage = "Could not retrieve monetized subscription info for : " + + subWorkflowDTO.getApplicationName() + " by application : " + subWorkflowDTO.getApplicationName(); + throw new WorkflowException(errorMessage, ex); + } + if (monetizedSubscription.getSubscriptionId() != null) { + try { + Subscription subscription = Subscription.retrieve(monetizedSubscription.getSubscriptionId(), + requestOptions); + Map params = new HashMap<>(); + //canceled subscription will be invoiced immediately + params.put(StripeMonetizationConstants.INVOICE_NOW, true); + subscription = subscription.cancel(params, requestOptions); + if (StringUtils.equals(subscription.getStatus(), StripeMonetizationConstants.CANCELED)) { + stripeMonetizationDAO.removeMonetizedSubscription(monetizedSubscription.getId()); + } + if (log.isDebugEnabled()) { + String msg = "Monetized subscriprion for : " + subWorkflowDTO.getApiName() + + " by application : " + subWorkflowDTO.getApplicationName() + " is removed successfully "; + log.debug(msg); + } + } catch (StripeException ex) { + String errorMessage = "Failed to remove subcription in billing engine for : " + + subWorkflowDTO.getApiName() + " by Application : " + subWorkflowDTO.getApplicationName(); + log.error(errorMessage); + throw new WorkflowException(errorMessage, ex); + } catch (StripeMonetizationException ex) { + String errorMessage = "Failed to remove monetization subcription info from DB of : " + subWorkflowDTO.getApiName() + " by Application : " + subWorkflowDTO.getApplicationName(); log.error(errorMessage); throw new WorkflowException(errorMessage, ex);