From 5ad9e3e6b452ae767056cf5ebca4ea726c48d3ba Mon Sep 17 00:00:00 2001 From: osh Date: Tue, 5 Apr 2022 22:59:23 +0530 Subject: [PATCH] Add billing data export api fixes https://gitlab.com/entgra/product-iots/-/issues/1226 --- .../device/mgt/jaxrs/beans/DeviceList.java | 22 ++ .../service/api/DeviceManagementService.java | 77 ++++++ .../impl/DeviceManagementServiceImpl.java | 157 +++++++---- .../carbon/device/mgt/common/Billing.java | 118 ++++++++ .../device/mgt/common/PaginationResult.java | 22 ++ .../mgt/core/DeviceManagementConstants.java | 1 + .../device/mgt/core/config/ui/Billing.java | 20 ++ .../device/mgt/core/dao/BillingDAO.java | 13 + .../carbon/device/mgt/core/dao/DeviceDAO.java | 18 +- .../core/dao/DeviceManagementDAOFactory.java | 6 + .../mgt/core/dao/impl/BillingDAOImpl.java | 71 +++++ .../dao/impl/device/GenericDeviceDAOImpl.java | 43 +-- .../dao/impl/device/OracleDeviceDAOImpl.java | 7 +- .../impl/device/PostgreSQLDeviceDAOImpl.java | 7 +- .../impl/device/SQLServerDeviceDAOImpl.java | 7 +- .../DeviceManagementProviderService.java | 11 + .../DeviceManagementProviderServiceImpl.java | 261 +++++++++++++----- 17 files changed, 664 insertions(+), 197 deletions(-) create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/Billing.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/BillingDAO.java create mode 100644 components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/BillingDAOImpl.java diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/beans/DeviceList.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/beans/DeviceList.java index 82a7131c403..8c6c4945c4c 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/beans/DeviceList.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/beans/DeviceList.java @@ -32,6 +32,12 @@ public class DeviceList extends BasePaginatedResult { @ApiModelProperty(name = "totalCost", value = "Total cost of all devices per tenant", required = false) private double totalCost; + @ApiModelProperty(name = "message", value = "Send information text to the billing UI", required = false) + private String message; + + @ApiModelProperty(name = "billedDateIsValid", value = "Check if user entered date is valid", required = false) + private boolean billedDateIsValid; + @ApiModelProperty(value = "List of devices returned") @JsonProperty("devices") public List getList() { @@ -42,6 +48,22 @@ public class DeviceList extends BasePaginatedResult { this.devices = devices; } + public boolean isBilledDateIsValid() { + return billedDateIsValid; + } + + public void setBilledDateIsValid(boolean billedDateIsValid) { + this.billedDateIsValid = billedDateIsValid; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + public double getTotalCost() { return totalCost; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java index 2cf1352b34b..e2d88ea046a 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java @@ -432,6 +432,83 @@ public interface DeviceManagementService { @QueryParam("limit") int limit); + + @GET + @Path("/billing/file") + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation( + produces = MediaType.APPLICATION_JSON, + httpMethod = "GET", + value = "Getting Cost details of devices in a tenant", + notes = "Provides individual cost and total cost of all devices per tenant.", + tags = "Device Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view") + }) + } + ) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK. \n Successfully fetched the list of devices.", + response = DeviceList.class, + responseHeaders = { + @ResponseHeader( + name = "Content-Type", + description = "The content type of the body"), + @ResponseHeader( + name = "Content-Disposition", + description = "The content disposition of the body"), + @ResponseHeader( + name = "ETag", + description = "Entity Tag of the response resource.\n" + + "Used by caches, or in conditional requests."), + @ResponseHeader( + name = "Last-Modified", + description = "Date and time the resource was last modified.\n" + + "Used by caches, or in conditional requests."), + }), + @ApiResponse( + code = 304, + message = "Not Modified. \n Empty body because the client already has the latest version of " + + "the requested resource.\n"), + @ApiResponse( + code = 400, + message = "The incoming request has more than one selection criteria defined via the query parameters.", + response = ErrorResponse.class), + @ApiResponse( + code = 404, + message = "The search criteria did not match any device registered with the server.", + response = ErrorResponse.class), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n The requested media type is not supported."), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Server error occurred while fetching the device list.", + response = ErrorResponse.class) + }) + Response exportBilling( + @ApiParam( + name = "tenantDomain", + value = "The tenant domain.", + required = false) + String tenantDomain, + @ApiParam( + name = "startDate", + value = "The start date.", + required = false) + Timestamp startDate, + @ApiParam( + name = "endDate", + value = "The end date.", + required = false) + Timestamp endDate, + @ApiParam( + name = "generateBill", + value = "The generate bill boolean.", + required = false) + boolean generateBill); + @GET @Produces(MediaType.APPLICATION_JSON) @ApiOperation( diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java index a54bdae7349..6e6882cfb85 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java @@ -124,24 +124,12 @@ import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import javax.validation.Valid; import javax.validation.constraints.Size; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; -import javax.ws.rs.DefaultValue; +import javax.ws.rs.*; import javax.ws.rs.core.Response; import java.sql.Timestamp; -import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; -import java.util.ArrayList; -import java.util.Properties; +import java.util.*; @Path("/devices") public class DeviceManagementServiceImpl implements DeviceManagementService { @@ -217,8 +205,8 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { } if (status != null && !status.isEmpty()) { boolean isStatusEmpty = true; - for (String statusString : status){ - if (StringUtils.isNotBlank(statusString)){ + for (String statusString : status) { + if (StringUtils.isNotBlank(statusString)) { isStatusEmpty = false; break; } @@ -348,10 +336,10 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { @Override @Path("/billing") public Response getDevicesBilling( - @QueryParam ("tenantDomain") String tenantDomain, - @QueryParam ("startDate") Timestamp startDate, - @QueryParam ("endDate") Timestamp endDate, - @QueryParam ("generateBill") boolean generateBill, + @QueryParam("tenantDomain") String tenantDomain, + @QueryParam("startDate") Timestamp startDate, + @QueryParam("endDate") Timestamp endDate, + @QueryParam("generateBill") boolean generateBill, @QueryParam("offset") int offset, @DefaultValue("10") @QueryParam("limit") int limit) { @@ -385,11 +373,12 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { } devices.setList((List) result.getData()); + devices.setBilledDateIsValid(result.isBilledDateIsValid()); + devices.setMessage(result.getMessage()); devices.setCount(result.getRecordsTotal()); devices.setTotalCost(result.getTotalCost()); return Response.status(Response.Status.OK).entity(devices).build(); - } - catch (Exception e) { + } catch (Exception e) { String msg = "Error occurred while retrieving billing data"; log.error(msg, e); return Response.serverError().entity( @@ -397,6 +386,51 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { } } + @GET + @Override + @Path("/billing/file") + public Response exportBilling( + @QueryParam("tenantDomain") String tenantDomain, + @QueryParam("startDate") Timestamp startDate, + @QueryParam("endDate") Timestamp endDate, + @QueryParam("generateBill") boolean generateBill) { + + try { + DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService(); + PaginationResult result; + int tenantId = 0; + RealmService realmService = DeviceMgtAPIUtils.getRealmService(); + DeviceList devices = new DeviceList(); + + if (!tenantDomain.isEmpty()) { + tenantId = realmService.getTenantManager().getTenantId(tenantDomain); + } else { + tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId(); + } + + try { + result = dms.createBillingFile(tenantId, tenantDomain, startDate, endDate, generateBill); + + } catch (Exception exception) { + String msg = "Error occurred when trying to retrieve billing data without pagination"; + log.error(msg, exception); + return null; + } + + devices.setList((List) result.getData()); + devices.setBilledDateIsValid(result.isBilledDateIsValid()); + devices.setMessage(result.getMessage()); + devices.setCount(result.getRecordsTotal()); + devices.setTotalCost(result.getTotalCost()); + return Response.status(Response.Status.OK).entity(devices).build(); + } catch (Exception e) { + String msg = "Error occurred while retrieving billing data without pagination"; + log.error(msg, e); + return null; + } + + } + @GET @Override @Path("/user-devices") @@ -433,8 +467,8 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { * Validate group Id and group Id greater than 0 and exist. * * @param groupId Group ID of the group - * @param from time to start getting DeviceLocationHistorySnapshotWrapper in milliseconds - * @param to time to end getting DeviceLocationHistorySnapshotWrapper in milliseconds + * @param from time to start getting DeviceLocationHistorySnapshotWrapper in milliseconds + * @param to time to end getting DeviceLocationHistorySnapshotWrapper in milliseconds */ private static void validateGroupId(int groupId, long from, long to) throws GroupManagementException, BadRequestException { if (from == 0 || to == 0) { @@ -463,7 +497,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { @QueryParam("to") long to, @QueryParam("type") String type, @DefaultValue("0") @QueryParam("offset") int offset, - @DefaultValue("100") @QueryParam("limit") int limit){ + @DefaultValue("100") @QueryParam("limit") int limit) { try { RequestValidationUtil.validatePaginationParameters(offset, limit); DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService(); @@ -472,31 +506,31 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { // this is the user who initiates the request String authorizedUser = CarbonContext.getThreadLocalCarbonContext().getUsername(); - try { - validateGroupId(groupId, from, to); - boolean isPermitted = DeviceMgtAPIUtils.checkPermission(groupId, authorizedUser); - if (isPermitted) { - request.setGroupId(groupId); - } else { - String msg = "Current user '" + authorizedUser - + "' doesn't have enough privileges to list devices of group '" - + groupId + "'"; - log.error(msg); - return Response.status(Response.Status.FORBIDDEN).entity(msg).build(); - } - } catch (GroupManagementException e) { - String msg = "Error occurred while getting the data using '" + groupId + "'"; - log.error(msg); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); - } catch (UserStoreException e){ - String msg = "Error occurred while retrieving role list of user '" + authorizedUser + "'"; + try { + validateGroupId(groupId, from, to); + boolean isPermitted = DeviceMgtAPIUtils.checkPermission(groupId, authorizedUser); + if (isPermitted) { + request.setGroupId(groupId); + } else { + String msg = "Current user '" + authorizedUser + + "' doesn't have enough privileges to list devices of group '" + + groupId + "'"; log.error(msg); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); + return Response.status(Response.Status.FORBIDDEN).entity(msg).build(); } + } catch (GroupManagementException e) { + String msg = "Error occurred while getting the data using '" + groupId + "'"; + log.error(msg); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); + } catch (UserStoreException e) { + String msg = "Error occurred while retrieving role list of user '" + authorizedUser + "'"; + log.error(msg); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); + } PaginationResult result = dms.getAllDevices(request, false); - if(!result.getData().isEmpty()){ + if (!result.getData().isEmpty()) { devices.setList((List) result.getData()); for (Device device : devices.getList()) { @@ -604,7 +638,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { DeviceData deviceData = new DeviceData(); deviceData.setDeviceIdentifier(deviceIdentifier); - if (!StringUtils.isBlank(ifModifiedSince)){ + if (!StringUtils.isBlank(ifModifiedSince)) { SimpleDateFormat format = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z"); try { sinceDate = format.parse(ifModifiedSince); @@ -617,10 +651,10 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { } } - if (!StringUtils.isBlank(owner)){ + if (!StringUtils.isBlank(owner)) { deviceData.setDeviceOwner(owner); } - if (!StringUtils.isBlank(ownership)){ + if (!StringUtils.isBlank(ownership)) { deviceData.setDeviceOwnership(ownership); } device = dms.getDevice(deviceData, true); @@ -710,7 +744,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { sinceDate = format.parse(ifModifiedSince); } catch (ParseException e) { String message = "Error occurred while parse the since date.Invalid date string is provided in " + - "'If-Modified-Since' header"; + "'If-Modified-Since' header"; log.error(message, e); return Response.status(Response.Status.BAD_REQUEST).entity( new ErrorResponse.ErrorResponseBuilder().setMessage("Invalid date " + @@ -723,7 +757,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { String message = "No device is modified after the timestamp provided in 'If-Modified-Since' header"; log.error(message); return Response.status(Response.Status.NOT_MODIFIED).entity("No device is modified " + - "after the timestamp provided in 'If-Modified-Since' header").build(); + "after the timestamp provided in 'If-Modified-Since' header").build(); } } else { device = dms.getDevice(id, requireDeviceInfo); @@ -738,7 +772,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { // check whether the user is authorized if (!deviceAccessAuthorizationService.isUserAuthorized(deviceIdentifier, authorizedUser)) { String message = "User '" + authorizedUser + "' is not authorized to retrieve the given " + - "device id '" + id + "'"; + "device id '" + id + "'"; log.error(message); return Response.status(Response.Status.UNAUTHORIZED).entity( new ErrorResponse.ErrorResponseBuilder().setCode(401l).setMessage(message).build()).build(); @@ -893,7 +927,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { List devices; DeviceList deviceList = new DeviceList(); try { - if(map.getProperties().isEmpty()){ + if (map.getProperties().isEmpty()) { if (log.isDebugEnabled()) { log.debug("No search criteria defined when querying devices."); } @@ -901,7 +935,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { } DeviceManagementProviderService dms = DeviceMgtAPIUtils.getDeviceManagementService(); devices = dms.getDevicesBasedOnProperties(map.getProperties()); - if(devices == null || devices.isEmpty()){ + if (devices == null || devices.isEmpty()) { if (log.isDebugEnabled()) { log.debug("No Devices Found for criteria : " + map); } @@ -1201,14 +1235,14 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { /** * List device status history * - * @param type Device type - * @param id Device id + * @param type Device type + * @param id Device id * @return {@link Response} object */ @GET @Path("/{type}/{id}/getstatushistory") public Response getDeviceStatusHistory(@PathParam("type") @Size(max = 45) String type, - @PathParam("id") @Size(max = 45) String id) { + @PathParam("id") @Size(max = 45) String id) { //TODO check authorization for this RequestValidationUtil.validateDeviceIdentifier(type, id); DeviceManagementProviderService deviceManagementProviderService = @@ -1233,14 +1267,14 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { /** * List device status history for the current enrolment * - * @param type Device type - * @param id Device id + * @param type Device type + * @param id Device id * @return {@link Response} object */ @GET @Path("/{type}/{id}/getenrolmentstatushistory") public Response getCurrentEnrolmentDeviceStatusHistory(@PathParam("type") @Size(max = 45) String type, - @PathParam("id") @Size(max = 45) String id) { + @PathParam("id") @Size(max = 45) String id) { //TODO check authorization for this or current enrolment should be based on for the enrolment associated with the user RequestValidationUtil.validateDeviceIdentifier(type, id); DeviceManagementProviderService deviceManagementProviderService = @@ -1544,7 +1578,7 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { if (MDMAppConstants.AndroidConstants.OPCODE_INSTALL_APPLICATION.equals(operation.getCode()) || MDMAppConstants.AndroidConstants.OPCODE_UNINSTALL_APPLICATION.equals(operation.getCode())) { ApplicationManager applicationManager = DeviceMgtAPIUtils.getApplicationManager(); - applicationManager.updateSubsStatus(device.getId(), operation.getId(),operation.getStatus().toString()); + applicationManager.updateSubsStatus(device.getId(), operation.getId(), operation.getStatus().toString()); } return Response.status(Response.Status.OK).entity("OperationStatus updated successfully.").build(); } catch (BadRequestException e) { @@ -1563,7 +1597,8 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { String msg = "Error occurred when updating the application subscription status of the operation. " + "The device identifier is: " + deviceIdentifier; log.error(msg, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); } + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); + } } @GET diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/Billing.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/Billing.java new file mode 100644 index 00000000000..79f398a5f80 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/Billing.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.wso2.carbon.device.mgt.common; + +import com.google.gson.Gson; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; + +@ApiModel(value = "Billing", description = "This class carries all information related to a device billing.") +public class Billing implements Serializable { + + private static final long serialVersionUID = 1998101711L; + + @ApiModelProperty(name = "invoiceId", value = "ID of the billing.", + required = false) + private int invoiceId; + + @ApiModelProperty(name = "deviceId", value = "Device id of the billing.", + required = false) + private int deviceId; + + @ApiModelProperty(name = "tenantId", value = "Tenant of the device.", + required = false) + private int tenantId; + + @ApiModelProperty(name = "billingStart", value = "Start date of the billing period.", required = false) + private Long billingStart; + + @ApiModelProperty(name = "billingEnd", value = "End date of the billing period.", required = false) + private Long billingEnd; + + @ApiModelProperty(name = "deviceCount", value = "Device count for a billing period", + required = false) + private int deviceCount; + + + public Billing() { + } + + public Billing(int invoiceId, int deviceId, int tenantId, Long billingStart, Long billingEnd) { + this.invoiceId = invoiceId; + this.deviceId = deviceId; + this.tenantId = tenantId; + this.billingStart = billingStart; + this.billingEnd = billingEnd; + } + + public int getInvoiceId() { + return invoiceId; + } + + public void setInvoiceId(int invoiceId) { + this.invoiceId = invoiceId; + } + + public int getDeviceId() { + return deviceId; + } + + public void setDeviceId(int deviceId) { + this.deviceId = deviceId; + } + + public int getTenantId() { + return tenantId; + } + + public void setTenantId(int tenantId) { + this.tenantId = tenantId; + } + + public Long getBillingStart() { + return billingStart; + } + + public void setBillingStart(Long billingStart) { + this.billingStart = billingStart; + } + + public Long getBillingEnd() { + return billingEnd; + } + + public void setBillingEnd(Long billingEnd) { + this.billingEnd = billingEnd; + } + + public int getDeviceCount() { + return deviceCount; + } + + public void setDeviceCount(int deviceCount) { + this.deviceCount = deviceCount; + } + + @Override + public String toString() { + return new Gson().toJson(this); + } + + +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/PaginationResult.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/PaginationResult.java index 9bb9fc59204..553618d80c5 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/PaginationResult.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/PaginationResult.java @@ -47,6 +47,28 @@ public class PaginationResult implements Serializable { @ApiModelProperty(name = "totalCost", value = "Total cost of all devices per tenant", required = false) private double totalCost; + @ApiModelProperty(name = "billedDateIsValid", value = "Check if user entered date is valid", required = false) + private boolean billedDateIsValid; + + @ApiModelProperty(name = "message", value = "Send information text to the billing UI", required = false) + private String message; + + public boolean isBilledDateIsValid() { + return billedDateIsValid; + } + + public void setBilledDateIsValid(boolean billedDateIsValid) { + this.billedDateIsValid = billedDateIsValid; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + public double getTotalCost() { return totalCost; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java index e9cfa13398a..884fdfa1cae 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/DeviceManagementConstants.java @@ -44,6 +44,7 @@ public final class DeviceManagementConstants { public static final String DEVICE_CACHE = "DEVICE_CACHE"; public static final String API_RESOURCE_PERMISSION_CACHE = "API_RESOURCE_CACHE_CACHE"; public static final String GEOFENCE_CACHE = "GEOFENCE_CACHE"; + public static final String META_KEY = "PER_DEVICE_COST"; public static final String ENROLLMENT_NOTIFICATION_API_ENDPOINT = "/api/device-mgt/enrollment-notification"; public static final String URL_SEPERATOR = "/"; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/ui/Billing.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/ui/Billing.java index 41283c899dc..11953bd3d22 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/ui/Billing.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/config/ui/Billing.java @@ -7,6 +7,26 @@ public class Billing { private boolean isHideBillGenerationInSubTenant; private boolean isHideTotalCalculationInSuperTenant; private boolean isHideTotalCalculationInSubTenant; + private boolean isHideDomainSelectionInSuperTenant; + private boolean isHideDomainSelectionInSubTenant; + + @XmlElement(name = "HideDomainSelectionInSuperTenant") + public boolean isHideDomainSelectionInSuperTenant() { + return isHideDomainSelectionInSuperTenant; + } + + public void setHideDomainSelectionInSuperTenant(boolean hideDomainSelectionInSuperTenant) { + isHideDomainSelectionInSuperTenant = hideDomainSelectionInSuperTenant; + } + + @XmlElement(name = "HideDomainSelectionInSubTenant") + public boolean isHideDomainSelectionInSubTenant() { + return isHideDomainSelectionInSubTenant; + } + + public void setHideDomainSelectionInSubTenant(boolean hideDomainSelectionInSubTenant) { + isHideDomainSelectionInSubTenant = hideDomainSelectionInSubTenant; + } @XmlElement(name = "HideBillGenerationInSuperTenant") public boolean isHideBillGenerationInSuperTenant() { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/BillingDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/BillingDAO.java new file mode 100644 index 00000000000..dd0ddf4e286 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/BillingDAO.java @@ -0,0 +1,13 @@ +package org.wso2.carbon.device.mgt.core.dao; + +import org.wso2.carbon.device.mgt.common.Billing; + +import java.sql.Timestamp; +import java.util.List; + +public interface BillingDAO { + + void addBilling(int deviceId, int tenantId, Timestamp billingStart, Timestamp billingEnd) throws DeviceManagementDAOException; + + List getBilling(int deviceId, Timestamp billingStart, Timestamp billingEnd) throws DeviceManagementDAOException; +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java index df2204125d0..8f23228bef9 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java @@ -294,24 +294,12 @@ public interface DeviceDAO { List getDevices(PaginationRequest request, int tenantId) throws DeviceManagementDAOException; /** - * This method is used to retrieve the not removed devices of a given tenant as a paginated result. - * - * @param request PaginationRequest object holding the data for pagination - * @param tenantId tenant id. - * @return returns paginated list of not removed devices of tenant. - * @throws DeviceManagementDAOException - */ - List getDeviceBillList(PaginationRequest request, int tenantId, Timestamp startDate, Timestamp endDate) throws DeviceManagementDAOException; - - /** - * This method is used to retrieve the removed devices of a given tenant as a paginated result. - * - * @param request PaginationRequest object holding the data for pagination + * This method is used to retrieve the devices of a given tenant without pagination. * @param tenantId tenant id. - * @return rreturns paginated list of removed devices of tenant. + * @return returns a list of devices of the tenant. * @throws DeviceManagementDAOException */ - List getRemovedDeviceBillList(PaginationRequest request, int tenantId) throws DeviceManagementDAOException; + List getDeviceListWithoutPagination(int tenantId) throws DeviceManagementDAOException; /** * This method is used to retrieve the devices of a given tenant as a paginated result, along the lines of diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceManagementDAOFactory.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceManagementDAOFactory.java index a07989e3385..6b594664f4f 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceManagementDAOFactory.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceManagementDAOFactory.java @@ -42,6 +42,7 @@ import org.wso2.carbon.device.mgt.core.privacy.dao.impl.PrivacyComplianceDAOImpl import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; +import java.sql.Timestamp; import java.util.Hashtable; import java.util.List; @@ -124,6 +125,11 @@ public class DeviceManagementDAOFactory { public static EnrollmentDAO getEnrollmentDAO() { return new EnrollmentDAOImpl(); } + + public static BillingDAO getBillingDAO() { + return new BillingDAOImpl(); + } + public static DeviceStatusDAO getDeviceStatusDAO() { return new DeviceStatusDAOImpl(); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/BillingDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/BillingDAOImpl.java new file mode 100644 index 00000000000..4af343012b0 --- /dev/null +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/BillingDAOImpl.java @@ -0,0 +1,71 @@ +package org.wso2.carbon.device.mgt.core.dao.impl; + +import org.wso2.carbon.device.mgt.common.Billing; +import org.wso2.carbon.device.mgt.common.EnrolmentInfo; +import org.wso2.carbon.device.mgt.core.dao.BillingDAO; +import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException; +import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory; +import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +public class BillingDAOImpl implements BillingDAO { + + @Override + public void addBilling(int deviceId, int tenantId, Timestamp billingStart, Timestamp billingEnd) throws DeviceManagementDAOException { + + Connection conn; + PreparedStatement stmt = null; + ResultSet rs = null; + try { + conn = this.getConnection(); + String sql = "INSERT INTO DM_BILLING(DEVICE_ID, TENANT_ID, BILLING_START, BILLING_END) VALUES(?, ?, ?, ?)"; + stmt = conn.prepareStatement(sql, new String[] {"invoice_id"}); + stmt.setInt(1, deviceId); + stmt.setInt(2,tenantId); + stmt.setTimestamp(3, billingStart); + stmt.setTimestamp(4, billingEnd); + stmt.execute(); + } catch (SQLException e) { + e.printStackTrace(); + throw new DeviceManagementDAOException("Error occurred while adding billing period", e); + } finally { + DeviceManagementDAOUtil.cleanupResources(stmt, rs); + } + } + + @Override + public List getBilling(int deviceId, Timestamp billingStart, Timestamp billingEnd) throws DeviceManagementDAOException { + List billings = new ArrayList<>(); + Connection conn; + PreparedStatement stmt = null; + ResultSet rs = null; + EnrolmentInfo.Status status = null; + try { + conn = this.getConnection(); + String sql; + + sql = "SELECT * FROM DM_BILLING WHERE DEVICE_ID = ?"; + stmt = conn.prepareStatement(sql); + stmt.setInt(1, deviceId); + rs = stmt.executeQuery(); + + while (rs.next()) { + Billing bill = new Billing(rs.getInt("INVOICE_ID"), rs.getInt("DEVICE_ID"),rs.getInt("TENANT_ID"), + (rs.getTimestamp("BILLING_START").getTime()), (rs.getTimestamp("BILLING_END").getTime())); + billings.add(bill); + } + } catch (SQLException e) { + throw new DeviceManagementDAOException("Error occurred getting billing periods", e); + } finally { + DeviceManagementDAOUtil.cleanupResources(stmt, null); + } + return billings; + } + + private Connection getConnection() throws SQLException { + return DeviceManagementDAOFactory.getConnection(); + } +} diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java index 1bda6cad1df..7e280d09c1b 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java @@ -185,23 +185,23 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { } @Override - public List getDeviceBillList(PaginationRequest request, int tenantId, Timestamp startDate, Timestamp endDate) + public List getDeviceListWithoutPagination(int tenantId) throws DeviceManagementDAOException { Connection conn; PreparedStatement stmt = null; - List devices = new ArrayList<>(); + List devices = new ArrayList<>(); try { conn = this.getConnection(); - String sql = "SELECT DM_DEVICE.ID, DEVICE_IDENTIFICATION, DESCRIPTION, NAME AS DEVICE_NAME, DM_ENROLMENT.ID AS ENROLMENT_ID,\n" + - " DATE_OF_ENROLMENT,STATUS, LAST_BILLED_DATE, TIMESTAMPDIFF('DAY', DATE_OF_ENROLMENT, CURDATE()) as DAYS_SINCE_ENROLLED\n" + - " FROM DM_DEVICE JOIN DM_ENROLMENT ON (DM_DEVICE.ID = DM_ENROLMENT.DEVICE_ID)\n" + - " WHERE DM_ENROLMENT.TENANT_ID=?"; + String sql = "SELECT DM_DEVICE.ID AS DEVICE_ID, DEVICE_IDENTIFICATION, DESCRIPTION, DM_DEVICE.NAME AS DEVICE_NAME, DM_DEVICE_TYPE.NAME AS DEVICE_TYPE,\n" + + "DM_ENROLMENT.ID AS ENROLMENT_ID, DATE_OF_ENROLMENT,OWNER, OWNERSHIP,IS_TRANSFERRED, STATUS, DATE_OF_LAST_UPDATE, LAST_BILLED_DATE,\n" + + "TIMESTAMPDIFF('DAY', DATE_OF_ENROLMENT, CURDATE()) as DAYS_SINCE_ENROLLED FROM DM_DEVICE JOIN DM_ENROLMENT\n" + + "ON (DM_DEVICE.ID = DM_ENROLMENT.DEVICE_ID) JOIN DM_DEVICE_TYPE ON (DM_DEVICE.DEVICE_TYPE_ID = DM_DEVICE_TYPE.ID) WHERE DM_ENROLMENT.TENANT_ID=?"; stmt = conn.prepareStatement(sql); stmt.setInt(1, tenantId); ResultSet rs = stmt.executeQuery(); while (rs.next()) { - DeviceBilling device = DeviceManagementDAOUtil.loadDeviceBilling(rs); + Device device = DeviceManagementDAOUtil.loadDevice(rs); devices.add(device); } } catch (SQLException e) { @@ -212,35 +212,6 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { return devices; } - @Override - public List getRemovedDeviceBillList(PaginationRequest request, int tenantId) - throws DeviceManagementDAOException { - Connection conn; - PreparedStatement stmt = null; - List devices = new ArrayList<>(); - try { - conn = this.getConnection(); - String sql = "select DEVICE_IDENTIFICATION, DESCRIPTION, NAME AS DEVICE_NAME, DATE_OF_ENROLMENT, LAST_BILLED_DATE, DATE_OF_LAST_UPDATE, STATUS, " + - "TIMESTAMPDIFF('DAY', DATE_OF_ENROLMENT, DATE_OF_LAST_UPDATE) AS DAYS_USED from DM_DEVICE d, DM_ENROLMENT e" + - " where e.TENANT_ID=? and d.ID=e.DEVICE_ID and STATUS ='REMOVED'\n"; - stmt = conn.prepareStatement(sql); - stmt.setInt(1, tenantId); - ResultSet rs = stmt.executeQuery(); - - while (rs.next()) { -// DeviceBilling device = DeviceManagementDAOUtil.loadDeviceBilling(rs, true); - DeviceBilling device = DeviceManagementDAOUtil.loadDeviceBilling(rs); - devices.add(device); - } - } catch (SQLException e) { - throw new DeviceManagementDAOException("Error occurred while fetching the list of devices belongs to '" + - request.getOwner() + "'", e); - } finally { - DeviceManagementDAOUtil.cleanupResources(stmt, null); - } - return devices; - } - @Override public List getAllocatedDevices(PaginationRequest request, int tenantId, int activeServerCount, int serverIndex) throws DeviceManagementDAOException { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java index aaadef26d16..beef6f15421 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java @@ -189,12 +189,7 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl { } @Override - public List getRemovedDeviceBillList(PaginationRequest request, int tenantId) throws DeviceManagementDAOException { - return null; - } - - @Override - public List getDeviceBillList(PaginationRequest request, int tenantId , Timestamp startDate, Timestamp endDate) throws DeviceManagementDAOException { + public List getDeviceListWithoutPagination(int tenantId) throws DeviceManagementDAOException { return null; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java index 4db568cf8d4..eb358004abf 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java @@ -180,12 +180,7 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl { } @Override - public List getRemovedDeviceBillList(PaginationRequest request, int tenantId) throws DeviceManagementDAOException { - return null; - } - - @Override - public List getDeviceBillList(PaginationRequest request, int tenantId, Timestamp startDate, Timestamp endDate) throws DeviceManagementDAOException { + public List getDeviceListWithoutPagination(int tenantId) throws DeviceManagementDAOException { return null; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java index 45fcd83cb74..f9e087e64e2 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java @@ -190,12 +190,7 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl { } @Override - public List getRemovedDeviceBillList(PaginationRequest request, int tenantId) throws DeviceManagementDAOException { - return null; - } - - @Override - public List getDeviceBillList(PaginationRequest request, int tenantId, Timestamp startDate, Timestamp endDate) throws DeviceManagementDAOException { + public List getDeviceListWithoutPagination(int tenantId) throws DeviceManagementDAOException { return null; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java index 4abe44a1a19..4b1a424d27a 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java @@ -209,6 +209,17 @@ public interface DeviceManagementProviderService { */ PaginationResult getAllDevicesBillings(PaginationRequest request, int tenantId, String tenantDomain, Timestamp startDate, Timestamp endDate, boolean generateBill) throws DeviceManagementException; + /** + * Method to retrieve all the devices with pagination support. + * + * @return PaginationResult - Result including the device bill list without pagination. + * @throws DeviceManagementException If some unusual behaviour is observed while fetching billing of + * devices. + */ + PaginationResult createBillingFile(int tenantId, String tenantDomain, Timestamp startDate, Timestamp endDate, boolean generateBill) throws DeviceManagementException; + + + /** * Returns the device of specified id. * diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java index a006bd16506..b92ab554003 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java @@ -138,6 +138,8 @@ import java.io.StringWriter; import java.lang.reflect.Type; import java.sql.SQLException; import java.sql.Timestamp; +import java.text.Format; +import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -156,6 +158,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv private final EnrollmentDAO enrollmentDAO; private final ApplicationDAO applicationDAO; private MetadataDAO metadataDAO; + private final BillingDAO billingDAO; private final DeviceStatusDAO deviceStatusDAO; public DeviceManagementProviderServiceImpl() { @@ -165,6 +168,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv this.deviceTypeDAO = DeviceManagementDAOFactory.getDeviceTypeDAO(); this.enrollmentDAO = DeviceManagementDAOFactory.getEnrollmentDAO(); this.metadataDAO = MetadataManagementDAOFactory.getMetadataDAO(); + this.billingDAO = DeviceManagementDAOFactory.getBillingDAO(); this.deviceStatusDAO = DeviceManagementDAOFactory.getDeviceStatusDAO(); /* Registering a listener to retrieve events when some device management service plugin is installed after @@ -768,8 +772,8 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv throw new DeviceManagementException(msg); } if (log.isDebugEnabled()) { - log.debug("Getting allocated Devices for Server with index "+ serverIndex + " and" + - " type '" + deviceType); + log.debug("Getting allocated Devices for Server with index " + serverIndex + " and" + + " type '" + deviceType); } List allocatedDevices; try { @@ -783,7 +787,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } } catch (DeviceManagementDAOException e) { String msg = "Error occurred while retrieving all devices of type '" + - deviceType + "' that are being managed within the scope of current tenant"; + deviceType + "' that are being managed within the scope of current tenant"; log.error(msg, e); throw new DeviceManagementException(msg, e); } catch (SQLException e) { @@ -937,101 +941,153 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv return this.getAllDevices(request, true); } - @Override - public PaginationResult getAllDevicesBillings(PaginationRequest request, int tenantId, String tenantDomain, Timestamp startDate, Timestamp endDate, boolean generateBill) throws DeviceManagementException { - if (request == null) { - String msg = "Received incomplete pagination request for method getAllDeviceBillings"; - log.error(msg); - throw new DeviceManagementException(msg); - } + public PaginationResult calculateCost(int tenantId, String tenantDomain, Timestamp startDate, Timestamp endDate, boolean generateBill, List allDevices) throws DeviceManagementException { - DeviceManagerUtil.validateDeviceListPageSize(request); PaginationResult paginationResult = new PaginationResult(); double totalCost = 0.0; - List allDevices; - int count = 0; + boolean allDevicesBilledDateIsValid = true; + String lastBilledDates = ""; + ArrayList lastBilledDatesList = new ArrayList<>(); + List invalidDevices = new ArrayList<>(); + List removeBillingPeriodInvalidDevices = new ArrayList<>() ; + List removeStatusUpdateInvalidDevices = new ArrayList<>() ; try { - DeviceManagementDAOFactory.beginTransaction(); -// allDevices = deviceDAO.getDeviceBillList(request, tenantId, startDate, endDate); - allDevices = deviceDAO.getDevices(request, tenantId); - count = deviceDAO.getDeviceCount(request, tenantId); - - String metaKey = "PER_DEVICE_COST"; MetadataManagementDAOFactory.beginTransaction(); - Metadata metadata = metadataDAO.getMetadata(tenantId, metaKey); + Metadata metadata = metadataDAO.getMetadata(-1234, DeviceManagementConstants.META_KEY); Gson g = new Gson(); Collection costData = null; - Type collectionType = new TypeToken>(){}.getType(); + + Type collectionType = new TypeToken>() {}.getType(); if (metadata != null) { costData = g.fromJson(metadata.getMetaValue(), collectionType); - for (Cost tenantCost: costData) { + for (Cost tenantCost : costData) { if (tenantCost.getTenantDomain().equals(tenantDomain)) { - for (Device device: allDevices) { - device.setDeviceStatusInfo(getDeviceStatusHistory(device, startDate, endDate, true)); + for (Device device : allDevices) { + device.setDeviceStatusInfo(getDeviceStatusHistory(device, null, null, true)); long dateDiff = 0; List deviceStatus = device.getDeviceStatusInfo(); boolean lastBilledDate = false; + boolean deviceStatusIsValid = false; + + List deviceBilling = billingDAO.getBilling(device.getId(), startDate, endDate); + boolean billDateIsInvalid = false; + + if (deviceBilling.isEmpty()) { + billDateIsInvalid = false; + } + + if (generateBill) { + for (Billing bill : deviceBilling) { + if ((bill.getBillingStart() <= startDate.getTime() && startDate.getTime() <= bill.getBillingEnd()) || + (bill.getBillingStart() <= endDate.getTime() && endDate.getTime() <= bill.getBillingEnd())) { + billDateIsInvalid = true; + invalidDevices.add(bill); + } + } + } - for (int i=0; i i+1) { - if (!lastBilledDate) { - lastBilledDate = true; - if (device.getEnrolmentInfo().getLastBilledDate() == 0) { - dateDiff = dateDiff + (deviceStatus.get(i+1).getUpdateTime().getTime() - deviceStatus.get(i).getUpdateTime().getTime()); + if (!billDateIsInvalid) { + for (int i = 0; i < deviceStatus.size(); i++) { + if (deviceStatus.get(i).getStatus().toString().equals("ACTIVE")) { + if (deviceStatus.size() > i + 1) { + if (!lastBilledDate) { + lastBilledDate = true; + if (device.getEnrolmentInfo().getLastBilledDate() == 0) { + deviceStatusIsValid = true; + dateDiff = dateDiff + (deviceStatus.get(i + 1).getUpdateTime().getTime() - deviceStatus.get(i).getUpdateTime().getTime()); + } else { + if (deviceStatus.get(i + 1).getUpdateTime().getTime() >= device.getEnrolmentInfo().getLastBilledDate()) { + deviceStatusIsValid = true; + dateDiff = dateDiff + (deviceStatus.get(i + 1).getUpdateTime().getTime() - device.getEnrolmentInfo().getLastBilledDate()); + } + } } else { - if (deviceStatus.get(i+1).getUpdateTime().getTime() >= device.getEnrolmentInfo().getLastBilledDate()) { - dateDiff = dateDiff + (deviceStatus.get(i+1).getUpdateTime().getTime() - device.getEnrolmentInfo().getLastBilledDate()); + if (deviceStatus.get(i).getUpdateTime().getTime() >= device.getEnrolmentInfo().getLastBilledDate()) { + deviceStatusIsValid = true; + dateDiff = dateDiff + (deviceStatus.get(i + 1).getUpdateTime().getTime() - deviceStatus.get(i).getUpdateTime().getTime()); } } - } else { - if ( deviceStatus.get(i).getUpdateTime().getTime() >= device.getEnrolmentInfo().getLastBilledDate()) { - dateDiff = dateDiff + (deviceStatus.get(i+1).getUpdateTime().getTime() - deviceStatus.get(i).getUpdateTime().getTime()); - } - } - } else { - if (!lastBilledDate) { - lastBilledDate = true; - if (device.getEnrolmentInfo().getLastBilledDate() == 0) { - dateDiff = dateDiff + (endDate.getTime() - deviceStatus.get(i).getUpdateTime().getTime()); + } else { // The last status update calculation is done in this block + // If only one status row is retrieved this block is executed + if (!lastBilledDate) { + lastBilledDate = true; + // Is executed if there is no lastBilled date and if the updates time is before the enddate + if (device.getEnrolmentInfo().getLastBilledDate() == 0) { + if (endDate.getTime() >= deviceStatus.get(i).getUpdateTime().getTime()) { + deviceStatusIsValid = true; + dateDiff = dateDiff + (endDate.getTime() - deviceStatus.get(i).getUpdateTime().getTime()); + } + } else { + if (endDate.getTime() >= device.getEnrolmentInfo().getLastBilledDate()) { + deviceStatusIsValid = true; + dateDiff = dateDiff + (endDate.getTime() - device.getEnrolmentInfo().getLastBilledDate()); + } + } } else { - if (endDate.getTime() >= device.getEnrolmentInfo().getLastBilledDate()) { - dateDiff = dateDiff +(endDate.getTime() - device.getEnrolmentInfo().getLastBilledDate()); + if (device.getEnrolmentInfo().getLastBilledDate() <= deviceStatus.get(i).getUpdateTime().getTime() + && endDate.getTime() >= deviceStatus.get(i).getUpdateTime().getTime()) { + deviceStatusIsValid = true; + dateDiff = dateDiff + (endDate.getTime() - deviceStatus.get(i).getUpdateTime().getTime()); + } + if (device.getEnrolmentInfo().getLastBilledDate() >= deviceStatus.get(i).getUpdateTime().getTime() + && endDate.getTime() >= device.getEnrolmentInfo().getLastBilledDate()) { + deviceStatusIsValid = true; + dateDiff = dateDiff + (endDate.getTime() - device.getEnrolmentInfo().getLastBilledDate()); } } - } else { - dateDiff = dateDiff + (endDate.getTime() - deviceStatus.get(i).getUpdateTime().getTime()); } } } - } - long dateInDays = TimeUnit.DAYS.convert(dateDiff, TimeUnit.MILLISECONDS);; - double cost = (tenantCost.getCost()/365)*dateInDays; - totalCost = cost + totalCost; - device.setCost(Math.round(cost * 100.0) / 100.0); - device.setDaysUsed((int) dateInDays); + long dateInDays = TimeUnit.DAYS.convert(dateDiff, TimeUnit.MILLISECONDS); + double cost = (tenantCost.getCost() / 365) * dateInDays; + totalCost = cost + totalCost; + device.setCost(Math.round(cost * 100.0) / 100.0); + device.setDaysUsed((int) dateInDays); - if (generateBill) { - Timestamp timestamp = new Timestamp(System.currentTimeMillis()); - enrollmentDAO.updateEnrollmentLastBilledDate(device.getEnrolmentInfo(), timestamp, tenantId); + if (generateBill) { + enrollmentDAO.updateEnrollmentLastBilledDate(device.getEnrolmentInfo(), endDate, tenantId); + billingDAO.addBilling(device.getId(), tenantId, startDate, endDate); + DeviceManagementDAOFactory.commitTransaction(); + } + + } else { + + for (int i = 0; i < deviceStatus.size(); i++) { + if (endDate.getTime() >= deviceStatus.get(i).getUpdateTime().getTime() + && startDate.getTime() <= deviceStatus.get(i).getUpdateTime().getTime()) { + deviceStatusIsValid = true; + } + } + if (device.getEnrolmentInfo().getLastBilledDate() != 0) { + Date date = new Date(device.getEnrolmentInfo().getLastBilledDate()); + Format format = new SimpleDateFormat("yyyy MM dd"); + if (!lastBilledDatesList.contains(lastBilledDatesList.add(format.format(date)))) { + lastBilledDatesList.add(format.format(date)); + } + + lastBilledDates = lastBilledDates + ' ' + lastBilledDatesList; + } + removeBillingPeriodInvalidDevices.add(device); } + if (!deviceStatusIsValid) { + removeStatusUpdateInvalidDevices.add(device); + } } + } } } - } catch (DeviceManagementDAOException e) { String msg = "Error occurred while retrieving device list pertaining to the current tenant"; log.error(msg, e); throw new DeviceManagementException(msg, e); - } - catch (Exception e) { + } catch (Exception e) { String msg = "Error occurred in getAllDevices"; log.error(msg, e); throw new DeviceManagementException(msg, e); @@ -1039,13 +1095,83 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv DeviceManagementDAOFactory.closeConnection(); MetadataManagementDAOFactory.closeConnection(); } + + if(!removeBillingPeriodInvalidDevices.isEmpty() && removeBillingPeriodInvalidDevices.size() == allDevices.size()) { + allDevicesBilledDateIsValid = false; + paginationResult.setMessage("Invalid bill period last billed dates of devices are " +lastBilledDates); + } + if(!removeStatusUpdateInvalidDevices.isEmpty() && removeStatusUpdateInvalidDevices.size() == allDevices.size()) { + allDevicesBilledDateIsValid = false; + if (paginationResult.getMessage() != null){ + paginationResult.setMessage(paginationResult.getMessage() + " and no device updates within entered bill period."); + } else { + paginationResult.setMessage("Devices have not been updated within the given period or entered end date comes before the last billed date"); + } + + } + allDevices.removeAll(removeBillingPeriodInvalidDevices); + allDevices.removeAll(removeStatusUpdateInvalidDevices); + + paginationResult.setBilledDateIsValid(allDevicesBilledDateIsValid); paginationResult.setData(allDevices); paginationResult.setTotalCost(Math.round(totalCost * 100.0) / 100.0); + return paginationResult; + } + + @Override + public PaginationResult getAllDevicesBillings(PaginationRequest request, int tenantId, String tenantDomain, Timestamp startDate, Timestamp endDate, boolean generateBill) throws DeviceManagementException { + if (request == null) { + String msg = "Received incomplete pagination request for method getAllDeviceBillings"; + log.error(msg); + throw new DeviceManagementException(msg); + } + + DeviceManagerUtil.validateDeviceListPageSize(request); + PaginationResult paginationResult = new PaginationResult(); + List allDevices; + int count = 0; + + try { + DeviceManagementDAOFactory.beginTransaction(); + allDevices = deviceDAO.getDevices(request, tenantId); + count = deviceDAO.getDeviceCount(request, tenantId); + paginationResult = calculateCost(tenantId, tenantDomain, startDate, endDate, generateBill, allDevices); + + } catch (DeviceManagementDAOException e) { + String msg = "Error occurred while retrieving device bill list pertaining to the current tenant"; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } catch (Exception e) { + String msg = "Error occurred in getAllDevicesBillings"; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } paginationResult.setRecordsFiltered(count); paginationResult.setRecordsTotal(count); return paginationResult; } + @Override + public PaginationResult createBillingFile(int tenantId, String tenantDomain, Timestamp startDate, Timestamp endDate, boolean generateBill) throws DeviceManagementException { + PaginationResult paginationResult = new PaginationResult(); + List allDevices; + try { + DeviceManagementDAOFactory.beginTransaction(); + allDevices = deviceDAO.getDeviceListWithoutPagination(tenantId); + paginationResult = calculateCost(tenantId, tenantDomain, startDate, endDate, generateBill, allDevices); + + } catch (DeviceManagementDAOException e) { + String msg = "Error occurred while retrieving device bill list without pagination pertaining to the current tenant"; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } catch (Exception e) { + String msg = "Error occurred in createBillingFile"; + log.error(msg, e); + throw new DeviceManagementException(msg, e); + } + return paginationResult; + } + @Override public PaginationResult getAllDevices(PaginationRequest request, boolean requireDeviceInfo) throws DeviceManagementException { if (request == null) { @@ -1862,8 +1988,9 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv DeviceManagementDAOFactory.closeConnection(); } } + @Override - public List getDeviceStatusHistory(Device device, Date fromDate, Date toDate, boolean billingStatus) throws DeviceManagementException{ + public List getDeviceStatusHistory(Device device, Date fromDate, Date toDate, boolean billingStatus) throws DeviceManagementException { if (log.isDebugEnabled()) { log.debug("get status history of device: " + device.getDeviceIdentifier()); } @@ -1883,7 +2010,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } @Override - public List getDeviceCurrentEnrolmentStatusHistory(Device device, Date fromDate, Date toDate) throws DeviceManagementException{ + public List getDeviceCurrentEnrolmentStatusHistory(Device device, Date fromDate, Date toDate) throws DeviceManagementException { if (log.isDebugEnabled()) { log.debug("get status history of device: " + device.getDeviceIdentifier()); } @@ -1912,12 +2039,12 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } @Override - public List getDeviceStatusHistory(Device device) throws DeviceManagementException{ + public List getDeviceStatusHistory(Device device) throws DeviceManagementException { return getDeviceStatusHistory(device, null, null, false); } @Override - public List getDeviceCurrentEnrolmentStatusHistory(Device device) throws DeviceManagementException{ + public List getDeviceCurrentEnrolmentStatusHistory(Device device) throws DeviceManagementException { return getDeviceCurrentEnrolmentStatusHistory(device, null, null); } @@ -3334,7 +3461,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv @Override public List getDeviceLocationInfo(DeviceIdentifier deviceIdentifier, long from, - long to) throws DeviceManagementException { + long to) throws DeviceManagementException { if (log.isDebugEnabled()) { log.debug("Get device location information"); } @@ -4489,7 +4616,7 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv @Override public void triggerCorrectiveActions(String deviceIdentifier, String featureCode, List actions, - List configList) throws DeviceManagementException, DeviceNotFoundException { + List configList) throws DeviceManagementException, DeviceNotFoundException { if (log.isDebugEnabled()) { log.debug("Triggering Corrective action. Device Identifier: " + deviceIdentifier); } @@ -4570,10 +4697,10 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } @Override - public License getLicenseConfig (String deviceTypeName) throws DeviceManagementException { + public License getLicenseConfig(String deviceTypeName) throws DeviceManagementException { DeviceManagementService deviceManagementService = pluginRepository.getDeviceManagementService(deviceTypeName, - this.getTenantId()); + this.getTenantId()); if (deviceManagementService == null) { String msg = "Device management service loading is failed for the device type: " + deviceTypeName; log.error(msg);