/// <summary> /// Create a single Transaction checkout /// </summary> /// <param name="key">Encrypted key of the transaction to claim</param> /// <returns>Transaction checkout view</returns> public ActionResult Checkout(string key) { var transactionId = Common.Utils.SafeConvert.ToGuid(key.DecryptUrl()); using (var context = dataContextFactory.CreateByUser()) using (var basket = BasketWrapper.CreateByTransaction(dataContextFactory, transactionId)) { if (basket.Transaction == null) { throw new EntityNotFoundException("Transaction SKUs are not accessible to current user!"); } if (basket.Transaction.Status == TransactionStatus.Complete) { throw new EntityOperationNotSupportedException("Transaction is already claimed!"); } var owningCustomerQuery = (from x in context.Customers orderby x.Name select x); var purchasingCustomerQuery = (from x in context.Customers orderby x.Name select x); var countryQuery = (from x in context.Countries orderby x.CountryName select x); var viewModel = new TransactionCheckoutViewModel(basket.Transaction, owningCustomerQuery.ToList(), purchasingCustomerQuery.ToList(), countryQuery.ToList()); return(View(viewModel)); } }
/// <summary> /// Transaction post /// </summary> /// <param name="transaction">Transaction to create</param> /// <returns>TransactionResult containing success status and optional errormessage</returns> /// <example> /// POST http://localhost:63436/api/transaction/ HTTP/1.2 /// User-Agent: Fiddler /// Host: localhost:63436 /// Content-Length: 185 /// Content-Type: application/xml /// <TransactionRequest PurchaserName="Steven Somer" PurchaserEmail="*****@*****.**"> /// <PurchasedSku>{guid}</PurchasedSku> /// </TransactionRequest> /// </example> public TransactionResult Post(TransactionRequest transaction) { using (var basket = BasketWrapper.CreateNewByIdentity(dataContextFactory)) { return(base.ProcessTransaction(transaction, basket)); } }
public ActionResult Create(TransactionCreateViewModel viewModel) { try { if (ModelState.IsValid) { using (var basket = BasketWrapper.CreateNewByIdentity(dataContextFactory)) { basket.AddItems(viewModel.Transaction.SelectedSKUGuids.Select(x => x.ToString()).ToList()); basket.Transaction.PurchaserEmail = "n/a"; basket.Transaction.PurchaserName = "n/a"; basket.ExecuteCreate(); return(RedirectToAction("Checkout", new { key = basket.Transaction.TransactionId.ToString().EncryptUrl() })); } } else { return(View(viewModel)); } } catch { throw; } }
/// <summary> /// Report transaction complete /// </summary> /// <param name="key">Encoded key for the transaction</param> /// <returns>Transaction complete view</returns> /// <remarks> /// Does not use cookie. Cookie is removed before this step so a new transaction can /// be started once the transaction has become pending. /// </remarks> public ActionResult Complete(string key) { var transactionId = Common.Utils.SafeConvert.ToGuid(key.DecryptUrl()); using (var basket = BasketWrapper.CreateByTransaction(dataContextFactory, transactionId)) { basket.ExecuteComplete(); var viewModel = new TransactionDetailsViewModel(basket.Transaction); return(View(viewModel)); } }
/// <summary> /// Resend an email to claim transaction /// </summary> /// <param name="key">Id of the transaction</param> /// <returns>Result of sending</returns> public ActionResult Remind(string key) { var transactionId = Common.Utils.SafeConvert.ToGuid(key.DecryptUrl()); using (var basket = BasketWrapper.CreateByTransaction(dataContextFactory, transactionId)) { if (basket.Transaction == null) { throw new EntityNotFoundException("Transaction could not be resolved!"); } basket.ExecuteRemind(); mailService.SendTransactionMail(basket.Transaction.PurchaserName, basket.Transaction.PurchaserEmail, basket.Transaction.TransactionId); return(RedirectToAction("Index")); } }
/// <summary> /// /// </summary> /// <param name="vendor"></param> /// <param name="postedData"></param> public HttpResponseMessage PostTransactionByIpn([FromUri] string id, [FromBody] FormDataCollection postedData) { var vendorId = Guid.Parse(id); var txn = new Transaction(); var d = postedData.ReadAsNameValueCollection(); //To calculate 'handshake', run 'md5 -s [password]', then 'md5 -s [email protected][Last MD5 result]' string handshakeParameter = d.Pluck("handshake", null); if (handshakeParameter == null) { throw new Exception("Missing parameter 'handshake'."); } using (var dataContext = dataContextFactory.Create()) { var vendor = dataContext.Vendors.Where(v => v.ObjectId == vendorId) .Include(v => v.VendorCredentials) .FirstOrDefault(); if (vendor == null) { throw new Exception("Could not find vendor with id: " + vendorId); } string[] vendorCredentials = vendor.VendorCredentials.Select( c => Encoding.UTF8.GetString(SymmetricEncryption.DecryptForDatabase(c.CredentialValue)).ToLower()).ToArray(); if (!vendorCredentials.Contains(handshakeParameter.ToLower())) { throw new Exception("Invalid handshake provided"); } } string txn_id = d.Pluck("txn_id"); //TODO: We must ignore duplicate POSTs with the same txn_id - all POSTs will contain the same information if (!"Completed".Equals(d.Pluck("payment_status"), StringComparison.OrdinalIgnoreCase)) { throw new Exception("Only completed transactions should be sent to this URL"); } //var txn = new Transaction(); txn.VendorId = vendorId; txn.ExternalTransactionId = txn_id; txn.PaymentDate = ConvertPayPalDateTime(d.Pluck("payment_date")); txn.PayerEmail = d.Pluck("payer_email"); txn.PassThroughData = d.Pluck("custom"); txn.Currency = d.Pluck("mc_currency"); txn.InvoiceId = d.Pluck("invoice"); txn.Gross = d.Pluck <double>("mc_gross"); txn.TransactionFee = d.Pluck <double>("mc_fee"); txn.Tax = d.Pluck <double>("tax"); txn.TransactionType = d.Pluck("transaction_type"); if (d["payer_name"] == null) { d["payer_name"] = d["first_name"] + " " + d["last_name"]; } txn.Billing = ParseFrom(d, "payer_"); txn.Shipping = ParseFrom(d, "address_"); var itemCount = d.Pluck <int>("num_cart_items", 1); txn.Items = new List <TransactionItem>(); for (var i = 1; i <= itemCount; i++) { string suffix = i.ToString(); var item = new TransactionItem(); item.Gross = d.Pluck <double>("mc_gross_" + i.ToString()).Value; item.ItemName = d.Pluck("item_name" + i.ToString()); item.SkuString = d.Pluck("item_number" + i.ToString()); item.Options = new List <KeyValuePair <string, string> >(); for (var j = 1; j < 4; j++) { string opt_key = d.Pluck("option_name" + j.ToString() + "_" + i.ToString()); string opt_val = d.Pluck("option_selection" + j.ToString() + "_" + i.ToString()); if (string.IsNullOrEmpty(opt_val)) { continue; } item.Options.Add(new KeyValuePair <string, string>(opt_key, opt_val)); } var qty = d.Pluck <int>("quantity" + i.ToString(), 1).Value; for (var j = 0; j < qty; j++) { txn.Items.Add(item.DeepCopy()); } } if (!string.IsNullOrEmpty(d["gc_xml"])) { txn.ProcessorXml = new XmlDocument(); txn.ProcessorXml.LoadXml(d.Pluck("gc_xml")); } txn.Other = d; //All transactions go through TransactionController using (var basket = BasketWrapper.CreateNewByVendor(dataContextFactory, vendorId)) { base.ProcessTransaction(txn.ToTransactionRequest(dataContextFactory), basket); } return(new HttpResponseMessage(HttpStatusCode.OK)); }
public ActionResult Checkout(string key, TransactionCheckoutViewModel viewModel) { var transactionId = Common.Utils.SafeConvert.ToGuid(key.DecryptUrl()); if (ModelState.IsValid) { using (var context = dataContextFactory.CreateByUser()) using (var basket = BasketWrapper.CreateByTransaction(dataContextFactory, transactionId)) { if (basket.Transaction == null) { throw new EntityNotFoundException("Transaction SKUs are not accessible to current user!"); } if (basket.Transaction.Status == TransactionStatus.Complete) { throw new EntityOperationNotSupportedException("Transaction is already claimed!"); } viewModel.ToEntity(basket.Transaction); Customer purchasingCustomer; Customer owningCustomer; if (viewModel.ExistingPurchasingCustomer) { purchasingCustomer = context.Customers.SingleOrDefault(x => x.ObjectId == viewModel.PurchasingCustomerId); if (purchasingCustomer == null) { return(new HttpStatusCodeResult(HttpStatusCode.InternalServerError)); } } else { purchasingCustomer = viewModel.NewPurchasingCustomer.ToEntity(null); } if (viewModel.OwningCustomerIsPurchasingCustomerId) { owningCustomer = purchasingCustomer; } else { if (viewModel.ExistingOwningCustomer) { owningCustomer = context.Customers.SingleOrDefault(x => x.ObjectId == viewModel.OwningCustomerId); if (owningCustomer == null) { return(new HttpStatusCodeResult(HttpStatusCode.InternalServerError)); } } else { owningCustomer = viewModel.NewOwningCustomer.ToEntity(null); } } basket.ExecuteCheckout(purchasingCustomer, owningCustomer); return(RedirectToAction("Complete", new { key = basket.Transaction.TransactionId.ToString().EncryptUrl() })); } } else { return(View(viewModel)); } }
protected TransactionResult ProcessTransaction(TransactionRequest transaction, BasketWrapper basket) { if (transaction == null) { return new TransactionResult { CreatedSuccessfull = false, ErrorMessage = "Invalid transaction format provided" } } ; if (string.IsNullOrEmpty(transaction.PurchaserName)) { return new TransactionResult { CreatedSuccessfull = false, ErrorMessage = "No purchaser name set" } } ; if (string.IsNullOrEmpty(transaction.PurchaserEmail)) { return new TransactionResult { CreatedSuccessfull = false, ErrorMessage = "No purchaser email set" } } ; if (!Strings.IsEmail(transaction.PurchaserEmail)) { return new TransactionResult { CreatedSuccessfull = false, ErrorMessage = string.Format("Purchaser email '{0}' is not an e-mailaddress", transaction.PurchaserEmail) } } ; try { basket.AddItems(transaction.PurchasedSkus); basket.Transaction.OriginalRequest = GetOriginalRequestValues(); basket.Transaction.PurchaserName = transaction.PurchaserName; basket.Transaction.PurchaserEmail = transaction.PurchaserEmail; basket.ExecuteCreate(); mailService.SendTransactionMail(transaction.PurchaserName, transaction.PurchaserEmail, basket.Transaction.TransactionId); return(new TransactionResult { CreatedSuccessfull = true }); } catch (BusinessRuleValidationException e) { // ReSharper disable RedundantToStringCall, expilicitly call diverted implementation of ToString() return(new TransactionResult { CreatedSuccessfull = false, ErrorMessage = string.Format("Could not process transaction: {0}", e.ToString()) }); // ReSharper restore RedundantToStringCall } catch (Exception e) { return(new TransactionResult { CreatedSuccessfull = false, ErrorMessage = string.Format("Could not process transaction due to exception: {0}", e.Message) }); } }