예제 #1
0
        public async Task <Account> GetOrCreateAccount(AccountIdentification id)
        {
            using (var con = new ConScope(_dataService))
                using (var trans = await con.BeginTransaction())
                {
                    var account = await GetAccount(id);

                    if (account == null)
                    {
                        if (!id.GlobalUserId.HasValue)
                        {
                            throw new Exception("Can only auto create account when using global user id.");
                        }

                        account = new Account
                        {
                            GlobalUserId = id.GlobalUserId.Value
                        };

                        await con.Connection.SaveAsync(account);

                        trans.Commit();

                        _logger.LogInformation("Created account {AccountId} for global user {GlobalUserId", account.Id, id.GlobalUserId);
                    }

                    return(account);
                }
        }
예제 #2
0
        private async Task <(Flow flow, Domain.Account)> GetFlow(string flowId)
        {
            flowId.NotNullOrEmpty();

            Flow flow = null;

            {
                var data = await _distributedCache.GetAsync($"flow-{flowId}");

                if (data == null || data.Length == 0)
                {
                    throw new Exception($"Invalid flow {flowId}");
                }

                flow = JsonSerializer.Deserialize <Flow>(data);
            }

            flow.NotNull();

            var account = await _accountsService.GetOrCreateAccount(AccountIdentification.ByGlobalUserId(User.GetUserId()));

            if (flow.AccountId != account.Id)
            {
                throw new Exception("Flow for wrong account.");
            }

            return(flow, account);
        }
예제 #3
0
        public async Task <IViewComponentResult> InvokeAsync(string selectedTab)
        {
            var account = await _accountsService.GetAccount(AccountIdentification.ByGlobalUserId(((ClaimsPrincipal)User).GetUserId()));

            return(View(new SideBarViewModel
            {
                SelectedTab = selectedTab,
                Amount = account?.CurrentBalance ?? 0
            }));
        }
예제 #4
0
        public async Task <CreateOrderResponse> CreateOrder([FromBody] CreateOrderRequest request)
        {
            var account = await _accountsService.GetOrCreateAccount(AccountIdentification.ByGlobalUserId(User.GetUserId()));

            var pendingOrder = await _payPalService.CreatePendingOrder(account.Id, request.Amount);

            return(new CreateOrderResponse
            {
                OrderId = pendingOrder.PayPalOrderId
            });
        }
예제 #5
0
        public async Task <ActionResult> PayPalOrderCreate([FromBody] CreatePayPalOrderRequest request)
        {
            var(flow, _) = await GetFlow(request.FlowId);

            var account = await _accountsService.GetOrCreateAccount(AccountIdentification.ByGlobalUserId(User.GetUserId()));

            var pendingOrder = await _payPalService.CreatePendingOrder(account.Id, flow.Amount);

            return(Json(new CreatePayPalOrderResponse
            {
                OrderId = pendingOrder.PayPalOrderId
            }));
        }
예제 #6
0
        public async Task <Account> GetAccount(AccountIdentification id)
        {
            using (var con = new ConScope(_dataService))
            {
                if (id.Id.HasValue)
                {
                    return(await con.Connection.SingleAsync <Account>(id.Id));
                }

                if (id.GlobalUserId.HasValue)
                {
                    return(await con.Connection.SingleAsync <Account>(x => x.GlobalUserId == id.GlobalUserId));
                }

                throw new Exception("Invalid id");
            }
        }
예제 #7
0
        public async Task <ActionResult> Index(SpecifyAmountInputModel model)
        {
            model.Amount = model.Amount.TrimMoney();

            if (!ModelState.IsValid)
            {
                return(View(new SpecifyAmountViewModel
                {
                    Amount = model.Amount
                }));
            }

            var flowId = Guid.NewGuid().ToString();
            await _distributedCache.SetAsync($"flow-{flowId}", JsonSerializer.SerializeToUtf8Bytes(new Flow
            {
                Amount    = model.Amount,
                AccountId = (await _accountsService.GetOrCreateAccount(AccountIdentification.ByGlobalUserId(User.GetUserId()))).Id
            }), new DistributedCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
            });

            return(RedirectToAction("Fund", new { flowId = flowId }));
        }
예제 #8
0
        public async Task <PayPalOrder> CreatePendingOrder(Guid accountId, decimal amount)
        {
            // TODO: Make this range configurable.
            if (amount <= 0 || amount > 500)
            {
                throw new Exception("Invalid amount.");
            }

            _logger.LogInformation("Creating pending paypal order for {AccountId} for {Amount}", accountId, amount);

            var account = await _accountsService.GetAccount(AccountIdentification.ById(accountId));

            account.NotNull();

            var    potentialOrderId = Guid.NewGuid();
            string paypalOrderId;

            {
                var client  = _payPalClientProvider.BuildHttpClient();
                var request = new OrdersCreateRequest();
                request.Prefer("return=representation");
                request.RequestBody(new OrderRequest
                {
                    CheckoutPaymentIntent = "CAPTURE",
                    PurchaseUnits         = new List <PurchaseUnitRequest>
                    {
                        new PurchaseUnitRequest
                        {
                            ReferenceId         = potentialOrderId.ToString(),
                            AmountWithBreakdown = new AmountWithBreakdown
                            {
                                Value        = amount.ToString(CultureInfo.InvariantCulture),
                                CurrencyCode = "USD"
                            }
                        }
                    }
                });

                var response = await client.Execute(request);

                if (response.StatusCode != HttpStatusCode.Created)
                {
                    _logger.LogError("Invalid status code from PayPal order create: status: {Status} response: {Response}", response.StatusCode, SerializePayPalType(response.Result <object>()));
                    throw new Exception("Invalid PayPal response");
                }

                paypalOrderId = response.Result <Order>().Id;
            }

            // Great, we created a PayPal order, let's add the record into the database.
            using (var con = new ConScope(_dataService))
            {
                var pendingOrder = new PayPalOrder
                {
                    Id            = potentialOrderId,
                    OrderStatus   = PayPalOrderStatus.Pending,
                    PayPalOrderId = paypalOrderId,
                    AccountId     = account.Id,
                    Amount        = amount
                };

                await con.Connection.InsertAsync(pendingOrder);

                return(pendingOrder);
            }
        }