Пример #1
0
        public async Task <ActionResult <ProcessPaymentResult> > ProcessOrderPayments(string orderId, string paymentId, [SwaggerOptional] BankCardInfo bankCardInfo)
        {
            var order = await _customerOrderService.GetByIdAsync(orderId, CustomerOrderResponseGroup.Full.ToString());

            if (order == null)
            {
                var searchCriteria = AbstractTypeFactory <CustomerOrderSearchCriteria> .TryCreateInstance();

                searchCriteria.Number        = orderId;
                searchCriteria.ResponseGroup = CustomerOrderResponseGroup.Full.ToString();

                var orders = await _searchService.SearchCustomerOrdersAsync(searchCriteria);

                order = orders.Results.FirstOrDefault();
            }

            if (order == null)
            {
                throw new InvalidOperationException($"Cannot find order with ID {orderId}");
            }

            var payment = order.InPayments.FirstOrDefault(x => x.Id == paymentId);

            if (payment == null)
            {
                throw new InvalidOperationException($"Cannot find payment with ID {paymentId}");
            }

            var store = await _storeService.GetByIdAsync(order.StoreId);

            var paymentMethod = store.PaymentMethods.FirstOrDefault(x => x.Code == payment.GatewayCode);

            if (paymentMethod == null)
            {
                throw new InvalidOperationException($"Cannot find payment method with code {payment.GatewayCode}");
            }

            var context = new ProcessPaymentEvaluationContext
            {
                OrderId   = order.Id,
                PaymentId = payment.Id,
                //TODO
                //Store = store,
                //BankCardInfo = bankCardInfo
            };

            var result = paymentMethod.ProcessPayment(context);

            if (result.OuterId != null)
            {
                payment.OuterId = result.OuterId;
            }

            await _customerOrderService.SaveChangesAsync(new[] { order });

            return(Ok(result));
        }
        public virtual async Task SaveSubscriptionsAsync(Subscription[] subscriptions)
        {
            var pkMap          = new PrimaryKeyResolvingMap();
            var changedEntries = new List <GenericChangedEntry <Subscription> >();

            using (var repository = _subscriptionRepositoryFactory())
            {
                var existEntities = await repository.GetSubscriptionsByIdsAsync(subscriptions.Where(x => !x.IsTransient()).Select(x => x.Id).ToArray());

                foreach (var subscription in subscriptions)
                {
                    //Generate numbers for new subscriptions
                    if (string.IsNullOrEmpty(subscription.Number))
                    {
                        var store = await _storeService.GetByIdAsync(subscription.StoreId, StoreResponseGroup.StoreInfo.ToString());

                        var numberTemplate = store.Settings.GetSettingValue(ModuleConstants.Settings.General.NewNumberTemplate.Name, ModuleConstants.Settings.General.NewNumberTemplate.DefaultValue.ToString());
                        subscription.Number = _uniqueNumberGenerator.GenerateNumber(numberTemplate);
                    }
                    //Save subscription order prototype with same as subscription Number
                    if (subscription.CustomerOrderPrototype != null)
                    {
                        subscription.CustomerOrderPrototype.Number      = subscription.Number;
                        subscription.CustomerOrderPrototype.IsPrototype = true;
                        await _customerOrderService.SaveChangesAsync(new[] { subscription.CustomerOrderPrototype });
                    }
                    var originalEntity = existEntities.FirstOrDefault(x => x.Id == subscription.Id);

                    var modifiedEntity = AbstractTypeFactory <SubscriptionEntity> .TryCreateInstance().FromModel(subscription, pkMap);

                    if (originalEntity != null)
                    {
                        changedEntries.Add(new GenericChangedEntry <Subscription>(subscription, originalEntity.ToModel(AbstractTypeFactory <Subscription> .TryCreateInstance()), EntryState.Modified));
                        modifiedEntity.Patch(originalEntity);
                        //force the subscription.ModifiedDate update, because the subscription object may not have any changes in its properties
                        originalEntity.ModifiedDate = DateTime.UtcNow;
                    }
                    else
                    {
                        repository.Add(modifiedEntity);
                        changedEntries.Add(new GenericChangedEntry <Subscription>(subscription, EntryState.Added));
                    }
                }

                //Raise domain events
                await _eventPublisher.Publish(new SubscriptionChangingEvent(changedEntries));

                await repository.UnitOfWork.CommitAsync();

                pkMap.ResolvePrimaryKeys();

                ClearCacheFor(subscriptions);

                await _eventPublisher.Publish(new SubscriptionChangedEvent(changedEntries));
            }
        }
        public async Task <bool> Handle(CancelOrderPaymentCommand request, CancellationToken cancellationToken)
        {
            var orderAggregate = await _customerOrderAggregateRepository.GetOrderByIdAsync(request.Payment.OrderId);

            orderAggregate.CancelOrderPayment(request.Payment);

            await _customerOrderService.SaveChangesAsync(new[] { orderAggregate.Order });

            return(true);
        }
Пример #4
0
        public async Task <CustomerOrderAggregate> Handle(AddOrUpdateOrderPaymentCommand request, CancellationToken cancellationToken)
        {
            var orderAggregate = await _customerOrderAggregateRepository.GetOrderByIdAsync(request.OrderId);

            var paymentId = request.Payment.Id?.Value;
            var payment   = orderAggregate.Order.InPayments.FirstOrDefault(s => paymentId != null && s.Id == paymentId);

            payment = request.Payment.MapTo(payment);

            var criteria = new PaymentMethodsSearchCriteria
            {
                IsActive = true,
                StoreId  = orderAggregate.Order.StoreId,
            };

            if (!string.IsNullOrEmpty(payment.GatewayCode))
            {
                criteria.Codes = new List <string> {
                    payment.GatewayCode
                };
            }

            var result = await _paymentMethodsSearchService.SearchAsync(criteria);

            await orderAggregate.AddPaymentAsync(payment, result.Results);

            if (!request.Payment.DynamicProperties.IsNullOrEmpty())
            {
                await orderAggregate.UpdatePaymentDynamicProperties(paymentId, request.Payment.DynamicProperties);
            }

            await _customerOrderService.SaveChangesAsync(new[] { orderAggregate.Order });

            return(orderAggregate);
        }
Пример #5
0
        protected virtual async Task HandleOrderChangesAsync(CustomerOrder customerOrder)
        {
            //Prevent creating subscription for customer orders with other operation type (it is need for preventing to handling  subscription prototype and recurring order creations)
            if (!customerOrder.IsPrototype && string.IsNullOrEmpty(customerOrder.SubscriptionId))
            {
                try
                {
                    var subscription = await _subscriptionBuilder.TryCreateSubscriptionFromOrderAsync(customerOrder);

                    if (subscription != null)
                    {
                        await _subscriptionBuilder.TakeSubscription(subscription).ActualizeAsync();

                        await _subscriptionService.SaveSubscriptionsAsync(new[] { subscription });

                        //Link subscription with customer order
                        customerOrder.SubscriptionId     = subscription.Id;
                        customerOrder.SubscriptionNumber = subscription.Number;
                        //Save order changes
                        await _customerOrderService.SaveChangesAsync(new[] { customerOrder });
                    }
                }
                catch (Exception ex)
                {
                    throw new CreateSubscriptionException(ex);
                }
            }
        }
Пример #6
0
        protected virtual async Task TryToCancelOrder(GenericChangedEntry <CustomerOrder> changedEntry)
        {
            var store = await _storeService.GetByIdAsync(changedEntry.NewEntry.StoreId);

            //Try to load payment methods for payments
            foreach (var payment in changedEntry.NewEntry.InPayments)
            {
                payment.PaymentMethod = store.PaymentMethods.FirstOrDefault(p => p.Code.EqualsInvariant(payment.GatewayCode));
            }

            var toCancelPayments = new List <PaymentIn>();
            var isOrderCancelled = !changedEntry.OldEntry.IsCancelled && changedEntry.NewEntry.IsCancelled;

            if (isOrderCancelled)
            {
                toCancelPayments = changedEntry.NewEntry.InPayments?.ToList();
            }
            else
            {
                foreach (var canceledPayment in changedEntry.NewEntry?.InPayments.Where(x => x.IsCancelled) ?? Enumerable.Empty <PaymentIn>())
                {
                    var oldSamePayment = changedEntry.OldEntry?.InPayments.FirstOrDefault(x => x == canceledPayment);
                    if (oldSamePayment != null && !oldSamePayment.IsCancelled)
                    {
                        toCancelPayments.Add(canceledPayment);
                    }
                }
            }
            TryToCancelOrderPayments(toCancelPayments);
            if (!toCancelPayments.IsNullOrEmpty())
            {
                await _orderService.SaveChangesAsync(new[] { changedEntry.NewEntry });
            }
        }
Пример #7
0
        public virtual async Task <CustomerOrder> PlaceCustomerOrderFromCartAsync(ShoppingCart cart)
        {
            var customerOrder = ConvertCartToOrder(cart);
            await _customerOrderService.SaveChangesAsync(new[] { customerOrder });

            return(customerOrder);
        }
Пример #8
0
        public async Task Process()
        {
            var criteria = new SubscriptionSearchCriteria
            {
                Statuses = new[] { SubscriptionStatus.Active, SubscriptionStatus.PastDue, SubscriptionStatus.Trialing, SubscriptionStatus.Unpaid }.Select(x => x.ToString()).ToArray(),
                Take     = 0,
            };
            var result = await _subscriptionSearchService.SearchSubscriptionsAsync(criteria);

            var batchSize = 20;

            for (var i = 0; i < result.TotalCount; i += batchSize)
            {
                criteria.Skip = i;
                criteria.Take = batchSize;
                result        = await _subscriptionSearchService.SearchSubscriptionsAsync(criteria);

                var subscriptions = await _subscriptionService.GetByIdsAsync(result.Results.Select(x => x.Id).ToArray());

                foreach (var subscription in subscriptions)
                {
                    var subscriptionBuilder = await _subscriptionBuilder.TakeSubscription(subscription).ActualizeAsync();

                    var newOrder = await subscriptionBuilder.TryToCreateRecurrentOrderAsync();

                    if (newOrder != null)
                    {
                        await _customerOrderService.SaveChangesAsync(new[] { newOrder });
                    }
                }
            }
        }
        public async Task SaveChangesAsync_CreateNewOrder()
        {
            //Arrange
            var order = GetTestOrder($"order{DateTime.Now:O}");

            //Act
            await _customerOrderService.SaveChangesAsync(new[] { order });

            order = await _customerOrderService.GetByIdAsync(order.Id);

            //Assert
            Assert.Equal(PaymentStatus.Pending, order.InPayments.First().PaymentStatus);
            Assert.NotNull(order);
            Assert.Equal(PaymentStatus.Pending, order.InPayments.First().PaymentStatus);
            Assert.NotNull(order.InPayments.First().Status);
        }
Пример #10
0
        public async Task ImportAsync(Stream inputStream, ExportImportOptions options, Action <ExportImportProgressInfo> progressCallback,
                                      ICancellationToken cancellationToken)
        {
            //TDODO: Use AbstractTypeFactory for deserialization of the derived types
            cancellationToken.ThrowIfCancellationRequested();

            var progressInfo    = new ExportImportProgressInfo();
            var orderTotalCount = 0;

            using (var streamReader = new StreamReader(inputStream))
                using (var reader = new JsonTextReader(streamReader))
                {
                    while (reader.Read())
                    {
                        if (reader.TokenType == JsonToken.PropertyName)
                        {
                            if (reader.Value.ToString() == "OrderTotalCount")
                            {
                                orderTotalCount = reader.ReadAsInt32() ?? 0;
                            }
                            else if (reader.Value.ToString() == "CustomerOrders")
                            {
                                reader.Read();
                                if (reader.TokenType == JsonToken.StartArray)
                                {
                                    reader.Read();

                                    var orders     = new List <CustomerOrder>();
                                    var orderCount = 0;
                                    while (reader.TokenType != JsonToken.EndArray)
                                    {
                                        var order = _serializer.Deserialize <CustomerOrder>(reader);
                                        orders.Add(order);
                                        orderCount++;

                                        reader.Read();
                                    }

                                    for (var i = 0; i < orderCount; i += _batchSize)
                                    {
                                        await _customerOrderService.SaveChangesAsync(orders.Skip(i).Take(_batchSize).ToArray());

                                        if (orderCount > 0)
                                        {
                                            progressInfo.Description = $"{ i } of { orderCount } orders have been imported";
                                        }
                                        else
                                        {
                                            progressInfo.Description = $"{ i } orders have been imported";
                                        }
                                        progressCallback(progressInfo);
                                    }
                                }
                            }
                        }
                    }
                }
        }
        public virtual async Task <bool> Handle(ChangeOrderStatusCommand request, CancellationToken cancellationToken)
        {
            var orderAggregate = await _customerOrderAggregateRepository.GetOrderByIdAsync(request.OrderId);

            orderAggregate.ChangeOrderStatus(request.Status);
            await _customerOrderService.SaveChangesAsync(new[] { orderAggregate.Order });

            return(true);
        }
Пример #12
0
        public async Task SaveChangesAsync_CreateNewOrder()
        {
            //Arrange
            var order    = GetTestOrder($"order{DateTime.Now:O}");
            var cacheKey = CacheKey.With(_customerOrderService.GetType(), "GetByIdsAsync", string.Join("-", order.Id), null);

            _platformMemoryCacheMock.Setup(pmc => pmc.CreateEntry(cacheKey)).Returns(_cacheEntryMock.Object);

            //Act
            await _customerOrderService.SaveChangesAsync(new[] { order });

            order = await _customerOrderService.GetByIdAsync(order.Id);

            //Assert
            Assert.Equal(PaymentStatus.Pending, order.InPayments.First().PaymentStatus);
            Assert.NotNull(order);
            Assert.Equal(PaymentStatus.Pending, order.InPayments.First().PaymentStatus);
            Assert.NotNull(order.InPayments.First().Status);
        }
Пример #13
0
        public async Task <IActionResult> CreateReccurentOrderForSubscription([FromBody] Subscription subscription)
        {
            var subscriptionBuilder = await _subscriptionBuilder.TakeSubscription(subscription).ActualizeAsync();

            var order = await subscriptionBuilder.TryToCreateRecurrentOrderAsync(forceCreation : true);

            await _customerOrderService.SaveChangesAsync(new[] { order });

            return(Ok(order));
        }
        public virtual async Task <CustomerOrderAggregate> Handle(UpdateOrderShipmentDynamicPropertiesCommand request, CancellationToken cancellationToken)
        {
            var orderAggregate = await _customerOrderAggregateRepository.GetOrderByIdAsync(request.OrderId);

            await orderAggregate.UpdateShipmentDynamicProperties(request.ShipmentId, request.DynamicProperties);

            await _customerOrderService.SaveChangesAsync(new[] { orderAggregate.Order });

            return(orderAggregate);
        }
Пример #15
0
        protected virtual async Task TryToCancelOrders(CustomerOrder changedOrder, CustomerOrder oldOrder)
        {
            var store = await _storeService.GetByIdAsync(changedOrder.StoreId, StoreResponseGroup.StoreInfo.ToString());

            //Try to load payment methods for payments
            var gatewayCodes   = changedOrder.InPayments.Select(x => x.GatewayCode).ToArray();
            var paymentMethods = await GetPaymentMethodsAsync(store.Id, gatewayCodes);

            foreach (var payment in changedOrder.InPayments)
            {
                payment.PaymentMethod = paymentMethods.FirstOrDefault(x => x.Code == payment.GatewayCode);
            }

            var toCancelPayments = new List <PaymentIn>();
            var isOrderCancelled = !oldOrder.IsCancelled && changedOrder.IsCancelled;

            if (isOrderCancelled)
            {
                toCancelPayments = changedOrder.InPayments?.ToList();
            }
            else
            {
                foreach (var canceledPayment in changedOrder?.InPayments.Where(x => x.IsCancelled))
                {
                    var oldSamePayment = oldOrder?.InPayments.FirstOrDefault(x => x == canceledPayment);
                    if (oldSamePayment != null && !oldSamePayment.IsCancelled)
                    {
                        toCancelPayments.Add(canceledPayment);
                    }
                }
            }
            TryToCancelOrderPayments(toCancelPayments, changedOrder);
            if (!toCancelPayments.IsNullOrEmpty())
            {
                await _orderService.SaveChangesAsync(new[] { changedOrder });
            }
        }
Пример #16
0
        public virtual async Task <ProcessPaymentRequestResult> Handle(ProcessOrderPaymentCommand request, CancellationToken cancellationToken)
        {
            var orderAggregate = await _customerOrderAggregateRepository.GetOrderByIdAsync(request.OrderId);

            if (orderAggregate == null)
            {
                throw new OperationCanceledException($"Can't find an order with ID: {request.OrderId}");
            }
            var store = await _storeService.GetByIdAsync(orderAggregate.Order.StoreId, StoreResponseGroup.StoreInfo.ToString());

            var processPaymentRequest = new ProcessPaymentRequest
            {
                OrderId      = orderAggregate.Order.Id,
                PaymentId    = request.PaymentId,
                StoreId      = orderAggregate.Order.StoreId,
                Store        = store,
                BankCardInfo = request.BankCardInfo
            };
            var result = orderAggregate.ProcessOrderPayment(processPaymentRequest);

            await _customerOrderService.SaveChangesAsync(new[] { orderAggregate.Order });

            return(result);
        }
Пример #17
0
        protected virtual async Task DoBulkActionsWithOrderAggregate(PaymentIn[] payments, Action <CustomerOrder, PaymentIn> action)
        {
            if (payments.Any(x => string.IsNullOrEmpty(x.OrderId)))
            {
                throw new OperationCanceledException($"{ nameof(PaymentIn.OrderId) } must be set.");
            }
            var oderIds = payments.Select(x => x.OrderId).Distinct().ToArray();

            if (oderIds.Any())
            {
                var ordersAggregates = await _customerOrderService.GetByIdsAsync(oderIds);

                foreach (var payment in payments)
                {
                    var orderAggregateRoot = ordersAggregates.FirstOrDefault(x => x.Id == payment.OrderId);
                    if (orderAggregateRoot != null)
                    {
                        orderAggregateRoot.InPayments.Remove(payment);
                        orderAggregateRoot.InPayments.Add(payment);
                    }
                }
                await _customerOrderService.SaveChangesAsync(ordersAggregates);
            }
        }
        [Consumes("application/json", new[] { "application/json-patch+json" })] // It's a trick that allows ASP.NET infrastructure to select this action with body and ProcessOrderPaymentsWithoutBankCardInfo if no body
        public async Task <ActionResult <ProcessPaymentRequestResult> > ProcessOrderPayments([FromRoute] string orderId, [FromRoute] string paymentId, [FromBody] BankCardInfo bankCardInfo)
        {
            var order = await _customerOrderService.GetByIdAsync(orderId, CustomerOrderResponseGroup.Full.ToString());

            if (order == null)
            {
                var searchCriteria = AbstractTypeFactory <CustomerOrderSearchCriteria> .TryCreateInstance();

                searchCriteria.Number        = orderId;
                searchCriteria.ResponseGroup = CustomerOrderResponseGroup.Full.ToString();

                var orders = await _searchService.SearchCustomerOrdersAsync(searchCriteria);

                order = orders.Results.FirstOrDefault();
            }

            if (order == null)
            {
                throw new InvalidOperationException($"Cannot find order with ID {orderId}");
            }

            var authorizationResult = await _authorizationService.AuthorizeAsync(User, order, new OrderAuthorizationRequirement(ModuleConstants.Security.Permissions.Update));

            if (!authorizationResult.Succeeded)
            {
                return(Unauthorized());
            }

            var inPayment = order.InPayments.FirstOrDefault(x => x.Id == paymentId);

            if (inPayment == null)
            {
                throw new InvalidOperationException($"Cannot find payment with ID {paymentId}");
            }
            if (inPayment.PaymentMethod == null)
            {
                throw new InvalidOperationException($"Cannot find payment method with code {inPayment.GatewayCode}");
            }

            var store = await _storeService.GetByIdAsync(order.StoreId, StoreResponseGroup.StoreInfo.ToString());

            if (store == null)
            {
                throw new InvalidOperationException($"Cannot find store with ID {order.StoreId}");
            }

            var request = new ProcessPaymentRequest
            {
                OrderId      = order.Id,
                Order        = order,
                PaymentId    = inPayment.Id,
                Payment      = inPayment,
                StoreId      = order.StoreId,
                Store        = store,
                BankCardInfo = bankCardInfo
            };
            var result = inPayment.PaymentMethod.ProcessPayment(request);

            if (result.OuterId != null)
            {
                inPayment.OuterId = result.OuterId;
            }

            // Exclusive status set for DefaultManualPaymentMethod, otherwise the order be stuck in the "New" state.
            // Current payment flow suggests payment processing by payment method code,
            // but, unfortunately, there is no way to do set status directly in DefaultManualPaymentMethod, because it will produce cyclical references between order and payment modules.
            // One day, we should change the flow to commonly divide payment and order processing, but now it isn't.
            if (inPayment.PaymentMethod is DefaultManualPaymentMethod)
            {
                order.Status = result.NewPaymentStatus.ToString();
            }

            await _customerOrderService.SaveChangesAsync(new[] { order });

            return(Ok(result));
        }
        [Consumes("application/json", new[] { "application/json-patch+json" })] // It's a trick that allows ASP.NET infrastructure to select this action with body and ProcessOrderPaymentsWithoutBankCardInfo if no body
        public async Task <ActionResult <ProcessPaymentRequestResult> > ProcessOrderPayments([FromRoute] string orderId, [FromRoute] string paymentId, [FromBody] BankCardInfo bankCardInfo)
        {
            var order = await _customerOrderService.GetByIdAsync(orderId, CustomerOrderResponseGroup.Full.ToString());

            if (order == null)
            {
                var searchCriteria = AbstractTypeFactory <CustomerOrderSearchCriteria> .TryCreateInstance();

                searchCriteria.Number        = orderId;
                searchCriteria.ResponseGroup = CustomerOrderResponseGroup.Full.ToString();

                var orders = await _searchService.SearchCustomerOrdersAsync(searchCriteria);

                order = orders.Results.FirstOrDefault();
            }

            if (order == null)
            {
                throw new InvalidOperationException($"Cannot find order with ID {orderId}");
            }

            var authorizationResult = await _authorizationService.AuthorizeAsync(User, order, new OrderAuthorizationRequirement(ModuleConstants.Security.Permissions.Update));

            if (!authorizationResult.Succeeded)
            {
                return(Unauthorized());
            }

            var inPayment = order.InPayments.FirstOrDefault(x => x.Id == paymentId);

            if (inPayment == null)
            {
                throw new InvalidOperationException($"Cannot find payment with ID {paymentId}");
            }
            if (inPayment.PaymentMethod == null)
            {
                throw new InvalidOperationException($"Cannot find payment method with code {inPayment.GatewayCode}");
            }

            var store = await _storeService.GetByIdAsync(order.StoreId, StoreResponseGroup.StoreInfo.ToString());

            if (store == null)
            {
                throw new InvalidOperationException($"Cannot find store with ID {order.StoreId}");
            }

            var request = new ProcessPaymentRequest
            {
                OrderId      = order.Id,
                Order        = order,
                PaymentId    = inPayment.Id,
                Payment      = inPayment,
                StoreId      = order.StoreId,
                Store        = store,
                BankCardInfo = bankCardInfo
            };
            var result = inPayment.PaymentMethod.ProcessPayment(request);

            if (result.OuterId != null)
            {
                inPayment.OuterId = result.OuterId;
            }

            await _customerOrderService.SaveChangesAsync(new[] { order });

            return(Ok(result));
        }
Пример #20
0
        public async Task DoImportAsync(Stream inputStream, Action <ExportImportProgressInfo> progressCallback, ICancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            var progressInfo = new ExportImportProgressInfo();

            using (var streamReader = new StreamReader(inputStream))
                using (var reader = new JsonTextReader(streamReader))
                {
                    while (reader.Read())
                    {
                        if (reader.TokenType == JsonToken.PropertyName)
                        {
                            if (reader.Value.ToString() == "CustomerOrders")
                            {
                                await reader.DeserializeJsonArrayWithPagingAsync <CustomerOrder>(_jsonSerializer, _batchSize, items => _customerOrderService.SaveChangesAsync(items.ToArray()), processedCount =>
                                {
                                    progressInfo.Description = $"{ processedCount } orders have been imported";
                                    progressCallback(progressInfo);
                                }, cancellationToken);
                            }
                        }
                    }
                }
        }