Help With JSON formatting

Post

Posted
Rating:
#1 (In Topic #886)
Enthusiast
AndyGable is in the usergroup ‘Enthusiast’
Hi Everyone

I need some help on the following

I am sending the following JSON to a web API that i use in Windows

Code

Dim jsonString As String = "\{""transactionType"":""SALE"",""amount"":""" & transAmount & """,""currency"":""GBP""}"

and in Windows this works fine but in Gambas none of the extra " are sent so I receive back from the API "Invalid JSON Received"

could someone show me how I can send the JSON to the API correctly

this is the code I am using to send to the API

Code

Dim hClient As HttpClient
    Dim sBuffer As String

    Dim jsonString As String = "\{" "transactionType" ":" "SALE" "," "amount" ":" "" & transAmount & "" "," "currency" ":" "GBP" "}"

   message(JSON.Encode(jsonString))
   
    hClient = New HttpClient As "hClient"

    With hClient
        .URL = global.PS_URL & "/terminals/" & global.terminalIDNumber & "/transactions"
        .Auth = 1
        .User = Global.PS_USER
        .Password = Global.PS_PASS
       ' .Headers.Add("Software-House-ID :SD45T92")
       ' .Headers.Add("Installer-Id: " & Global.InstallerID)
        .Async = False
        .Timeout = 60
        .Post("application/connect.v2+json", JSON.Encode(jsonString))
    End With

    global.showResult("POST", hClient)

as yes as you can all see i am still struggling to work out how to send the extra 2 Headers to the API as well (i need to send them so the API would work at 100% service)
Online now: No Back to the top

Post

Posted
Rating:
#2
Avatar
Enthusiast
PJBlack is in the usergroup ‘Enthusiast’
escape the quotation mark with \

string = " <COLOR color="#FF0000">"</COLOR>this should work <COLOR color="#FF0000">"</COLOR>"
Online now: No Back to the top

Post

Posted
Rating:
#3
Enthusiast
AndyGable is in the usergroup ‘Enthusiast’

PJBlack said

escape the quotation mark with \

string = " <COLOR color="#FF0000">"</COLOR>this should work <COLOR color="#FF0000">"</COLOR>"

    Dim jsonString As String = "{" "transactionType" ":" "SALE" ",""amount" ":" "" & transAmount & "" "," "currency" ":" "GBP" "}"

Something like that?
Online now: No Back to the top

Post

Posted
Rating:
#4
Avatar
Enthusiast
PJBlack is in the usergroup ‘Enthusiast’
don't know your json but if you like to have a quotation mark inside a string you have to escape it with a backslash …

OR

something like so:

Code (gambas)

  1. string = "first part" & chr(34) & "second part"

will result in: firstpart"second part
Online now: No Back to the top

Post

Posted
Rating:
#5
Enthusiast
AndyGable is in the usergroup ‘Enthusiast’
 Thanks PJBlack

I shall try that and let you know what the status message is from the cloud server
Online now: No Back to the top

Post

Posted
Rating:
#6
Enthusiast
AndyGable is in the usergroup ‘Enthusiast’
Hi Everyone

I have tired the corrections as you all said and I am still getting a Error from the API

I have even tried this bit of code

Code

 Dim hClient As HttpClient
    Dim sBuffer As String
'   Dim jsonString As String = "\{""transactionType"":""SALE"",""amount"":""" & transAmount  & """,""currency"":""GBP""}"
    Dim jsonString As String = "\{¬¬transactionType¬¬:¬¬SALE¬¬,¬¬amount¬¬:¬¬" & transAmount & "¬¬¬,¬¬currency¬¬:¬¬GBP¬¬}"
    
    jsonString = Replace(jsonString, "¬", Chr(34))
    
    message(JSON.Encode(jsonString))
   
    hClient = New HttpClient As "hClient"

    With hClient
        .URL = global.PS_URL & "/terminals/" & global.terminalIDNumber & "/transactions"
        .Auth = 1
        .User = Global.PS_USER
        .Password = Global.PS_PASS
       ' .Headers.Add("Software-House-ID :SD45T92")
       ' .Headers.Add("Installer-Id: " & Global.InstallerID)
        .Async = False
        .Timeout = 60
        .Post("application/connect.v2+json", JSON.Encode(jsonString))
    End With

    global.showResult("POST", hClient)

as you can see I replaced every " with a ¬ with in the string formation and then did a replace function at the end to get the format correct

This is what I am getting on the message box

Code

"\{\" \"transactionType\" \":\" \"SALE\" \",\" \"amount\" \":\" \"\"153\"\"\",\" \"currency\" \":\" \"GBP\" \"}"

But I am still getting a Error from the card Server API I get in my list box

{"messages":{"error":["Invalid JSON received."]}}

so I am completely stumped as to what to try now I have even asked the Card Service providers as to what they are getting their end but I have not had a replay back yet.

Does anyone know what I have done wrong?
Online now: No Back to the top

Post

Posted
Rating:
#7
Avatar
Enthusiast
GrayGhost is in the usergroup ‘Enthusiast’
 I know nothing about what your are doing  

Do you want the 153 to be double quoted ? and there are spaces between each element except the 153 and the comma following it has no space.

If it does require double quotes …. does it need spaces between the quotes ?
Online now: No Back to the top

Post

Posted
Rating:
#8
Avatar
Enthusiast
PJBlack is in the usergroup ‘Enthusiast’
try this one :

Code (gambas)

  1. Dim jsonString As String = "\{\"transactionType\":\"SALE\",\"amount\":\"" & transAmount & \"",\"currency\":\"GBP\"}"
Online now: No Back to the top

Post

Posted
Rating:
#9
Enthusiast
AndyGable is in the usergroup ‘Enthusiast’
 hi PJBlack

I am getting Unexpected "" and it is flashing next to the & \ just after the amount

so it is showing   transAmount & \ "", it is the \ i am getting the error on

Sorry if I am not any help I am still figuring this out as I go along.
Online now: No Back to the top

Post

Posted
Rating:
#10
Avatar
Enthusiast
GrayGhost is in the usergroup ‘Enthusiast’
Try this :  

Code (gambas)

  1.   Dim transAmount As String = "2345.45"
  2.   Dim TraType As String = "SALE"
  3.    Dim jsonString As String = "\{\"transactionType\":" & Quote(TraType) & ",\"amount\":" & Quote(transAmount) & ",\"currency\":\"GBP\"}"
  4.  
  5.  
It produces this:
{"transactionType":"SALE","amount":"2345.45","currency":"GBP"}
Online now: No Back to the top

Post

Posted
Rating:
#11
Enthusiast
AndyGable is in the usergroup ‘Enthusiast’
hi Grayghost4

Thank you for your example It worked

Thank-you

Now i just need to get status again :)
Online now: No Back to the top

Post

Posted
Rating:
#12
Enthusiast
AndyGable is in the usergroup ‘Enthusiast’
hi Everyone

so I have this working now (the JSON is being sent to the server with no errors) but when I get the data back from the Server it is in the following format

Code

\{"location":"https://test.connect.paymentsense.cloud/pac/terminals/12345678/transactions/661c943f","notifications":["TRANSACTION_STARTED"]}

Ivbe tried to use this

Code

If http.Status < 0 Then
        Global.addtoStatusList("SORRY A Error was detected")
        global.AddToDebugList(http.ErrorText)
    Else
        ' Success - read data
        If Lof(http) Then Read #http, global.sBuffer, Lof(http)
                Global.addtoStatusList(global.sBuffer)


            Dim vNew As Variant = JSON.Decode(global.sBuffer)
            
                global.AddToDebugList(global.sBuffer)
               
                Message(vNew["notifications"])
End if

but I get a error on Message(vNew["notifications"]) saying "Type Mismatch: wanted string got Variant[] instead"

do i have to process the output differently when it has more then one feed? Im trying to get the TRANSACTION_STARTED bit
Online now: No Back to the top

Post

Posted
Rating:
#13
Avatar
Enthusiast
GrayGhost is in the usergroup ‘Enthusiast’
 Message requires a string and vNew is a variant … try this :    


           Message(Str(vNew["notifications"]))
Online now: No Back to the top

Post

Posted
Rating:
#14
Enthusiast
AndyGable is in the usergroup ‘Enthusiast’
That now show but I can not seem to get the second set of data in the JSON feed

I need to read from the notifications Section

I have the following

Code

\{"location":"https://test.connect.paymentsense.cloud/pac/terminals/12345678/transactions/661c943f","notifications":["TRANSACTION_STARTED"]}

How do I get the "TRANSACTION_STARTED" from the notifications area?
Online now: No Back to the top

Post

Posted
Rating:
#15
Guru
BruceSteers is in the usergroup ‘Guru’
The format is a JSON string so use Decode to process it as a collection.
the notifications is an array so use [0] to get the first item.

Code (gambas)

  1. ' this is your string...
  2.  
  3. Dim s As String = "\{\"location\":\"https://test.connect.paymentsense.cloud/pac/terminals/12345678/transactions/661c943f\",\"notifications\":[\"TRANSACTION_STARTED\"]}"
  4.  
  5.  ' turn the JSON string into a collection
  6. Dim jc As Collection = JSON.Decode(s)
  7.  
  8. ' print the data..
  9. Print jc["location"]
  10. Print jc["notifications"][0]
  11.  
  12.  
Online now: No Back to the top

Post

Posted
Rating:
#16
Enthusiast
AndyGable is in the usergroup ‘Enthusiast’

BruceSteers said

The format is a JSON string so use Decode to process it as a collection.
the notifications is an array so use [0] to get the first item.

Code (gambas)

  1. ' this is your string...
  2.  
  3. Dim s As String = "\{\"location\":\"https://test.connect.paymentsense.cloud/pac/terminals/12345678/transactions/661c943f\",\"notifications\":[\"TRANSACTION_STARTED\"]}"
  4.  
  5.  ' turn the JSON string into a collection
  6. Dim jc As Collection = JSON.Decode(s)
  7.  
  8. ' print the data..
  9. Print jc["location"]
  10. Print jc["notifications"][0]
  11.  
  12.  

THANK-YOU THANK-YOU THANK-YOU :)
Online now: No Back to the top

Post

Posted
Rating:
#17
Guru
BruceSteers is in the usergroup ‘Guru’

AndyGable said

BruceSteers said

The format is a JSON string so use Decode to process it as a collection.
the notifications is an array so use [0] to get the first item.


THANK-YOU THANK-YOU THANK-YOU :)

You're welcome.
It would probably be good to make a class to handle your messages and fire events relevant to the message type.

attached is a simple example I just made of a class that you can send your device text to and it will fire events based on the message type. I called it DeviceMessage.class
It just handles 'notifications' or it reports an unhandled message for anything else…

Code (gambas)

  1. ' Gambas class file
  2.  
  3. '' Get the notifications sent
  4. Static Property Read Notifications As String[] Use $aNotifications
  5. '' get the location
  6. Static Property Read Location As String Use $sLocation
  7.  
  8. '' fires when a message contains notifications.
  9. Event Notify
  10.  
  11. '' process text from the device
  12. Public Sub _call(Text As String)
  13.  
  14.   Dim jc As Collection = JSON.Decode(Text)
  15.  
  16.   $sLocation = jc["location"]
  17.   jc.Remove("location")
  18.  
  19.   For Each jc
  20.  
  21.     If jc.Key = "notifications" ' message is notifications so set property, raise event and remove from message list
  22.       $aNotifications = jc["notifications"]
  23.       Raise Notify
  24.       jc.Remove("notifications")
  25.       Continue
  26.     Endif
  27.  
  28.     ' If here there is an unhandled message
  29.     Print "\e[31mUnhandled message!!\e[0m " & jc.Key;;
  30.  
  31.     If TypeOf(jc[jc.Key]) = gb.String Then
  32.       Print "'string'";; jc[jc.Key]
  33.     Else If TypeOf(jc[jc.Key]) = gb.Integer Then
  34.       Print "'integer'";; Str(jc[jc.Key])
  35.  
  36.     Else If TypeOf(jc[jc.Key]) = gb.Object Then ' any array is an Object type
  37.       If Object.Type(jc[jc.Key]) Ends "[]" Then
  38.         Print "'array'";; Object.Type(jc[jc.Key])
  39.       Else
  40.         Print "'object'";; Object.Type(jc[jc.Key])
  41.       Endif
  42.  
  43.     Else
  44.       Print "Unhandled type"
  45.     Endif
  46.   Next
  47.  
  48.  

Now in your application you would create the instance of the DeviceMessage class like so…

Code (gambas)

  1.   hMessager = New DeviceMessage As "DeviceMessage"
  2.  

then send the global.sBuffer strings like

Code (gambas)

  1.            Global.addtoStatusList(global.sBuffer)
  2.            hMessager(global.sBuffer)
  3.            global.AddToDebugList(global.sBuffer)
  4.  

a notifications message will fire the Notify event

Code (gambas)

  1. '' a notifications message sent to the buffer triggers this event filling in the Location and Notifications property
  2. Public Sub DeviceMessage_Notify()
  3.  
  4.  

possibly not what you want but I was bored and thought this might help you with understanding collections, how to process various unknown variant types and setting up events.
Perhaps you could expand it do suit your needs.

Happy coding :)
BruceS

Attachment
Online now: No Back to the top

Post

Posted
Rating:
#18
Enthusiast
AndyGable is in the usergroup ‘Enthusiast’
Would that class help send status messages to my point of sale software?
Online now: No Back to the top

Post

Posted
Rating:
#19
Guru
BruceSteers is in the usergroup ‘Guru’

AndyGable said

Would that class help send status messages to my point of sale software?

It's a bare bones example.
I don't know your device , you would have to add what you want to it and make it work how you need it to.

If there is a status specific message string then process it like the notifications message.

The above post has a test source app attached showing how to use it.

It will print messages about anything sent that is not notifications showing the datatype of the message so you can figure it out from there I should think <EMOJI seq="1f60a" tseq="1f60a">😊</EMOJI>
Online now: No Back to the top

Post

Posted
Rating:
#20
Guru
BruceSteers is in the usergroup ‘Guru’
 Pretty sure you could reverse the process, so make a collection then use JSON.Encode() to create a message string to send to the device. (Only a guess though, you'd have to experiment)

You could then add a DeviceMessage.Send() command to the class easily enough.
Online now: No Back to the top

Post

Posted
Rating:
#21
Enthusiast
AndyGable is in the usergroup ‘Enthusiast’
basically the app is a go between my EPoS Software and a Card Processing machine

Once a sale starts it output status in the same message

how would I pole the url? do I just have to call the same Function or can it be made to do that?

Code

Private Sub ShowSaleResults(RequestID As String, http As HttpClient)

    FMain.Refresh


    If http.Status < 0 Then
        Global.addtoStatusList("SORRY A Error was detected")
        global.AddToDebugList(http.ErrorText)
    Else
        ' Success - read data
        If Lof(http) Then Read #http, global.sBuffer, Lof(http)
                Global.addtoStatusList(global.sBuffer)


            Dim vNew As Variant = JSON.Decode(global.sBuffer, True)
            
                global.AddToDebugList(global.sBuffer)
                
                Select Case UCase(vNew["notifications"][0])
                    Case ""
                        ShowSaleResults(requestId, http)
                        
                    Case "CARD_ERROR"
                        Global.addtoStatusList("Sorry a error has been detected with the customers card")

                    Case "PROCESSING_ERROR"
                        Global.ddtoStatusList("Sorry there has been a processing Error." & gb.CrLf & "Please check the PinPad Screen for further information")

                    Case "SIGNATURE_VERIFICATION"
                        If global.WaitingForPoS = 0 Then
                            Global.addtoStatusList("Requesting PoS User to confirm Card Signture")
                            global.WaitingForPoS = 1
                            'CreateSigntureSlip_FromPDQ(TerminalType, responseFromServer, IDNumber)
                            'SendToPoSterminal("Printdata_Signture|" & PoSSlipData)
                            'SendToPoSterminal("SigntureCheck")
                            ShowSaleResults(requestId, http)
                        End If
                        
                    Case "TRANSACTION_FINISHED"
                            If Global.SigntureReq = 1 Then
                                LoadCardSlipData(RequestID)
                                'selectSlipToPrint(1, responseFromServer)
                                'SendToPoSterminal("Printdata_Recipit|" & PoSSlipData)
                                'SendToPoSterminal("TransactionCompleted|" & cardSchemeName & "|" & (amountTotal * 100))
                                Global.WaitingForPoS = 0
                                ShowSaleResults(requestId, http)
                                
                            Else
                                If Global.WaitingForPoS = 0 Then
                                    LoadCardSlipData(RequestID, requestId)

                                    If UCase(Global.paymentMethod) = "KEYED" Then Global.SigntureNotNeeded = 1

                                        Select Case Global.SigntureNotNeeded
                                            Case 0 ' No Signutre needed
                                               'selectSlipToPrint(0, responseFromServer) '
                                                Select Case Global.PrintStoreSlip
                                                    Case "Yes"
                                                        'SendToPoSterminal("Printdata_Store|" & PoSSlipData)

                                                    Case "No"
                                                       'SendToPoSterminal("Storedata_Store|" & PoSSlipData & "|" & transactionNumber & "|" & IDNumber & "|" & transactionId)
                                                End Select
                                                
                                            Case 1 ' Signture needed
                                                'CustomerNOTPresentCardSlip_FromPDQ(TerminalType, responseFromServer, IDNumberLocal)
                                                'SendToPoSterminal("Printdata_Store|" & PoSSlipData)
                                                ShowSaleResults(requestId, http)
                                                
                                        End Select
                                    Else
                                        LoadCardSlipData(requestID)
                                        'selectSlipToPrint(2, responseFromServer)

                                        Select Case Global.PrintStoreSlip
                                            Case "Yes"
                                                'SendToPoSterminal("Printdata_Store|" & PoSSlipData)

                                            Case "No"
                                                'SendToPoSterminal("Storedata_Store|" & PoSSlipData & "|" & transactionNumber & "|" & IDNumber & "|" & transactionId)
                                        End Select

                                        LoadCardSlipData(Requestid)
                                        'selectSlipToPrint(1, responseFromServer)
                                        'SendToPoSterminal("Printdata_Recipit|" & PoSSlipData)
                                        'SendToPoSterminal("TransactionCompleted|" & cardSchemeName & "|" & (amountTotal * 100))
                                        ShowSaleResults(requestId, http)
                                    End If
                                End If

                    Case "REMOVE_CARD"
                        'SendToPoSterminal("RemoveCard")
                        Global.addtoStatusList("Please ask customer to remove card") ''
                        ShowSaleResults(requestId, http)

                    Case "APPROVED"
                        'SendToPoSterminal("Approved")
                        Global.addtoStatusList("Transaction has been approved")
                       ShowSaleResults(requestId, http)

                    Case "CONNECTION_MADE"
                        'SendToPoSterminal("ConnectionMade")
                        Global.addtoStatusList("Connection Established to Payment Provider")
                        ShowSaleResults(requestId, http)
                        
                                
                    Case "CONNECTING"
                        'SendToPoSterminal("Connecting")
                        Global.addtoStatusList("Connecting to Payment Provider")
                        ShowSaleResults(requestId, http)

                    Case "PIN_ENTRY"
                        'SendToPoSterminal("EnterPIN")
                        Global.addtoStatusList("Waiting for customer to enter PIN")
                        ShowSaleResults(requestId, http)

                    Case "PLEASE_WAIT"
                        'SendToPoSterminal("PleaseWait")
                        Global.addtoStatusList("Please Wait...")
                        ShowSaleResults(requestId, http)

                    Case "PRESENT_CARD"
                        'SendToPoSterminal("InsertCard")
                        Global.addtoStatusList("Please insert card")
                        ShowSaleResults(requestId, http)

                    Case "INSERT_CARD"
                        'SendToPoSterminal("InsertCard")
                        Global.addtoStatusList("Card has been inserted")
                        ShowSaleResults(requestId, http)

                    Case "TRANSACTION_STARTED"
                        'Global.SigntureNotNeeded = 0
                      '  Global.SigntureReq = 0
                        Global.addtoStatusList("Starting transacation One moment...")
                        ShowSaleResults(requestId, http)
                End Select
        End If
End

As you can see the system uses the same feed to send the full status of the transaction (from Insert Card to Complete sale)
Online now: No Back to the top

Post

Posted
Rating:
#22
Guru
BruceSteers is in the usergroup ‘Guru’
 Pole?

When a message is processed the DeviceMessage.Location property is filled.
Online now: No Back to the top

Post

Posted
Rating:
#23
Enthusiast
AndyGable is in the usergroup ‘Enthusiast’
 opps sorry that was a typo it should have said poll

with your class do I still call ShowSaleResults? to get the newest status message?

also could someone tell me why while running the transaction nothing is being added to the listbox even though I am adding messages to the list
Online now: No Back to the top

Post

Posted
Rating:
#24
Guru
BruceSteers is in the usergroup ‘Guru’

AndyGable said

opps sorry that was a typo it should have said poll

with your class do I still call ShowSaleResults? to get the newest status message?

also could someone tell me why while running the transaction nothing is being added to the listbox even though I am adding messages to the list

How are you adding messages to the listbox?

Note.
ListBox1.List.Add(sText) will not work.

ListBox1.Add(sText) is how to do it.


A ListBox.List read returns a copy of the list only not a pointer to it.


And.
The class has one function _call() did you even read the source code i posted?
Or download the source i uploaded to see?
Or read the last message about it being bare bones and doesn't do anything much?

Good luck with your problem.
Online now: No Back to the top

Post

Posted
Rating:
#25
Enthusiast
AndyGable is in the usergroup ‘Enthusiast’

BruceSteers said

AndyGable said

opps sorry that was a typo it should have said poll

with your class do I still call ShowSaleResults? to get the newest status message?

also could someone tell me why while running the transaction nothing is being added to the listbox even though I am adding messages to the list

How are you adding messages to the listbox?

Note.
ListBox1.List.Add(sText) will not work.

ListBox1.Add(sText) is how to do it.


A ListBox.List read returns a copy of the list only not a pointer to it.


And.
The class has one function _call() did you even read the source code i posted?
Or download the source i uploaded to see?
Or read the last message about it being bare bones and doesn't do anything much?

Good luck with your problem.

Hi This is the code I am using to add to my listbox

Code

Public Sub addtoStatusList(textToShow As String)
  Dim gw As GridView
    Dim b As Byte

    fmain.lstSystemMessages.Add(Trim(textToShow)) ' add to list box
    fmain.lstSystemMessages.Index = fmain.lstSystemMessages.Count - 1 ' places the blue line onto the newly added item
    gw = fmain.lstSystemMessages.Children[0]

    b = fmain.lstSystemMessages.List.Max

    gw.Rows[b].Height = -1 ' adjust blue line if the data is over 2 or more lines
    
    fmain.lstSystemMessages.Refresh
    fmain.Refresh
End Sub

if i am not doing anything with the Status of the transaction I get Messages Showing up (Example when I click Check Status i get the Message "Terminal Ready for Transaction" but the moment a sale starts nothing seems to be added to the list (even though I have the code to do it see example)

Code

Case "TRANSACTION_STARTED"
   'Global.SigntureNotNeeded = 0
   'Global.SigntureReq = 0
   Global.addtoStatusList("Starting transacation One moment...")
   ShowSaleResults(requestId, http)
 

as you can see I am adding the message "Starting transaction One moment…" but it does not get added

once the transaction is cancelled on the PinPad the list box refresh and everything is showing up

could this be a update issues between the thread running on the update command?

any help would be most appreachated
Online now: No Back to the top
1 guest and 0 members have just viewed this.