mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2026-01-03 06:04:24 +01:00
Importing hosted service that will register transactions on Shopify
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Services.Shopify
|
||||
{
|
||||
public class OrderTransactionRegisterLogic
|
||||
{
|
||||
private readonly ShopifyApiClient _client;
|
||||
|
||||
public OrderTransactionRegisterLogic(ShopifyApiClient client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public async Task<dynamic> Process(string orderId, string currency = null, string amountCaptured = null)
|
||||
{
|
||||
dynamic resp = await _client.TransactionsList(orderId);
|
||||
|
||||
JArray transactions = resp.transactions;
|
||||
if (transactions != null && transactions.Count >= 1)
|
||||
{
|
||||
dynamic transaction = transactions[0];
|
||||
|
||||
if (currency != null && currency.Equals(transaction.currency, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// 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 TransactionCreate
|
||||
{
|
||||
transaction = new TransactionCreate.DataHolder
|
||||
{
|
||||
parent_id = transaction.id,
|
||||
currency = transaction.currency,
|
||||
amount = amountCaptured ?? transaction.amount,
|
||||
kind = "capture",
|
||||
gateway = "BTCPayServer",
|
||||
source = "external"
|
||||
}
|
||||
};
|
||||
|
||||
dynamic createResp = await _client.TransactionCreate(orderId, createTransaction);
|
||||
return createResp;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Data;
|
||||
using BTCPayServer.Logging;
|
||||
using BTCPayServer.Services.Invoices;
|
||||
using BTCPayServer.Services.Stores;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer.Services.Shopify
|
||||
{
|
||||
public class ShopifyOrderMarkerHostedService : IHostedService
|
||||
{
|
||||
private readonly EventAggregator _eventAggregator;
|
||||
private readonly StoreRepository _storeRepository;
|
||||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
public ShopifyOrderMarkerHostedService(EventAggregator eventAggregator, StoreRepository storeRepository, IHttpClientFactory httpClientFactory)
|
||||
{
|
||||
_eventAggregator = eventAggregator;
|
||||
_storeRepository = storeRepository;
|
||||
_httpClientFactory = httpClientFactory;
|
||||
}
|
||||
|
||||
private CancellationTokenSource _Cts;
|
||||
private readonly CompositeDisposable leases = new CompositeDisposable();
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_Cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
|
||||
leases.Add(_eventAggregator.Subscribe<Events.InvoiceEvent>(async b =>
|
||||
{
|
||||
var invoice = b.Invoice;
|
||||
var shopifyOrderId = invoice.Metadata?.OrderId;
|
||||
if (invoice.Status == Client.Models.InvoiceStatus.Paid && shopifyOrderId != null)
|
||||
{
|
||||
var storeData = await _storeRepository.FindStore(invoice.StoreId);
|
||||
var storeBlob = storeData.GetStoreBlob();
|
||||
|
||||
if (storeBlob.Shopify?.IntegratedAt.HasValue == true)
|
||||
{
|
||||
var client = createShopifyApiClient(storeBlob.Shopify);
|
||||
|
||||
try
|
||||
{
|
||||
var logic = new OrderTransactionRegisterLogic(client);
|
||||
await logic.Process(shopifyOrderId, invoice.Currency, invoice.Price.ToString(CultureInfo.InvariantCulture));
|
||||
Logs.PayServer.LogInformation("Registered order transaction on Shopify. " +
|
||||
$"Triggered by invoiceId: {invoice.Id}, Shopify orderId: {shopifyOrderId}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logs.PayServer.LogError(ex, $"Shopify error while trying to register order transaction. " +
|
||||
$"Triggered by invoiceId: {invoice.Id}, Shopify orderId: {shopifyOrderId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private ShopifyApiClient createShopifyApiClient(StoreBlob.ShopifyDataHolder shopify)
|
||||
{
|
||||
return new ShopifyApiClient(_httpClientFactory, null, new ShopifyApiClientCredentials
|
||||
{
|
||||
ShopName = shopify.ShopName,
|
||||
ApiKey = shopify.ApiKey,
|
||||
ApiPassword = shopify.Password,
|
||||
SharedSecret = shopify.SharedSecret
|
||||
});
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_Cts?.Cancel();
|
||||
leases.Dispose();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user