public async Task <InitializeCreditRequestResult> HandleAsync( UserId userId, PositiveInt amount, PositiveInt expectedTotalAmount, UserType userType) { userId.AssertNotNull("userId"); amount.AssertNotNull("amount"); var origin = await this.getUserPaymentOrigin.ExecuteAsync(userId); if (origin.PaymentOriginKey == null || origin.PaymentOriginKeyType == PaymentOriginKeyType.None) { throw new CreditCardDetailsDoNotExistException(); } // Create taxamo transaction. var taxamoTransaction = await this.createTaxamoTransaction.ExecuteAsync( amount, origin.CountryCode, origin.CreditCardPrefix, origin.IpAddress, origin.OriginalTaxamoTransactionKey, userType); // Verify expected amount matches data returned from taxamo. if (expectedTotalAmount != null && taxamoTransaction.TotalAmount.Value != expectedTotalAmount.Value) { await this.deleteTaxamoTransaction.ExecuteAsync(taxamoTransaction.Key, userType); throw new BadRequestException("The expected total amount did not match the calculated total amount."); } return(new InitializeCreditRequestResult(taxamoTransaction, origin)); }
public async Task ExecuteAsync( UserId enactingUserId, string stripeChargeId, PositiveInt totalRefundAmount, RefundCreditReason reason, UserType userType) { enactingUserId.AssertNotNull("enactingUserId"); stripeChargeId.AssertNotNull("stripeChargeId"); totalRefundAmount.AssertNotNull("totalRefundAmount"); var apiKey = this.apiKeyRepository.GetApiKey(userType); var options = new StripeRefundCreateOptions { Amount = totalRefundAmount.Value, Reason = this.GetReason(reason), Metadata = new Dictionary <string, string> { { EnactingUserIdMetadataKey, enactingUserId.ToString() }, } }; await this.stripeService.RefundChargeAsync(stripeChargeId, options, apiKey); }
public async Task <TaxamoRefundResult> ExecuteAsync( string taxamoTransactionKey, PositiveInt refundCreditAmount, UserType userType) { taxamoTransactionKey.AssertNotNull("taxamoTransactionKey"); refundCreditAmount.AssertNotNull("refundCreditAmount"); var amount = AmountInMinorDenomination.Create(refundCreditAmount).ToMajorDenomination(); var apiKey = this.taxamoApiKeyRepository.GetApiKey(userType); var input = new CreateRefundIn { Amount = amount, CustomId = CreateTaxamoTransaction.CustomId, }; var result = await this.taxamoService.CreateRefundAsync(taxamoTransactionKey, input, apiKey); var totalAmount = AmountInMinorDenomination.FromMajorDenomination(result.TotalAmount.Value); var taxAmount = AmountInMinorDenomination.FromMajorDenomination(result.TaxAmount.Value); return(new TaxamoRefundResult(totalAmount.ToPositiveInt(), taxAmount.ToNonNegativeInt())); }
public async Task HandleAsync( UserId userId, PositiveInt amount) { userId.AssertNotNull("userId"); amount.AssertNotNull("amount"); var timestamp = this.timestampCreator.Now(); // Just update account balance directly. await this.setTestUserAccountBalance.ExecuteAsync(userId, timestamp, amount); }
public async Task <TaxamoCalculationResult> ExecuteAsync( PositiveInt amount, string billingCountryCode, string creditCardPrefix, string ipAddress, string originalTaxamoTransactionKey, UserType userType) { amount.AssertNotNull("amount"); var apiKey = this.taxamoApiKeyRepository.GetApiKey(userType); var input = new CalculateTaxIn { Transaction = new InputTransaction { CurrencyCode = PaymentConstants.Usd, TransactionLines = new List <InputTransactionLine> { new InputTransactionLine { CustomId = CreateTaxamoTransaction.CustomId, Amount = new AmountInMinorDenomination(amount.Value).ToMajorDenomination() } }, BuyerCreditCardPrefix = creditCardPrefix, BuyerIp = ipAddress, BillingCountryCode = billingCountryCode, OriginalTransactionKey = originalTaxamoTransactionKey } }; var result = await this.taxamoService.CalculateTaxAsync(input, apiKey); var countryDetected = this.IsCountryDetected(result); return(new TaxamoCalculationResult( result.Transaction.Amount == null ? null : AmountInMinorDenomination.FromMajorDenomination(result.Transaction.Amount.Value), result.Transaction.TotalAmount == null ? null : AmountInMinorDenomination.FromMajorDenomination(result.Transaction.TotalAmount.Value), result.Transaction.TaxAmount == null ? null : AmountInMinorDenomination.FromMajorDenomination(result.Transaction.TaxAmount.Value), result.Transaction.TransactionLines[0].TaxRate, result.Transaction.TransactionLines[0].TaxName, result.Transaction.TaxEntityName, countryDetected ? result.Transaction.CountryName : null, countryDetected ? null : this.GetPossibleCountries(result))); }
public async Task ExecuteAsync(UserId userId, DateTime timestamp, PositiveInt amount) { userId.AssertNotNull("userId"); amount.AssertNotNull("amount"); using (var connection = this.connectionFactory.CreateConnection()) { await connection.ExecuteAsync( Sql, new { UserId = userId.Value, Timestamp = timestamp, Amount = amount.Value, }); } }
public async Task <GetNewsfeedDbResult> ExecuteAsync( UserId requestorId, UserId creatorId, IReadOnlyList <ChannelId> requestedChannelIds, DateTime now, DateTime origin, bool searchForwards, NonNegativeInt startIndex, PositiveInt count) { requestorId.AssertNotNull("requestorId"); startIndex.AssertNotNull("startIndex"); count.AssertNotNull("count"); var parameters = new { RequestorId = requestorId.Value, CreatorId = creatorId == null ? null : (Guid?)creatorId.Value, RequestedChannelIds = requestedChannelIds == null ? null : requestedChannelIds.Select(v => v.Value).ToList(), Now = now, Origin = origin, StartIndex = startIndex.Value, Count = count.Value }; using (var connection = this.connectionFactory.CreateConnection()) { var query = new StringBuilder(); query.Append(GetSqlStart(requestorId, SqlQuerySource.Newsfeed)); query.Append(CreateFilter(requestorId, creatorId, requestedChannelIds, now, origin, searchForwards, startIndex, count, false)); query.Append(SqlEnd); var entities = (await connection.QueryAsync <NewsfeedPost.Builder>(query.ToString(), parameters)).ToList(); ProcessNewsfeedResults(entities); return(new GetNewsfeedDbResult(entities.Select(_ => _.Build()).ToList())); } }
public async Task ExecuteAsync( UserId userId, DateTime timestamp, TransactionReference transactionReference, PositiveInt amount, PositiveInt expectedTotalAmount, UserType userType) { userId.AssertNotNull("userId"); transactionReference.AssertNotNull("transactionReference"); amount.AssertNotNull("amount"); // We split this up into three phases that have individual retry handlers. // The first phase can be retried without issue if there are transient failures. var initializeResult = await this.retryOnTransientFailure.HandleAsync( () => this.initializeCreditRequest.HandleAsync(userId, amount, expectedTotalAmount, userType)); // This phase could be put at the end of the first phase, but it runs the risk of someone inserting // a statement afterwards that causes a transient failure, so for safety it has been isolated. var stripeTransactionResult = await this.retryOnTransientFailure.HandleAsync( () => this.performCreditRequest.HandleAsync( userId, timestamp, transactionReference, initializeResult.TaxamoTransaction, initializeResult.Origin, userType)); try { Task commitToDatabaseTask; if (userType == UserType.StandardUser) { // Finally we commit to the local database... commitToDatabaseTask = this.retryOnTransientFailure.HandleAsync( () => this.commitCreditToDatabase.HandleAsync( userId, initializeResult.TaxamoTransaction, initializeResult.Origin, stripeTransactionResult)); } else { commitToDatabaseTask = this.retryOnTransientFailure.HandleAsync( () => this.commitTestUserCreditToDatabase.HandleAsync( userId, amount)); } // ... and commit taxamo transaction. var commitToTaxamoTask = this.retryOnTransientFailure.HandleAsync( () => this.commitTaxamoTransaction.ExecuteAsync( initializeResult.TaxamoTransaction, stripeTransactionResult, userType)); // We run the two committing tasks in parallel as even if one fails we would like the other to try and succeed. await Task.WhenAll(commitToDatabaseTask, commitToTaxamoTask); } catch (Exception t) { var json = JsonConvert.SerializeObject( new { UserId = userId, InitializeResult = initializeResult, StripeTransactionResult = stripeTransactionResult, }); throw new FailedToApplyCreditException(json, t); } }
public async Task ExecuteAsync( UserId enactingUserId, UserId userId, DateTime timestamp, PositiveInt totalAmount, PositiveInt creditAmount, TransactionReference transactionReference, string stripeChargeId, string taxamoTransactionKey, string comment) { enactingUserId.AssertNotNull("enactingUserId"); userId.AssertNotNull("userId"); totalAmount.AssertNotNull("totalAmount"); creditAmount.AssertNotNull("creditAmount"); transactionReference.AssertNotNull("transactionReference"); stripeChargeId.AssertNotNull("stripeChargeId"); taxamoTransactionKey.AssertNotNull("taxamoTransactionKey"); comment.AssertNotNull("comment"); if (totalAmount.Value < creditAmount.Value) { throw new InvalidOperationException(string.Format( "The total charged amount ({0}) cannot be less than the amount credited ({1}).", totalAmount.Value, creditAmount.Value)); } var formattedComment = string.Format("{0} (Performed By {1})", comment, enactingUserId); var committedRecords = new List <AppendOnlyLedgerRecord>(); committedRecords.Add(new AppendOnlyLedgerRecord( this.guidCreator.CreateSqlSequential(), userId.Value, null, timestamp, totalAmount.Value, LedgerAccountType.Stripe, LedgerTransactionType.CreditRefund, transactionReference.Value, null, formattedComment, stripeChargeId, taxamoTransactionKey)); committedRecords.Add(new AppendOnlyLedgerRecord( this.guidCreator.CreateSqlSequential(), userId.Value, null, timestamp, -creditAmount.Value, LedgerAccountType.FifthweekCredit, LedgerTransactionType.CreditRefund, transactionReference.Value, null, formattedComment, stripeChargeId, taxamoTransactionKey)); var tax = totalAmount.Value - creditAmount.Value; if (tax > 0) { committedRecords.Add(new AppendOnlyLedgerRecord( this.guidCreator.CreateSqlSequential(), userId.Value, null, timestamp, -tax, LedgerAccountType.SalesTax, LedgerTransactionType.CreditRefund, transactionReference.Value, null, formattedComment, stripeChargeId, taxamoTransactionKey)); } await this.persistCommittedRecords.ExecuteAsync(committedRecords); }
public async Task <UserId> ExecuteAsync( UserId enactingUserId, TransactionReference transactionReference, DateTime timestamp, PositiveInt refundCreditAmount, RefundCreditReason reason, string comment) { enactingUserId.AssertNotNull("enactingUserId"); transactionReference.AssertNotNull("transactionReference"); refundCreditAmount.AssertNotNull("refundCreditAmount"); var transaction = await this.retryOnTransientFailure.HandleAsync( () => this.getCreditTransaction.ExecuteAsync(transactionReference)); if (transaction == null) { throw new BadRequestException( "Transaction reference " + transactionReference + " was not a valid transaction, or the user is not a standard user."); } if (refundCreditAmount.Value > transaction.CreditAmountAvailableForRefund) { throw new BadRequestException( "Requested refund amount was greater than amount available for refund."); } var userId = transaction.UserId; // Refund on taxamo, get tax refund amount. var taxamoResult = await this.retryOnTransientFailure.HandleAsync( () => this.createTaxamoRefund.ExecuteAsync(transaction.TaxamoTransactionKey, refundCreditAmount, UserType.StandardUser)); try { // Call CreateCreditRefundDbStatement await this.retryOnTransientFailure.HandleAsync( () => this.persistCreditRefund.ExecuteAsync( enactingUserId, userId, timestamp, taxamoResult.TotalRefundAmount, refundCreditAmount, transactionReference, transaction.StripeChargeId, transaction.TaxamoTransactionKey, comment)); // refund on stripe. await this.retryOnTransientFailure.HandleAsync( () => this.createStripeRefund.ExecuteAsync(enactingUserId, transaction.StripeChargeId, taxamoResult.TotalRefundAmount, reason, UserType.StandardUser)); } catch (Exception t) { var json = JsonConvert.SerializeObject( new { TransactionReference = transactionReference, Transaction = transaction, TaxamoResult = taxamoResult, }); throw new FailedToRefundCreditException(json, t); } return(userId); }