private async Task ChargeSucceededAsync(DomainEvent billingEvent) { // Retrieve company by charge data DomainCharge charge = await _billingChargeService.GetAsync(new DomainCharge { Id = billingEvent.ObjectId }); DomainCompany company = await _companyService.FindByCustomerAsync(charge.CustomerId); // Updating balance var balanceRecord = new DomainBalanceHistory { Amount = charge.AmountInCents, Description = BillingMessages.ChargeSucceeded, CompanyId = company.Id }; await _balanceService.AddAsync(balanceRecord); // Notify client about payment operation result try { await _notificationService.SendPaymentNotificationAsync(billingEvent, company, charge); } catch (Exception e) { Trace.TraceError("Failed to send payment notification e-mail to company {0}: {1}", company.Id, e); } }
public async Task <DomainCompany> AddAsync(DomainCompany company) { company.Created = DateTime.UtcNow; company.Email = company.Email.ToLowerInvariant(); CompanyEntity entity = _mapper.Map <DomainCompany, CompanyEntity>(company); // Creating customer in billing system var customerCreateOptions = new DomainCustomerCreateOptions { Email = entity.Email }; DomainCustomer customer; try { customer = await _billingCustomerService.AddAsync(customerCreateOptions); } catch (BillingException e) { throw new BadRequestException(string.Format("Failed to register customer {0}: {1}", entity.Email, e)); } entity.BillingCustomerId = customer.Id; entity = await _companyRepository.AddAsync(entity); return(_mapper.Map <CompanyEntity, DomainCompany>(entity)); }
public async Task <HttpResponseMessage> Put(ClientModel model) { // Change e-mail await _userService.ChangeEmailAsync(UserId, model.Email); // Update user var userUpdate = new UserUpdateOptions { Country = model.Country, UserName = model.ContactPerson }; DomainUser user = await _userService.UpdateAsync(UserId, userUpdate); // Update company var companyUpdate = new CompanyUpdateOptions { Address = model.Address, Country = model.Country, Ein = model.Ein, Name = model.CompanyName, Phone = model.PhoneNumber, ZipCode = model.ZipCode, Email = model.Email }; DomainCompany company = await _companyService.UpdateByUserAsync(UserId, companyUpdate); Client client = _mapper.Map <Tuple <DomainUser, DomainCompany>, Client>(new Tuple <DomainUser, DomainCompany>(user, company)); HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, client); return(response); }
private async Task SyncCompanyAsync(DomainCompany company, JObject subscriptionPlans, DateTime?syncDate = null) { syncDate = syncDate ?? DateTime.UtcNow.AddMinutes(-1); // just to be sure that all transactions were committed List <CompanySubscription> subscriptions = company.Subscriptions.Where(s => s.State == ResourceState.Available).ToList(); List <Task> subscriptionTasks = subscriptions.Select(s => SyncSubscriptionAsync(company.Id, s, syncDate.Value, subscriptionPlans)).ToList(); await Task.WhenAll(subscriptionTasks); }
public async Task <IEnumerable <Subscription> > Get() { // Get company for user DomainCompany company = await _companyService.FindByUserAsync(UserId); List <CompanySubscription> activeSubscriptions = company.Subscriptions; return(_mapper.Map <List <CompanySubscription>, List <Subscription> >(activeSubscriptions)); }
public async Task <IEnumerable <BalanceHistory> > Get() { // Get company for user DomainCompany company = await _companyService.FindByUserAsync(UserId); IEnumerable <DomainBalanceHistory> balanceHistory = await _balanceService.QueryHistoryAsync(company.Id); return(_mapper.Map <IEnumerable <DomainBalanceHistory>, IEnumerable <BalanceHistory> >(balanceHistory)); }
// // GET: /api/clients/balance /// <summary> /// Gets accumulative client company balance. /// </summary> /// <returns></returns> public async Task <Balance> Get() { // Get company for user DomainCompany company = await _companyService.FindByUserAsync(UserId); decimal balance = await _balanceService.GetBalanceAsync(company.Id); return(new Balance { Amount = balance, Date = DateTime.UtcNow }); }
// // GET: /api/clients/subscriptions/{id} /// <summary> /// Gets client subscription. /// </summary> /// <returns></returns> public async Task <Subscription> Get(string id) { // Get company for user DomainCompany company = await _companyService.FindByUserAsync(UserId); CompanySubscription subscription = company.Subscriptions.FirstOrDefault(s => s.Id == id); if (subscription == null) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.NotFound, ResponseMessages.ResourceNotFound)); } return(_mapper.Map <CompanySubscription, Subscription>(subscription)); }
// // GET: /api/clients /// <summary> /// Gets client profile information. /// </summary> /// <returns>Client profile information.</returns> public async Task <HttpResponseMessage> Get() { // Get profile DomainUser user = await _userService.GetAsync(UserId); // Get company DomainCompany company = await _companyService.FindByUserAsync(UserId); Client client = _mapper.Map <Tuple <DomainUser, DomainCompany>, Client>(new Tuple <DomainUser, DomainCompany>(user, company)); HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, client); response.SetLastModifiedDate(user.Modified); return(response); }
private async Task ChargeFailedAsync(DomainEvent billingEvent) { // Retrieve company by charge data DomainCharge charge = await _billingChargeService.GetAsync(new DomainCharge { Id = billingEvent.ObjectId }); DomainCompany company = await _companyService.FindByCustomerAsync(charge.CustomerId); // Notify client about payment operation result try { await _notificationService.SendPaymentNotificationAsync(billingEvent, company, charge); } catch (Exception e) { Trace.TraceError("Failed to send payment notification e-mail to company {0}: {1}", company.Id, e); } }
private async Task ChargeRefundedAsync(DomainEvent billingEvent) { // Get charge info DomainCharge charge = await _billingChargeService.GetAsync(new DomainCharge { Id = billingEvent.ObjectId }); var refunds = billingEvent.Object["refunds"] as JArray; if (refunds != null) { // refund can be partial, accounting only last refund JToken lastRefund = refunds.Last; int refundInCents = Int32.Parse(lastRefund["amount"].ToString()); charge.AmountInCents = refundInCents; } // Retrieve company by customer DomainCompany company = await _companyService.FindByCustomerAsync(charge.CustomerId); // updating balance var balanceRecord = new DomainBalanceHistory { Amount = -charge.AmountInCents, Description = BillingMessages.ChargeRefunded, CompanyId = company.Id }; await _balanceService.AddAsync(balanceRecord); // Notify client about payment operation result try { await _notificationService.SendPaymentNotificationAsync(billingEvent, company, charge); } catch (Exception e) { Trace.TraceError("Failed to send payment notification e-mail to company {0}: {1}", company.Id, e); } }
public async Task <HttpResponseMessage> Post(ClientPaymentModel model) { // Get company for user DomainCompany company = await _companyService.FindByUserAsync(UserId); var chargeCreateOptions = new CompanyChargeOptions { Id = company.Id, AmountInCents = model.AmountInCents, Currency = DomainCurrencies.Default, Description = model.Description, TokenId = model.TokenId }; // Charging // balance will be updated after callback (webhook) from billing system await _companyService.ChargeAsync(chargeCreateOptions); HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created); return(response); }
public async Task <ActionResult> ActivateClient(string code) { DomainPendingClient model; try { model = await _pendingClientService.GetAndDeleteAsync(code); } catch (NotFoundException) { return((ActionResult)RedirectToAction("Index", "Home")); } catch (Exception e) { Trace.TraceError("Failed to find client: {0}", e); return(new HttpStatusCodeResult(HttpStatusCode.InternalServerError)); } // Add profile var user = new DomainUser { ApplicationName = AppName, Name = model.ContactPerson, Country = model.Country, UserAgent = _productIdExtractor.Get(Request.UserAgent), Email = model.Email, Roles = new List <string> { DomainRoles.Client } }; try { user = await _userService.AddAsync(user); } catch (ConflictException) { return(new HttpStatusCodeResult(HttpStatusCode.Conflict)); } catch (Exception e) { Trace.TraceError("Failed to create user profile for {0}: {1}", model.Email, e); return(new HttpStatusCodeResult(HttpStatusCode.InternalServerError)); } // Set user password try { await _passwordService.SetPasswordAsync(user.Id, model.Password, model.PasswordSalt); } catch (Exception e) { Trace.TraceError("Failed to set user {0} password: {1}", user.Id, e); return(new HttpStatusCodeResult(HttpStatusCode.InternalServerError)); } // Add company var company = new DomainCompany { Email = model.Email, Name = model.CompanyName, Address = model.Address, ZipCode = model.ZipCode, Phone = model.PhoneNumber, Country = model.Country, Ein = model.Ein, Users = new List <string> { user.Id } }; try { await _companyService.AddAsync(company); } catch (Exception e) { Trace.TraceError("Failed to create company for user {0}: {1}", user.Id, e); return(new HttpStatusCodeResult(HttpStatusCode.InternalServerError)); } // Authenticate await _authenticationService.SetUserAsync(user, null, true); return(RedirectToRoute(RouteNames.ClientSubscriptions)); }
public async Task <IEnumerable <TrackingStatPerDate> > Get(string id, [FromUri] ClientSubscriptionStatUrlModel model, ODataQueryOptions <TrackingStatPerDate> options) { var validationSettings = new ODataValidationSettings { AllowedArithmeticOperators = AllowedArithmeticOperators.None, AllowedFunctions = AllowedFunctions.None, AllowedLogicalOperators = AllowedLogicalOperators.Equal | AllowedLogicalOperators.LessThan | AllowedLogicalOperators.LessThanOrEqual | AllowedLogicalOperators.GreaterThan | AllowedLogicalOperators.GreaterThanOrEqual | AllowedLogicalOperators.And, AllowedQueryOptions = AllowedQueryOptions.Filter }; // Validating query options try { options.Validate(validationSettings); } catch (Exception) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.InvalidQueryOptions)); } // Parsing filter parameters DataQueryOptions filter; try { filter = _mapper.Map <ODataQueryOptions, DataQueryOptions>(options); } catch (AutoMapperMappingException) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.InvalidQueryOptions)); } // Get company for user DomainCompany company = await _companyService.FindBySubscriptionAsync(id); if (!company.Users.Contains(UserId)) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Forbidden, ResponseMessages.Forbidden)); } // Find subscription CompanySubscription subscription = company.Subscriptions.FirstOrDefault(s => s.Id == id); if (subscription == null) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.NotFound, ResponseMessages.ResourceNotFound)); } // Get stats IEnumerable <DomainTrackingStatPerDate> stats; try { stats = await _urlTrackingStatService.GetStatsPerDateAsync(id, model.Url, filter); } catch (NotSupportedException) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.BadRequest)); } catch (ArgumentException) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.BadRequest)); } IEnumerable <TrackingStatPerDate> results = stats.Select(r => _mapper.Map <DomainTrackingStatPerDate, TrackingStatPerDate>(r)); return(results); }
public void TestInaccauntableClicks() { // 1. Arrange // config _config.Setup(x => x.SubscriptionPlans) .Returns( () => JObject.Parse( "{ 0: { syncPeriodMs: 0, cyclePeriodMs: 0, clickRates: { 0: 0 } }, 1: { syncPeriodMs: 60000, cyclePeriodMs: 2592000000, clickRates: { 0: 0, 20: 10 } }, 2: { syncPeriodMs: 2592000000, cyclePeriodMs: 2592000000, clickRates: { 0: 0, 100000: 0.05, 1000000: 0.01 } }, 3: { syncPeriodMs: 2592000000, cyclePeriodMs: 2592000000, clickRates: { 0: 0, 100000: 0.05, 1000000: 0.01 } } }")); _config.Setup(x => x.BillingInvoiceItemDescriptionTemplate).Returns(() => "{0}"); // stats service var stas = new List <TrackingStatEntity> { new TrackingStatEntity { Date = new DateTime(2014, 6, 4, 14, 28, 35, 596) }, new TrackingStatEntity { Date = new DateTime(2014, 6, 4, 14, 28, 36, 995) }, new TrackingStatEntity { Date = new DateTime(2014, 6, 4, 14, 28, 41, 889) }, new TrackingStatEntity { Date = new DateTime(2014, 6, 4, 14, 28, 44, 249) }, new TrackingStatEntity { Date = new DateTime(2014, 6, 4, 14, 28, 48, 335) } }; _statService.Setup(x => x.GetTotalAsync(It.IsAny <string>(), It.IsAny <DateTime?>(), It.IsAny <DateTime?>())).Returns <string, DateTime?, DateTime?>((i, f, t) => { IQueryable <TrackingStatEntity> r = stas.AsQueryable(); if (f.HasValue) { r = r.Where(s => s.Date >= f.Value); } if (t.HasValue) { r = r.Where(s => s.Date < t.Value); } return(Task.FromResult(r.LongCount())); }); // company service var company = new DomainCompany { State = ResourceState.Available, Subscriptions = new List <CompanySubscription> { new CompanySubscription { State = ResourceState.Available, Type = SubscriptionType.Basic, Created = new DateTime(2014, 6, 4, 14, 25, 14, 133), LastSyncDate = null, LastCycleDate = new DateTime(2014, 6, 4, 14, 27, 37, 939), HasTrialClicks = false } } }; var companies = new List <DomainCompany> { company }; _companyService.Setup(x => x.ListAsync()).Returns(() => Task.FromResult(companies.AsEnumerable())); // balance service var balance = new DomainBalanceHistory(); _balanceService.Setup(x => x.AddAsync(It.IsAny <DomainBalanceHistory>())).Returns <DomainBalanceHistory>(b => { balance = b; return(Task.FromResult(balance)); }); // 2. Act var syncDate = new DateTime(2014, 6, 4, 14, 28, 37, 939); _syncManager.SyncAsync(syncDate).Wait(); // 3. Assert long actualCount = Int64.Parse(balance.Description); Assert.AreEqual(2, actualCount); }
public async Task <HttpResponseMessage> Get(string id, ODataQueryOptions <TrackingStatPerUrl> options) { var validationSettings = new ODataValidationSettings { MaxTop = 100, AllowedArithmeticOperators = AllowedArithmeticOperators.None, AllowedFunctions = AllowedFunctions.None, AllowedLogicalOperators = AllowedLogicalOperators.Equal | AllowedLogicalOperators.And, AllowedQueryOptions = AllowedQueryOptions.Filter | AllowedQueryOptions.OrderBy | AllowedQueryOptions.Skip | AllowedQueryOptions.Top | AllowedQueryOptions.InlineCount }; // Validating query options try { options.Validate(validationSettings); } catch (Exception) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.InvalidQueryOptions)); } // Parsing filter parameters DataQueryOptions filter; try { filter = _mapper.Map <ODataQueryOptions, DataQueryOptions>(options); } catch (AutoMapperMappingException) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.InvalidQueryOptions)); } // Get company for user DomainCompany company = await _companyService.FindByUserAsync(UserId); // Find subscription CompanySubscription subscription = company.Subscriptions.FirstOrDefault(s => s.Id == id); if (subscription == null) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.NotFound, ResponseMessages.ResourceNotFound)); } // Get stats DataResult <DomainTrackingStatPerUrl> stats; try { stats = await _urlTrackingStatService.GetStatsPerUrlAsync(id, filter); } catch (NotSupportedException) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.BadRequest)); } catch (ArgumentException) { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ResponseMessages.BadRequest)); } IEnumerable <TrackingStatPerUrl> results = stats.Results.Select(r => _mapper.Map <DomainTrackingStatPerUrl, TrackingStatPerUrl>(r)); if (filter.Count) { var pageResult = new PageResult <TrackingStatPerUrl>(results, null, stats.Count); return(Request.CreateResponse(HttpStatusCode.OK, pageResult)); } return(Request.CreateResponse(HttpStatusCode.OK, results)); }
public async Task SendPaymentNotificationAsync(DomainEvent billingEvent, DomainCompany company, DomainCharge charge) { if (billingEvent == null) { throw new ArgumentNullException("billingEvent"); } if (company == null) { throw new ArgumentNullException("company"); } if (charge == null) { throw new ArgumentNullException("charge"); } if (!_settings.EmailNotifications) { return; } var email = new SendEmailDomain { Address = _settings.EmailAddressAlerts, DisplayName = Emails.SenderDisplayName, Emails = new List <string> { company.Email } }; switch (billingEvent.Type) { case EventType.ChargeFailed: email.Subject = Emails.SubjectPaymentFailed; email.Body = string.Format( PortalResources.PaymentFailed, company.Name, billingEvent.Id, string.Format("{0} {1}", charge.AmountInCents * 0.01, charge.Currency), charge.Created); break; case EventType.ChargeSucceeded: email.Subject = Emails.SubjectPaymentCompleted; email.Body = string.Format( PortalResources.PaymentCompleted, company.Name, billingEvent.Id, string.Format("{0} {1}", charge.AmountInCents * 0.01, charge.Currency), charge.Created); break; case EventType.ChargeRefunded: email.Subject = Emails.SubjectPaymentRefunded; email.Body = string.Format( PortalResources.PaymentRefunded, company.Name, billingEvent.Id, string.Format("{0} {1}", charge.AmountInCents * 0.01, charge.Currency), charge.Created); break; default: return; } // Send email on user registration await _emailSenderService.SendEmailAsync(email); }