From 30bdfeee37b9164cec322aca8805ffaed954cdf6 Mon Sep 17 00:00:00 2001 From: Andrew Camilleri Date: Sat, 26 Jan 2019 05:26:49 +0100 Subject: [PATCH] Enhance PosData Viewer & add cart to posdata in POS app (#559) --- BTCPayServer.Tests/UnitTest1.cs | 40 +++++++++---------- .../Controllers/AppsPublicController.cs | 13 ++++-- .../Controllers/InvoiceController.UI.cs | 15 +++++-- .../InvoicingModels/InvoiceDetailsModel.cs | 2 +- .../Views/AppsPublic/ViewPointOfSale.cshtml | 1 + BTCPayServer/Views/Invoice/Invoice.cshtml | 19 +-------- BTCPayServer/Views/Invoice/PosData.cshtml | 37 +++++++++++++++++ BTCPayServer/wwwroot/cart/js/cart.js | 19 ++++++++- 8 files changed, 96 insertions(+), 50 deletions(-) create mode 100644 BTCPayServer/Views/Invoice/PosData.cshtml diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index 4853ea32c..3122ed643 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -1629,18 +1629,16 @@ donation: public void PosDataParser_ParsesCorrectly() { var testCases = - new List<(string input, Dictionary expectedOutput)>() + new List<(string input, Dictionary expectedOutput)>() { - { (null, new Dictionary())}, - {("", new Dictionary())}, - {("{}", new Dictionary())}, - {("non-json-content", new Dictionary(){ {string.Empty, "non-json-content"}})}, - {("[1,2,3]", new Dictionary(){ {string.Empty, "[1,2,3]"}})}, - {("{ \"key\": \"value\"}", new Dictionary(){ {"key", "value"}})}, - {("{ \"key\": true}", new Dictionary(){ {"key", "True"}})}, - {("{ \"key\": \"value\", \"key2\": [\"value\", \"value2\"]}", - new Dictionary(){ {"key", "value"}, {"key2", "value,value2"}})}, - {("{ invalidjson file here}", new Dictionary(){ {String.Empty, "{ invalidjson file here}"}})} + { (null, new Dictionary())}, + {("", new Dictionary())}, + {("{}", new Dictionary())}, + {("non-json-content", new Dictionary(){ {string.Empty, "non-json-content"}})}, + {("[1,2,3]", new Dictionary(){ {string.Empty, "[1,2,3]"}})}, + {("{ \"key\": \"value\"}", new Dictionary(){ {"key", "value"}})}, + {("{ \"key\": true}", new Dictionary(){ {"key", "True"}})}, + {("{ invalidjson file here}", new Dictionary(){ {String.Empty, "{ invalidjson file here}"}})} }; testCases.ForEach(tuple => @@ -1663,18 +1661,16 @@ donation: var controller = tester.PayTester.GetController(null); var testCases = - new List<(string input, Dictionary expectedOutput)>() + new List<(string input, Dictionary expectedOutput)>() { - { (null, new Dictionary())}, - {("", new Dictionary())}, - {("{}", new Dictionary())}, - {("non-json-content", new Dictionary(){ {string.Empty, "non-json-content"}})}, - {("[1,2,3]", new Dictionary(){ {string.Empty, "[1,2,3]"}})}, - {("{ \"key\": \"value\"}", new Dictionary(){ {"key", "value"}})}, - {("{ \"key\": true}", new Dictionary(){ {"key", "True"}})}, - {("{ \"key\": \"value\", \"key2\": [\"value\", \"value2\"]}", - new Dictionary(){ {"key", "value"}, {"key2", "value,value2"}})}, - {("{ invalidjson file here}", new Dictionary(){ {String.Empty, "{ invalidjson file here}"}})} + { (null, new Dictionary())}, + {("", new Dictionary())}, + {("{}", new Dictionary())}, + {("non-json-content", new Dictionary(){ {string.Empty, "non-json-content"}})}, + {("[1,2,3]", new Dictionary(){ {string.Empty, "[1,2,3]"}})}, + {("{ \"key\": \"value\"}", new Dictionary(){ {"key", "value"}})}, + {("{ \"key\": true}", new Dictionary(){ {"key", "True"}})}, + {("{ invalidjson file here}", new Dictionary(){ {String.Empty, "{ invalidjson file here}"}})} }; var tasks = new List(); diff --git a/BTCPayServer/Controllers/AppsPublicController.cs b/BTCPayServer/Controllers/AppsPublicController.cs index 10067e021..8c0b706a0 100644 --- a/BTCPayServer/Controllers/AppsPublicController.cs +++ b/BTCPayServer/Controllers/AppsPublicController.cs @@ -25,6 +25,7 @@ using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using NBitpayClient; +using Newtonsoft.Json.Linq; using YamlDotNet.RepresentationModel; using static BTCPayServer.Controllers.AppsController; @@ -155,10 +156,11 @@ namespace BTCPayServer.Controllers var store = await _AppsHelper.GetStore(app); var title = settings.Title; var price = request.Amount; + ViewPointOfSaleViewModel.Item choice = null; if (!string.IsNullOrEmpty(request.ChoiceKey)) { var choices = _AppsHelper.Parse(settings.PerksTemplate, settings.TargetCurrency); - var choice = choices.FirstOrDefault(c => c.Id == request.ChoiceKey); + choice = choices.FirstOrDefault(c => c.Id == request.ChoiceKey); if (choice == null) return NotFound("Incorrect option provided"); title = choice.Title; @@ -211,7 +213,8 @@ namespace BTCPayServer.Controllers string orderId, string notificationUrl, string redirectUrl, - string choiceKey) + string choiceKey, + string posData = null) { var app = await _AppsHelper.GetApp(appId, AppType.PointOfSale); if (string.IsNullOrEmpty(choiceKey) && amount <= 0) @@ -227,10 +230,11 @@ namespace BTCPayServer.Controllers } string title = null; var price = 0.0m; + ViewPointOfSaleViewModel.Item choice = null; if (!string.IsNullOrEmpty(choiceKey)) { var choices = _AppsHelper.Parse(settings.Template, settings.Currency); - var choice = choices.FirstOrDefault(c => c.Id == choiceKey); + choice = choices.FirstOrDefault(c => c.Id == choiceKey); if (choice == null) return NotFound(); title = choice.Title; @@ -249,7 +253,7 @@ namespace BTCPayServer.Controllers store.AdditionalClaims.Add(new Claim(Policies.CanCreateInvoice.Key, store.Id)); var invoice = await _InvoiceController.CreateInvoiceCore(new NBitpayClient.Invoice() { - ItemCode = choiceKey ?? string.Empty, + ItemCode = choice?.Id, ItemDesc = title, Currency = settings.Currency, Price = price, @@ -258,6 +262,7 @@ namespace BTCPayServer.Controllers NotificationURL = notificationUrl, RedirectURL = redirectUrl ?? Request.GetDisplayUrl(), FullNotifications = true, + PosData = string.IsNullOrEmpty(posData) ? null : posData }, store, HttpContext.Request.GetAbsoluteRoot()); return RedirectToAction(nameof(InvoiceController.Checkout), "Invoice", new { invoiceId = invoice.Data.Id }); } diff --git a/BTCPayServer/Controllers/InvoiceController.UI.cs b/BTCPayServer/Controllers/InvoiceController.UI.cs index e94cdabe3..95ec84f9d 100644 --- a/BTCPayServer/Controllers/InvoiceController.UI.cs +++ b/BTCPayServer/Controllers/InvoiceController.UI.cs @@ -21,6 +21,7 @@ using BTCPayServer.Services.Invoices.Export; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.EntityFrameworkCore.Internal; using NBitcoin; using NBitpayClient; using NBXplorer; @@ -679,9 +680,9 @@ namespace BTCPayServer.Controllers public class PosDataParser { - public static Dictionary ParsePosData(string posData) + public static Dictionary ParsePosData(string posData) { - var result = new Dictionary(); + var result = new Dictionary(); if (string.IsNullOrEmpty(posData)) { return result; @@ -689,7 +690,6 @@ namespace BTCPayServer.Controllers try { - var jObject =JObject.Parse(posData); foreach (var item in jObject) { @@ -697,7 +697,14 @@ namespace BTCPayServer.Controllers switch (item.Value.Type) { case JTokenType.Array: - result.Add(item.Key, string.Join(',', item.Value.AsEnumerable())); + var items = item.Value.AsEnumerable().ToList(); + for (var i = 0; i < items.Count(); i++) + { + result.Add($"{item.Key}[{i}]", ParsePosData(items[i].ToString())); + } + break; + case JTokenType.Object: + result.Add(item.Key, ParsePosData(item.Value.ToString())); break; default: result.Add(item.Key, item.Value.ToString()); diff --git a/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs b/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs index be04b907b..081141b51 100644 --- a/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs +++ b/BTCPayServer/Models/InvoicingModels/InvoiceDetailsModel.cs @@ -143,6 +143,6 @@ namespace BTCPayServer.Models.InvoicingModels public DateTimeOffset MonitoringDate { get; internal set; } public List Events { get; internal set; } public string NotificationEmail { get; internal set; } - public Dictionary PosData { get; set; } + public Dictionary PosData { get; set; } } } diff --git a/BTCPayServer/Views/AppsPublic/ViewPointOfSale.cshtml b/BTCPayServer/Views/AppsPublic/ViewPointOfSale.cshtml index 52e3c41c5..3118a4d8d 100644 --- a/BTCPayServer/Views/AppsPublic/ViewPointOfSale.cshtml +++ b/BTCPayServer/Views/AppsPublic/ViewPointOfSale.cshtml @@ -194,6 +194,7 @@ diff --git a/BTCPayServer/Views/Invoice/Invoice.cshtml b/BTCPayServer/Views/Invoice/Invoice.cshtml index 03fed5d38..72605ca39 100644 --- a/BTCPayServer/Views/Invoice/Invoice.cshtml +++ b/BTCPayServer/Views/Invoice/Invoice.cshtml @@ -192,24 +192,7 @@

Point of Sale Data

- - @foreach (var posDataItem in Model.PosData) - { - - @if (!string.IsNullOrEmpty(posDataItem.Key)) - { - - - - } - else - { - - - } - - } -
@posDataItem.Key@posDataItem.Value@posDataItem.Value
+
} diff --git a/BTCPayServer/Views/Invoice/PosData.cshtml b/BTCPayServer/Views/Invoice/PosData.cshtml new file mode 100644 index 000000000..1fe398ebd --- /dev/null +++ b/BTCPayServer/Views/Invoice/PosData.cshtml @@ -0,0 +1,37 @@ +@model Dictionary + + + @foreach (var posDataItem in Model) + { + + @if (!string.IsNullOrEmpty(posDataItem.Key)) + { + + + } + else + { + + } + + } +
@posDataItem.Key + @if (posDataItem.Value is string) + { + @posDataItem.Value + } + else + { + + } + + + @if (posDataItem.Value is string) + { + @posDataItem.Value + } + else + { + + } +
diff --git a/BTCPayServer/wwwroot/cart/js/cart.js b/BTCPayServer/wwwroot/cart/js/cart.js index ca0bd8fcb..a748ddf3a 100644 --- a/BTCPayServer/wwwroot/cart/js/cart.js +++ b/BTCPayServer/wwwroot/cart/js/cart.js @@ -21,6 +21,7 @@ function Cart() { this.updateItemsCount(); this.updateAmount(); + this.updatePosData(); } Cart.prototype.setCustomAmount = function(amount) { @@ -243,6 +244,7 @@ Cart.prototype.updateAll = function() { this.updateSummaryTotal(); this.updateTotal(); this.updateAmount(); + this.updatePosData(); } // Update number of cart items @@ -290,6 +292,20 @@ Cart.prototype.updateTip = function(amount) { Cart.prototype.updateAmount = function() { $('#js-cart-amount').val(this.getTotal(true)); } +Cart.prototype.updatePosData = function() { + + var result = { + cart: this.content, + customAmount: this.fromCents(this.getCustomAmount()), + discountPercentage: this.discount? parseFloat(this.discount): 0, + subTotal: this.fromCents(this.getTotalProducts()), + discountAmount: this.fromCents(this.getDiscountAmount(this.totalAmount)), + tip: this.tip? this.tip: 0, + total: this.getTotal(true) + }; + console.warn(result); + $('#js-cart-posdata').val(JSON.stringify(result)); +} Cart.prototype.resetDiscount = function() { this.setDiscount(0); @@ -644,6 +660,7 @@ $.fn.inputAmount = function(obj, type) { obj.updateSummaryTotal(); obj.updateAmount(); + obj.updatePosData(); obj.emptyCartToggle(); }); } @@ -668,4 +685,4 @@ $.fn.removeAmount = function(obj, type) { obj.updateSummaryTotal(); obj.emptyCartToggle(); }); -} \ No newline at end of file +}