(function () { "use strict"; var serviceId = "paymentsDataContext"; var app = angular.module("payments"); function datacontext( $q, $http, config, orgAdminService, $window, fsl, $filter, rootConfig ) { var selectedPlan = {}; var additionalProperties = {}; var currencyOptions = [ { name: "£ GBP", symbol: "£", code: "gbp" }, { name: "$ USD", symbol: "$", code: "usd" }, { name: "€ EUR", symbol: "€", code: "eur" } ]; var myshowcaseImage = "https://uiframework.mkmapps.com/latest/lib/products/myshowcase/images/stripe-logo.png"; var obImage = rootConfig.sysUrl + "img/icons/180.png"; var currentPaymentDetail; var service = { getHandler: getHandler, getGroupedPlans: getGroupedPlans, getPlans: getPlans, getPlan: getPlan, getSelectedPlan: getSelectedPlan, setSelectedPlan: setSelectedPlan, setAdditionalProperties: setAdditionalProperties, getAdditionalProperties: getAdditionalProperties, sendRequest: sendRequest, getCurrentPaymentDetails: getCurrentPaymentDetails, previewPlanUpgrade: previewPlanUpgrade, planUpgrade: planUpgrade, getInvoices: getInvoices, getCurrencyOptions: getCurrencyOptions, changeCard: changeCard, planCancel: planCancel, planCancelDowngrade: planCancelDowngrade, planEnable: planEnable, planRestart: planRestart, showStripeForNewAccount: showStripeForNewAccount, validateVat: validateVat }; return service; function validateVat(vatregno) { var request = $http({ method: "GET", url: "https://apilayer.net/api/validate?access_key=b22a49e56f39a3b47fdd87acfac9e98b&vat_number=" + vatregno + "&format=1" }); return request.then(function (response) { return response.data.valid; }, handleError); } function changeCard(email, billing) { var description = "Update payment card"; var label = "Change card"; if (!billing) { billing = false; } else { description = "Update payment details"; label = "Change details"; } var options = { name: currentPaymentDetail.name, email: email, description: description, locale: "auto", currency: currentPaymentDetail.currency, zipCode: true, amount: 0, panelLabel: label, image: myshowcaseImage, billingAddress: billing } if (rootConfig.appCode === "OB") { options.image = obImage; } return getHandler(handleTokenForChangeCard).open(options); } function planRestart(email, users, cost, noVat) { additionalProperties = { Users: users }; selectedPlan = currentPaymentDetail; var label = "{{amount}} per " + selectedPlan.frequency; if (!noVat) { label = label + " excl. Tax"; } var options = { name: currentPaymentDetail.name, email: email, description: users + " Users @ " + currentPaymentDetail.currencySymbol + currentPaymentDetail.cost * 1.0 / 100 + " per user per " + currentPaymentDetail.frequency, locale: "auto", currency: currentPaymentDetail.currency, zipCode: true, amount: cost, panelLabel: label, image: myshowcaseImage, billingAddress: true }; if (rootConfig.appCode === "OB") { options.image = obImage; } return getHandler().open(options); } function showStripeForNewAccount(plan, email, users, cost, noVat, euVat) { additionalProperties = { Users: users, noVAT: noVat }; if (euVat) { additionalProperties.euVAT = euVat; } selectedPlan = plan; var label = "{{amount}} per " + plan.frequency; if (!noVat) { label = label + " excl. Tax"; } var options = { name: plan.name, email: email, description: users + " Users @ " + plan.currencySymbol + plan.cost * 1.0 / 100 + " per user per " + plan.frequency, locale: "auto", currency: plan.currency, zipCode: true, amount: cost, panelLabel: label, image: myshowcaseImage, billingAddress: true }; if (rootConfig.appCode === "OB") { options.image = obImage; } return getHandler().open(options); } function getCurrencyOptions() { return $q.resolve(currencyOptions); } function setAdditionalProperties(properties) { additionalProperties = properties; } function getAdditionalProperties() { return additionalProperties; } var orderedPlans; var orderedPlansPromise; function getGroupedPlans() { if (!orderedPlans) { if (!orderedPlansPromise) { orderedPlansPromise = getPlans().then(function (data) { orderedPlans = { plans: {}, frequencies: [], currencies: [] }; //create a dictionary of all the different plans and var costOrderedPlans = $filter("orderBy")(data, "cost"); costOrderedPlans.forEach(function (plan) { if (!(plan.groupName in orderedPlans.plans)) { orderedPlans.plans[plan.groupName] = {}; orderedPlans.plans[plan.groupName].currency = {}; } if (!(orderedPlans.currencies.indexOf(plan.currency) >= 0)) { orderedPlans.currencies.push(plan.currency) } if (!(orderedPlans.frequencies.indexOf(plan.frequency) >= 0)) { orderedPlans.frequencies.push(plan.frequency) } var group = orderedPlans.plans[plan.groupName]; group.freePlan = plan.isFreePlan; if (!(plan.currency in group.currency)) { group.currency[plan.currency] = {}; } var currency = group.currency[plan.currency]; if (!(plan.frequency in currency)) { currency[plan.frequency] = plan; } }); return orderedPlans; }); } return orderedPlansPromise; } return $q.resolve(orderedPlans); } var plans; var plansPromise; function getPlans() { if (!plans) { if (!plansPromise) { plansPromise = $http({ method: "GET", url: config.paymentsRemoteServiceUrl + "api/applications/" + rootConfig.appCode + "/plans" }).then(function (response) { plans = []; response.data.forEach(function (item) { plans.push(myPaymentsPlanToSimplePlan(item)); }); return plans; }, handleError); } return plansPromise; } return $q.resolve(plans); } function getPlan(plan) { if (!plans) { return getPlans().then(function (data) { return $filter("filter")(data, { id: plan })[0]; }); } return $q.resolve($filter("filter")(plans, { id: plan })[0]); } function setSelectedPlan(plan) { selectedPlan = plan; } function getSelectedPlan() { return selectedPlan; } function handleError(response) { // The API response from the server should be returned in a // nomralized format. However, if the request was not handled by the // server (or what not handles properly - ex. server error), then we // may have to normalize it on our end, as best we can. if (response.data && response.data.Message !== null) { response.data.message = response.data.Message; } if (angular.isObject(response.data) && response.data.Status == "requires_action") { return $q.reject(response.data); } if (!angular.isObject(response.data) || !response.data.message) { return $q.reject("An unknown error occurred."); } if (response.data.ExceptionMessage !== null) { return $q.reject(response.data.ExceptionMessage); } // Otherwise, use expected error message. return $q.reject(response.data.message); } function handleSuccess(response) { return response.data; } function handleSuccessAndRedirect() { var path = ""; if (appCode == "OB") { path = sysUrl + "#!/subscription/details"; path = sysUrl + "#!/dashboard?updated=successfully"; } else { path = myShowcaseAdminSiteUrl + "#!/account/details"; } window.location = path; return $window.location.reload(); } function getInvoices() { return orgAdminService.getTopLevelOrg().then(function (data) { var request = $http({ method: "GET", url: config.paymentsRemoteServiceUrl + "api/organisationadministration/" + data.id + "/applications/" + rootConfig.appCode + "/invoice" + '?cache=' + Date.now() }); return request.then(handleSuccess, handleError); }); } function previewPlanUpgrade(updateData, orgId) { var orgPromise; if (!orgId) { orgPromise = orgAdminService.getTopLevelOrg(); } else { orgPromise = $q.resolve({ id: orgId }); } return orgPromise.then(function (data) { var request = $http({ method: "POST", url: config.paymentsRemoteServiceUrl + "api/organisationadministration/" + data.id + "/applications/" + rootConfig.appCode + "/preview", data: { PlanId: updateData.planId, PlanProperties: updateData.properties, VatCode: updateData.vatCode, CountryCode: updateData.countryCode } }).then(function (data) { if (data.data) { if (data.data.Results) { if (data.data.Results.NextInvoice) { var invoice = data.data.Results.NextInvoice; if (invoice.Total) { invoice.Total = invoice.Total * 1.0 / 100; } if (invoice.SubTotal) { invoice.SubTotal = invoice.SubTotal * 1.0 / 100; } if (invoice.Taxes) { invoice.Taxes = invoice.Taxes * 1.0 / 100; } } if (data.data.Results.NormalInvoice) { var invoice = data.data.Results.NormalInvoice; if (invoice.Total) { invoice.Total = invoice.Total * 1.0 / 100; } if (invoice.SubTotal) { invoice.SubTotal = invoice.SubTotal * 1.0 / 100; } if (invoice.Taxes) { invoice.Taxes = invoice.Taxes * 1.0 / 100; } } } } return data; }); return request.then(handleSuccess, handleError); }); } function planUpgrade(token, paymentId) { return orgAdminService.getTopLevelOrg().then(function (data) { var request = $http({ method: "POST", url: config.paymentsRemoteServiceUrl + "api/organisationadministration/" + data.id + "/applications/" + rootConfig.appCode + "/confirm", data: { Token: token, PaymentId: paymentId } }).then(function (data) { var result = data; return result; }); return request.then(handleSuccessAndRedirect, handleError); }); } function myPaymentsPlanToSimplePlan(data) { var simplePlan = { lastFour: data.LastFour, expiresYear: data.ExpiryDateYear, expiresMonth: data.ExpiryDateMonth, isFreePlan: data.IsFreePlan, name: data.PlanName, id: data.PlanId, PlanId: data.PlanId, cost: data.PlanCost / 100, currency: data.PlanCurrency, frequency: data.PlanFrequency, quantity: data.PlanQuantity, minUsers: data.MinQuantity, maxUsers: data.MaxQuantity, cancelsAtPeriodEnd: data.CancelsAtPeriodEnd, changesAtPeriodEnd: data.ChangesAtPeriodEnd, changePlanId: data.ChangePlanId, cancelled: data.Cancelled, addressLine1: data.AddressLine1, addressLine2: data.AddressLine2, addressCity: data.AddressCity, addressCountry: data.AddressCountry, addressZip: data.AddressZip, addressState: data.AddressState, addressValid: data.AddressValid, addressName: data.AddressName, groupName: data.PlanGroupName, invoiceEmail: data.InvoiceEmail }; simplePlan.currencySymbol = currencyOptions.filter(function (item) { return item.code === simplePlan.currency; })[0].symbol; if (simplePlan.isFreePlan) { simplePlan.status = "Free"; } else if (simplePlan.cancelled) { simplePlan.status = "Cancelled"; } else if (simplePlan.cancelsAtPeriodEnd) { simplePlan.status = "Cancelling"; } else if (simplePlan.changesAtPeriodEnd) { simplePlan.status = "Downgrading"; } else { simplePlan.status = "Active"; } if (data.PaymentAttemptDate) { simplePlan.paymentAttemptDate = moment(data.PaymentAttemptDate); } if (data.TaxRate) { simplePlan.TaxRate = data.TaxRate * 1.0 / 100; simplePlan.cost = simplePlan.cost * (1 + simplePlan.TaxRate); } if (data.StartedDate) { simplePlan.startedDate = moment(data.StartedDate); } return simplePlan; } function getCurrentPaymentDetails() { if (!currentPaymentDetail) { return orgAdminService.getTopLevelOrg().then(function (data) { return getPaymentDetails(data.id) .then(function (data) { currentPaymentDetail = myPaymentsPlanToSimplePlan(data); return currentPaymentDetail; }) .catch(function (e) { // handle errors in processing or in error. return null; }); }); } return $q.resolve(currentPaymentDetail); } function getPaymentDetails(orgId) { var request = $http({ method: "get", url: config.paymentsRemoteServiceUrl + "api/organisationadministration/" + orgId + "/applications/" + rootConfig.appCode + "/plan" }); return request.then(handleSuccess, handleError); } function getHandler(afterFunction) { if (!afterFunction) { afterFunction = handleToken; } return StripeCheckout.configure({ key: config.publicKey, image: "https://stripe.com/img/documentation/checkout/marketplace.png", locale: "auto", token: afterFunction }); } function sendRequest(noRedirect, organisationId) { var orgIdPromise; if (!organisationId) { orgIdPromise = orgAdminService.getTopLevelOrg(); } else { orgIdPromise = $q.resolve({ id: organisationId }); } return orgIdPromise.then(function (data) { var request = $http({ method: "post", url: config.paymentsRemoteServiceUrl + "api/organisationadministration/" + data.id + "/applications/" + rootConfig.appCode + "/plan", data: { PlanId: selectedPlan.PlanId, PlanProperties: additionalProperties } }); if (noRedirect) { return request.then(handleSuccess, handleError); } else { return request.then(handleSuccessAndRedirect, handleError); } }); } function changeDetails(noRedirect) { return orgAdminService.getTopLevelOrg().then(function (data) { var request = $http({ method: "PUT", url: config.paymentsRemoteServiceUrl + "api/organisationadministration/" + data.id + "/billing", data: { Properties: additionalProperties } }); if (noRedirect) { return request.then(handleSuccess, handleError); } else { return request.then(handleSuccessAndRedirect, handleError); } }); } function planCancel(noRedirect) { return orgAdminService.getTopLevelOrg().then(function (data) { var request = $http({ method: "DELETE", url: config.paymentsRemoteServiceUrl + "api/organisationadministration/" + data.id + "/applications/" + rootConfig.appCode + "/plan" }); if (noRedirect) { return request.then(handleSuccess, handleError); } else { return request.then(handleSuccessAndRedirect, handleError); } }); } function planCancelDowngrade(noRedirect) { return orgAdminService.getTopLevelOrg().then(function (data) { var request = $http({ method: "DELETE", url: config.paymentsRemoteServiceUrl + "api/organisationadministration/" + data.id + "/applications/" + rootConfig.appCode + "/downgrade" }); if (noRedirect) { return request.then(handleSuccess, handleError); } else { return request.then(handleSuccessAndRedirect, handleError); } }); } function planEnable(noRedirect) { return orgAdminService.getTopLevelOrg().then(function (data) { var request = $http({ method: "POST", url: config.paymentsRemoteServiceUrl + "api/organisationadministration/" + data.id + "/applications/" + rootConfig.appCode + "/plan/enable" }); if (noRedirect) { return request.then(handleSuccess, handleError); } else { return request.then(handleSuccessAndRedirect, handleError); } }); } function handleToken(token) { // You can access the token ID with `token.id`. // Get the token ID to your server-side code for use. // At this point, we need to send the token to our code // the server side needs to create a stripe customer // and adds that customer to the subscription. // stripe then attempts to bill the customer, and tells the server if it works. //the server then needs to tell us the result. //So process is: Post to method, then wait for signalr result. //the signalr bit isn't done, so just do a page refresh //Spinner needed here fsl.show("Processing payment"); additionalProperties["Token"] = token.id; return sendRequest(); } function handleTokenForChangeCard(token) { fsl.show("Changing payment details"); additionalProperties["Token"] = token.id; return changeDetails(); } function handleTokenForChangeCardNoRedirect(token) { fsl.show("Changing payment details"); additionalProperties["Token"] = token.id; return changeDetails(true); } } app.factory(serviceId, [ "$q", "$http", "paymentsConfig", "OrganisationAdminService", "$window", "fullScreenLoaderContext", "$filter", "config", datacontext ]); })();