/// <summary> /// Purchases one or more partner offers. /// </summary> /// <param name="order">The order to execute.</param> /// <returns>A transaction result which summarizes its outcome.</returns> public async Task <TransactionResult> PurchaseAsync(OrderViewModel order) { // use the normalizer to validate the order. OrderNormalizer orderNormalizer = new OrderNormalizer(ApplicationDomain, order); order = await orderNormalizer.NormalizePurchaseSubscriptionOrderAsync().ConfigureAwait(false); // build the purchase line items. List <PurchaseLineItem> purchaseLineItems = new List <PurchaseLineItem>(); foreach (OrderSubscriptionItemViewModel orderItem in order.Subscriptions) { string offerId = orderItem.OfferId; int quantity = orderItem.Quantity; purchaseLineItems.Add(new PurchaseLineItem(offerId, quantity)); } // associate line items in order to partner offers. IEnumerable <PurchaseLineItemWithOffer> lineItemsWithOffers = await AssociateWithPartnerOffersAsync(purchaseLineItems).ConfigureAwait(false); ICollection <IBusinessTransaction> subTransactions = new List <IBusinessTransaction>(); // prepare payment authorization AuthorizePayment paymentAuthorization = new AuthorizePayment(PaymentGateway); subTransactions.Add(paymentAuthorization); BrandingConfiguration portalBranding = await ApplicationDomain.Instance.PortalBranding.RetrieveAsync().ConfigureAwait(false); // build the Partner Center order and pass it to the place order transaction Order partnerCenterPurchaseOrder = BuildPartnerCenterOrder(lineItemsWithOffers, portalBranding.BillingCycle); PlaceOrder placeOrder = new PlaceOrder( ApplicationDomain.PartnerCenterClient.Customers.ById(CustomerId), partnerCenterPurchaseOrder); subTransactions.Add(placeOrder); // configure a transaction to save the new resulting subscriptions and purchases into persistence PersistNewlyPurchasedSubscriptions persistSubscriptionsAndPurchases = new PersistNewlyPurchasedSubscriptions( CustomerId, ApplicationDomain.CustomerSubscriptionsRepository, ApplicationDomain.CustomerPurchasesRepository, () => new Tuple <Order, IEnumerable <PurchaseLineItemWithOffer> >(placeOrder.Result, lineItemsWithOffers)); subTransactions.Add(persistSubscriptionsAndPurchases); // configure a capture payment transaction and let it read the auth code from the payment authorization output CapturePayment capturePayment = new CapturePayment(PaymentGateway, () => paymentAuthorization.Result); subTransactions.Add(capturePayment); // build an aggregated transaction from the previous steps and execute it as a whole await RunAggregatedTransaction(subTransactions).ConfigureAwait(false); return(new TransactionResult(persistSubscriptionsAndPurchases.Result, DateTime.UtcNow)); }
/// <summary> /// Purchases additional seats for an existing subscription the customer has already bought. /// </summary> /// <param name="order">The order to execute.</param> /// <returns>A transaction result which summarizes its outcome.</returns> public async Task <TransactionResult> PurchaseAdditionalSeatsAsync(OrderViewModel order) { // use the normalizer to validate the order. OrderNormalizer orderNormalizer = new OrderNormalizer(ApplicationDomain, order); order = await orderNormalizer.NormalizePurchaseAdditionalSeatsOrderAsync().ConfigureAwait(false); List <OrderSubscriptionItemViewModel> orderSubscriptions = order.Subscriptions.ToList(); string subscriptionId = orderSubscriptions.First().SubscriptionId; int seatsToPurchase = orderSubscriptions.First().Quantity; decimal proratedSeatCharge = orderSubscriptions.First().SeatPrice; string partnerOfferId = orderSubscriptions.First().PartnerOfferId; // we will add up the transactions here ICollection <IBusinessTransaction> subTransactions = new List <IBusinessTransaction>(); // configure a transaction to charge the payment gateway with the prorated rate AuthorizePayment paymentAuthorization = new AuthorizePayment(PaymentGateway); subTransactions.Add(paymentAuthorization); // configure a purchase additional seats transaction with the requested seats to purchase subTransactions.Add(new PurchaseExtraSeats( ApplicationDomain.PartnerCenterClient.Customers.ById(CustomerId).Subscriptions.ById(subscriptionId), seatsToPurchase)); DateTime rightNow = DateTime.UtcNow; // record the purchase in our purchase store subTransactions.Add(new RecordPurchase( ApplicationDomain.CustomerPurchasesRepository, new CustomerPurchaseEntity(CommerceOperationType.AdditionalSeatsPurchase, Guid.NewGuid().ToString(), CustomerId, subscriptionId, seatsToPurchase, proratedSeatCharge, rightNow))); // add a capture payment to the transaction pipeline subTransactions.Add(new CapturePayment(PaymentGateway, () => paymentAuthorization.Result)); // build an aggregated transaction from the previous steps and execute it as a whole await RunAggregatedTransaction(subTransactions).ConfigureAwait(false); TransactionResultLineItem additionalSeatsPurchaseResult = new TransactionResultLineItem( subscriptionId, partnerOfferId, seatsToPurchase, proratedSeatCharge, seatsToPurchase * proratedSeatCharge); return(new TransactionResult( new TransactionResultLineItem[] { additionalSeatsPurchaseResult }, rightNow)); }
/// <summary> /// Renews an existing subscription for a customer. /// </summary> /// <param name="order">The order to execute.</param> /// <returns>A transaction result which summarizes its outcome.</returns> public async Task <TransactionResult> RenewSubscriptionAsync(OrderViewModel order) { // use the normalizer to validate the order. OrderNormalizer orderNormalizer = new OrderNormalizer(ApplicationDomain, order); order = await orderNormalizer.NormalizeRenewSubscriptionOrderAsync().ConfigureAwait(false); List <OrderSubscriptionItemViewModel> orderSubscriptions = order.Subscriptions.ToList(); string subscriptionId = orderSubscriptions.First().SubscriptionId; string partnerOfferId = orderSubscriptions.First().PartnerOfferId; decimal partnerOfferPrice = orderSubscriptions.First().SeatPrice; DateTime subscriptionExpiryDate = orderSubscriptions.First().SubscriptionExpiryDate; int quantity = orderSubscriptions.First().Quantity; decimal totalCharge = Math.Round(quantity * partnerOfferPrice, Resources.Culture.NumberFormat.CurrencyDecimalDigits); // retrieve the subscription from Partner Center Subscriptions.ISubscription subscriptionOperations = ApplicationDomain.PartnerCenterClient.Customers.ById(CustomerId).Subscriptions.ById(subscriptionId); PartnerCenter.Models.Subscriptions.Subscription partnerCenterSubscription = await subscriptionOperations.GetAsync().ConfigureAwait(false); // we will add up the transactions here ICollection <IBusinessTransaction> subTransactions = new List <IBusinessTransaction>(); // configure a transaction to charge the payment gateway with the prorated rate AuthorizePayment paymentAuthorization = new AuthorizePayment(PaymentGateway); subTransactions.Add(paymentAuthorization); // add a renew subscription transaction to the pipeline subTransactions.Add(new RenewSubscription( subscriptionOperations, partnerCenterSubscription)); DateTime rightNow = DateTime.UtcNow; // record the renewal in our purchase store subTransactions.Add(new RecordPurchase( ApplicationDomain.CustomerPurchasesRepository, new CustomerPurchaseEntity(CommerceOperationType.Renewal, Guid.NewGuid().ToString(), CustomerId, subscriptionId, partnerCenterSubscription.Quantity, partnerOfferPrice, rightNow))); DateTime expirationDate = subscriptionExpiryDate; BrandingConfiguration portalBranding = await ApplicationDomain.Instance.PortalBranding.RetrieveAsync().ConfigureAwait(false); switch (portalBranding.BillingCycle) { case BillingCycleType.Annual: expirationDate = expirationDate.AddYears(1); break; case BillingCycleType.Monthly: expirationDate = expirationDate.AddMonths(1); break; default: throw new NotImplementedException($"Billing cycle {portalBranding.BillingCycle} is not implemented"); } // extend the expiry date by one month or one year subTransactions.Add(new UpdatePersistedSubscription( ApplicationDomain.CustomerSubscriptionsRepository, new CustomerSubscriptionEntity(CustomerId, subscriptionId, partnerOfferId, expirationDate))); // add a capture payment to the transaction pipeline subTransactions.Add(new CapturePayment(PaymentGateway, () => paymentAuthorization.Result)); // run the pipeline await RunAggregatedTransaction(subTransactions).ConfigureAwait(false); TransactionResultLineItem renewSubscriptionResult = new TransactionResultLineItem( subscriptionId, partnerOfferId, partnerCenterSubscription.Quantity, partnerOfferPrice, totalCharge); return(new TransactionResult( new TransactionResultLineItem[] { renewSubscriptionResult }, rightNow)); }