Implement bitcoin donations via BTCPay
This commit is contained in:
35
spec/features/contributions/donations_spec.rb
Normal file
35
spec/features/contributions/donations_spec.rb
Normal file
@@ -0,0 +1,35 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Donations page', type: :feature do
|
||||
let(:user) { create :user }
|
||||
|
||||
before do
|
||||
login_as user, :scope => :user
|
||||
end
|
||||
|
||||
describe "Donation methods" do
|
||||
scenario "Only BTCPay enabled" do
|
||||
Setting.btcpay_enabled = true
|
||||
Setting.lndhub_enabled = false
|
||||
Setting.opencollective_enabled = false
|
||||
visit contributions_donations_url
|
||||
|
||||
within ".donation-methods" do
|
||||
expect(page).to have_content("Bitcoin")
|
||||
expect(page).not_to have_content("OpenCollective")
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Only OpenCollective enabled" do
|
||||
Setting.btcpay_enabled = false
|
||||
Setting.lndhub_enabled = false
|
||||
Setting.opencollective_enabled = true
|
||||
visit contributions_donations_url
|
||||
|
||||
within ".donation-methods" do
|
||||
expect(page).not_to have_content("Bitcoin")
|
||||
expect(page).to have_content("OpenCollective")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
32
spec/fixtures/btcpay/create_invoice.rb
vendored
Normal file
32
spec/fixtures/btcpay/create_invoice.rb
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"id" => "Q9GBe143MXHkdpZeH4Ftx5",
|
||||
"storeId" => "AxQQ6oH4YX7n5pH1JPBLu97QD6RTybtj8m2W8YzhYr6T",
|
||||
"amount" => "1",
|
||||
"checkoutLink" => "http://10.1.1.163:23001/i/Q9GBe143MXHkdpZeH4Ftx5",
|
||||
"status" => "New",
|
||||
"additionalStatus" => "None",
|
||||
"monitoringExpiration" => 1707995026,
|
||||
"expirationTime" => 1707908626,
|
||||
"createdTime" => 1707907726,
|
||||
"availableStatusesForManualMarking" =>["Settled", "Invalid"],
|
||||
"archived" => false,
|
||||
"type" => "Standard",
|
||||
"currency" => "EUR",
|
||||
"metadata" => {},
|
||||
"checkout" => {
|
||||
"speedPolicy" => "MediumSpeed",
|
||||
"paymentMethods" => ["BTC", "BTC-LightningNetwork"],
|
||||
"defaultPaymentMethod" => "BTC-LightningNetwork",
|
||||
"expirationMinutes" => 15,
|
||||
"monitoringMinutes" => 1440,
|
||||
"paymentTolerance" => 0.0,
|
||||
"redirectURL" => "http://localhost:3000/contributions/donations",
|
||||
"redirectAutomatically" => false,
|
||||
"requiresRefundEmail" => false,
|
||||
"defaultLanguage" => nil,
|
||||
"checkoutType" => nil,
|
||||
"lazyPaymentMethods" => nil},
|
||||
"receipt" => {
|
||||
"enabled" => nil, "showQR" => nil, "showPayments" => nil
|
||||
}
|
||||
}
|
||||
41
spec/fixtures/btcpay/lightning_eur_settled_invoice.json
vendored
Normal file
41
spec/fixtures/btcpay/lightning_eur_settled_invoice.json
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"id": "MCkDbf2cUgBuuisUCgnRnb",
|
||||
"storeId": "AxQQ6oH4YX7n5pH1JPBLu97QD6RTybtj8m2W8YzhYr6T",
|
||||
"amount": "1",
|
||||
"checkoutLink": "http://10.1.1.163:23001/i/MCkDbf2cUgBuuisUCgnRnb",
|
||||
"status": "Settled",
|
||||
"additionalStatus": "None",
|
||||
"monitoringExpiration": 1708169508,
|
||||
"expirationTime": 1708083108,
|
||||
"createdTime": 1708082208,
|
||||
"availableStatusesForManualMarking": [
|
||||
|
||||
],
|
||||
"archived": false,
|
||||
"type": "Standard",
|
||||
"currency": "EUR",
|
||||
"metadata": {
|
||||
},
|
||||
"checkout": {
|
||||
"speedPolicy": "MediumSpeed",
|
||||
"paymentMethods": [
|
||||
"BTC",
|
||||
"BTC-LightningNetwork"
|
||||
],
|
||||
"defaultPaymentMethod": "BTC-LightningNetwork",
|
||||
"expirationMinutes": 15,
|
||||
"monitoringMinutes": 1440,
|
||||
"paymentTolerance": 0.0,
|
||||
"redirectURL": "http://localhost:3000/contributions/donations/27/confirm_btcpay",
|
||||
"redirectAutomatically": true,
|
||||
"requiresRefundEmail": false,
|
||||
"defaultLanguage": null,
|
||||
"checkoutType": null,
|
||||
"lazyPaymentMethods": null
|
||||
},
|
||||
"receipt": {
|
||||
"enabled": null,
|
||||
"showQR": null,
|
||||
"showPayments": null
|
||||
}
|
||||
}
|
||||
46
spec/fixtures/btcpay/lightning_eur_settled_payments.json
vendored
Normal file
46
spec/fixtures/btcpay/lightning_eur_settled_payments.json
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
[
|
||||
{
|
||||
"activated": true,
|
||||
"destination": "bc1qtvwjguv679lcch9a9zxzxcengq3t3zgd5zm0pd",
|
||||
"paymentLink": "bitcoin:bc1qtvwjguv679lcch9a9zxzxcengq3t3zgd5zm0pd",
|
||||
"rate": "48532.8",
|
||||
"paymentMethodPaid": "0",
|
||||
"totalPaid": "0.00002061",
|
||||
"due": "0",
|
||||
"amount": "0.00002061",
|
||||
"networkFee": "0",
|
||||
"payments": [
|
||||
|
||||
],
|
||||
"paymentMethod": "BTC",
|
||||
"cryptoCode": "BTC",
|
||||
"additionalData": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"activated": true,
|
||||
"destination": "lnbc20610n1pju73pqpp5rrvhc34tzt3vz70r33c2n2qqtm6hxau2hyl9w23kvrx56vhsfh5sdphg3hkuct5d9hkugr5dus8g6r9yp9k7umddaejqcm0dacx2unpw35hvegcqzzsxqyz5vqsp56grmnp2ezj4n323squu2p2e09g5lgncsr7f34084p5dyjgmwcssq9qyyssqfrc9x37qcvvpsx8m4zvu9glvcfcmqzs9ttfsg30g2gjxfkylvp8rdud2yx8gshs2jv0rea0etjrcygrc0hp4vckgsfs4grsnl854ajgpurzzp4",
|
||||
"paymentLink": "lightning:lnbc20610n1pju73pqpp5rrvhc34tzt3vz70r33c2n2qqtm6hxau2hyl9w23kvrx56vhsfh5sdphg3hkuct5d9hkugr5dus8g6r9yp9k7umddaejqcm0dacx2unpw35hvegcqzzsxqyz5vqsp56grmnp2ezj4n323squu2p2e09g5lgncsr7f34084p5dyjgmwcssq9qyyssqfrc9x37qcvvpsx8m4zvu9glvcfcmqzs9ttfsg30g2gjxfkylvp8rdud2yx8gshs2jv0rea0etjrcygrc0hp4vckgsfs4grsnl854ajgpurzzp4",
|
||||
"rate": "48532.8",
|
||||
"paymentMethodPaid": "0.00002061",
|
||||
"totalPaid": "0.00002061",
|
||||
"due": "0",
|
||||
"amount": "0.00002061",
|
||||
"networkFee": "0",
|
||||
"payments": [
|
||||
{
|
||||
"id": "18d97c46ab12e2c179e38c70a9a8005ef573778ab93e572a3660cd4d32f04de9",
|
||||
"receivedDate": 1708082214,
|
||||
"value": "0.00002061",
|
||||
"fee": "0.0",
|
||||
"status": "Settled",
|
||||
"destination": "lnbc20610n1pju73pqpp5rrvhc34tzt3vz70r33c2n2qqtm6hxau2hyl9w23kvrx56vhsfh5sdphg3hkuct5d9hkugr5dus8g6r9yp9k7umddaejqcm0dacx2unpw35hvegcqzzsxqyz5vqsp56grmnp2ezj4n323squu2p2e09g5lgncsr7f34084p5dyjgmwcssq9qyyssqfrc9x37qcvvpsx8m4zvu9glvcfcmqzs9ttfsg30g2gjxfkylvp8rdud2yx8gshs2jv0rea0etjrcygrc0hp4vckgsfs4grsnl854ajgpurzzp4"
|
||||
}
|
||||
],
|
||||
"paymentMethod": "BTC-LightningNetwork",
|
||||
"cryptoCode": "BTC",
|
||||
"additionalData": {
|
||||
"paymentHash": "18d97c46ab12e2c179e38c70a9a8005ef573778ab93e572a3660cd4d32f04de9"
|
||||
}
|
||||
}
|
||||
]
|
||||
41
spec/fixtures/btcpay/lightning_sats_settled_invoice.json
vendored
Normal file
41
spec/fixtures/btcpay/lightning_sats_settled_invoice.json
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"id": "JxjfeJi1TtX8FcWSjEvGxg",
|
||||
"storeId": "AxQQ6oH4YX7n5pH1JPBLu97QD6RTybtj8m2W8YzhYr6T",
|
||||
"amount": "0.0001",
|
||||
"checkoutLink": "http://10.1.1.163:23001/i/JxjfeJi1TtX8FcWSjEvGxg",
|
||||
"status": "Settled",
|
||||
"additionalStatus": "None",
|
||||
"monitoringExpiration": 1708180292,
|
||||
"expirationTime": 1708093892,
|
||||
"createdTime": 1708092992,
|
||||
"availableStatusesForManualMarking": [
|
||||
|
||||
],
|
||||
"archived": false,
|
||||
"type": "Standard",
|
||||
"currency": "BTC",
|
||||
"metadata": {
|
||||
},
|
||||
"checkout": {
|
||||
"speedPolicy": "MediumSpeed",
|
||||
"paymentMethods": [
|
||||
"BTC",
|
||||
"BTC-LightningNetwork"
|
||||
],
|
||||
"defaultPaymentMethod": "BTC-LightningNetwork",
|
||||
"expirationMinutes": 15,
|
||||
"monitoringMinutes": 1440,
|
||||
"paymentTolerance": 0.0,
|
||||
"redirectURL": "http://localhost:3000/contributions/donations/32/confirm_btcpay",
|
||||
"redirectAutomatically": true,
|
||||
"requiresRefundEmail": false,
|
||||
"defaultLanguage": null,
|
||||
"checkoutType": null,
|
||||
"lazyPaymentMethods": null
|
||||
},
|
||||
"receipt": {
|
||||
"enabled": null,
|
||||
"showQR": null,
|
||||
"showPayments": null
|
||||
}
|
||||
}
|
||||
46
spec/fixtures/btcpay/lightning_sats_settled_payments.json
vendored
Normal file
46
spec/fixtures/btcpay/lightning_sats_settled_payments.json
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
[
|
||||
{
|
||||
"activated": true,
|
||||
"destination": "bc1q9fay59qdmtv46d5hpf62vt5eyd7ag98t4h0s3g",
|
||||
"paymentLink": "bitcoin:bc1q9fay59qdmtv46d5hpf62vt5eyd7ag98t4h0s3g",
|
||||
"rate": "1.0",
|
||||
"paymentMethodPaid": "0",
|
||||
"totalPaid": "0.0001",
|
||||
"due": "0",
|
||||
"amount": "0.0001",
|
||||
"networkFee": "0",
|
||||
"payments": [
|
||||
|
||||
],
|
||||
"paymentMethod": "BTC",
|
||||
"cryptoCode": "BTC",
|
||||
"additionalData": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"activated": true,
|
||||
"destination": "lnbc100u1pju7mjqpp54yt6z4g4j294vta90yn35pwch76a4h47txx4m4njfdqmcsa4w50qdphg3hkuct5d9hkugr5dus8g6r9yp9k7umddaejqcm0dacx2unpw35hvegcqzzsxqyz5vqsp5gx3wee4c2gsl7lnmx4qkrha3mkxh926j5qpdqz7wyyya04wks7cq9qyyssq4ft7a69c93kr04hamp5ah958ay222dvdrzr3nl599nx0l3ejpqe4ktarkxdymsxgg6v3evat9e9u0fp2vg2r2z860fn0h04znq9c6psqh8s53q",
|
||||
"paymentLink": "lightning:lnbc100u1pju7mjqpp54yt6z4g4j294vta90yn35pwch76a4h47txx4m4njfdqmcsa4w50qdphg3hkuct5d9hkugr5dus8g6r9yp9k7umddaejqcm0dacx2unpw35hvegcqzzsxqyz5vqsp5gx3wee4c2gsl7lnmx4qkrha3mkxh926j5qpdqz7wyyya04wks7cq9qyyssq4ft7a69c93kr04hamp5ah958ay222dvdrzr3nl599nx0l3ejpqe4ktarkxdymsxgg6v3evat9e9u0fp2vg2r2z860fn0h04znq9c6psqh8s53q",
|
||||
"rate": "1.0",
|
||||
"paymentMethodPaid": "0.0001",
|
||||
"totalPaid": "0.0001",
|
||||
"due": "0",
|
||||
"amount": "0.0001",
|
||||
"networkFee": "0",
|
||||
"payments": [
|
||||
{
|
||||
"id": "a917a15515928b562fa579271a05d8bfb5dadebe598d5dd6724b41bc43b5751e",
|
||||
"receivedDate": 1708093015,
|
||||
"value": "0.0001",
|
||||
"fee": "0.0",
|
||||
"status": "Settled",
|
||||
"destination": "lnbc100u1pju7mjqpp54yt6z4g4j294vta90yn35pwch76a4h47txx4m4njfdqmcsa4w50qdphg3hkuct5d9hkugr5dus8g6r9yp9k7umddaejqcm0dacx2unpw35hvegcqzzsxqyz5vqsp5gx3wee4c2gsl7lnmx4qkrha3mkxh926j5qpdqz7wyyya04wks7cq9qyyssq4ft7a69c93kr04hamp5ah958ay222dvdrzr3nl599nx0l3ejpqe4ktarkxdymsxgg6v3evat9e9u0fp2vg2r2z860fn0h04znq9c6psqh8s53q"
|
||||
}
|
||||
],
|
||||
"paymentMethod": "BTC-LightningNetwork",
|
||||
"cryptoCode": "BTC",
|
||||
"additionalData": {
|
||||
"paymentHash": "a917a15515928b562fa579271a05d8bfb5dadebe598d5dd6724b41bc43b5751e"
|
||||
}
|
||||
}
|
||||
]
|
||||
42
spec/fixtures/btcpay/onchain_eur_processing_invoice.json
vendored
Normal file
42
spec/fixtures/btcpay/onchain_eur_processing_invoice.json
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"id": "K4e31MhbLKmr3D7qoNYRd3",
|
||||
"storeId": "AxQQ6oH4YX7n5pH1JPBLu97QD6RTybtj8m2W8YzhYr6T",
|
||||
"amount": "100",
|
||||
"checkoutLink": "http://10.1.1.163:23001/i/K4e31MhbLKmr3D7qoNYRd3",
|
||||
"status": "Processing",
|
||||
"additionalStatus": "None",
|
||||
"monitoringExpiration": 1708173683,
|
||||
"expirationTime": 1708087283,
|
||||
"createdTime": 1708086383,
|
||||
"availableStatusesForManualMarking": [
|
||||
"Settled",
|
||||
"Invalid"
|
||||
],
|
||||
"archived": false,
|
||||
"type": "Standard",
|
||||
"currency": "USD",
|
||||
"metadata": {
|
||||
},
|
||||
"checkout": {
|
||||
"speedPolicy": "MediumSpeed",
|
||||
"paymentMethods": [
|
||||
"BTC",
|
||||
"BTC-LightningNetwork"
|
||||
],
|
||||
"defaultPaymentMethod": "BTC-LightningNetwork",
|
||||
"expirationMinutes": 15,
|
||||
"monitoringMinutes": 1440,
|
||||
"paymentTolerance": 0.0,
|
||||
"redirectURL": "http://localhost:3000/contributions/donations/28/confirm_btcpay",
|
||||
"redirectAutomatically": true,
|
||||
"requiresRefundEmail": false,
|
||||
"defaultLanguage": null,
|
||||
"checkoutType": null,
|
||||
"lazyPaymentMethods": null
|
||||
},
|
||||
"receipt": {
|
||||
"enabled": null,
|
||||
"showQR": null,
|
||||
"showPayments": null
|
||||
}
|
||||
}
|
||||
46
spec/fixtures/btcpay/onchain_eur_processing_payments.json
vendored
Normal file
46
spec/fixtures/btcpay/onchain_eur_processing_payments.json
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
[
|
||||
{
|
||||
"activated": true,
|
||||
"destination": "bc1qqxm55h6yzych9kg6kquak4c73nyv352070tsmh",
|
||||
"paymentLink": "bitcoin:bc1qqxm55h6yzych9kg6kquak4c73nyv352070tsmh",
|
||||
"rate": "52259.2",
|
||||
"paymentMethodPaid": "0.00191354",
|
||||
"totalPaid": "0.00191354",
|
||||
"due": "0",
|
||||
"amount": "0.00191354",
|
||||
"networkFee": "0",
|
||||
"payments": [
|
||||
{
|
||||
"id": "21da85563274d0c3975273c1a2a8551bddeebb68b8f8a3242f63dd4cc238b480-1",
|
||||
"receivedDate": 1708086448,
|
||||
"value": "0.00191354",
|
||||
"fee": "0.0",
|
||||
"status": "Processing",
|
||||
"destination": "bc1qqxm55h6yzych9kg6kquak4c73nyv352070tsmh"
|
||||
}
|
||||
],
|
||||
"paymentMethod": "BTC",
|
||||
"cryptoCode": "BTC",
|
||||
"additionalData": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"activated": true,
|
||||
"destination": "lnbc1913540n1pju74r0pp5vpnw6l84ytu5u5evehn00xwsrppg7w45cj4mrwjwng474w7x3ugqdphg3hkuct5d9hkugr5dus8g6r9yp9k7umddaejqcm0dacx2unpw35hvegcqzzsxqyz5vqsp5sscc8ufdw29lpv9z09c6edhzc2njg0lmspsk8sdunek7yrkeu3mq9qyyssqnzz9xrhpy7sej5k62vcjju253kxx87jveq7vusl2sgaeuyh48ph9ecuud6f329syuut3z8w544c6ynhtx4ratundzmp7fs6sdll8g0spurjhnx",
|
||||
"paymentLink": "lightning:lnbc1913540n1pju74r0pp5vpnw6l84ytu5u5evehn00xwsrppg7w45cj4mrwjwng474w7x3ugqdphg3hkuct5d9hkugr5dus8g6r9yp9k7umddaejqcm0dacx2unpw35hvegcqzzsxqyz5vqsp5sscc8ufdw29lpv9z09c6edhzc2njg0lmspsk8sdunek7yrkeu3mq9qyyssqnzz9xrhpy7sej5k62vcjju253kxx87jveq7vusl2sgaeuyh48ph9ecuud6f329syuut3z8w544c6ynhtx4ratundzmp7fs6sdll8g0spurjhnx",
|
||||
"rate": "52259.2",
|
||||
"paymentMethodPaid": "0",
|
||||
"totalPaid": "0.00191354",
|
||||
"due": "0",
|
||||
"amount": "0.00191354",
|
||||
"networkFee": "0",
|
||||
"payments": [
|
||||
|
||||
],
|
||||
"paymentMethod": "BTC-LightningNetwork",
|
||||
"cryptoCode": "BTC",
|
||||
"additionalData": {
|
||||
"paymentHash": "6066ed7cf522f94e532ccde6f799d018428f3ab4c4abb1ba4e9a2beabbc68f10"
|
||||
}
|
||||
}
|
||||
]
|
||||
41
spec/fixtures/btcpay/onchain_eur_settled_invoice.json
vendored
Normal file
41
spec/fixtures/btcpay/onchain_eur_settled_invoice.json
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"id": "K4e31MhbLKmr3D7qoNYRd3",
|
||||
"storeId": "AxQQ6oH4YX7n5pH1JPBLu97QD6RTybtj8m2W8YzhYr6T",
|
||||
"amount": "100",
|
||||
"checkoutLink": "http://10.1.1.163:23001/i/K4e31MhbLKmr3D7qoNYRd3",
|
||||
"status": "Settled",
|
||||
"additionalStatus": "None",
|
||||
"monitoringExpiration": 1708173683,
|
||||
"expirationTime": 1708087283,
|
||||
"createdTime": 1708086383,
|
||||
"availableStatusesForManualMarking": [
|
||||
|
||||
],
|
||||
"archived": false,
|
||||
"type": "Standard",
|
||||
"currency": "USD",
|
||||
"metadata": {
|
||||
},
|
||||
"checkout": {
|
||||
"speedPolicy": "MediumSpeed",
|
||||
"paymentMethods": [
|
||||
"BTC",
|
||||
"BTC-LightningNetwork"
|
||||
],
|
||||
"defaultPaymentMethod": "BTC-LightningNetwork",
|
||||
"expirationMinutes": 15,
|
||||
"monitoringMinutes": 1440,
|
||||
"paymentTolerance": 0.0,
|
||||
"redirectURL": "http://localhost:3000/contributions/donations/28/confirm_btcpay",
|
||||
"redirectAutomatically": true,
|
||||
"requiresRefundEmail": false,
|
||||
"defaultLanguage": null,
|
||||
"checkoutType": null,
|
||||
"lazyPaymentMethods": null
|
||||
},
|
||||
"receipt": {
|
||||
"enabled": null,
|
||||
"showQR": null,
|
||||
"showPayments": null
|
||||
}
|
||||
}
|
||||
46
spec/fixtures/btcpay/onchain_eur_settled_payments.json
vendored
Normal file
46
spec/fixtures/btcpay/onchain_eur_settled_payments.json
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
[
|
||||
{
|
||||
"activated": true,
|
||||
"destination": "bc1qqxm55h6yzych9kg6kquak4c73nyv352070tsmh",
|
||||
"paymentLink": "bitcoin:bc1qqxm55h6yzych9kg6kquak4c73nyv352070tsmh",
|
||||
"rate": "52259.2",
|
||||
"paymentMethodPaid": "0.00191354",
|
||||
"totalPaid": "0.00191354",
|
||||
"due": "0",
|
||||
"amount": "0.00191354",
|
||||
"networkFee": "0",
|
||||
"payments": [
|
||||
{
|
||||
"id": "218652f351508c46cfd99de1c6cdc0dcb66bc1bbfaf38578235d080046a96305-1",
|
||||
"receivedDate": 1708106396,
|
||||
"value": "0.00191354",
|
||||
"fee": "0.0",
|
||||
"status": "Settled",
|
||||
"destination": "bc1qqxm55h6yzych9kg6kquak4c73nyv352070tsmh"
|
||||
}
|
||||
],
|
||||
"paymentMethod": "BTC",
|
||||
"cryptoCode": "BTC",
|
||||
"additionalData": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"activated": true,
|
||||
"destination": "lnbc1913540n1pju74r0pp5vpnw6l84ytu5u5evehn00xwsrppg7w45cj4mrwjwng474w7x3ugqdphg3hkuct5d9hkugr5dus8g6r9yp9k7umddaejqcm0dacx2unpw35hvegcqzzsxqyz5vqsp5sscc8ufdw29lpv9z09c6edhzc2njg0lmspsk8sdunek7yrkeu3mq9qyyssqnzz9xrhpy7sej5k62vcjju253kxx87jveq7vusl2sgaeuyh48ph9ecuud6f329syuut3z8w544c6ynhtx4ratundzmp7fs6sdll8g0spurjhnx",
|
||||
"paymentLink": "lightning:lnbc1913540n1pju74r0pp5vpnw6l84ytu5u5evehn00xwsrppg7w45cj4mrwjwng474w7x3ugqdphg3hkuct5d9hkugr5dus8g6r9yp9k7umddaejqcm0dacx2unpw35hvegcqzzsxqyz5vqsp5sscc8ufdw29lpv9z09c6edhzc2njg0lmspsk8sdunek7yrkeu3mq9qyyssqnzz9xrhpy7sej5k62vcjju253kxx87jveq7vusl2sgaeuyh48ph9ecuud6f329syuut3z8w544c6ynhtx4ratundzmp7fs6sdll8g0spurjhnx",
|
||||
"rate": "52259.2",
|
||||
"paymentMethodPaid": "0",
|
||||
"totalPaid": "0.00191354",
|
||||
"due": "0",
|
||||
"amount": "0.00191354",
|
||||
"networkFee": "0",
|
||||
"payments": [
|
||||
|
||||
],
|
||||
"paymentMethod": "BTC-LightningNetwork",
|
||||
"cryptoCode": "BTC",
|
||||
"additionalData": {
|
||||
"paymentHash": "6066ed7cf522f94e532ccde6f799d018428f3ab4c4abb1ba4e9a2beabbc68f10"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1,9 +1,4 @@
|
||||
require 'rails_helper'
|
||||
|
||||
describe ApplicationHelper do
|
||||
describe "sats_to_btc" do
|
||||
it "converts satoshis to BTC" do
|
||||
expect(helper.sats_to_btc(120000000)).to eq(1.2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
63
spec/jobs/btcpay_check_donation_job_spec.rb
Normal file
63
spec/jobs/btcpay_check_donation_job_spec.rb
Normal file
@@ -0,0 +1,63 @@
|
||||
require 'rails_helper'
|
||||
require 'webmock/rspec'
|
||||
|
||||
RSpec.describe BtcpayCheckDonationJob, type: :job do
|
||||
let(:user) { create :user, cn: 'jimmy', ou: 'kosmos.org' }
|
||||
|
||||
let(:donation) do
|
||||
user.donations.create!(
|
||||
donation_method: "btcpay", btcpay_invoice_id: "K4e31MhbLKmr3D7qoNYRd3",
|
||||
paid_at: nil, payment_status: "processing",
|
||||
fiat_amount: 120, fiat_currency: "USD"
|
||||
)
|
||||
end
|
||||
|
||||
after(:each) do
|
||||
clear_enqueued_jobs
|
||||
clear_performed_jobs
|
||||
end
|
||||
|
||||
describe "invoice still processing" do
|
||||
subject(:job) { described_class.perform_later(donation) }
|
||||
|
||||
before do
|
||||
invoice = File.read("#{Rails.root}/spec/fixtures/btcpay/onchain_eur_processing_invoice.json")
|
||||
payments = File.read("#{Rails.root}/spec/fixtures/btcpay/onchain_eur_processing_payments.json")
|
||||
stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/invoices/K4e31MhbLKmr3D7qoNYRd3")
|
||||
.to_return(status: 200, headers: {}, body: invoice)
|
||||
stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/invoices/K4e31MhbLKmr3D7qoNYRd3/payment-methods")
|
||||
.to_return(status: 200, headers: {}, body: payments)
|
||||
end
|
||||
|
||||
it "enqueues itself to check again later" do
|
||||
expect_any_instance_of(described_class).to receive(:re_enqueue_job).once
|
||||
perform_enqueued_jobs { job }
|
||||
end
|
||||
end
|
||||
|
||||
describe "invoice settled" do
|
||||
subject(:job) { described_class.perform_later(donation) }
|
||||
|
||||
before do
|
||||
invoice = File.read("#{Rails.root}/spec/fixtures/btcpay/onchain_eur_settled_invoice.json")
|
||||
payments = File.read("#{Rails.root}/spec/fixtures/btcpay/onchain_eur_settled_payments.json")
|
||||
stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/invoices/K4e31MhbLKmr3D7qoNYRd3")
|
||||
.to_return(status: 200, headers: {}, body: invoice)
|
||||
stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/invoices/K4e31MhbLKmr3D7qoNYRd3/payment-methods")
|
||||
.to_return(status: 200, headers: {}, body: payments)
|
||||
end
|
||||
|
||||
it "updates the donation record" do
|
||||
perform_enqueued_jobs { job }
|
||||
|
||||
donation.reload
|
||||
expect(donation.paid_at).not_to be_nil
|
||||
expect(donation.payment_status).to eq("settled")
|
||||
end
|
||||
|
||||
it "does not enqueue itself again" do
|
||||
expect_any_instance_of(described_class).not_to receive(:re_enqueue_job)
|
||||
perform_enqueued_jobs { job }
|
||||
end
|
||||
end
|
||||
end
|
||||
233
spec/requests/contributions/donations_spec.rb
Normal file
233
spec/requests/contributions/donations_spec.rb
Normal file
@@ -0,0 +1,233 @@
|
||||
require 'rails_helper'
|
||||
require 'webmock/rspec'
|
||||
|
||||
RSpec.describe "Donations", type: :request do
|
||||
let(:user) { create :user, cn: 'jimmy', ou: 'kosmos.org' }
|
||||
|
||||
before do
|
||||
Warden.test_mode!
|
||||
login_as user, scope: :user
|
||||
end
|
||||
|
||||
after { Warden.test_reset! }
|
||||
|
||||
describe "#create" do
|
||||
describe "with disabled methods" do
|
||||
before do
|
||||
Setting.btcpay_enabled = false
|
||||
end
|
||||
|
||||
it "returns a 403" do
|
||||
post "/contributions/donations", params: { donation_method: "btcpay" }
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
describe "with fake methods" do
|
||||
it "returns a 403" do
|
||||
post "/contributions/donations", params: { donation_method: "remotestorage" }
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
describe "with invalid fiat currency" do
|
||||
it "returns a 422" do
|
||||
post "/contributions/donations", params: {
|
||||
donation_method: "btcpay", amount: "10", currency: "GBP"
|
||||
}
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
end
|
||||
end
|
||||
|
||||
describe "with bad amount" do
|
||||
it "returns a 422" do
|
||||
post "/contributions/donations", params: {
|
||||
donation_method: "btcpay", amount: ""
|
||||
}
|
||||
expect(response).to have_http_status(:unprocessable_entity)
|
||||
end
|
||||
end
|
||||
|
||||
describe "with BTCPay" do
|
||||
before { Setting.btcpay_enabled = true }
|
||||
|
||||
describe "amount in EUR" do
|
||||
before do
|
||||
expect(BtcpayManager::CreateInvoice).to receive(:call)
|
||||
.with(amount: 25, currency: "EUR", redirect_url: "http://www.example.com/contributions/donations/1/confirm_btcpay")
|
||||
.and_return({
|
||||
"id" => "Q9GBe143HJIkdpZeH4Ftx5",
|
||||
"amount" => "25",
|
||||
"currency" => "EUR",
|
||||
"checkoutLink" => "#{Setting.btcpay_api_url}/i/Q9GBe143HJIkdpZeH4Ftx5",
|
||||
"expirationTime" => 1707908626,
|
||||
"checkout" => { "redirectURL" => "http://www.example.com/contributions/donations/1/confirm_btcpay" }
|
||||
})
|
||||
|
||||
post "/contributions/donations", params: {
|
||||
donation_method: "btcpay", amount: "25", currency: "EUR",
|
||||
public_name: "Mickey"
|
||||
}
|
||||
end
|
||||
|
||||
it "creates a new donation record" do
|
||||
expect(user.donations.count).to eq(1)
|
||||
donation = user.donations.first
|
||||
expect(donation.donation_method).to eq("btcpay")
|
||||
expect(donation.payment_method).to be_nil
|
||||
expect(donation.paid_at).to be_nil
|
||||
expect(donation.public_name).to eq("Mickey")
|
||||
expect(donation.amount_sats).to be_nil
|
||||
expect(donation.fiat_amount).to eq(2500)
|
||||
expect(donation.fiat_currency).to eq("EUR")
|
||||
expect(donation.btcpay_invoice_id).to eq("Q9GBe143HJIkdpZeH4Ftx5")
|
||||
end
|
||||
|
||||
it "redirects to the BTCPay checkout page" do
|
||||
expect(response).to redirect_to("https://btcpay.example.com/i/Q9GBe143HJIkdpZeH4Ftx5")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#confirm_btcpay" do
|
||||
before { Setting.btcpay_enabled = true }
|
||||
|
||||
describe "with donation of another user" do
|
||||
let(:other_user) { create :user, id: 3, cn: "carl", ou: 'kosmos.org', email: "carl@example.com" }
|
||||
|
||||
before do
|
||||
@donation = other_user.donations.create!(
|
||||
donation_method: "btcpay", btcpay_invoice_id: "123abc",
|
||||
fiat_amount: 25, fiat_currency: "EUR", paid_at: nil
|
||||
)
|
||||
get confirm_btcpay_contributions_donation_path(@donation.id)
|
||||
end
|
||||
|
||||
it "returns a 404" do
|
||||
expect(response).to have_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
describe "with confirmed donation" do
|
||||
before do
|
||||
@donation = user.donations.create!(
|
||||
donation_method: "btcpay", btcpay_invoice_id: "123abc",
|
||||
fiat_amount: 25, fiat_currency: "EUR",
|
||||
paid_at: "2024-02-16", payment_status: "settled"
|
||||
)
|
||||
get confirm_btcpay_contributions_donation_path(@donation.id)
|
||||
end
|
||||
|
||||
it "redirects to the donations index" do
|
||||
expect(response).to redirect_to(contributions_donations_url)
|
||||
end
|
||||
end
|
||||
|
||||
describe "settled via Lightning" do
|
||||
describe "amount in EUR" do
|
||||
subject do
|
||||
user.donations.create!(
|
||||
donation_method: "btcpay", btcpay_invoice_id: "MCkDbf2cUgBuuisUCgnRnb",
|
||||
fiat_amount: 25, fiat_currency: "EUR", paid_at: nil
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
invoice = File.read("#{Rails.root}/spec/fixtures/btcpay/lightning_eur_settled_invoice.json")
|
||||
payments = File.read("#{Rails.root}/spec/fixtures/btcpay/lightning_eur_settled_payments.json")
|
||||
stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/invoices/MCkDbf2cUgBuuisUCgnRnb")
|
||||
.to_return(status: 200, headers: {}, body: invoice)
|
||||
stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/invoices/MCkDbf2cUgBuuisUCgnRnb/payment-methods")
|
||||
.to_return(status: 200, headers: {}, body: payments)
|
||||
|
||||
get confirm_btcpay_contributions_donation_path(subject)
|
||||
end
|
||||
|
||||
it "updates the donation record" do
|
||||
subject.reload
|
||||
expect(subject.paid_at).not_to be_nil
|
||||
expect(subject.amount_sats).to eq(2061)
|
||||
end
|
||||
|
||||
it "redirects to the donations index" do
|
||||
expect(response).to redirect_to(contributions_donations_url)
|
||||
end
|
||||
end
|
||||
|
||||
describe "amount in sats" do
|
||||
subject do
|
||||
user.donations.create!(
|
||||
donation_method: "btcpay", btcpay_invoice_id: "JxjfeJi1TtX8FcWSjEvGxg",
|
||||
amount_sats: 10000, fiat_amount: nil, fiat_currency: nil, paid_at: nil
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
invoice = File.read("#{Rails.root}/spec/fixtures/btcpay/lightning_sats_settled_invoice.json")
|
||||
payments = File.read("#{Rails.root}/spec/fixtures/btcpay/lightning_sats_settled_payments.json")
|
||||
stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/invoices/JxjfeJi1TtX8FcWSjEvGxg")
|
||||
.to_return(status: 200, headers: {}, body: invoice)
|
||||
stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/invoices/JxjfeJi1TtX8FcWSjEvGxg/payment-methods")
|
||||
.to_return(status: 200, headers: {}, body: payments)
|
||||
|
||||
expect(BtcpayManager::FetchExchangeRate).to receive(:call)
|
||||
.with(fiat_currency: "EUR").and_return(48532.00)
|
||||
|
||||
get confirm_btcpay_contributions_donation_path(subject)
|
||||
end
|
||||
|
||||
it "updates the donation record" do
|
||||
subject.reload
|
||||
expect(subject.paid_at).not_to be_nil
|
||||
expect(subject.amount_sats).to eq(10000)
|
||||
expect(subject.fiat_amount).to eq(485)
|
||||
expect(subject.fiat_currency).to eq("EUR")
|
||||
end
|
||||
|
||||
it "redirects to the donations index" do
|
||||
expect(response).to redirect_to(contributions_donations_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "on-chain" do
|
||||
describe "waiting for confirmations" do
|
||||
subject do
|
||||
user.donations.create!(
|
||||
donation_method: "btcpay", btcpay_invoice_id: "K4e31MhbLKmr3D7qoNYRd3",
|
||||
fiat_amount: 120, fiat_currency: "USD", paid_at: nil
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
invoice = File.read("#{Rails.root}/spec/fixtures/btcpay/onchain_eur_processing_invoice.json")
|
||||
payments = File.read("#{Rails.root}/spec/fixtures/btcpay/onchain_eur_processing_payments.json")
|
||||
stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/invoices/K4e31MhbLKmr3D7qoNYRd3")
|
||||
.to_return(status: 200, headers: {}, body: invoice)
|
||||
stub_request(:get, "http://btcpay.example.com/api/v1/stores/123456/invoices/K4e31MhbLKmr3D7qoNYRd3/payment-methods")
|
||||
.to_return(status: 200, headers: {}, body: payments)
|
||||
|
||||
get confirm_btcpay_contributions_donation_path(subject)
|
||||
end
|
||||
|
||||
it "updates the donation record" do
|
||||
subject.reload
|
||||
expect(subject.paid_at).to be_nil
|
||||
expect(subject.amount_sats).to eq(191354)
|
||||
expect(subject.payment_status).to eq("processing")
|
||||
end
|
||||
|
||||
it "enqueues a job to periodically check the invoice status" do
|
||||
expect(enqueued_jobs.size).to eq(1)
|
||||
expect(enqueued_jobs.first["job_class"]).to eq("BtcpayCheckDonationJob")
|
||||
expect(enqueued_jobs.first['arguments'][0]["_aj_globalid"]).to eq("gid://akkounts/Donation/#{subject.id}")
|
||||
end
|
||||
|
||||
it "redirects to the donations index" do
|
||||
expect(response).to redirect_to(contributions_donations_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user