com.citrix.cpbm.portal.fragment.controllers.AbstractBillingController.java Source code

Java tutorial

Introduction

Here is the source code for com.citrix.cpbm.portal.fragment.controllers.AbstractBillingController.java

Source

/*
 * Copyright  2013 Citrix Systems, Inc. You may not use, copy, or modify this file except pursuant to a valid license
 * agreement from Citrix Systems, Inc.
 */
package com.citrix.cpbm.portal.fragment.controllers;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException;
import org.springframework.ui.ModelMap;
import org.springframework.util.FileCopyUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.citrix.cpbm.core.workflow.service.BusinessTransactionService;
import com.citrix.cpbm.core.workflow.service.TaskService;
import com.citrix.cpbm.platform.admin.service.ConnectorConfigurationManager;
import com.citrix.cpbm.platform.admin.service.ConnectorManagementService;
import com.citrix.cpbm.platform.spi.CloudConnectorFactory.ConnectorType;
import com.vmops.config.BillingPostProcessor;
import com.vmops.internal.service.ActorService;
import com.vmops.internal.service.CustomFieldService;
import com.vmops.internal.service.EventService;
import com.vmops.internal.service.PaymentGatewayService;
import com.vmops.internal.service.SubscriptionService;
import com.vmops.internal.service.UsageService;
import com.vmops.model.AccountType;
import com.vmops.model.Address;
import com.vmops.model.CreditCard;
import com.vmops.model.DepositRecord;
import com.vmops.model.Event.Category;
import com.vmops.model.Event.Scope;
import com.vmops.model.Event.Severity;
import com.vmops.model.Event.Source;
import com.vmops.model.Invoice;
import com.vmops.model.PendingChange;
import com.vmops.model.ServiceFilter;
import com.vmops.model.ServiceResourceType;
import com.vmops.model.ServiceResourceTypeGroupComponent;
import com.vmops.model.ServiceResourceTypeProperty;
import com.vmops.model.Subscription;
import com.vmops.model.Subscription.State;
import com.vmops.model.SubscriptionHandle;
import com.vmops.model.Tenant;
import com.vmops.model.User;
import com.vmops.model.billing.AccountStatement;
import com.vmops.model.billing.PaymentTransaction;
import com.vmops.model.billing.SalesLedgerCreditRecord;
import com.vmops.model.billing.SalesLedgerRecord;
import com.vmops.model.billing.SalesLedgerRecord.Type;
import com.vmops.portal.config.Configuration.Names;
import com.vmops.service.ConfigurationService;
import com.vmops.service.EmailTemplateService;
import com.vmops.service.ProductBundleService;
import com.vmops.service.ReportService;
import com.vmops.service.billing.BillingAdminService;
import com.vmops.service.billing.BillingService;
import com.vmops.service.exceptions.AjaxFormValidationException;
import com.vmops.service.exceptions.BillingAdminServiceException;
import com.vmops.service.exceptions.BillingServiceException;
import com.vmops.service.exceptions.CloudServiceException;
import com.vmops.service.exceptions.CreditCardFraudCheckException;
import com.vmops.service.exceptions.InvalidAjaxRequestException;
import com.vmops.service.exceptions.PaymentGatewayServiceException;
import com.vmops.service.exceptions.TenantStateChangeFailedException;
import com.vmops.utils.Transformer;
import com.vmops.utils.pdf.PdfGenerator;
import com.vmops.web.controllers.AbstractAuthenticatedController;
import com.vmops.web.controllers.menu.Page;
import com.vmops.web.forms.BillingInfoForm;
import com.vmops.web.forms.DepositRecordForm;
import com.vmops.web.forms.SetAccountTypeForm;
import com.vmops.web.forms.SubscriptionSearchForm;
import com.vmops.web.interceptors.UserContextInterceptor;
import com.vmops.web.validators.DepositRecordValidator;

/**
 * Handles billing requests
 * 
 * @author Fatima
 */

public abstract class AbstractBillingController extends AbstractAuthenticatedController {

    protected final String SEPARATOR = " ";

    protected final String BILLING_START_DATE = "BILLING_START_DATE";

    protected final String BILLING_END_DATE = "BILLING_END_DATE";

    @Autowired
    protected BillingAdminService billingAdminService;

    @Autowired
    private BillingPostProcessor billingPostProcessor;

    @Autowired
    protected SubscriptionService subscriptionService;

    @Autowired
    private CustomFieldService customFieldService;

    @Autowired
    protected ReportService reportService;

    @Autowired
    protected ConfigurationService configurationService;

    @Autowired
    protected ActorService actorService;

    @Autowired
    protected UsageService usageService;

    @Autowired
    protected PdfGenerator pdfGenerator;

    @Autowired
    EmailTemplateService emailTemplateService;

    @Autowired
    protected EventService eventService;

    @Autowired
    private TaskService taskService;

    @Autowired
    BillingService billingService;

    @Autowired
    ProductBundleService productBundleService;

    @Autowired
    protected ConnectorManagementService connectorManagementService;

    private final String utiltyInvoices = "__UTILITY__CHARGES__INVOICES__";

    private final String serviceBundleInvoices = "__SERVICE__BUNDLE__INVOICES__";

    protected Logger logger = Logger.getLogger(AbstractBillingController.class);

    @Autowired
    private BusinessTransactionService businessTransactionService;

    @Autowired
    ConnectorConfigurationManager connectorConfigurationManager;

    protected boolean hasFullBillingView(User user) {
        // only master user has ROLE_ACCOUNT_ADMIN, certain system users has finance role.
        return userHasPrivilegeOf(user, "ROLE_ACCOUNT_ADMIN") || userHasFinancePrivilege(user)
                || userHasBillingPrivilege(user);
    }

    @RequestMapping(value = { "/subscriptions" }, method = RequestMethod.GET)
    public String showSubscriptions(@RequestParam(value = "tenant", required = false) String tenantParam,
            @RequestParam(value = "page", required = false, defaultValue = "1") String currentPage,
            @RequestParam(value = "id", required = false) String uuid,
            @RequestParam(value = "state", required = false) String state,
            @RequestParam(value = "useruuid", required = false) String useruuid,
            @RequestParam(value = "instanceuuid", required = false) String instanceuuid,
            @RequestParam(value = "productBundleID", required = false) Long productBundleID, ModelMap map,
            HttpServletRequest request) {

        int page;
        int perPage;

        try {
            page = Integer.parseInt(currentPage);
        } catch (NumberFormatException nFE) {
            page = 1;
        }

        try {
            perPage = getDefaultPageSize();
        } catch (NumberFormatException nFE) {
            perPage = 14;
        }
        State subscriptionState = null;
        if (state == null) {
            subscriptionState = State.ACTIVE;
            state = subscriptionState.getName();
        } else if (!state.equalsIgnoreCase("All")) {
            subscriptionState = State.getState(state);
        }
        User currentUser = getCurrentUser();
        boolean showUserProfile = false;
        Tenant effectiveTenant = (Tenant) request.getAttribute(UserContextInterceptor.EFFECTIVE_TENANT_KEY);

        if ((Boolean) request.getAttribute("isSurrogatedTenant")) {
            showUserProfile = true;
            setPage(map, Page.CRM_USAGE_BILLING_SUBSCRIPTION);
            map.addAttribute("userHasCloudServiceAccount",
                    userService.isUserHasAnyActiveCloudService(effectiveTenant.getOwner()));
        } else {
            setPage(map, Page.USAGE_BILLING_SUBSCRIPTION);
            map.addAttribute("userHasCloudServiceAccount", userService.isUserHasAnyActiveCloudService(currentUser));
        }
        map.addAttribute("showUserProfile", showUserProfile);
        map.addAttribute("tenant", effectiveTenant);
        int totalSubscriptions = 0;
        int filtersApplied = 0;
        List<Subscription> subscriptions = null;
        Long instanceID = null;
        if (StringUtils.isNotBlank(instanceuuid)) {
            instanceID = connectorConfigurationManager.getInstance(instanceuuid).getId();
        }

        if (uuid == null) {
            if (hasFullBillingView(currentUser)) {
                if (useruuid == null) {
                    subscriptions = subscriptionService.getSubscriptions(effectiveTenant, subscriptionState,
                            instanceID, productBundleID, page, perPage);
                    totalSubscriptions = subscriptionService.getSubscriptionCount(effectiveTenant,
                            subscriptionState, instanceID, productBundleID, 0, 0);
                } else {
                    User filterUser = userService.get(useruuid);
                    subscriptions = subscriptionService.getSubscriptions(filterUser, subscriptionState, instanceID,
                            productBundleID, page, perPage);
                    totalSubscriptions = subscriptionService.getSubscriptionCount(filterUser, subscriptionState,
                            instanceID, productBundleID, 0, 0);
                    map.addAttribute("useruuid", useruuid);
                }
            } else {
                subscriptions = subscriptionService.getSubscriptions(currentUser, subscriptionState, instanceID,
                        productBundleID, page, perPage);
                totalSubscriptions = subscriptionService.getSubscriptionCount(currentUser, subscriptionState,
                        instanceID, productBundleID, 0, 0);
            }
        } else {
            subscriptions = new ArrayList<Subscription>();
            Subscription subscription = subscriptionService.locateSubscriptionByParam(uuid, true);
            state = subscription.getState().getName();
            subscriptions.add(subscription);
            totalSubscriptions = subscriptions != null ? subscriptions.size() : 0;
            map.addAttribute("idForDetails", uuid);
        }
        for (Subscription subscription : subscriptions) {
            customFieldService.populateCustomFields(subscription);
            customFieldService.populateCustomFields(subscription.getTenant());
            customFieldService.populateCustomFields(subscription.getUser());
        }
        map.addAttribute("subscriptions", subscriptions);
        map.addAttribute("stateSelected", state);
        map.addAttribute("instanceuuid", instanceuuid);
        map.addAttribute("productBundleID", productBundleID);

        filtersApplied = StringUtils.isNotBlank(useruuid) ? filtersApplied + 1 : filtersApplied;
        filtersApplied = StringUtils.isNotBlank(state) && !state.equalsIgnoreCase("ALL") ? filtersApplied + 1
                : filtersApplied;
        filtersApplied = StringUtils.isNotBlank(instanceuuid) ? filtersApplied + 1 : filtersApplied;
        filtersApplied = productBundleID != null ? filtersApplied + 1 : filtersApplied;
        map.addAttribute("filtersApplied", filtersApplied);

        if (totalSubscriptions - page * perPage > 0) {
            map.addAttribute("enable_next", true);
        } else {
            map.addAttribute("enable_next", false);
        }

        map.addAttribute("current_page", page);
        map.addAttribute("states", State.values());

        SubscriptionSearchForm searchForm = new SubscriptionSearchForm();
        searchForm.setUsers(effectiveTenant.getUsers());
        searchForm.setStates(Arrays.asList(State.values()));
        searchForm.setServiceInstances(tenantService.getEnabledCSInstances(effectiveTenant));
        searchForm.setProductBundles(productBundleService.listProductBundles(0, 0));
        map.addAttribute("searchForm", searchForm);

        return "billing.showSubscriptions";
    }

    @RequestMapping(value = "/subscriptions/showDetails", method = RequestMethod.POST)
    public String showSubscriptionDetails(@RequestParam(value = "id", required = true) String uuid,
            @RequestParam(value = "tenant", required = false) String tenantParam, ModelMap map) {
        logger.debug("Entry ShowSubscriptionDetails with Id:" + uuid);
        map.addAttribute("tenantParam", tenantParam);
        Subscription subscription = subscriptionService.locateSubscriptionByParam(uuid, true);
        subscription = subscriptionService.updateFilterAndResourceComponentNamesinConfigurationData(subscription);
        customFieldService.populateCustomFields(subscription);
        customFieldService.populateCustomFields(subscription.getTenant());
        customFieldService.populateCustomFields(subscription.getUser());
        map.addAttribute("subscription", subscription);
        Map<String, String> configurationProperties = prepareConfigurationMap(subscription);
        map.addAttribute("configurationProperties", configurationProperties);
        SubscriptionHandle activeHandle = subscription.getActiveHandle();
        if (activeHandle != null) {
            map.addAttribute("vmId", activeHandle.getResourceHandle());
        }
        Boolean hasCloudAccess = false;
        if (userService.isUserHasAnyActiveCloudService(getCurrentUser())) {
            hasCloudAccess = true;
        }

        map.addAttribute("allowTermination", subscription.getState().equals(State.ACTIVE));
        map.addAttribute("toProvision", false);
        map.addAttribute("toReconfigure", false);

        boolean isValid = false;
        try {
            isValid = subscriptionService.validateAndUpdateStates(subscription);

            SubscriptionHandle subscriptionHandle = subscription.getHandle();

            if (subscriptionHandle != null) {
                com.vmops.model.SubscriptionHandle.State handleState = subscriptionHandle.getState();
                map.addAttribute("allowTermination", subscription.getState().equals(State.ACTIVE));
                if (subscription.getState().equals(State.NEW)) {
                    if (handleState.equals(com.vmops.model.SubscriptionHandle.State.ERROR)) {
                        map.addAttribute("toProvision", true);
                    }
                } else if (subscription.getState().equals(State.ACTIVE)) {
                    if (handleState.equals(com.vmops.model.SubscriptionHandle.State.ACTIVE) || isValid) {
                        map.addAttribute("toReconfigure", true);
                    } else if (handleState.equals(com.vmops.model.SubscriptionHandle.State.ERROR)
                            || handleState.equals(com.vmops.model.SubscriptionHandle.State.TERMINATED)
                            || !isValid) {
                        map.addAttribute("toProvision", true);
                    }
                }
            } else if (subscription.getState().equals(State.ACTIVE)) {
                map.addAttribute("toProvision", true);
            }
            map.addAttribute("cloudStackCallFailed", false);
        } catch (CloudServiceException cse) {
            map.addAttribute("cloudStackCallFailed", true);
            map.addAttribute("cloudServiceErrorMessage", cse.getMessage());
        }
        map.addAttribute("hasCloudAccess", hasCloudAccess);
        map.addAttribute("endDate", subscription.getTerminationDate());
        String workflowUuid = businessTransactionService.getWorkflowUuid(subscription);
        if (StringUtils.isNotEmpty(workflowUuid)) {
            map.addAttribute("workflowUuid", workflowUuid);
        }
        boolean isPayAsYouGoChosen = config.getBooleanValue(Names.com_citrix_cpbm_catalog_payAsYouGoMode);
        map.addAttribute("isPayAsYouGoChosen", isPayAsYouGoChosen);
        logger.debug("Exit ShowSubscriptionDetails");
        return "billing.viewSubscription";
    }

    private Map<String, String> prepareConfigurationMap(Subscription subscription) {
        Map<String, String> configurationProperties = new LinkedHashMap<String, String>();
        Map<String, String> configurationMap = subscription.getConfigurationMap();
        for (ServiceFilter filter : subscription.getServiceInstance().getService().getServiceFilters()) {
            putValueToMap(configurationProperties, configurationMap, filter.getDiscriminatorName());
        }

        if (subscription.getResourceType() != null) {
            List<ServiceResourceTypeGroupComponent> uniqueResourceTypeComponents = connectorConfigurationManager
                    .getResourceComponents(subscription.getServiceInstance().getUuid(),
                            subscription.getResourceType().getResourceTypeName());
            for (ServiceResourceTypeGroupComponent serviceResourceTypeGroupComponent : uniqueResourceTypeComponents) {
                putValueToMap(configurationProperties, configurationMap,
                        serviceResourceTypeGroupComponent.getResourceComponentName());
            }
            for (ServiceResourceTypeProperty property : subscription.getResourceType()
                    .getServiceResourceTypeProperty()) {
                putValueToMap(configurationProperties, configurationMap, property.getName());
            }
        }

        return configurationProperties;
    }

    private void putValueToMap(Map<String, String> configurationProperties, Map<String, String> configurationMap,
            String name) {
        String value = configurationMap.get(name);
        if (value == null) {
            return;
        }
        value = configurationMap.get(name + "_name");
        if (StringUtils.isBlank(value)) {
            value = configurationMap.get(name);
        }
        configurationProperties.put(name, value);
    }

    @RequestMapping(value = "/subscriptions/terminate/{subscriptionParam}", method = RequestMethod.POST)
    @ResponseBody
    public Subscription terminateSubscription(@PathVariable String subscriptionParam, ModelMap map) {
        logger.debug("Entry terminateSubscription with Id:" + subscriptionParam);
        Subscription subscription = subscriptionService.locateSubscriptionByParam(subscriptionParam, false);
        subscriptionService.terminateSubscription(subscription, true);
        logger.debug("Exit terminateSubscription");
        return subscription;
    }

    @RequestMapping(value = "/subscriptions/cancel/{subscriptionParam}", method = RequestMethod.POST)
    @ResponseBody
    public Subscription cancelSubscription(@PathVariable String subscriptionParam, ModelMap map) {
        logger.debug("Entry cancelSubscription with Id:" + subscriptionParam);
        Subscription subscription = subscriptionService.locateSubscriptionByParam(subscriptionParam, false);
        subscriptionService.cancelSubscription(subscription);
        logger.debug("Exit cancelSubscription");
        return subscription;
    }

    @RequestMapping(value = { "/history" }, method = RequestMethod.GET)
    public String showHistory(@ModelAttribute("currentTenant") Tenant currentTenant,
            @RequestParam(value = "tenant", required = false) String tenantParam,
            @RequestParam(value = "user", required = false) String userParam,
            @RequestParam(value = "page", required = false, defaultValue = "1") String currentPage,
            HttpSession session, ModelMap map, HttpServletRequest request) {
        int page;
        int perPage;
        try {
            page = Integer.parseInt(currentPage);
        } catch (NumberFormatException nFE) {
            page = 1;
        }
        try {
            perPage = getDefaultPageSize();
            if (perPage > 14) {
                perPage = 14;
            }
        } catch (NumberFormatException nFE) {
            perPage = 14;
        }

        setPage(map, Page.USAGE_BILLING_BILLING_HISTORY);

        User currentUser = getCurrentUser();
        boolean showUserProfile = false;
        Tenant effectiveTenant = (Tenant) request.getAttribute(UserContextInterceptor.EFFECTIVE_TENANT_KEY);

        if ((Boolean) request.getAttribute("isSurrogatedTenant")) {
            showUserProfile = true;
            map.addAttribute("userHasCloudServiceAccount",
                    userService.isUserHasAnyActiveCloudService(effectiveTenant.getOwner()));
        } else {
            map.addAttribute("userHasCloudServiceAccount", userService.isUserHasAnyActiveCloudService(currentUser));
        }

        map.addAttribute("showUserProfile", showUserProfile);
        map.addAttribute("currentUser", currentUser);

        boolean showUsers = false;
        try {
            List<AccountStatement> accountStatements = billingService.getAccountStatements(effectiveTenant, null,
                    page, perPage, null, null, null);
            map.addAttribute("billingActivities", accountStatements);
        } catch (Exception e) {
            logger.error("Error occurred while getting account statements " + e);

        }
        if (hasFullBillingView(currentUser)) {
            List<User> users = effectiveTenant.getUsers();
            map.addAttribute("users", users);
            showUsers = true;

        }
        map.addAttribute("showUsers", showUsers);
        map.addAttribute("tenant", effectiveTenant);

        /*
         * if(totalInvoices-(page*perPage)>0){ map.addAttribute("enable_next", true); } else{
         * map.addAttribute("enable_next", false); }
         */

        map.addAttribute("current_page", page);

        if (session.getAttribute("makepayment_status") != null
                && session.getAttribute("makepayment_status").equals("true")) {
            map.addAttribute("statusMessage", "succeeded");
            session.removeAttribute("makepayment_status");
        } else if (session.getAttribute("makepayment_status") != null
                && session.getAttribute("makepayment_status").equals("false")) {
            map.addAttribute("statusMessage", "failed");
            session.removeAttribute("makepayment_status");
        }
        return "billing.history";

    }

    @RequestMapping(value = { "/paymenthistory" }, method = RequestMethod.GET)
    public String showPaymentHistory(@ModelAttribute("currentTenant") Tenant currentTenant,
            @RequestParam(value = "tenant", required = false) String tenantParam,
            @RequestParam(value = "page", required = false, defaultValue = "1") String currentPage,
            HttpSession session, HttpServletRequest request, ModelMap map) {
        int page;
        int perPage;
        try {
            page = Integer.parseInt(currentPage);
        } catch (NumberFormatException nFE) {
            page = 1;
        }
        try {
            perPage = getDefaultPageSize();
            if (perPage > 14) {
                perPage = 14;
            }
        } catch (NumberFormatException nFE) {
            perPage = 14;
        }
        setPage(map, Page.USAGE_BILLING_BILLING_HISTORY);

        boolean showUserProfile = false;
        Tenant effectiveTenant = (Tenant) request.getAttribute(UserContextInterceptor.EFFECTIVE_TENANT_KEY);
        User currentUser = getCurrentUser();
        if ((Boolean) request.getAttribute("isSurrogatedTenant")) {
            showUserProfile = true;
            map.addAttribute("userHasCloudServiceAccount",
                    userService.isUserHasAnyActiveCloudService(effectiveTenant.getOwner()));
        } else {
            map.addAttribute("userHasCloudServiceAccount", userService.isUserHasAnyActiveCloudService(currentUser));
        }

        map.addAttribute("showUserProfile", showUserProfile);
        map.addAttribute("errorMsg", "");
        map.addAttribute("tenant", effectiveTenant);
        List<SalesLedgerRecord> slrList = billingService.listPaymentAndCredits(effectiveTenant, page, perPage);
        long totalPayments = 0l;
        try {
            totalPayments = billingService.getPaymentAndCreditsRecordCount(effectiveTenant);
        } catch (Exception e) {
            map.addAttribute("errorMsg",
                    messageSource.getMessage("error.message.tenant.not.active", null, getSessionLocale(request)));
        }

        map.addAttribute("salesLedgerRecords", slrList);

        if (totalPayments - page * perPage > 0) {
            map.addAttribute("enable_next", true);
        } else {
            map.addAttribute("enable_next", false);
        }

        map.addAttribute("current_page", page);

        return "billing.paymentHistory";

    }

    /**
     * view billing activity
     * 
     * @param activityId(invoice p or payment id
     * @param type
     * @param map
     * @return
     */
    @RequestMapping(value = { "/{activityParam}/viewbillingactivity" }, method = RequestMethod.GET)
    public String viewBillingActivity(@PathVariable String activityParam,
            @RequestParam(value = "type", required = true) String type,
            @RequestParam(value = "user", required = false) String userParam, ModelMap map) {

        User currentUser = getCurrentUser();
        try {
            AccountStatement accountStatement = billingService.getAccountStatement(activityParam);

            if (hasFullBillingView(currentUser)) {
                if (userParam != null && !userParam.equals("All")) {
                    User effectiveUser = userService.get(userParam);
                    Set<Invoice> invoices = accountStatement.getInvoices(effectiveUser);
                    map.addAttribute("invoices", invoices);
                } else {
                    Set<Invoice> invoices = accountStatement.getInvoices();
                    map.addAttribute("invoices", invoices);
                }
            } else {
                Set<Invoice> invoices = accountStatement.getInvoices(currentUser);
                map.addAttribute("invoices", invoices);
            }
        } catch (Exception e) {
            logger.error("###Failed to get account statement", e);
        }

        if (type.equals("Invoice")) {
            return "billing.view.billing.activity";
        }
        return "billing.view.billing.paymentactivity";
    }

    @RequestMapping(value = { "/{slrUuid}/viewslr" }, method = RequestMethod.GET)
    public String viewSalesLedgerRecord(@PathVariable String slrUuid, ModelMap map) {
        SalesLedgerRecord slr = billingAdminService.getSalesLedgerRecord(slrUuid);
        map.addAttribute("salesLedgerRecord", slr);
        return "billing.view.billing.paymentactivity";
    }

    @RequestMapping(value = "/showcreditcarddetails", method = RequestMethod.GET)
    public String showCreditCard(@ModelAttribute("currentTenant") Tenant currentTenant,
            @RequestParam(value = "tenant", required = false) String tenantParam, ModelMap map,
            HttpServletRequest request) {
        logger.debug("###Entering in edit()");

        setPage(map, Page.USAGE_BILLING_PAYMENT_INFO);

        CreditCard creditCard = null;
        map.addAttribute("showUserProfile", request.getAttribute("isSurrogatedTenant"));
        Tenant effectiveTenant = tenantService.get(tenantParam);

        map.addAttribute("tenant", effectiveTenant);
        List<AccountType> allowedTargetTypes = tenantService.getAllowedTargetAccountTypes(effectiveTenant);
        if (allowedTargetTypes != null && !allowedTargetTypes.isEmpty()) {
            map.addAttribute("showChangeAccountType", true);
        } else {
            map.addAttribute("showChangeAccountType", false);
        }
        List<PendingChange> pendingConversions = tenantService.getPendingConversions(effectiveTenant);

        if (pendingConversions != null && !pendingConversions.isEmpty()) {
            map.addAttribute("showMessagePendingConversion", true);
        } else {
            map.addAttribute("showMessagePendingConversion", false);
        }

        BillingInfoForm billingInfoForm = null;
        try {
            creditCard = billingService.getCreditCard(effectiveTenant);
            billingInfoForm = new BillingInfoForm(effectiveTenant, null, creditCard);
            billingInfoForm.setCountryList(countryService.getCountries(null, null, null, null, null, null, null));

        } catch (Exception e) {
            logger.error("###Failed to get payment information", e);
            creditCard = new CreditCard();
            billingInfoForm = new BillingInfoForm(effectiveTenant, null, creditCard);
            map.addAttribute("errormsg", messageSource.getMessage("ui.usage.billing.paymentinfo.cc.errormsg", null,
                    getSessionLocale(request)));
        }
        logger.debug("###Exiting showCreditCard()");
        map.addAttribute("billingInfo", billingInfoForm);

        return "billing.showCreditCardDetails";

    }

    @RequestMapping(value = "/editcreditcarddetails", method = RequestMethod.POST)
    public ModelMap editCreditCard(@RequestParam(value = "tenant", required = false) String tenantParam,
            @ModelAttribute("billingInfo") BillingInfoForm form, HttpServletResponse response,
            HttpServletRequest request, ModelMap map) throws IOException {
        logger.debug("###Entering in edit(tenantId, billingAddress,response) method @POST");

        Tenant effectiveTenant = tenantService.get(tenantParam);
        map.addAttribute("tenant", effectiveTenant);
        try {
            map.addAttribute("isAccountExistInPaymentGateway",
                    ((PaymentGatewayService) connectorManagementService
                            .getOssServiceInstancebycategory(ConnectorType.PAYMENT_GATEWAY))
                                    .isAccountExistInPaymentGateway(effectiveTenant));
            CreditCard creditCard = form.getCreditCard();
            billingService.editCreditCard(effectiveTenant, creditCard, getRemoteUserIp(request),
                    request.getLocale(), getCurrentUser());
        } catch (CreditCardFraudCheckException ex) {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            throw new InvalidAjaxRequestException(ex.getMessage());
        } catch (PaymentGatewayServiceException e) {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            throw new InvalidAjaxRequestException(e.getMessage());
        } catch (BillingServiceException e) {
            response.setStatus(HttpStatus.PRECONDITION_FAILED.value());
            throw new InvalidAjaxRequestException(e.getMessage());
        } catch (Exception e) {
            logger.error("Got Exception while updating billing info : ", e);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            throw new InvalidAjaxRequestException(messageSource
                    .getMessage("ui.usage.billing.paymentinfo.cc.edit.errormsg", null, getSessionLocale(request)));
        }
        String redirectToURL = "/portal/portal/tenants/editcurrent?action=showcreditcardtab&tenant=" + tenantParam;
        map.put("redirecturl", redirectToURL);
        String message = "billing.info.updated";
        String messageArgs = effectiveTenant.getName();
        eventService.createEvent(new Date(), effectiveTenant, message, messageArgs, Source.PORTAL, Scope.ACCOUNT,
                Category.ACCOUNT, Severity.INFORMATION, true);
        return map;
    }

    private ServiceResourceType getNewDummyResourceType(String resourceTypeName) {
        ServiceResourceType dummyResourceType = new ServiceResourceType();
        dummyResourceType.setResourceTypeName(resourceTypeName);
        return dummyResourceType;
    }

    private void pushInvoiceToMap(LinkedHashMap<ServiceResourceType, ArrayList<Invoice>> chargesMap,
            ServiceResourceType serviceResourceType, Invoice invoice, List<Invoice> newServiceInvoices,
            List<Invoice> renewServiceInvoices) {
        if (serviceResourceType == null) {
            if (invoice.getType().equals(com.vmops.model.Invoice.Type.Subscription)) {
                newServiceInvoices.add(invoice);
            } else {
                renewServiceInvoices.add(invoice);
            }
            return;
        }
        if (chargesMap.containsKey(serviceResourceType)) {
            chargesMap.get(serviceResourceType).add(invoice);
        } else {
            ArrayList<Invoice> newInvoiceList = new ArrayList<Invoice>();
            newInvoiceList.add(invoice);
            chargesMap.put(serviceResourceType, newInvoiceList);
        }
    }

    @RequestMapping(value = { "/usageBilling" }, method = RequestMethod.GET)
    public String usageBilling(@ModelAttribute("currentTenant") Tenant tenant,
            @RequestParam(value = "viewBy", required = false) String viewBy,
            @RequestParam(value = "tenant", required = false) String tenantParam,
            @RequestParam(value = "page", required = false, defaultValue = "1") String currentPage,
            @RequestParam(value = "accountStatementUuid", required = false) String accountStatementUuid,
            @RequestParam(value = "useruuid", required = false, defaultValue = "ALL_USERS") String useruuid,
            ModelMap map, HttpServletRequest request) {
        int page;
        int perPage;
        try {
            page = Integer.parseInt(currentPage);
        } catch (NumberFormatException nFE) {
            page = 1;
        }
        try {
            perPage = getDefaultPageSize();
            if (perPage > 14) {
                perPage = 14;
            }
        } catch (NumberFormatException nFE) {
            perPage = 14;
        }
        User user = getCurrentUser();
        if (tenantService.getSystemTenant().equals(user.getTenant())) {
            map.addAttribute("isSystemProviderUser", "Y");
        } else {
            map.addAttribute("isSystemProviderUser", "N");
        }
        AccountStatement accountStatement = null;

        if ((userService.hasAuthority(user, "ROLE_ACCOUNT_CRUD")
                || userService.hasAuthority(user, "ROLE_ACCOUNT_MGMT"))
                && (Boolean) request.getAttribute("isSurrogatedTenant")) {
            tenant = tenantService.get(tenantParam);
            user = tenant.getOwner();
            setPage(map, Page.CRM_USAGE_BILLING);
            map.addAttribute("userHasCloudServiceAccount",
                    userService.isUserHasAnyActiveCloudService(tenant.getOwner()));
            map.addAttribute("showUserProfile", true);
        } else {

            setPage(map, Page.DASHBOARD_USAGE_BILLING);
            map.addAttribute("userHasCloudServiceAccount", userService.isUserHasAnyActiveCloudService(user));
        }
        if (accountStatementUuid == null) {
            accountStatement = billingAdminService.getOrCreateProvisionalAccountStatement(tenant);
        } else {
            accountStatement = billingAdminService.getAccountStatement(accountStatementUuid);
        }

        List<AccountStatement> accountStatements = billingAdminService.getAccountStatements(tenant, null, page,
                perPage, null, null, null);
        map.addAttribute("accountStatements", accountStatements);
        map.addAttribute("accountStatementUuid", accountStatement.getUuid());
        map.addAttribute("accountStatementState", accountStatement.getState().name());
        int accStatSize = billingAdminService.countAccountStatements(tenant, null, null);
        if (accStatSize - page * perPage > 0) {
            map.addAttribute("enable_next", true);
        } else {
            map.addAttribute("enable_next", false);
        }

        map.addAttribute("current_page", page);
        LinkedHashMap<ServiceResourceType, ArrayList<Invoice>> newChargesMap = new LinkedHashMap<ServiceResourceType, ArrayList<Invoice>>();
        LinkedHashMap<ServiceResourceType, ArrayList<Invoice>> renewalChargesMap = new LinkedHashMap<ServiceResourceType, ArrayList<Invoice>>();

        ArrayList<Invoice> utilityInvoiceList = new ArrayList<Invoice>();
        ArrayList<Invoice> newServiceInvoiceList = new ArrayList<Invoice>();
        ArrayList<Invoice> renewServiceInvoiceList = new ArrayList<Invoice>();

        Set<Invoice> invoices = null;
        if (StringUtils.isNotBlank(useruuid) && !useruuid.equals("ALL_USERS")) {
            // if user does not have permission to access somebody else's invoice then change the uuid to his own uuid.
            if (!userService.hasAuthority(user, "ROLE_ACCOUNT_BILLING_ADMIN")) {
                useruuid = user.getUuid();
            }
            User filterUser = userService.get(useruuid);
            invoices = accountStatement.getInvoices(filterUser);
            map.addAttribute("useruuid", useruuid);
        } else {
            if (userService.hasAuthority(user, "ROLE_ACCOUNT_CRUD")
                    || userService.hasAuthority(user, "ROLE_ACCOUNT_MGMT")
                    || userService.hasAuthority(user, "ROLE_ACCOUNT_BILLING_ADMIN")) {
                invoices = accountStatement.getInvoices();
            } else {
                // For regular user send only their invoices regardless of what they call.
                invoices = accountStatement.getInvoices(user);
            }
        }

        BigDecimal newBigAmount = BigDecimal.ZERO;
        BigDecimal newBigDiscount = BigDecimal.ZERO;
        BigDecimal newBigSubTotal = BigDecimal.ZERO;
        BigDecimal newBigTax = BigDecimal.ZERO;
        BigDecimal newBigTotal = BigDecimal.ZERO;
        BigDecimal renewBigAmount = BigDecimal.ZERO;
        BigDecimal renewBigDiscount = BigDecimal.ZERO;
        BigDecimal renewBigSubTotal = BigDecimal.ZERO;
        BigDecimal renewBigTax = BigDecimal.ZERO;
        BigDecimal renewBigTotal = BigDecimal.ZERO;

        for (Invoice invoice : invoices) {
            if (invoice.getType().equals(com.vmops.model.Invoice.Type.Renewal)) {
                pushInvoiceToMap(renewalChargesMap, invoice.getSubscription().getProductBundle().getResourceType(),
                        invoice, newServiceInvoiceList, renewServiceInvoiceList);
                renewBigAmount = renewBigAmount.add(invoice.getRawAmount());
                renewBigDiscount = renewBigDiscount.add(invoice.getDiscountAmount());
                renewBigSubTotal = renewBigSubTotal.add(invoice.getSubTotal());
                renewBigTax = renewBigTax.add(invoice.getTaxAmount());
                renewBigTotal = renewBigTotal.add(invoice.getAmount());
            } else if (invoice.getType().equals(com.vmops.model.Invoice.Type.Subscription)) {
                pushInvoiceToMap(newChargesMap, invoice.getSubscription().getProductBundle().getResourceType(),
                        invoice, newServiceInvoiceList, renewServiceInvoiceList);
                newBigAmount = newBigAmount.add(invoice.getRawAmount());
                newBigDiscount = newBigDiscount.add(invoice.getDiscountAmount());
                newBigSubTotal = newBigSubTotal.add(invoice.getSubTotal());
                newBigTax = newBigTax.add(invoice.getTaxAmount());
                newBigTotal = newBigTotal.add(invoice.getAmount());
            } else {
                Collections.sort(invoice.getInvoiceItems());
                utilityInvoiceList.add(invoice);
                newBigAmount = newBigAmount.add(invoice.getRawAmount());
                newBigDiscount = newBigDiscount.add(invoice.getDiscountAmount());
                newBigSubTotal = newBigSubTotal.add(invoice.getSubTotal());
                newBigTax = newBigTax.add(invoice.getTaxAmount());
                newBigTotal = newBigTotal.add(invoice.getAmount());
            }
        }

        Collections.sort(utilityInvoiceList);

        newChargesMap.put(getNewDummyResourceType(serviceBundleInvoices), newServiceInvoiceList);
        newChargesMap.put(getNewDummyResourceType(utiltyInvoices), utilityInvoiceList);
        renewalChargesMap.put(getNewDummyResourceType(serviceBundleInvoices), renewServiceInvoiceList);

        map.addAttribute("newChargesMap", newChargesMap);
        map.addAttribute("renewalChargesMap", renewalChargesMap);
        map.addAttribute("newBigAmount", newBigAmount);
        map.addAttribute("newBigDiscount", newBigDiscount);
        map.addAttribute("newBigTax", newBigTax);
        map.addAttribute("newBigSubTotal", newBigSubTotal);
        map.addAttribute("newBigTotal", newBigTotal);
        map.addAttribute("renewBigAmount", renewBigAmount);
        map.addAttribute("renewBigDiscount", renewBigDiscount);
        map.addAttribute("renewBigTax", renewBigTax);
        map.addAttribute("renewBigSubTotal", renewBigSubTotal);
        map.addAttribute("renewBigTotal", renewBigTotal);

        map.addAttribute("tenant", tenant);
        map.addAttribute("user", user);
        map.addAttribute("accountStatement", accountStatement);
        map.addAttribute("current_page", page);

        List<SalesLedgerCreditRecord> creditRecords = accountStatement.getSalesLedgerCreditRecords();
        List<SalesLedgerCreditRecord> payments = new ArrayList<SalesLedgerCreditRecord>();
        List<SalesLedgerCreditRecord> creditsIssued = new ArrayList<SalesLedgerCreditRecord>();
        BigDecimal bigPaymentsSum = BigDecimal.ZERO;

        for (SalesLedgerCreditRecord creditRecord : creditRecords) {
            if (!creditRecord.isVoided()) {
                if (creditRecord.getType().equals(Type.SERVICE_CREDIT)) {
                    creditsIssued.add(creditRecord);
                } else {
                    payments.add(creditRecord);
                }
                bigPaymentsSum = bigPaymentsSum.add(creditRecord.getTransactionAmount());
            }
        }

        map.addAttribute("payments", payments);
        map.addAttribute("creditsIssued", creditsIssued);
        map.addAttribute("bigPaymentsSum", bigPaymentsSum);

        return "billing.usageBilling";
    }

    @RequestMapping(value = { "/generateUDR" }, method = RequestMethod.GET)
    public void generateUDR(@ModelAttribute("currentTenant") Tenant tenant,
            @RequestParam(value = "viewBy", required = false) String viewBy,
            @RequestParam(value = "tenant", required = false) String tenantParam,
            @RequestParam(value = "accountStatementUuid", required = false) String accountStatementUuid,
            @RequestParam(value = "page", required = false, defaultValue = "1") String currentPage, ModelMap map,
            HttpServletRequest request, HttpServletResponse response) {

        String portalTempPath = config.getValue(Names.com_citrix_cpbm_portal_settings_temp_path);
        String fileExtension = config.getValue(Names.com_citrix_cpbm_portal_billing_export_fileExtension);
        File targetXmlFile = new File(
                portalTempPath + File.separator + "UB" + System.currentTimeMillis() + "." + fileExtension);

        AccountStatement accountStatement = null;
        if (accountStatementUuid == null) {
            accountStatement = billingAdminService.getOrCreateProvisionalAccountStatement(tenant);
        } else {
            accountStatement = billingAdminService.getAccountStatement(accountStatementUuid);
        }

        InputStream templateInputStream = null;

        try {
            Transformer.transform(accountStatement, targetXmlFile, templateInputStream);
        } catch (Exception ex) {
            logger.error("### Exception in transforming usage", ex);
        }
        logger.info("### Leaving Transform");

        if (fileExtension.equals("csv")) {
            response.setContentType("text/csv");
        } else {
            response.setContentType("application/xml");
        }
        response.setHeader("Content-Disposition", "attachment; filename=" + targetXmlFile.getName());
        OutputStream out = null;
        InputStream is = null;
        try {
            out = response.getOutputStream();
            is = new BufferedInputStream(new FileInputStream(targetXmlFile));
            FileCopyUtils.copy(is, response.getOutputStream());
            out.flush();
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                out.close();
            } catch (IOException e) {
                logger.error("Error while closing streams", e);
            }

        }
    }

    @RequestMapping(value = "/make_payment", method = RequestMethod.POST)
    @ResponseBody
    public String makePayment(@RequestParam BigDecimal amount, @RequestParam String memo,
            @RequestParam String tenantParam, HttpSession session, HttpServletResponse response) {
        logger.debug("###Entering in makePaymentInvoice(tenantId,invoiceId,form, amount,response) method @POST");
        try {
            Tenant tenant = tenantService.get(tenantParam);
            BigDecimal paymentAmount = billingPostProcessor.setScaleByCurrency(amount, tenant.getCurrency());
            if (amount.compareTo(BigDecimal.ZERO) <= 0) {
                return "failed";
            }
            SalesLedgerRecord salesLedgerRecord = billingService.addPaymentOrCredit(tenant, paymentAmount,
                    Type.MANUAL, memo, null);
            if (salesLedgerRecord != null && salesLedgerRecord.getPaymentTransaction().getState()
                    .equals(PaymentTransaction.State.COMPLETED)) {
                response.setStatus(HttpStatus.OK.value());
                logger.debug("###Exiting makePaymentInvoice(tenantId,form ,response) method @POST");

                String message = "payment.received";
                String messageArgs = tenant.getName();
                eventService.createEvent(new Date(), tenant, message, messageArgs, Source.PORTAL, Scope.ACCOUNT,
                        Category.ACCOUNT, Severity.INFORMATION, true);

                return "success";
            }
            response.setStatus(HttpStatus.OK.value());
            logger.debug(
                    "###Exiting makePaymentInvoice(tenantId,form ,response) method @POST. Failed to make the payment.");
            return "failed";

        } catch (BillingServiceException e) {
            session.setAttribute("makepayment_status", "false");
            response.setStatus(HttpStatus.OK.value());
            logger.debug(
                    "###Exiting makePaymentInvoice(tenantId,form ,response) method @POST. Failed to make the payment.");
            return "failed";
        }

    }

    @RequestMapping(value = "/recordpayment", method = RequestMethod.POST)
    @ResponseBody
    public String recordPayment(@RequestParam BigDecimal amount, @RequestParam String memo,
            @RequestParam String tenantParam, HttpServletResponse response, ModelMap map) {
        logger.debug("###Entering in recordPaymentInvoice(tenantId,form, amount,response) method @POST");
        Tenant tenant = tenantService.get(tenantParam);
        try {
            if (amount.compareTo(BigDecimal.ZERO) <= 0) {
                return "failed";
            }
            BigDecimal roundedAmount = billingPostProcessor.setScaleByCurrency(amount, tenant.getCurrency());
            billingService.addPaymentOrCredit(tenant, roundedAmount, Type.RECORD, memo, null);

            String message = "payment.received";
            String messageArgs = tenant.getName();
            eventService.createEvent(new Date(), tenant, message, messageArgs, Source.PORTAL, Scope.ACCOUNT,
                    Category.ACCOUNT, Severity.INFORMATION, true);
            logger.debug("###Exiting recordPaymentInvoice(tenantId,amount,form ,response) method @POST");
        } catch (BillingServiceException e) {
            response.setStatus(HttpStatus.PRECONDITION_FAILED.value());
            return "failed";
        }
        map.addAttribute("tenant", tenant);
        return "success";
    }

    @RequestMapping(value = "/chargeback", method = RequestMethod.POST)
    @ResponseBody
    public String chargeBack(@RequestParam(value = "slrparam", required = true) String slrparam,
            @RequestParam String tenantParam, HttpServletRequest request, HttpServletResponse response,
            ModelMap map) {
        logger.debug("###Entering in chargeBack() @POST");
        Tenant tenant = tenantService.get(tenantParam);
        try {
            SalesLedgerRecord slr = billingAdminService.cancelPayment(tenant, slrparam);
            if (slr == null) {
                throw new InvalidAjaxRequestException(
                        "Charge back failed. Please contact your admin about this failure.");
            }
        } catch (BillingAdminServiceException e) {
            throw new InvalidAjaxRequestException(e.getMessage());
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new InvalidAjaxRequestException(
                    "Charge back failed. Please contact your admin about this failure.");
        }
        response.setStatus(HttpStatus.OK.value());
        map.addAttribute("tenant", tenant);
        return "success";
    }

    @RequestMapping(value = "/changeaccounttype", method = RequestMethod.POST)
    public ModelMap changeAccountType(@RequestParam(value = "tenant", required = false) String tenantParam,
            @Valid @ModelAttribute("setAccountTypeForm") SetAccountTypeForm form, HttpServletRequest request,
            HttpServletResponse response, ModelMap map) {
        logger.debug("###Entering in setAccountType(tenantId, form, request, response, map) method @POST");
        Map<String, String> browserDetails = new HashMap<String, String>();
        browserDetails.put("remoteAddress", getRemoteUserIp(request));
        browserDetails.put("userAgent", request.getHeader("User-Agent"));
        browserDetails.put("referer", request.getHeader("Referer"));
        Address billingAddress = form.getBillingAddress();
        CreditCard creditCard = form.getCreditCard();
        try {
            tenantService.convertAccountType(tenantService.get(tenantParam), creditCard, billingAddress,
                    form.getInitialPayment(), form.getAccountTypeName(), browserDetails, getRemoteUserIp(request),
                    getSessionLocale(request), getCurrentUser(), form.getTenant().isSyncBillingAddress());
        } catch (HibernateOptimisticLockingFailureException ex) {
            logger.error(ex);
            tenantService.refresh(tenantService.get(tenantParam));
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            throw new InvalidAjaxRequestException(ex.getMessage());
        } catch (TenantStateChangeFailedException ex) {
            logger.error(ex);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            throw new InvalidAjaxRequestException(ex.getMessage());
        } catch (CreditCardFraudCheckException ex) {
            logger.error(ex);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            throw new InvalidAjaxRequestException(ex.getMessage());
        } catch (Exception ex) {
            logger.error(ex);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            throw new InvalidAjaxRequestException(messageSource
                    .getMessage("ui.usage.billing.paymentinfo.cc.edit.errormsg", null, getSessionLocale(request)));
        }
        map.put("redirecturl", "/portal/portal/tenants/editcurrent");
        return map;
    }

    @RequestMapping(value = "/changeaccounttype", method = RequestMethod.GET)
    public String changeAccountType(@RequestParam(value = "tenant", required = false) String tenantParam,
            ModelMap map) {
        logger.debug("###Entering in changeAccountType(tenantId,map,) method @GET");
        Tenant tenant = tenantService.get(tenantParam);
        List<AccountType> targetAccountTypes = tenantService.getAllowedTargetAccountTypes(tenant.getAccountType());
        SetAccountTypeForm setAccountTypeForm = new SetAccountTypeForm(tenant);
        map.addAttribute("setAccountTypeForm", setAccountTypeForm);
        map.addAttribute("targetAccountTypes", targetAccountTypes);
        map.addAttribute("tenant", tenant);
        return "billing.change.account.type";
    }

    @RequestMapping(value = "/show_record_deposit", method = RequestMethod.GET)
    public String showRecordDeposit(@RequestParam(value = "tenant", required = true) String tenantParam,
            @ModelAttribute("currentTenant") Tenant currentTenant, ModelMap map, HttpServletRequest request) {
        logger.debug("###Entering in record deposit");

        setPage(map, Page.USAGE_BILLING_RECORD_DEPOSIT);

        boolean showUserProfile = false;
        Tenant effectiveTenant = (Tenant) request.getAttribute(UserContextInterceptor.EFFECTIVE_TENANT_KEY);
        User currentUser = getCurrentUser();
        if ((Boolean) request.getAttribute("isSurrogatedTenant")) {
            showUserProfile = true;
            map.addAttribute("userHasCloudServiceAccount",
                    userService.isUserHasAnyActiveCloudService(effectiveTenant.getOwner()));
        } else {
            map.addAttribute("userHasCloudServiceAccount", userService.isUserHasAnyActiveCloudService(currentUser));
        }

        map.addAttribute("showUserProfile", showUserProfile);

        Tenant tenant = tenantService.get(tenantParam);
        DepositRecord depositRecord = tenantService.getDepositRecordByTenant(tenant);
        if (depositRecord != null) {
            map.addAttribute("show_deposit_record", true);
            map.addAttribute("depositRecord", depositRecord);
        } else {
            map.addAttribute("show_deposit_record", false);
        }

        map.addAttribute("tenant", tenant);
        return "billing.show_record_deposit";
    }

    @RequestMapping(value = "/record_deposit", method = RequestMethod.GET)
    public String recordDeposit(@RequestParam(value = "tenant", required = true) String tenantParam,
            @ModelAttribute("currentTenant") Tenant currentTenant, ModelMap map, HttpServletRequest request) {
        logger.debug("###Entering in record deposit");

        setPage(map, Page.USAGE_BILLING_RECORD_DEPOSIT);
        map.addAttribute("showUserProfile", request.getAttribute("isSurrogatedTenant"));

        Tenant tenant = tenantService.get(tenantParam);
        map.addAttribute("tenant", tenant);
        DepositRecordForm depositRecordForm = new DepositRecordForm();
        depositRecordForm.setAmount(
                tenant.getAccountType().getInitialDeposit(tenant.getCurrency().getCurrencyCode()).toPlainString());
        map.addAttribute("depositRecordForm", depositRecordForm);
        return "billing.record_deposit";
    }

    @RequestMapping(value = "/record_deposit", method = RequestMethod.POST)
    @ResponseBody
    public DepositRecordForm recordDeposit(@RequestParam(value = "tenant", required = false) String tenantParam,
            @Valid @ModelAttribute("depositRecordForm") DepositRecordForm depositRecordForm, BindingResult result,
            ModelMap map, HttpServletResponse response) {
        logger.debug("###Entering in recordDeposit method @POST");

        setPage(map, Page.USAGE_BILLING_RECORD_DEPOSIT);
        map.addAttribute("showUserProfile", true);

        Tenant tenant = tenantService.get(tenantParam);
        map.addAttribute("tenant", tenant);
        map.addAttribute("depositForm", depositRecordForm);
        DepositRecordValidator depositRecordValidator = new DepositRecordValidator();
        depositRecordValidator.validate(depositRecordForm, result);
        if (result.hasErrors()) {
            map.addAttribute("depositRecordForm", depositRecordForm);
            List<FieldError> l = result.getFieldErrors();
            for (FieldError f : l) {
                if (f.getCode().equals("js.deposit.record.validationReceivedOn")) {
                    throw new AjaxFormValidationException(result);
                }
            }
        }

        try {
            SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
            Date recievedOn = null;
            try {
                recievedOn = sdf.parse(depositRecordForm.getReceivedOn());
            } catch (ParseException e) {
            }
            tenantService.recordDeposit(tenant,
                    new DepositRecord(
                            tenant, recievedOn, tenant.getAccountType()
                                    .getInitialDeposit(tenant.getCurrency().getCurrencyCode()).doubleValue(),
                            getCurrentUser()));

        } catch (HibernateOptimisticLockingFailureException ex) {
            logger.error(ex);
            tenantService.refresh(tenant);
            throw new InvalidAjaxRequestException(ex.getMessage());
        }
        response.setStatus(HttpStatus.OK.value());
        logger.debug("###Exiting recordDeposit method @POST");

        return depositRecordForm;
    }

    @RequestMapping(value = { "/generatePdfInvoice" }, method = RequestMethod.GET)
    public String generatePdfAccountStatement(@ModelAttribute("currentTenant") Tenant tenant,
            @RequestParam(value = "viewBy", required = false) String viewBy,
            @RequestParam(value = "tenant", required = false) String tenantParam,
            @RequestParam(value = "accountStatementUuid", required = false) String accountStatementUuid,
            @RequestParam(value = "page", required = false, defaultValue = "1") String currentPage, ModelMap map,
            HttpServletRequest request, HttpServletResponse response) {

        logger.debug("###Entering in generatePdfAccountStaement method @GET");

        Tenant effectiveTenant = (Tenant) request.getAttribute(UserContextInterceptor.EFFECTIVE_TENANT_KEY);

        String targetXmlFile = "UB" + System.currentTimeMillis() + "." + "pdf";

        OutputStream pdfOut = null;
        AccountStatement accountStatement = billingService.getAccountStatement(accountStatementUuid);
        Locale locale = getCurrentUser().getLocale() != null ? getCurrentUser().getLocale() : getDefaultLocale();
        String pdfHtmlString = getInvoicePdfHtmlString(effectiveTenant, accountStatement, locale.toString());

        if (pdfHtmlString != null) {
            ByteArrayInputStream htmlSource;
            try {
                htmlSource = new ByteArrayInputStream(pdfHtmlString.getBytes("UTF-8"));
                pdfOut = pdfGenerator.generatePdfFromHtml(htmlSource);
            } catch (UnsupportedEncodingException e) {
                logger.error(e.getMessage(), e);
            } catch (FileNotFoundException e) {
                logger.error(e.getMessage(), e);
            } catch (IOException e) {
                logger.error(e.getMessage(), e);
            }
        }

        if (pdfOut != null) {
            response.setHeader("Content-Disposition", "attachment; filename=" + targetXmlFile);
            response.setContentType("application/pdf");
            OutputStream out = null;
            InputStream is = null;
            try {
                out = response.getOutputStream();
                is = new BufferedInputStream(
                        new ByteArrayInputStream(((ByteArrayOutputStream) pdfOut).toByteArray()));
                FileCopyUtils.copy(is, response.getOutputStream());
                out.flush();
            } catch (IOException e) {
                logger.error(e.getMessage(), e);
            } finally {
                try {
                    if (is != null) {
                        is.close();
                    }
                    out.close();
                } catch (IOException e) {
                    logger.error("Error while closing streams", e);
                }
            }
        } else {
            return "generatePdfAccountStatement.error";
        }
        return null;
    }

    @RequestMapping(value = { "/sendEmailPdfInvoice" }, method = RequestMethod.GET)
    public void sendEmailPdfAccountStatement(@ModelAttribute("currentTenant") Tenant tenant,
            @RequestParam(value = "viewBy", required = false) String viewBy,
            @RequestParam(value = "tenant", required = false) String tenantParam,
            @RequestParam(value = "accountStatementUuid", required = false) String accountStatementUuid,
            @RequestParam(value = "page", required = false, defaultValue = "1") String currentPage, ModelMap map,
            HttpServletRequest request, HttpServletResponse response) {

        logger.debug("###Entering in sendEmailPdfAccountStaement method @GET");

        Tenant effectiveTenant = (Tenant) request.getAttribute(UserContextInterceptor.EFFECTIVE_TENANT_KEY);

        AccountStatement accountStatement = billingService.getAccountStatement(accountStatementUuid);
        Locale locale = getCurrentUser().getLocale() != null ? getCurrentUser().getLocale() : getDefaultLocale();
        String invoicePdfString = getInvoicePdfHtmlString(effectiveTenant, accountStatement, locale.toString());

        List<String> listUser = new ArrayList<String>();
        User currentUser = getCurrentUser();
        listUser.add(currentUser.getEmail());
        billingService.sendInvoiceEmail(currentUser, invoicePdfString, accountStatement, locale, listUser);
    }

    private String getInvoicePdfHtmlString(Tenant tenant, AccountStatement accountStatement, String locale) {
        User currentUser = getCurrentUser();
        boolean hasFullView = hasFullBillingView(currentUser);
        if (hasFullView) {
            currentUser = null;
        }
        return billingService.getInvoiceAsHTMLString(accountStatement, currentUser, locale);
    }

}