From 5f2795d91161b36e4796a6facfde321da68330cb Mon Sep 17 00:00:00 2001 From: Joerg Lehmann Date: Mon, 12 Apr 2021 19:18:57 +0200 Subject: [PATCH] refactor payment process --- abocost.go | 40 +++++ main.go | 1 + persistence.go | 25 +++ static/js/chekout.js | 81 --------- static/js/scales.js | 385 +++++++++++++++++++++++-------------------- stripe.go | 18 +- 6 files changed, 285 insertions(+), 265 deletions(-) create mode 100644 abocost.go delete mode 100644 static/js/chekout.js diff --git a/abocost.go b/abocost.go new file mode 100644 index 0000000..88e8bab --- /dev/null +++ b/abocost.go @@ -0,0 +1,40 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" +) + +// abocost handler +func abocostHandler(response http.ResponseWriter, request *http.Request) { + body, err := ioutil.ReadAll(request.Body) + if err != nil { + panic(err) + } + log.Println(string(body)) + + var data map[string]int + err2 := json.Unmarshal([]byte(body), &data) + if err2 != nil { + log.Println("Error, invalid json: %v", err) + } + response.Header().Set("Content-Type", "text/json; charset=utf-8") + fmt.Fprintf(response, "{\n") + fmt.Fprintf(response, " \"stripe_pk\": \"%s\",\n", getStripePK()) + fmt.Fprintf(response, " \"data\": {\n") + first := true + for key, value := range data { + fmt.Println("Key:", key, "Value:", value) + if first { + first = false + } else { + fmt.Fprintf(response, " ,") + } + fmt.Fprintf(response, " \"%s\": [ %d, %d, \"%s\", \"%s\" ]\n", key, int(value), int(getYearlyAboCost(key)*int(value)), getActiveUntil(key), getDevAlias(key)) + } + fmt.Fprintf(response, " }\n") + fmt.Fprintf(response, "}\n") +} diff --git a/main.go b/main.go index a3ed6aa..251998d 100644 --- a/main.go +++ b/main.go @@ -94,6 +94,7 @@ func main() { http.HandleFunc("/logout", logoutHandler) http.HandleFunc("/confirm", confirmHandler) http.HandleFunc("/metrics", metricsHandler) + http.HandleFunc("/abocost", abocostHandler) http.HandleFunc("/lastmetrics", lastmetricsHandler) http.HandleFunc("/save_scale_settings", save_scale_settingsHandler) http.HandleFunc("/getstripepaymentintent", getstripepaymentintentHandler) diff --git a/persistence.go b/persistence.go index 1b82b80..d11b954 100644 --- a/persistence.go +++ b/persistence.go @@ -239,6 +239,31 @@ func getActiveUntil(deveui string) string { return res } +func getYearlyAboCost(deveui string) int { + res := 0 + + logit("getYearlyAboCost: Deveui: " + deveui) + + conn := globalPool.Get() + defer conn.Close() + + // first we get the default + yearlyAboCostDefault, err := redis.Int(conn.Do("HGET", "settings", "default_yearly_abo_cost")) + if err == nil { + yearlyAboCost, err := redis.Int(conn.Do("HGET", devPrefix+deveui, "yearly_abo_cost")) + if err == nil { + res = yearlyAboCost + } else { + res = yearlyAboCostDefault + } + } else { + log.Print(err) + + } + + return res +} + func AboExpired(deveui string) bool { active_until := getActiveUntil(deveui) diff --git a/static/js/chekout.js b/static/js/chekout.js deleted file mode 100644 index af9d3ef..0000000 --- a/static/js/chekout.js +++ /dev/null @@ -1,81 +0,0 @@ -// Set your publishable key: remember to change this to your live publishable key in production -// See your keys here: https://dashboard.stripe.com/account/apikeys -var stripe = Stripe('pk_test_YkSGqH3Tk9WKK9HrlY63GhAg'); -var elements = stripe.elements(); - -// Set up Stripe.js and Elements to use in checkout form -var style = { - base: { - color: "#32325d", - } -}; - -var card = elements.create("card", { style: style }); -card.mount("#card-element"); - - -card.addEventListener('change', ({error}) => { - const displayError = document.getElementById('card-errors'); - if (error) { - displayError.textContent = error.message; - } else { - displayError.textContent = ''; - } -}); - - -var submitButton = document.getElementById('submit'); - -function GetClientSecret() { - var result = ""; - $.ajax({ - async: false, - url: "getstripepaymentintent", - type: "get", //send it through get method - dataType: "json", - data: { - charge_data: $("#charge_data").html() - }, - success: function(response) { - console.log('pay success'); - console.log(response.stripesessionid); - console.log('rc: '+response.rc); - if (response.rc == 0) { - result = response.stripeclientsecret; - } - }, - error: function(xhr) { - console.log('getstripepaymentintent error'); - //Do Something to handle error - } - }); - - return result; -} - -submitButton.addEventListener('click', function(ev) { - var clientSecret = GetClientSecret(); - stripe.confirmCardPayment(clientSecret, { - payment_method: { - card: card, - billing_details: { - name: 'Jenny Rosen' - } - } - }).then(function(result) { - if (result.error) { - // Show error to your customer (e.g., insufficient funds) - console.log(result.error.message); - } else { - // The payment has been processed! - if (result.paymentIntent.status === 'succeeded') { - // Show a success message to your customer - // There's a risk of the customer closing the window before callback - // execution. Set up a webhook or plugin to listen for the - // payment_intent.succeeded event that handles any business critical - // post-payment actions. - alert("Payment succeeded!!!"); - } - } - }); -}); diff --git a/static/js/scales.js b/static/js/scales.js index eee8894..cc10dca 100644 --- a/static/js/scales.js +++ b/static/js/scales.js @@ -1,3 +1,7 @@ +// dictionary: deveui as key, count as value +var abos_to_buy = {} +var stripe_pk = ""; + function validate(what, text) { if (what == 'alias') { var re = /^[a-zA-Z0-9 ]{1,25}$/; @@ -7,186 +11,213 @@ function validate(what, text) { return re.test(text); } -// A $( document ).ready() block. -$( document ).ready(function() { -$(".show-modal").click(function() { - $("#alias_exclamation").hide(); - $("#smsnumber_exclamation").hide(); - var alias = $(this).prev().html(); - var deveui = $(this).prev().attr('id').replace("alias_",""); - $('#deveui').html(deveui); - var alarmactive = $('#alarmactive_'+deveui).html(); - var smsnumber = $('#smsnumber_'+deveui).html(); - - $("#alias").val(alias); - console.log(alarmactive); - if (alarmactive == "1") { - $('#checkbox').prop('checked', true); - } else { - $('#checkbox').prop('checked', false); - } - $("#smsnumber").val(smsnumber); - $("#modal").addClass("is-active"); -}); +function HandleAbocostResponse(data) { + var ordered = Object.keys(data).sort().reduce( + (obj, key) => { + obj[key] = data[key]; + return obj; + }, + {} + ); -$("#cart-close").click(function() { - $("#cart").removeClass("is-active"); -}); - -$("#payment_notifier_close").click(function() { - $("#payment_notifier").removeClass("is-active"); - location.reload(true); -}); - -$(".abo_plus").click(function() { - console.log("abo_plus"); - el = $(this).parent().find(".abo_add_years"); - el_text = $(this).parent().parent().find(".abo_add_years_text"); - counter = Number(el.html()); - if (counter < 3) { - counter = counter + 1; - el.html(counter); - if (counter == 1) { - el_text.html("+" + counter + " Jahr"); - } else { - el_text.html("+" + counter + " Jahre"); - } - } -}); - -$(".abo_minus").click(function() { - console.log("abo_minus"); - el = $(this).parent().find(".abo_add_years"); - el_text = $(this).parent().parent().find(".abo_add_years_text"); - counter = Number(el.html()); - if (counter > 0) { - counter = counter - 1; - el.html(counter); - if (counter == 0) { - el_text.html(" "); - } else if (counter == 1) { - el_text.html("+" + counter + " Jahr"); - } else { - el_text.html("+" + counter + " Jahre"); - } - } -}); - -function add_years(dt,n) -{ - return new Date(dt.setFullYear(dt.getFullYear() + n)); + counter = 0; + total_amount = 0; + charge_data = ''; + abo_table = ''; + abo_table += ''; + jQuery.each(ordered, function (index, val) { + counter += 1; + abo_table += ''; + total_amount += (val[1] / 100); + if (charge_data == '') { + charge_data = index + ":" + val[0] + ":" + val[1]; + } else { + charge_data += "," + index + ":" + val[0] + ":" + val[1]; + } + }); + abo_table += ''; + abo_table += "
Aliasverlängern bisBetrag
' + val[3] + '' + moment(val[2], 'DD.MM.YYYY').add(val[0], 'years').format('DD.MM.YYYY') + '' + (val[1] / 100).toFixed(2) + '
Total CHF' + (total_amount).toFixed(2) + '
"; + if (counter > 0) { + $("#abos_verlaengern").html(abo_table); + $("#charge_data").html(charge_data); + $("#cart").addClass("is-active"); + } } -$(".abo_pay").click(function() { - console.log("pay..."); - loadStripeLibrary(); - counter = 0; - charge_data = ''; - abo_table = ''; - abo_table += ''; - $(".waage").each(function( index ) { - console.log( index + ": " + $( this ).find(".alias").html() ); - this_count = Number($( this ).find(".abo_add_years").html()); - if (this_count > 0) { - counter += this_count; - paid_until = $( this ).find(".paid_until").html(); - if (moment(paid_until,'DD.MM.YYYY') < moment()) { - this_date = moment().format('DD.MM.YYYY'); - } else { - this_date = paid_until; - } - abo_table += ''; - if (charge_data == '') { - charge_data = $( this ).find("div").first().attr('id') + ":" + this_count; - } else { - charge_data += "," + $( this ).find("div").first().attr('id') + ":" + this_count; - } +$( document ).ready(function() { + abos_to_buy = {}; + + $(".show-modal").click(function() { + $("#alias_exclamation").hide(); + $("#smsnumber_exclamation").hide(); + var alias = $(this).prev().html(); + var deveui = $(this).prev().attr('id').replace("alias_",""); + $('#deveui').html(deveui); + var alarmactive = $('#alarmactive_'+deveui).html(); + var smsnumber = $('#smsnumber_'+deveui).html(); + + $("#alias").val(alias); + console.log(alarmactive); + if (alarmactive == "1") { + $('#checkbox').prop('checked', true); + } else { + $('#checkbox').prop('checked', false); } - console.log( counter ); + $("#smsnumber").val(smsnumber); + $("#modal").addClass("is-active"); }); - abo_table += ''; - console.log("Counter: "+counter); - abo_table += "
Aliasverlängern bisBetrag
' + $( this ).find('.alias').html() + '' + moment(this_date,'DD.MM.YYYY').add('years', this_count).format('DD.MM.YYYY') + '' + (this_count * 24).toFixed(2) + '
Total CHF' + (counter * 24).toFixed(2) + '
"; - if (counter > 0) { - console.log(abo_table); - console.log("charge_data: "+charge_data); - $("#abos_verlaengern").html(abo_table); - $("#charge_data").html(charge_data); - $("#cart").addClass("is-active"); - } -}); -$("#modal-close").click(function() { - console.log("blabla"); - $("#modal").removeClass("is-active"); -}); + $("#cart-close").click(function() { + $("#cart").removeClass("is-active"); + }); -$("#modal-save").click(function() { - var alarmactive = "0"; - if ($('#checkbox').prop('checked')) { - alarmactive = "1"; - } + $("#payment_notifier_close").click(function() { + $("#payment_notifier").removeClass("is-active"); + location.reload(true); + }); - // Validation Code - var is_valid = true; - if (!validate('alias',$('#alias').val())) { - $('#alias_errormsg').html('Ungültige Bezeichnung; erlaubte Zeichen A-Z, 0-9 und Leerschlag'); - $("#alias").addClass("is-danger"); - $("#alias_exclamation").show(); - is_valid = false; - } else { - $('#alias_errormsg').html(''); - $("#alias").removeClass("is-danger"); - $("#alias_exclamation").hide(); - } - - if (!validate('smsnumber',$('#smsnumber').val())) { - $('#smsnumber_errormsg').html('Beispiel einer gültigen SMS Nummer: +41761234567'); - $("#smsnumber").addClass("is-danger"); - $("#smsnumber_exclamation").show(); - is_valid = false; - } else { - $('#smsnumber_errormsg').html(''); - $("#smsnumber").removeClass("is-danger"); - $("#smsnumber_exclamation").hide(); - } - - if (!(is_valid)) { - return; - } - - $.ajax({ - url: "save_scale_settings", - type: "get", //send it through get method - dataType: "json", - data: { - deveui: $('#deveui').html(), - alias: $('#alias').val(), - smsnumber: $("#smsnumber").val(), - alarmactive: alarmactive - }, - success: function(response) { - console.log('save success'); - if (response.rc == 0) { - $('#alias_'+$('#deveui').html()).html($('#alias').val()); - var alarmactive = "0"; - if ($('#checkbox').prop('checked')) { - alarmactive = "1"; - } - $('#alarmactive_'+$('#deveui').html()).html(alarmactive); - $('#smsnumber_'+$('#deveui').html()).html($('#smsnumber').val()); + $(".abo_plus").click(function () { + var deveui = $(this).prev().attr('id').replace("abo_add_years_", ""); + el = $(this).parent().find(".abo_add_years"); + el_text = $(this).parent().parent().find(".abo_add_years_text"); + counter = Number(el.html()); + if (counter < 3) { + counter = counter + 1; + if (deveui in abos_to_buy) { + abos_to_buy[deveui] += 1; + } else { + abos_to_buy[deveui] = 1; + } + el.html(counter); + if (counter == 1) { + el_text.html("+" + counter + " Jahr"); + } else { + el_text.html("+" + counter + " Jahre"); } - }, - error: function(xhr) { - console.log('save error'); - //Do Something to handle error } }); - console.log("save"); - $("#modal").removeClass("is-active"); -}); + $(".abo_minus").click(function () { + var deveui = $(this).prev().attr('id').replace("abo_", ""); + el = $(this).parent().find(".abo_add_years"); + el_text = $(this).parent().parent().find(".abo_add_years_text"); + counter = Number(el.html()); + if (counter > 0) { + counter = counter - 1; + el.html(counter); + if (deveui in abos_to_buy) { + abos_to_buy[deveui] -= 1; + if (abos_to_buy[deveui] == 0) { + delete abos_to_buy[deveui]; + } + } + if (counter == 0) { + el_text.html(" "); + } else if (counter == 1) { + el_text.html("+" + counter + " Jahr"); + } else { + el_text.html("+" + counter + " Jahre"); + } + } + }); + function add_years(dt, n) { + return new Date(dt.setFullYear(dt.getFullYear() + n)); + } + + $(".abo_pay").click(function () { + if (Object.keys(abos_to_buy).length < 1) { + return; + } + + $.ajax({ + url: "abocost", + type: "POST", //send it through post method + dataType: "json", + data: JSON.stringify(abos_to_buy), + success: function(response) { + if (stripe_pk == "") { + stripe_pk = response['stripe_pk']; + loadStripeLibrary(); + } + HandleAbocostResponse(response['data']); + }, + error: function(xhr) { + } + }); + + }); + + $("#modal-close").click(function () { + $("#modal").removeClass("is-active"); + }); + + + $("#modal-save").click(function() { + var alarmactive = "0"; + if ($('#checkbox').prop('checked')) { + alarmactive = "1"; + } + + // Validation Code + var is_valid = true; + if (!validate('alias',$('#alias').val())) { + $('#alias_errormsg').html('Ungültige Bezeichnung; erlaubte Zeichen A-Z, 0-9 und Leerschlag'); + $("#alias").addClass("is-danger"); + $("#alias_exclamation").show(); + is_valid = false; + } else { + $('#alias_errormsg').html(''); + $("#alias").removeClass("is-danger"); + $("#alias_exclamation").hide(); + } + + if (!validate('smsnumber',$('#smsnumber').val())) { + $('#smsnumber_errormsg').html('Beispiel einer gültigen SMS Nummer: +41761234567'); + $("#smsnumber").addClass("is-danger"); + $("#smsnumber_exclamation").show(); + is_valid = false; + } else { + $('#smsnumber_errormsg').html(''); + $("#smsnumber").removeClass("is-danger"); + $("#smsnumber_exclamation").hide(); + } + + if (!(is_valid)) { + return; + } + + $.ajax({ + url: "save_scale_settings", + type: "get", //send it through get method + dataType: "json", + data: { + deveui: $('#deveui').html(), + alias: $('#alias').val(), + smsnumber: $("#smsnumber").val(), + alarmactive: alarmactive + }, + success: function(response) { + console.log('save success'); + if (response.rc == 0) { + $('#alias_'+$('#deveui').html()).html($('#alias').val()); + var alarmactive = "0"; + if ($('#checkbox').prop('checked')) { + alarmactive = "1"; + } + $('#alarmactive_'+$('#deveui').html()).html(alarmactive); + $('#smsnumber_'+$('#deveui').html()).html($('#smsnumber').val()); + } + }, + error: function(xhr) { + console.log('save error'); + //Do Something to handle error + } + }); + + console.log("save"); + $("#modal").removeClass("is-active"); + }); }); function loadStripeLibrary() { @@ -206,24 +237,23 @@ function loadStripeLibrary() { } function SetupStripe() { - console.log("SetupStripe"); // Set your publishable key: remember to change this to your live publishable key in production // See your keys here: https://dashboard.stripe.com/account/apikeys - stripe = Stripe('pk_test_YkSGqH3Tk9WKK9HrlY63GhAg'); + stripe = Stripe(stripe_pk); elements = stripe.elements({ locale: "de" }); - + // Set up Stripe.js and Elements to use in checkout form style = { base: { color: "#32325d", } }; - + card = elements.create("card", { style: style }); card.mount("#card-element"); $("#card-errors-article").hide(); - - card.addEventListener('change', ({error}) => { + + card.addEventListener('change', ({ error }) => { if (error) { $("#card-errors").text(error.message); $("#card-errors-article").show(); @@ -284,18 +314,15 @@ function PayMe() { url: "getstripepaymentintent", type: "get", //send it through get method dataType: "json", - data: { + data: { charge_data: $("#charge_data").html() }, - success: function(response) { - console.log('pay success'); - console.log('rc: '+response.rc); + success: function (response) { if (response.rc == 0) { ConfirmPayment(response.stripeclientsecret); } }, - error: function(xhr) { - console.log('getstripepaymentintent error'); + error: function (xhr) { //Do Something to handle error EndPaymentProgress(); } diff --git a/stripe.go b/stripe.go index 674fe73..eb655cb 100644 --- a/stripe.go +++ b/stripe.go @@ -14,7 +14,11 @@ import ( ) func getStripeKey() string { - return "sk_test_GJbXPD0IAFNvvGpNEpaeDfhl" + return os.Getenv("STRIPE_KEY") +} + +func getStripePK() string { + return os.Getenv("STRIPE_PK") } func getstripepaymentintentHandler(response http.ResponseWriter, request *http.Request) { @@ -32,16 +36,18 @@ func getstripepaymentintentHandler(response http.ResponseWriter, request *http.R var abo_years = 0 var items []string + amount := 0 for _, scale := range scales { items = strings.Split(scale, ":") - if len(items) == 2 { + if len(items) >= 2 { abo_count, err := strconv.Atoi(items[1]) if err == nil { abo_years += abo_count + amount += (abo_count * getYearlyAboCost(items[0])) } } } - abo_amount := int64(abo_years * 2400) + abo_amount := int64(amount) stripe.Key = getStripeKey() @@ -51,6 +57,7 @@ func getstripepaymentintentHandler(response http.ResponseWriter, request *http.R ReceiptEmail: stripe.String(name), } params.AddMetadata("charge_data", charge_data[0]) + params.AddMetadata("login_user", name) paymentintent, err := paymentintent.New(params) if err != nil { @@ -70,12 +77,13 @@ func HandlePayment(user string, charge_data string, amount int64) { charge_data_email_text = charge_data_email_text + strings.Repeat("-", 62) + "\n" for _, token := range strings.Split(charge_data, ",") { res := strings.Split(token, ":") - if (len(res)) == 2 { + if (len(res)) == 3 { deveui := res[0] years, _ := strconv.Atoi(res[1]) + amount, _ := strconv.Atoi(res[2]) fmt.Printf("prolongActivation %s: %d\n", deveui, years) prolongActivation(deveui, years) - line := fmt.Sprintf("%-30s %20s %10.2f\n", getDevAlias(deveui), getActiveUntil(deveui), float64(24*years)) + line := fmt.Sprintf("%-30s %20s %10.2f\n", getDevAlias(deveui), getActiveUntil(deveui), float64(amount/100)) charge_data_email_text = charge_data_email_text + line } }