public async Task <IActionResult> ShopifyInvoiceEndpoint(
            [FromServices] InvoiceRepository invoiceRepository,
            [FromServices] InvoiceController invoiceController,
            [FromServices] IHttpClientFactory httpClientFactory,
            string storeId, string orderId, decimal amount, bool checkOnly = false)
        {
            var invoiceOrderId          = $"{ShopifyOrderMarkerHostedService.SHOPIFY_ORDER_ID_PREFIX}{orderId}";
            var matchedExistingInvoices = await invoiceRepository.GetInvoices(new InvoiceQuery()
            {
                OrderId = new[] { invoiceOrderId }, StoreId = new[] { storeId }
            });

            matchedExistingInvoices = matchedExistingInvoices.Where(entity =>
                                                                    entity.GetInternalTags(ShopifyOrderMarkerHostedService.SHOPIFY_ORDER_ID_PREFIX)
                                                                    .Any(s => s == orderId))
                                      .ToArray();

            var firstInvoiceStillPending =
                matchedExistingInvoices.FirstOrDefault(entity => entity.GetInvoiceState().Status == InvoiceStatus.New);

            if (firstInvoiceStillPending != null)
            {
                return(Ok(new
                {
                    invoiceId = firstInvoiceStillPending.Id,
                    status = firstInvoiceStillPending.Status.ToString().ToLowerInvariant()
                }));
            }

            var firstInvoiceSettled =
                matchedExistingInvoices.LastOrDefault(entity =>
                                                      new[] { InvoiceStatus.Paid, InvoiceStatus.Complete, InvoiceStatus.Confirmed }.Contains(
                                                          entity.GetInvoiceState().Status));

            var store = await _Repo.FindStore(storeId);

            var shopify             = store?.GetStoreBlob()?.Shopify;
            ShopifyApiClient client = null;
            ShopifyOrder     order  = null;

            if (shopify?.IntegratedAt.HasValue is true)
            {
                client = new ShopifyApiClient(httpClientFactory, shopify.CreateShopifyApiCredentials());
                order  = await client.GetOrder(orderId);

                if (string.IsNullOrEmpty(order?.Id))
                {
                    return(NotFound());
                }
            }

            if (firstInvoiceSettled != null)
            {
                //if BTCPay was shut down before the tx managed to get registered on shopify, this will fix it on the next UI load in shopify
                if (client != null && order?.FinancialStatus == "pending" &&
                    firstInvoiceSettled.Status != InvoiceStatus.Paid)
                {
                    await new OrderTransactionRegisterLogic(client).Process(orderId, firstInvoiceSettled.Id,
                                                                            firstInvoiceSettled.Currency,
                                                                            firstInvoiceSettled.Price.ToString(CultureInfo.InvariantCulture), true);
                    order = await client.GetOrder(orderId);
                }

                if (order?.FinancialStatus != "pending" && order?.FinancialStatus != "partially_paid")
                {
                    return(Ok(new
                    {
                        invoiceId = firstInvoiceSettled.Id,
                        status = firstInvoiceSettled.Status.ToString().ToLowerInvariant()
                    }));
                }
            }

            if (checkOnly)
            {
                return(Ok());
            }

            if (shopify?.IntegratedAt.HasValue is true)
            {
                if (string.IsNullOrEmpty(order?.Id) ||
                    !new[] { "pending", "partially_paid" }.Contains(order.FinancialStatus))
                {
                    return(NotFound());
                }

                //we create the invoice at due amount provided from order page or full amount if due amount is bigger than order amount
                var invoice = await invoiceController.CreateInvoiceCoreRaw(
                    new CreateInvoiceRequest()
                {
                    Amount   = amount < order.TotalPrice ? amount : order.TotalPrice,
                    Currency = order.Currency,
                    Metadata = new JObject {
                        ["orderId"] = invoiceOrderId
                    }
                }, store,
                    Request.GetAbsoluteUri(""), new List <string>() { invoiceOrderId });

                return(Ok(new { invoiceId = invoice.Id, status = invoice.Status.ToString().ToLowerInvariant() }));
            }

            return(NotFound());
        }
        public async Task <IActionResult> PayPaymentRequest(string id, bool redirectToInvoice = true,
                                                            decimal?amount = null, CancellationToken cancellationToken = default)
        {
            if (amount.HasValue && amount.Value <= 0)
            {
                return(BadRequest("Please provide an amount greater than 0"));
            }

            var result = await _PaymentRequestService.GetPaymentRequest(id, GetUserId());

            if (result == null)
            {
                return(NotFound());
            }

            if (result.Archived)
            {
                if (redirectToInvoice)
                {
                    return(RedirectToAction("ViewPaymentRequest", new { Id = id }));
                }

                return(BadRequest("Payment Request cannot be paid as it has been archived"));
            }

            result.HubPath = PaymentRequestHub.GetHubPath(Request);
            if (result.AmountDue <= 0)
            {
                if (redirectToInvoice)
                {
                    return(RedirectToAction("ViewPaymentRequest", new { Id = id }));
                }

                return(BadRequest("Payment Request has already been settled."));
            }

            if (result.ExpiryDate.HasValue && DateTime.Now >= result.ExpiryDate)
            {
                if (redirectToInvoice)
                {
                    return(RedirectToAction("ViewPaymentRequest", new { Id = id }));
                }

                return(BadRequest("Payment Request has expired"));
            }

            var stateAllowedToDisplay = new HashSet <InvoiceState>
            {
                new InvoiceState(InvoiceStatusLegacy.New, InvoiceExceptionStatus.None),
                new InvoiceState(InvoiceStatusLegacy.New, InvoiceExceptionStatus.PaidPartial),
            };
            var currentInvoice = result
                                 .Invoices
                                 .FirstOrDefault(invoice => stateAllowedToDisplay.Contains(invoice.State));

            if (currentInvoice != null)
            {
                if (redirectToInvoice)
                {
                    return(RedirectToAction("Checkout", "Invoice", new { currentInvoice.Id }));
                }

                return(Ok(currentInvoice.Id));
            }

            if (result.AllowCustomPaymentAmounts && amount != null)
            {
                amount = Math.Min(result.AmountDue, amount.Value);
            }
            else
            {
                amount = result.AmountDue;
            }

            var pr = await _PaymentRequestRepository.FindPaymentRequest(id, null, cancellationToken);

            var blob  = pr.GetBlob();
            var store = pr.StoreData;

            try
            {
                var redirectUrl = _linkGenerator.PaymentRequestLink(id, Request.Scheme, Request.Host, Request.PathBase);

                var invoiceMetadata =
                    new InvoiceMetadata
                {
                    OrderId          = PaymentRequestRepository.GetOrderIdForPaymentRequest(id),
                    PaymentRequestId = id,
                    BuyerEmail       = result.Email
                };

                var invoiceRequest =
                    new CreateInvoiceRequest
                {
                    Metadata = invoiceMetadata.ToJObject(),
                    Currency = blob.Currency,
                    Amount   = amount.Value,
                    Checkout = { RedirectURL = redirectUrl }
                };

                var additionalTags = new List <string> {
                    PaymentRequestRepository.GetInternalTag(id)
                };
                var newInvoice = await _InvoiceController.CreateInvoiceCoreRaw(invoiceRequest, store, "/", additionalTags, cancellationToken);

                if (redirectToInvoice)
                {
                    return(RedirectToAction("Checkout", "Invoice", new { newInvoice.Id }));
                }

                return(Ok(newInvoice.Id));
            }
            catch (BitpayHttpException e)
            {
                return(BadRequest(e.Message));
            }
        }