OrdersCount()
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Get, $"orders/count.json");
@@ -126,11 +154,11 @@ namespace BTCPayServer.Services.Shopify
return strResp?.Contains(orderId, StringComparison.OrdinalIgnoreCase) == true;
}
}
-
- public class ShopifyApiClientCredentials
- {
- public string ShopName { get; set; }
- public string ApiKey { get; set; }
- public string ApiPassword { get; set; }
- }
+}
+
+public class ShopifyApiClientCredentials
+{
+ public string ShopName { get; set; }
+ public string ApiKey { get; set; }
+ public string ApiPassword { get; set; }
}
diff --git a/BTCPayServer/Views/Stores/Integrations/Shopify.cshtml b/BTCPayServer/Views/Stores/Integrations/Shopify.cshtml
index b8b85c213..2c56a5778 100644
--- a/BTCPayServer/Views/Stores/Integrations/Shopify.cshtml
+++ b/BTCPayServer/Views/Stores/Integrations/Shopify.cshtml
@@ -81,7 +81,7 @@ function promptExampleUrl(){
}
else
{
- Checkout scripts should be automatically added to the order status page to display the BTCPay payment option.
+ Checkout scripts should be automatically added to the order status page to display the BTCPay payment option.
}
Please add a payment method at Settings > Payments > Manual Payment Methods with the name Bitcoin with BTCPay Server
@@ -90,10 +90,6 @@ function promptExampleUrl(){
@if (shopifyCredsSet)
{
- if (!shopify.IntegratedAt.HasValue)
- {
- Integrate Shopify Order Paid Marking
- }
@(shopify.IntegratedAt.HasValue ? "Stop Shopify calls and clear credentials" : "Clear credentials")
From f77c27ca71d51705089f6219e2ec10be96aad934 Mon Sep 17 00:00:00 2001
From: Kukks
Date: Sat, 19 Sep 2020 16:54:09 +0200
Subject: [PATCH 26/63] Make BTCPay Modal refer to mattermost instead of slack
---
BTCPayServer/wwwroot/modal/btcpay.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/BTCPayServer/wwwroot/modal/btcpay.js b/BTCPayServer/wwwroot/modal/btcpay.js
index 15a972b81..358ec14ef 100644
--- a/BTCPayServer/wwwroot/modal/btcpay.js
+++ b/BTCPayServer/wwwroot/modal/btcpay.js
@@ -40,7 +40,7 @@
iframe.style.width = '100%';
iframe.style.zIndex = '2000';
- var origin = 'http://slack.btcpayserver.org join us there, and initialize this with your origin url through setApiUrlPrefix';
+ var origin = 'http://chat.btcpayserver.org join us there, and initialize this with your origin url through setApiUrlPrefix';
var scriptMatch = thisScript.match(scriptSrcRegex)
if (scriptMatch) {
// We can't just take the domain as btcpay can run under a sub path with RootPath
From 91da129abcd637351d385c9b565d73251cc960e4 Mon Sep 17 00:00:00 2001
From: Kukks
Date: Sat, 19 Sep 2020 16:54:40 +0200
Subject: [PATCH 27/63] Include missing Shopify API models
---
.../Shopify/ApiModels/ShopifyOrder.cs | 19 ++++++++
.../Shopify/ApiModels/ShopifyTransaction.cs | 48 +++++++++++++++++++
2 files changed, 67 insertions(+)
create mode 100644 BTCPayServer/Services/Shopify/ApiModels/ShopifyOrder.cs
create mode 100644 BTCPayServer/Services/Shopify/ApiModels/ShopifyTransaction.cs
diff --git a/BTCPayServer/Services/Shopify/ApiModels/ShopifyOrder.cs b/BTCPayServer/Services/Shopify/ApiModels/ShopifyOrder.cs
new file mode 100644
index 000000000..1b7e513fe
--- /dev/null
+++ b/BTCPayServer/Services/Shopify/ApiModels/ShopifyOrder.cs
@@ -0,0 +1,19 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace BTCPayServer.Services.Shopify.ApiModels
+{
+ public class ShopifyOrder
+ {
+ [JsonProperty("id")]
+ public string Id { get; set; }
+ [JsonProperty("total_price")]
+ public decimal TotalPrice { get; set; }
+ [JsonProperty("currency")]
+ public string Currency { get; set; }
+ [JsonProperty("financial_status")]
+ public string FinancialStatus { get; set; }
+ [JsonProperty("transactions")]
+ public IEnumerable Transactions { get; set; }
+ }
+}
diff --git a/BTCPayServer/Services/Shopify/ApiModels/ShopifyTransaction.cs b/BTCPayServer/Services/Shopify/ApiModels/ShopifyTransaction.cs
new file mode 100644
index 000000000..80ed1842c
--- /dev/null
+++ b/BTCPayServer/Services/Shopify/ApiModels/ShopifyTransaction.cs
@@ -0,0 +1,48 @@
+using System;
+using Newtonsoft.Json;
+
+namespace BTCPayServer.Services.Shopify.ApiModels
+{
+ public class ShopifyTransaction
+ {
+ [JsonProperty("amount")]
+ public decimal? Amount { get; set; }
+
+ [JsonProperty("authorization")]
+ public string Authorization { get; set; }
+
+ [JsonProperty("created_at")]
+ public DateTimeOffset? CreatedAt { get; set; }
+
+ [JsonProperty("device_id")]
+ public string DeviceId { get; set; }
+
+ [JsonProperty("gateway")]
+ public string Gateway { get; set; }
+ [JsonProperty("kind")]
+ public string Kind { get; set; }
+ [JsonProperty("order_id")]
+ public long? OrderId { get; set; }
+
+ ///
+ /// A standardized error code, e.g. 'incorrect_number', independent of the payment provider. Value can be null. A full list of known values can be found at https://help.shopify.com/api/reference/transaction.
+ ///
+ [JsonProperty("error_code")]
+ public string ErrorCode { get; set; }
+
+ ///
+ /// The status of the transaction. Valid values are: pending, failure, success or error.
+ ///
+ [JsonProperty("status")]
+ public string Status { get; set; }
+ [JsonProperty("test")]
+ public bool? Test { get; set; }
+ [JsonProperty("currency")]
+ public string Currency { get; set; }
+ ///
+ /// This property is undocumented by Shopify.
+ ///
+ [JsonProperty("parent_id")]
+ public long? ParentId { get; set; }
+ }
+}
From 3054f91fe7ad8c84cc4b816f2186ec183ce3eb94 Mon Sep 17 00:00:00 2001
From: Kukks
Date: Mon, 21 Sep 2020 10:24:56 +0200
Subject: [PATCH 28/63] Fix typo in Invoice method param
---
BTCPayServer/Services/Invoices/InvoiceEntity.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/BTCPayServer/Services/Invoices/InvoiceEntity.cs b/BTCPayServer/Services/Invoices/InvoiceEntity.cs
index aff8665a4..cd80d7d31 100644
--- a/BTCPayServer/Services/Invoices/InvoiceEntity.cs
+++ b/BTCPayServer/Services/Invoices/InvoiceEntity.cs
@@ -259,11 +259,11 @@ namespace BTCPayServer.Services.Invoices
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public HashSet InternalTags { get; set; } = new HashSet();
- public string[] GetInternalTags(string suffix)
+ public string[] GetInternalTags(string prefix)
{
return InternalTags == null ? Array.Empty() : InternalTags
- .Where(t => t.StartsWith(suffix, StringComparison.InvariantCulture))
- .Select(t => t.Substring(suffix.Length)).ToArray();
+ .Where(t => t.StartsWith(prefix, StringComparison.InvariantCulture))
+ .Select(t => t.Substring(prefix.Length)).ToArray();
}
[Obsolete("Use GetDerivationStrategies instead")]
From 9aed4b0e87cac10c55eb2a2973a8197265a931bd Mon Sep 17 00:00:00 2001
From: Kukks
Date: Mon, 21 Sep 2020 12:32:52 +0200
Subject: [PATCH 29/63] Allow receiving events from the BTCPay modal library
---
BTCPayServer/wwwroot/modal/btcpay.js | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/BTCPayServer/wwwroot/modal/btcpay.js b/BTCPayServer/wwwroot/modal/btcpay.js
index 358ec14ef..14a64d69f 100644
--- a/BTCPayServer/wwwroot/modal/btcpay.js
+++ b/BTCPayServer/wwwroot/modal/btcpay.js
@@ -56,6 +56,7 @@
var onModalWillEnterMethod = function () { };
var onModalWillLeaveMethod = function () { };
+ var onModalReceiveMessageMethod = function (event) { };
function showFrame() {
if (window.document.getElementsByName('btcpay').length === 0) {
@@ -80,6 +81,10 @@
onModalWillLeaveMethod = customOnModalWillLeave;
}
+ function onModalReceiveMessage(customOnModalReceiveMessage) {
+ onModalReceiveMessageMethod = customOnModalReceiveMessage;
+ }
+
function receiveMessage(event) {
var uri;
@@ -101,6 +106,7 @@
window.location = uri;
}
}
+ onModalReceiveMessageMethod(event);
}
function showInvoice(invoiceId, params) {
@@ -134,7 +140,8 @@
showInvoice: showInvoice,
onModalWillEnter: onModalWillEnter,
onModalWillLeave: onModalWillLeave,
- setApiUrlPrefix: setApiUrlPrefix
+ setApiUrlPrefix: setApiUrlPrefix,
+ onModalReceiveMessage: onModalReceiveMessage
};
})();
From 0b2f115b73147f35e0549a796a1dfd7353977936 Mon Sep 17 00:00:00 2001
From: Kukks
Date: Mon, 21 Sep 2020 12:33:46 +0200
Subject: [PATCH 30/63] Fix issue with new Invoice API ignoring internal tags
---
BTCPayServer/Controllers/InvoiceController.cs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/BTCPayServer/Controllers/InvoiceController.cs b/BTCPayServer/Controllers/InvoiceController.cs
index c4eba1e73..d86a4f862 100644
--- a/BTCPayServer/Controllers/InvoiceController.cs
+++ b/BTCPayServer/Controllers/InvoiceController.cs
@@ -175,6 +175,8 @@ namespace BTCPayServer.Controllers
excludeFilter = PaymentFilter.Where(p => !supportedTransactionCurrencies.Contains(p));
}
entity.PaymentTolerance = invoice.Checkout.PaymentTolerance ?? storeBlob.PaymentTolerance;
+ if (additionalTags != null)
+ entity.InternalTags.AddRange(additionalTags);
return await CreateInvoiceCoreRaw(entity, store, excludeFilter, cancellationToken);
}
From f352399428f5aacfaa237061488771f023c7f7fd Mon Sep 17 00:00:00 2001
From: Kukks
Date: Mon, 21 Sep 2020 12:34:09 +0200
Subject: [PATCH 31/63] Make Invoices save internal tags in the text search
---
BTCPayServer/Services/Invoices/InvoiceRepository.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/BTCPayServer/Services/Invoices/InvoiceRepository.cs b/BTCPayServer/Services/Invoices/InvoiceRepository.cs
index 8c40e40f7..4c6ec3331 100644
--- a/BTCPayServer/Services/Invoices/InvoiceRepository.cs
+++ b/BTCPayServer/Services/Invoices/InvoiceRepository.cs
@@ -204,7 +204,7 @@ retry:
textSearch.Add(invoice.Metadata.OrderId);
textSearch.Add(ToString(invoice.Metadata, null));
textSearch.Add(invoice.StoreId);
-
+ textSearch.AddRange(invoice.InternalTags);
AddToTextSearch(invoice.Id, textSearch.ToArray());
return invoice;
}
From 078a2d7e392ad5b1443dd74087428b6f7924ffad Mon Sep 17 00:00:00 2001
From: Kukks
Date: Mon, 21 Sep 2020 12:36:09 +0200
Subject: [PATCH 32/63] Reduce Shopify integration steps and make sure checks
work.
---
BTCPayServer/Controllers/StoresController.Integrations.cs | 7 +++++--
BTCPayServer/Services/Shopify/Models/ShopifySettings.cs | 2 --
BTCPayServer/Services/Shopify/ShopifyApiClient.cs | 2 +-
BTCPayServer/Views/Stores/Integrations/Shopify.cshtml | 6 +++---
4 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/BTCPayServer/Controllers/StoresController.Integrations.cs b/BTCPayServer/Controllers/StoresController.Integrations.cs
index e5a84f6f9..ec960e892 100644
--- a/BTCPayServer/Controllers/StoresController.Integrations.cs
+++ b/BTCPayServer/Controllers/StoresController.Integrations.cs
@@ -116,8 +116,6 @@ namespace BTCPayServer.Controllers
return View("Integrations", vm);
}
- shopify.CredentialsValid = true;
-
var scopesGranted = await apiClient.CheckScopes();
if (!scopesGranted.Contains("read_orders") || !scopesGranted.Contains("write_script_tags"))
{
@@ -125,6 +123,11 @@ namespace BTCPayServer.Controllers
"Please grant the private app permissions for read_orders, write_script_tags";
return View("Integrations", vm);
}
+ var result = await apiClient.CreateScript(Url.Action("ShopifyJavascript", "Stores",
+ new {storeId = CurrentStore.Id}, Request.Scheme));
+
+ shopify.ScriptId = result.ScriptTag?.Id.ToString(CultureInfo.InvariantCulture);
+ shopify.IntegratedAt = DateTimeOffset.Now;
var blob = CurrentStore.GetStoreBlob();
blob.Shopify = shopify;
diff --git a/BTCPayServer/Services/Shopify/Models/ShopifySettings.cs b/BTCPayServer/Services/Shopify/Models/ShopifySettings.cs
index e7216afcf..59ea917ee 100644
--- a/BTCPayServer/Services/Shopify/Models/ShopifySettings.cs
+++ b/BTCPayServer/Services/Shopify/Models/ShopifySettings.cs
@@ -17,8 +17,6 @@ namespace BTCPayServer.Services.Shopify.Models
!string.IsNullOrWhiteSpace(ApiKey) &&
!string.IsNullOrWhiteSpace(Password);
}
-
- public bool CredentialsValid { get; set; }
public DateTimeOffset? IntegratedAt { get; set; }
public string ScriptId { get; set; }
}
diff --git a/BTCPayServer/Services/Shopify/ShopifyApiClient.cs b/BTCPayServer/Services/Shopify/ShopifyApiClient.cs
index 5da3df3ac..9ba4c412e 100644
--- a/BTCPayServer/Services/Shopify/ShopifyApiClient.cs
+++ b/BTCPayServer/Services/Shopify/ShopifyApiClient.cs
@@ -70,7 +70,7 @@ namespace BTCPayServer.Services.Shopify
public async Task CheckScopes()
{
- var req = CreateRequest(_credentials.ShopName, HttpMethod.Delete, null, "admin/oauth/access_scopes.json");
+ var req = CreateRequest(_credentials.ShopName, HttpMethod.Get, null, "admin/oauth/access_scopes.json");
return JObject.Parse(await SendRequest(req))["access_scopes"].Values()
.Select(token => token["handle"].Value()).ToArray();
}
diff --git a/BTCPayServer/Views/Stores/Integrations/Shopify.cshtml b/BTCPayServer/Views/Stores/Integrations/Shopify.cshtml
index 2c56a5778..ef5bd6157 100644
--- a/BTCPayServer/Views/Stores/Integrations/Shopify.cshtml
+++ b/BTCPayServer/Views/Stores/Integrations/Shopify.cshtml
@@ -1,7 +1,7 @@
@model IntegrationsViewModel
@{
var shopify = Model.Shopify;
- var shopifyCredsSet = shopify?.CredentialsValid == true;
+ var shopifyCredsSet = shopify?.IntegratedAt.HasValue is true;
}
-
-
- */
-
-! function () {
- // extracted from shopify initialized page
- const shopify_price = Shopify.checkout.payment_due;
- const shopify_currency = Shopify.checkout.currency;
- const shopify_order_id = "shopify-" + Shopify.checkout.order_id;
-
- "use strict";
- const pageElements = document.querySelector.bind(document),
- insertElement = (document.querySelectorAll.bind(document),
- (e,
- n) => {
- n.parentNode.insertBefore(e,
- n.nextSibling)
- });
-
- let pageItems = {},
- pageheader = "Thank you!",
- buttonElement = null;
-
- const setPageItems = () => {
- pageItems = {
- mainHeader: pageElements("#main-header"),
- orderConfirmed: pageElements(".os-step__title"),
- orderConfirmedDescription: pageElements(".os-step__description"),
- continueButton: pageElements(".step__footer__continue-btn"),
- checkMarkIcon: pageElements(".os-header__hanging-icon"),
- orderStatus: pageElements(".os-header__title"),
- paymentMethod: pageElements(".payment-method-list__item__info"),
- price: pageElements(".payment-due__price"),
- finalPrice: pageElements(".total-recap__final-price"),
- orderNumber: pageElements(".os-order-number"),
- }
- }
-
- const orderPaid = () => {
- pageItems.mainHeader.innerText = pageheader,
- pageItems.orderConfirmed && (pageItems.orderConfirmed.style.display = "block"),
- pageItems.orderConfirmedDescription && (pageItems.orderConfirmedDescription.style.display = "block"),
- pageItems.continueButton && (pageItems.continueButton.style.visibility = "visible"),
- pageItems.checkMarkIcon && (pageItems.checkMarkIcon.style.visibility = "visible"),
- buttonElement && (buttonElement.style.display = "none");
- };
-
- window.setOrderAsPaid = orderPaid,
- window.openBtcPayShopify = function waitForPaymentMethod() {
- if (setPageItems(), "Order canceled" === pageItems.orderStatus.innerText) {
- return;
- }
-
- const paymentMethod = pageItems.paymentMethod;
-
- if (null === paymentMethod) {
- return void setTimeout(() => {
- waitForPaymentMethod();
- }, 10);
- }
-
- if (-1 === paymentMethod.innerText.toLowerCase().indexOf("bitcoin")) return;
-
- // If payment method is bitcoin, display instructions and payment button.
- pageheader = pageItems.mainHeader.innerText,
- pageItems.mainHeader && (pageItems.mainHeader.innerText = "Review and pay!"),
- pageItems.continueButton && (pageItems.continueButton.style.visibility = "hidden"),
- pageItems.checkMarkIcon && (pageItems.checkMarkIcon.style.visibility = "hidden"),
- pageItems.orderConfirmed && (pageItems.orderConfirmed.style.display = "none"),
- pageItems.orderConfirmedDescription && (pageItems.orderConfirmedDescription.style.display = "none");
-
- const url = BTCPAYSERVER_URL + "/invoices" + "?storeId=" + STORE_ID + "&orderId=" + shopify_order_id + "&status=complete";
-
- // Check if already paid.
- fetch(url, {
- method: "GET",
- mode: "cors", // no-cors, cors, *same-origin,
- headers: {
- "Content-Type": "application/json",
- "accept": "application/json",
- },
- })
- .then(function (response) {
- return response.json();
- })
- .then(function (json) {
- return json.data;
- })
- .then(function (data) {
- if (data.length != 0) {
- orderPaid();
- }
- });
-
- window.waitForPayment = function () {
- buttonElement.innerHTML = "Displaying Invoice... ";
- BtcPayServerModal.show(
- BTCPAYSERVER_URL,
- STORE_ID,
- {
- price: shopify_price,
- currency: shopify_currency,
- orderId: shopify_order_id
- }
- )
- .then(function (invoice) {
- buttonElement.innerHTML = payButtonHtml;
- if (invoice != null) {
- orderPaid();
- }
- });
- }
-
- // Payment button that opens modal
- const payButtonHtml = ' ';
-
- buttonElement = document.createElement("div");
- buttonElement.innerHTML = payButtonHtml;
- insertElement(buttonElement, pageItems.orderConfirmed);
-
- }
-
- window.openBtcPayShopify();
-}();
diff --git a/BTCPayServer/wwwroot/shopify/btcpay-shopify.js b/BTCPayServer/wwwroot/shopify/btcpay-shopify.js
new file mode 100644
index 000000000..c2c1e28ea
--- /dev/null
+++ b/BTCPayServer/wwwroot/shopify/btcpay-shopify.js
@@ -0,0 +1,150 @@
+window.BTCPayShopifyIntegrationModule = function () {
+ if (!window.btcpay) {
+ throw new Error("The BTCPay modal js was not loaded on this page.");
+ }
+ if (!window.Shopify) {
+ throw new Error("The Shopify global object was not loaded on this page.");
+ }
+ if (!window.BTCPAYSERVER_URL || !window.STORE_ID) {
+ throw new Error("The BTCPAYSERVER_URL STORE_ID global vars were not set on this page.");
+ }
+ const shopify_order_id = Shopify.checkout.order_id;
+ const btcPayServerUrl = window.BTCPAYSERVER_URL;
+ const storeId = window.STORE_ID;
+ var currentInvoiceData;
+ var modalShown = false;
+
+ const pageElements = document.querySelector.bind(document);
+ const insertElement = (document.querySelectorAll.bind(document),
+ (e,
+ n) => {
+ n.parentNode.insertBefore(e,
+ n.nextSibling)
+ });
+
+ let buttonElement = null;
+
+ const pageItems = {
+ mainHeader: pageElements("#main-header"),
+ orderConfirmed: pageElements(".os-step__title"),
+ orderConfirmedDescription: pageElements(".os-step__description"),
+ continueButton: pageElements(".step__footer__continue-btn"),
+ checkMarkIcon: pageElements(".os-header__hanging-icon"),
+ orderStatus: pageElements(".os-header__title"),
+ paymentMethod: pageElements(".payment-method-list__item__info"),
+ price: pageElements(".payment-due__price"),
+ finalPrice: pageElements(".total-recap__final-price"),
+ orderNumber: pageElements(".os-order-number"),
+ }
+
+ function setOrderAsPaid() {
+ pageItems.mainHeader.innerText = "Thank you!",
+ pageItems.orderConfirmed && (pageItems.orderConfirmed.style.display = "block"),
+ pageItems.orderConfirmedDescription && (pageItems.orderConfirmedDescription.style.display = "block"),
+ pageItems.continueButton && (pageItems.continueButton.style.visibility = "visible"),
+ pageItems.checkMarkIcon && (pageItems.checkMarkIcon.style.visibility = "visible"),
+ buttonElement && (buttonElement.style.display = "none");
+ }
+
+ function showPaymentInstructions() {
+ pageItems.mainHeader && (pageItems.mainHeader.innerText = "Review and pay!"),
+ pageItems.continueButton && (pageItems.continueButton.style.visibility = "hidden"),
+ pageItems.checkMarkIcon && (pageItems.checkMarkIcon.style.visibility = "hidden"),
+ pageItems.orderConfirmed && (pageItems.orderConfirmed.style.display = "none"),
+ pageItems.orderConfirmedDescription && (pageItems.orderConfirmedDescription.style.display = "none");
+ }
+
+ function getOrCheckInvoice(backgroundCheck) {
+ const url = btcPayServerUrl + "/stores/" + storeId + "/integrations/shopify/" + shopify_order_id + (backgroundCheck ? "?checkonly=true" : "");
+ return fetch(url, {
+ method: "GET",
+ mode: "cors", // no-cors, cors, *same-origin,
+ headers: {
+ "Content-Type": "application/json",
+ "accept": "application/json",
+ }
+ })
+ .then(function (response) {
+ return response.json();
+ }).catch(function () {
+ if (!backgroundCheck)
+ alert("Could not initiate BTCPay Server payment method, try again later.");
+ })
+ }
+
+ function onPayButtonClicked() {
+ buttonElement.innerHTML = "Displaying Invoice... ";
+
+ getOrCheckInvoice().then(handleInvoiceData).catch(fail.bind(this));
+ }
+
+ function handleInvoiceData(data, opts) {
+ currentInvoiceData = data;
+ if (!currentInvoiceData) {
+ window.btcpay.hideFrame();
+ return;
+ }
+ if (["complete", "confirmed", "paid"].indexOf(currentInvoiceData.status.toLowerCase()) >= 0) {
+ setOrderAsPaid();
+ } else if (["invalid", "expired"].indexOf(currentInvoiceData.status.toLowerCase()) >= 0) {
+ fail();
+ } else if (!opts || !opts.backgroundCheck) {
+ showModal();
+ }
+ }
+
+ function showModal() {
+ if (currentInvoiceData && !modalShown) {
+ modalShown = true;
+ window.btcpay.setApiUrlPrefix(btcPayServerUrl);
+
+ window.btcpay.onModalReceiveMessage(function (evt) {
+ if (evt && evt.invoiceId && evt.status) {
+ currentInvoiceData = evt;
+ }
+ });
+
+ window.btcpay.onModalWillEnter(function () {
+ modalShown = true;
+ });
+
+ window.btcpay.onModalWillLeave(function () {
+ modalShown = false;
+ fail();
+ });
+ window.btcpay.showInvoice(currentInvoiceData.invoiceId);
+ }
+ }
+
+ function fail() {
+ currentInvoiceData = null;
+ buttonElement.innerHTML = payButtonHtml;
+ }
+
+ const payButtonHtml = ' ';
+
+ function injectPaymentButtonHtml() {
+ // Payment button that opens modal
+ buttonElement = document.getElementById("btcpayserver-pay");
+ if (buttonElement) {
+ return;
+ }
+ buttonElement = document.createElement("div");
+ buttonElement.id = "btcpayserver-pay";
+ buttonElement.innerHTML = payButtonHtml;
+ insertElement(buttonElement, pageItems.orderConfirmed);
+ }
+
+ if (["bitcoin", "btc", "btcpayserver"].filter(value => pageItems.paymentMethod.innerText.toLowerCase().indexOf(value) !== -1).length === 0) {
+ return;
+ }
+ showPaymentInstructions();
+ injectPaymentButtonHtml();
+ window.onPayButtonClicked = onPayButtonClicked.bind(this);
+ getOrCheckInvoice(true).then(function (d) {
+ handleInvoiceData(d, {backgroundCheck: true})
+ });
+
+};
+
+window.addEventListener("load", BTCPayShopifyIntegrationModule);
From c9f02955168697d514f09c0002beda4b34804885 Mon Sep 17 00:00:00 2001
From: Kukks
Date: Mon, 21 Sep 2020 15:34:41 +0200
Subject: [PATCH 34/63] Make Shopify transaction register system handle marked
payments slightly more
---
.../Shopify/OrderTransactionRegisterLogic.cs | 84 ++++++++++++-------
.../wwwroot/shopify/btcpay-shopify.js | 16 +++-
2 files changed, 65 insertions(+), 35 deletions(-)
diff --git a/BTCPayServer/Services/Shopify/OrderTransactionRegisterLogic.cs b/BTCPayServer/Services/Shopify/OrderTransactionRegisterLogic.cs
index 4735f9bac..23e391d49 100644
--- a/BTCPayServer/Services/Shopify/OrderTransactionRegisterLogic.cs
+++ b/BTCPayServer/Services/Shopify/OrderTransactionRegisterLogic.cs
@@ -20,40 +20,62 @@ namespace BTCPayServer.Services.Shopify
{
currency = currency.ToUpperInvariant().Trim();
var existingShopifyOrderTransactions = (await _client.TransactionsList(orderId)).transactions;
- // only register transactions if first, parent_id transaction is present and we haven't already registered transaction for this invoice( or if there was one registered but it was a failure and this one is success, in the case of a merchant marking it as complete)
- if (existingShopifyOrderTransactions != null && existingShopifyOrderTransactions.Count >= 1 && existingShopifyOrderTransactions.All(a => a.authorization != invoiceId || (!success || a.status == "failure")))
+
+ if (existingShopifyOrderTransactions?.Count < 1)
{
- var transaction = existingShopifyOrderTransactions[0];
-
- if (currency.ToUpperInvariant().Trim() != transaction.currency.ToUpperInvariant().Trim())
- {
- // because of parent_id present, currency will always be the one from parent transaction
- // malicious attacker could potentially exploit this by creating invoice
- // in different currency and paying that one, registering order on Shopify as paid
- // so if currency is supplied and is different from parent transaction currency we just won't register
- return null;
- }
-
- var createTransaction = new TransactionsCreateReq
- {
- transaction = new TransactionsCreateReq.DataHolder
- {
- parent_id = transaction.id,
- currency = currency,
- amount = amountCaptured,
- kind = "capture",
- gateway = "BTCPayServer",
- source = "external",
- authorization = invoiceId,
- status = success? "success": "failure"
- }
- };
-
- var createResp = await _client.TransactionCreate(orderId, createTransaction);
- return createResp;
+ return null;
+ }
+
+
+ var baseParentTransaction = existingShopifyOrderTransactions[0];
+
+ if (currency.ToUpperInvariant().Trim() != baseParentTransaction.currency.ToUpperInvariant().Trim())
+ {
+ // because of parent_id present, currency will always be the one from parent transaction
+ // malicious attacker could potentially exploit this by creating invoice
+ // in different currency and paying that one, registering order on Shopify as paid
+ // so if currency is supplied and is different from parent transaction currency we just won't register
+ return null;
}
- return null;
+ var kind = "capture";
+ var parentId = baseParentTransaction.id;
+ var status = success ? "success" : "failure";
+ var existingShopifyOrderTransactionsOnSameInvoice =
+ existingShopifyOrderTransactions.Where(holder => holder.authorization == invoiceId);
+
+ var successfulActions =
+ existingShopifyOrderTransactionsOnSameInvoice.Where(holder => holder.status == "success").ToArray();
+
+ var successfulCaptures = successfulActions.Where(holder => holder.kind == "capture").ToArray();
+ var refunds = successfulActions.Where(holder => holder.kind == "refund").ToArray();
+
+ if (!success && successfulCaptures.Length > 0 && (successfulCaptures.Length - refunds.Length) > 0)
+ {
+ kind = "void";
+ parentId = successfulCaptures.Last().id;
+ status = "success";
+ }
+ else if(success && successfulCaptures.Length >0 && (successfulCaptures.Length - refunds.Length ) > 0 )
+ {
+ return null;
+ }
+ var createTransaction = new TransactionsCreateReq
+ {
+ transaction = new TransactionsCreateReq.DataHolder
+ {
+ parent_id = parentId,
+ currency = currency,
+ amount = amountCaptured,
+ kind = kind,
+ gateway = "BTCPayServer",
+ source = "external",
+ authorization = invoiceId,
+ status = status
+ }
+ };
+ var createResp = await _client.TransactionCreate(orderId, createTransaction);
+ return createResp;
}
}
}
diff --git a/BTCPayServer/wwwroot/shopify/btcpay-shopify.js b/BTCPayServer/wwwroot/shopify/btcpay-shopify.js
index c2c1e28ea..d9cdaf1e0 100644
--- a/BTCPayServer/wwwroot/shopify/btcpay-shopify.js
+++ b/BTCPayServer/wwwroot/shopify/btcpay-shopify.js
@@ -81,7 +81,14 @@ window.BTCPayShopifyIntegrationModule = function () {
function handleInvoiceData(data, opts) {
currentInvoiceData = data;
if (!currentInvoiceData) {
- window.btcpay.hideFrame();
+ if (modalShown) {
+ window.btcpay.hideFrame();
+ fail();
+ }else if(opts && opts.backgroundCheck){
+ injectPaymentButtonHtml();
+ }else{
+ fail();
+ }
return;
}
if (["complete", "confirmed", "paid"].indexOf(currentInvoiceData.status.toLowerCase()) >= 0) {
@@ -90,7 +97,7 @@ window.BTCPayShopifyIntegrationModule = function () {
fail();
} else if (!opts || !opts.backgroundCheck) {
showModal();
- }
+ }
}
function showModal() {
@@ -110,7 +117,9 @@ window.BTCPayShopifyIntegrationModule = function () {
window.btcpay.onModalWillLeave(function () {
modalShown = false;
- fail();
+ getOrCheckInvoice(true).then(function (d) {
+ handleInvoiceData(d, {backgroundCheck: true})
+ });
});
window.btcpay.showInvoice(currentInvoiceData.invoiceId);
}
@@ -139,7 +148,6 @@ window.BTCPayShopifyIntegrationModule = function () {
return;
}
showPaymentInstructions();
- injectPaymentButtonHtml();
window.onPayButtonClicked = onPayButtonClicked.bind(this);
getOrCheckInvoice(true).then(function (d) {
handleInvoiceData(d, {backgroundCheck: true})
From e9bd1bad67cc4a1c5668e7794d38a31f49c9163f Mon Sep 17 00:00:00 2001
From: rockstardev
Date: Wed, 23 Sep 2020 00:04:48 -0500
Subject: [PATCH 35/63] Removing reference to Nethereum, Bitcoin only build
---
BTCPayServer/Controllers/StoresController.Integrations.cs | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/BTCPayServer/Controllers/StoresController.Integrations.cs b/BTCPayServer/Controllers/StoresController.Integrations.cs
index c136d869a..cb3b10782 100644
--- a/BTCPayServer/Controllers/StoresController.Integrations.cs
+++ b/BTCPayServer/Controllers/StoresController.Integrations.cs
@@ -15,7 +15,6 @@ using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
-using Nethereum.Util;
using NicolasDorier.RateLimits;
namespace BTCPayServer.Controllers
@@ -85,7 +84,7 @@ namespace BTCPayServer.Controllers
return Ok(new
{
invoiceId = firstInvoiceStillPending.Id,
- status = firstInvoiceStillPending.Status.ToStringInvariant().ToLowerInvariant()
+ status = firstInvoiceStillPending.Status.ToString().ToLowerInvariant()
});
}
@@ -97,7 +96,7 @@ namespace BTCPayServer.Controllers
return Ok(new
{
invoiceId = firstInvoiceSettled.Id,
- status = firstInvoiceSettled.Status.ToStringInvariant().ToLowerInvariant()
+ status = firstInvoiceSettled.Status.ToString().ToLowerInvariant()
});
}
@@ -123,7 +122,7 @@ namespace BTCPayServer.Controllers
return Ok(new
{
invoiceId = invoice.Id,
- status = invoice.Status.ToStringInvariant().ToLowerInvariant()
+ status = invoice.Status.ToString().ToLowerInvariant()
});
}
return NotFound();
From 03d6c8689956a73e58e495fa4788dd399ff6c0e2 Mon Sep 17 00:00:00 2001
From: Kukks
Date: Thu, 24 Sep 2020 17:33:15 +0200
Subject: [PATCH 36/63] Revert "Make Invoices save internal tags in the text
search"
This reverts commit f352399428f5aacfaa237061488771f023c7f7fd.
---
BTCPayServer/Services/Invoices/InvoiceRepository.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/BTCPayServer/Services/Invoices/InvoiceRepository.cs b/BTCPayServer/Services/Invoices/InvoiceRepository.cs
index 4c6ec3331..8c40e40f7 100644
--- a/BTCPayServer/Services/Invoices/InvoiceRepository.cs
+++ b/BTCPayServer/Services/Invoices/InvoiceRepository.cs
@@ -204,7 +204,7 @@ retry:
textSearch.Add(invoice.Metadata.OrderId);
textSearch.Add(ToString(invoice.Metadata, null));
textSearch.Add(invoice.StoreId);
- textSearch.AddRange(invoice.InternalTags);
+
AddToTextSearch(invoice.Id, textSearch.ToArray());
return invoice;
}
From a7d7b5abc33092949be205f1da3746ccef4f37af Mon Sep 17 00:00:00 2001
From: Kukks
Date: Thu, 24 Sep 2020 18:18:17 +0200
Subject: [PATCH 37/63] set order id of shopify invoice and serch by order id +
storeId
---
BTCPayServer/Controllers/StoresController.Integrations.cs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/BTCPayServer/Controllers/StoresController.Integrations.cs b/BTCPayServer/Controllers/StoresController.Integrations.cs
index cb3b10782..12d991d99 100644
--- a/BTCPayServer/Controllers/StoresController.Integrations.cs
+++ b/BTCPayServer/Controllers/StoresController.Integrations.cs
@@ -15,6 +15,7 @@ using BTCPayServer.Services.Stores;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
+using Newtonsoft.Json.Linq;
using NicolasDorier.RateLimits;
namespace BTCPayServer.Controllers
@@ -55,7 +56,6 @@ namespace BTCPayServer.Controllers
return Content(jsFile, "text/javascript");
}
-
[RateLimitsFilter(ZoneLimits.Shopify, Scope = RateLimitsScope.RemoteAddress)]
[AllowAnonymous]
[EnableCors(CorsPolicies.All)]
@@ -70,7 +70,7 @@ namespace BTCPayServer.Controllers
var invoiceOrderId = $"{ShopifyOrderMarkerHostedService.SHOPIFY_ORDER_ID_PREFIX}{orderId}";
var matchedExistingInvoices = await invoiceRepository.GetInvoices(new InvoiceQuery()
{
- TextSearch = invoiceOrderId
+ OrderId = new[] {invoiceOrderId}, StoreId = new[] {storeId}
});
matchedExistingInvoices = matchedExistingInvoices.Where(entity =>
entity.GetInternalTags(ShopifyOrderMarkerHostedService.SHOPIFY_ORDER_ID_PREFIX)
@@ -116,7 +116,7 @@ namespace BTCPayServer.Controllers
}
var invoice = await invoiceController.CreateInvoiceCoreRaw(
- new CreateInvoiceRequest() {Amount = order.TotalPrice, Currency = order.Currency}, store,
+ new CreateInvoiceRequest() {Amount = order.TotalPrice, Currency = order.Currency, Metadata = new JObject {["orderId"] = invoiceOrderId} }, store,
Request.GetAbsoluteUri(""), new List() {invoiceOrderId});
return Ok(new
From 47e9f820e48fcef9f18c2d5ea546183c0fc87f7b Mon Sep 17 00:00:00 2001
From: rockstardev
Date: Fri, 25 Sep 2020 13:50:04 -0500
Subject: [PATCH 38/63] Switching the flow to exclusively use Example Url
---
.../StoresController.Integrations.cs | 2 +-
.../Views/Stores/Integrations/Shopify.cshtml | 85 +++++++++----------
2 files changed, 39 insertions(+), 48 deletions(-)
diff --git a/BTCPayServer/Controllers/StoresController.Integrations.cs b/BTCPayServer/Controllers/StoresController.Integrations.cs
index 12d991d99..1148ff7f4 100644
--- a/BTCPayServer/Controllers/StoresController.Integrations.cs
+++ b/BTCPayServer/Controllers/StoresController.Integrations.cs
@@ -164,7 +164,7 @@ namespace BTCPayServer.Controllers
}
catch (Exception)
{
- TempData[WellKnownTempData.ErrorMessage] = "The provided example url was invalid.";
+ TempData[WellKnownTempData.ErrorMessage] = "The provided Example Url was invalid.";
return View("Integrations", vm);
}
}
diff --git a/BTCPayServer/Views/Stores/Integrations/Shopify.cshtml b/BTCPayServer/Views/Stores/Integrations/Shopify.cshtml
index ef5bd6157..6b66ff9f5 100644
--- a/BTCPayServer/Views/Stores/Integrations/Shopify.cshtml
+++ b/BTCPayServer/Views/Stores/Integrations/Shopify.cshtml
@@ -3,15 +3,6 @@
var shopify = Model.Shopify;
var shopifyCredsSet = shopify?.IntegratedAt.HasValue is true;
}
-