public async Task <DomainTrackingUrl> AddAsync(DomainTrackingUrl trackingUrl) { // Get subscription CompanySubscription subscription = await _subscriptionService.GetAsync(trackingUrl.SubscriptionId); // Check redirect url if (trackingUrl.RedirectUrl == null) { throw new ArgumentException("RedirectUrl required"); } if (!string.Equals(trackingUrl.RedirectUrl.Host, subscription.SiteHostname, StringComparison.InvariantCultureIgnoreCase)) { throw new BadRequestException( string.Format("Client subscription {0} allows only URLs starting with {1}: {2}", subscription.Id, subscription.SiteHostname, trackingUrl.RedirectUrl)); } // Add tracking url TrackingUrlEntity entity = _mappingEngine.Map <DomainTrackingUrl, TrackingUrlEntity>(trackingUrl); entity = await _trackingUrlRepository.AddAsync(entity); DomainTrackingUrl result = _mappingEngine.Map <TrackingUrlEntity, DomainTrackingUrl>(entity); result.Key = _urlShortenerService.Encode(Int64.Parse(result.Id)); return(result); }
public async Task <CompanySubscription> AddAsync(string userId, CompanySubscriptionCreateOptions options) { CompanySubscription subscription = _mapper.Map <CompanySubscriptionCreateOptions, CompanySubscription>(options); // Searching for company CompanyEntity company = await _companyRepository.FindByUserAsync(userId); if (company == null) { throw new NotFoundException(string.Format("Could not find company by user '{0}'", userId)); } CheckCompanyAccess(company); // Setting defaults subscription.Id = Guid.NewGuid().ToString(); subscription.Created = DateTime.UtcNow; subscription.HasTrialClicks = true; SubscriptionEntity subscriptionEntity = _mapper.Map <CompanySubscription, SubscriptionEntity>(subscription); // Updating company company.Subscriptions.Add(subscriptionEntity); await _companyRepository.UpdateAsync(company); return(subscription); }
public async Task <HttpResponseMessage> Post(CreateSubscriptionModel model) { // Create subscription CompanySubscription subscription = await _subscriptionService.AddAsync(UserId, model); Subscription subscriptionResponse = _mapper.Map <CompanySubscription, Subscription>(subscription); HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, subscriptionResponse); return(response); }
public async Task <HttpResponseMessage> Put(string id, SubscriptionModel model) { // Update subscription CompanySubscription subscription = await _subscriptionService.UpdateAsync(UserId, id, model); Subscription profileResponse = _mapper.Map <CompanySubscription, Subscription>(subscription); HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, profileResponse); return(response); }
// // 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)); }
public CompanyDto CreateCompany(CompanyCreateDto dto) { var repoUser = _contextManager.CreateRepositiry <IUserRepo>(); var user = repoUser.GetById(dto.UserId); var repoCompany = _contextManager.CreateRepositiry <ICompanyRepo>(); var company = repoCompany.GetCompanyByName(dto.Name); if (!(company == null)) { throw new ValidationException("Company with name <" + dto.Name + "> is already exists."); } var entity = _mapper.Map <Company>(dto); repoCompany.Add(entity); _contextManager.Save(); var repoCompUser = _contextManager.CreateRepositiry <ICompanyUserLinkRepo>(); var companyUser = new CompanyUserLink { CompanyId = entity.Id, UserId = user.Id, UserCompanyRole = (int)Model.Enums.CompanyUserRoleEnum.Owner }; repoCompUser.Add(companyUser); _contextManager.Save(); var repoCompSub = _contextManager.CreateRepositiry <ICompanySubRepo>(); var companySub = new CompanySubscription { CompanyId = entity.Id, UserId = user.Id, SubEndDt = DateTime.UtcNow.Date, UseTrialVersion = (int)Model.Enums.CompanyTrialVersionEnum.ReadyToUseTrial }; repoCompSub.Add(companySub); _contextManager.Save(); return(_mapper.Map <CompanyDto>(entity)); }
public async Task <bool> SubscribeAsync(int companyId, string userId) { var company = await this.dbContext.FindAsync <Company>(companyId); if (company == null) { return(false); } var sub = new CompanySubscription { UserId = userId, CompanyId = companyId }; await this.dbContext.AddAsync(sub); await this.dbContext.SaveChangesAsync(); return(true); }
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 bool SaveCompanySubscription(CompanySubscription CompanySubscription) { return(_businessInstance.SaveCompanySubscriptionInfo(CompanySubscription)); }
private async Task SyncSubscriptionAsync(string companyId, CompanySubscription subscription, DateTime syncDate, JObject subscriptionPlans) { if (subscription.Type == SubscriptionType.Free) { // nothing to sync return; } JToken planInfo = subscriptionPlans[((int)subscription.Type).ToString(CultureInfo.InvariantCulture)]; // Check invoice period DateTime lastSyncDate = subscription.LastSyncDate ?? subscription.Created; long syncPeriodMs = Int64.Parse((string)planInfo["syncPeriodMs"]); if (syncPeriodMs <= 0 || syncDate.Subtract(lastSyncDate).TotalMilliseconds < syncPeriodMs) { // its too early for invoice return; } // Calculate clicks for sync period long periodClicks = await _statService.GetTotalAsync(subscription.Id, lastSyncDate, syncDate); // Calculate clicks for cycle DateTime lastCycleDate = subscription.LastCycleDate ?? subscription.Created; long cycleClicks = await _statService.GetTotalAsync(subscription.Id, lastCycleDate, lastSyncDate); JToken clickRatesInfo = planInfo["clickRates"]; var charges = new List <Tuple <decimal, long, long, long?> >(); long clicks = periodClicks; decimal lastRate = 0; long lastCount = 0; long clicksMargin = cycleClicks; foreach (JToken clickRate in clickRatesInfo) { var r = clickRate as JProperty; if (r == null) { continue; } long count = Int64.Parse(r.Name); decimal rate = Decimal.Parse((string)r.Value); if (count <= 0) { // skip free/initial rate range lastRate = rate; continue; } if (clicksMargin >= count) { // skip last bill lastRate = rate; lastCount = count; continue; } // calculate charge for range of clicks long lastRange = Math.Max(clicksMargin, lastCount); long rangeClicks = lastRange + clicks < count ? clicks : count - lastRange; // reseting margin clicksMargin = 0; // creating charge if (rangeClicks > 0) { charges.Add(new Tuple <decimal, long, long, long?>(lastRate, rangeClicks, lastCount, count)); } // going to next range lastRate = rate; lastCount = count; clicks -= rangeClicks; if (clicks == 0) { break; } } if (clicks > 0) { // using last specified rate for exceeded clicks charges.Add(new Tuple <decimal, long, long, long?>(lastRate, clicks, lastCount, null)); } // Synchronizing var chargeRecords = new List <DomainBalanceHistory>(); try { if (charges.Count > 0) { if (charges.Sum(c => c.Item1) > 0) { // trial clicks ended await _subscriptionService.UpdateHasTrialClicksAsync(subscription.Id, false); } else { // trial clicks await _subscriptionService.UpdateHasTrialClicksAsync(subscription.Id, true); } foreach (var charge in charges) { decimal rate = charge.Item1; long count = charge.Item2; long lowCount = charge.Item3; long? highCount = charge.Item4; string packageName = highCount.HasValue ? string.Format("{0}-{1}", lowCount, highCount) : string.Format("{0}+", lowCount); var balanceRecord = new DomainBalanceHistory { CompanyId = companyId, Amount = -(rate * count), Description = string.Format(_config.BillingInvoiceItemDescriptionTemplate, count, subscription.SiteName, subscription.Id, subscription.Type, rate / 100, packageName, lastSyncDate, syncDate) }; await _balanceService.AddAsync(balanceRecord); chargeRecords.Add(balanceRecord); } } // cycle completed long cyclePeriodMs = Int64.Parse((string)planInfo["cyclePeriodMs"]); if (cyclePeriodMs > 0 && syncDate.Subtract(lastCycleDate).TotalMilliseconds >= cyclePeriodMs) { // updating last cycle date if cycle completed await _subscriptionService.UpdateLastCycleDateAsync(subscription.Id, syncDate); // enabling trial clicks await _subscriptionService.UpdateHasTrialClicksAsync(subscription.Id, true); } // updating last sync date await _subscriptionService.UpdateLastSyncDateAsync(subscription.Id, syncDate); } catch (Exception e) { Trace.TraceError("Failed to sync balance for subscription {0} of company {1}: {2}", companyId, subscription.Id, e); // trying rollback try { // rollback balance if (chargeRecords.Count > 0) { foreach (DomainBalanceHistory record in chargeRecords) { _balanceService.DeleteAsync(record.Id).Wait(); } } // rollback subscription state _subscriptionService.UpdateLastCycleDateAsync(subscription.Id, lastCycleDate).Wait(); _subscriptionService.UpdateHasTrialClicksAsync(subscription.Id, subscription.HasTrialClicks).Wait(); } catch (Exception ex) { Trace.TraceError("Failed to roll back subscription {0} state for company {1}. Subscription data is corrupted: {2}", subscription.Id, companyId, ex); } } }
public bool SaveCompanySubscriptionInfo(CompanySubscription CompanySubscription) { return(_userDataAccess.SaveCompanySubscriptionInfo(CompanySubscription)); }
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)); }