tulir / whatsmeow

Go library for the WhatsApp web multidevice API
https://go.mau.fi/whatsmeow
Mozilla Public License 2.0
2.1k stars 385 forks source link

OrderMessage details #21

Open adarosci opened 2 years ago

adarosci commented 2 years ago

I working on a feature and I need to get a order message and get the order details, I'd like to know if is it possible to get this content? Today only some information arrived, how total quantity and price.

image image image

tks

Romerito007 commented 2 years ago

You need to implement a function to get the order details by passing orderId go-whatsapp. I believe the ways of implementation are similar. Multi Device

adarosci commented 2 years ago

You need to implement a function to get the order details by passing orderId go-whatsapp. I believe the ways of implementation are similar. Multi Device

I tried using the go-whatsapp idea image

Implemented it this way, but it's resulting in timeout, some idea how to solve it?

image

image

Att

adarosci commented 2 years ago

You need to implement a function to get the order details by passing orderId go-whatsapp. I believe the ways of implementation are similar. Multi Device

I tried using the go-whatsapp idea image

Implemented it this way, but it's resulting in timeout, some idea how to solve it?

image

image

Att

@Romerito007

Ased2235 commented 2 years ago

You need to implement a function to get the order details by passing orderId go-whatsapp. I believe the ways of implementation are similar. Multi Device

I tried using the go-whatsapp idea image Implemented it this way, but it's resulting in timeout, some idea how to solve it? image image Att

@Romerito007

It's not tested yet but i think it's something like this

func (cli *Client) GetOrderdetails(smax_id, pid, token string) {

    attrs := waBinary.Attrs{
        "smax_id": smax_id,
    }
    orderNode, err := cli.sendIQ(infoQuery{
        Namespace: "fb:thrift_i",
        Type:      "get",
        To:        types.ServerJID,
        ID:        cli.generateRequestID(),
        Attrs:     attrs,
        Content: []waBinary.Node{{
            Tag: "order",
            Attrs: waBinary.Attrs{
                "op": "get",
                "id": pid,
            },
            Content: []waBinary.Node{
                {
                    Tag:     "token",
                    Content: []byte(token),
                },
                {
                    Tag: "image_dimensions",
                    Content: []waBinary.Node{
                        {
                            Tag:     "width",
                            Content: []byte("88"),
                        }, {
                            Tag:     "height",
                            Content: []byte("88"),
                        },
                    },
                },
            },
        }},
    })

}
Romerito007 commented 2 years ago

was trying to run this parser to check how to run the query WhatsappWebRequestAnalyzer

Ased2235 commented 2 years ago

was trying to run this parser to check how to run the query WhatsappWebRequestAnalyzer

That tool didn't work for me, do you have another one which i can use? I'm using javascript but idk now to decode unit8bytes.

Ased2235 commented 2 years ago

was trying to run this parser to check how to run the query WhatsappWebRequestAnalyzer

That tool didn't work for me, do you have another one which i can use? I'm using javascript but idk now to decode unit8bytes.

[ { "tag": "iq", "attrs": { "to": { "_jid": { "type": 0, "user": null, "server": "s.whatsapp.net" } }, "xmlns": "w:sync:app:state", "type": "set", "id": "18199.58984-652" }, "content": [ { "tag": "sync", "attrs": {}, "content": [ { "tag": "collection", "attrs": { "name": "regular_high", "version": "46", "return_snapshot": "false" }, "content": [ { "tag": "patch", "attrs": {}, "content": { "0": 18, "1": 167, "2": 1, "3": 8, "4": 0, "5": 18, "6": 162, "7": 1, "8": 10, "9": 34, "10": 10, "11": 32, "12": 65, "13": 236, "14": 190, "15": 38, "16": 146, "17": 141, "18": 84, "19": 93, "20": 74, "21": 89, "22": 137, "23": 11, "24": 113, "25": 98, "26": 121, "27": 55, "28": 85, "29": 34, "30": 75, "31": 15, "32": 24, "33": 244, "34": 58, "35": 104, "36": 216, "37": 14, "38": 255, "39": 53, "40": 32, "41": 218, "42": 120, "43": 251, "44": 18, "45": 114, "46": 10, "47": 112, "48": 49, "49": 51, "50": 242, "51": 0, "52": 154, "53": 152, "54": 119, "55": 135, "56": 41, "57": 118, "58": 83, "59": 205, "60": 87, "61": 213, "62": 37, "63": 104, "64": 87, "65": 154, "66": 67, "67": 139, "68": 208, "69": 176, "70": 73, "71": 34, "72": 112, "73": 106, "74": 30, "75": 72, "76": 93, "77": 17, "78": 74, "79": 47, "80": 244, "81": 49, "82": 67, "83": 180, "84": 15, "85": 167, "86": 251, "87": 227, "88": 43, "89": 66, "90": 180, "91": 177, "92": 102, "93": 230, "94": 239, "95": 240, "96": 217, "97": 219, "98": 17, "99": 253, "100": 133, "101": 218, "102": 32, "103": 169, "104": 45, "105": 177, "106": 107, "107": 82, "108": 111, "109": 117, "110": 19, "111": 12, "112": 119, "113": 193, "114": 55, "115": 220, "116": 43, "117": 7, "118": 216, "119": 23, "120": 173, "121": 18, "122": 169, "123": 237, "124": 51, "125": 111, "126": 129, "127": 79, "128": 164, "129": 199, "130": 174, "131": 20, "132": 217, "133": 63, "134": 168, "135": 125, "136": 31, "137": 203, "138": 71, "139": 36, "140": 232, "141": 197, "142": 233, "143": 187, "144": 19, "145": 53, "146": 147, "147": 24, "148": 50, "149": 152, "150": 208, "151": 254, "152": 58, "153": 106, "154": 6, "155": 71, "156": 121, "157": 52, "158": 155, "159": 104, "160": 26, "161": 8, "162": 10, "163": 6, "164": 0, "165": 21, "166": 0, "167": 0, "168": 184, "169": 238, "170": 18, "171": 167, "172": 1, "173": 8, "174": 0, "175": 18, "176": 162, "177": 1, "178": 10, "179": 34, "180": 10, "181": 32, "182": 164, "183": 162, "184": 39, "185": 4, "186": 170, "187": 40, "188": 136, "189": 92, "190": 112, "191": 122, "192": 208, "193": 21, "194": 101, "195": 243, "196": 38, "197": 61, "198": 78, "199": 22, "200": 180, "201": 41, "202": 53, "203": 232, "204": 122, "205": 175, "206": 142, "207": 240, "208": 162, "209": 128, "210": 166, "211": 93, "212": 35, "213": 31, "214": 18, "215": 114, "216": 10, "217": 112, "218": 156, "219": 228, "220": 244, "221": 74, "222": 190, "223": 88, "224": 22, "225": 229, "226": 212, "227": 248, "228": 195, "229": 205, "230": 244, "231": 167, "232": 79, "233": 249, "234": 119, "235": 178, "236": 180, "237": 2, "238": 106, "239": 52, "240": 247, "241": 22, "242": 8, "243": 254, "244": 250, "245": 64, "246": 17, "247": 127, "248": 237, "249": 32, "250": 120, "251": 45, "252": 56, "253": 198, "254": 145, "255": 103, "256": 178, "257": 91, "258": 209, "259": 52, "260": 254, "261": 84, "262": 196, "263": 234, "264": 10, "265": 194, "266": 86, "267": 211, "268": 203, "269": 33, "270": 255, "271": 197, "272": 28, "273": 50, "274": 11, "275": 63, "276": 113, "277": 252, "278": 20, "279": 190, "280": 121, "281": 136, "282": 213, "283": 18, "284": 202, "285": 114, "286": 126, "287": 131, "288": 71, "289": 56, "290": 48, "291": 158, "292": 37, "293": 110, "294": 83, "295": 97, "296": 6, "297": 81, "298": 118, "299": 90, "300": 67, "301": 111, "302": 19, "303": 85, "304": 24, "305": 65, "306": 187, "307": 226, "308": 74, "309": 130, "310": 235, "311": 56, "312": 161, "313": 203, "314": 214, "315": 221, "316": 142, "317": 251, "318": 79, "319": 122, "320": 148, "321": 193, "322": 222, "323": 95, "324": 12, "325": 6, "326": 254, "327": 129, "328": 163, "329": 204, "330": 26, "331": 8, "332": 10, "333": 6, "334": 0, "335": 21, "336": 0, "337": 0, "338": 184, "339": 238, "340": 18, "341": 167, "342": 1, "343": 8, "344": 1, "345": 18, "346": 162, "347": 1, "348": 10, "349": 34, "350": 10, "351": 32, "352": 109, "353": 42, "354": 211, "355": 63, "356": 240, "357": 70, "358": 67, "359": 70, "360": 247, "361": 27, "362": 194, "363": 33, "364": 150, "365": 139, "366": 125, "367": 18, "368": 253, "369": 226, "370": 49, "371": 168, "372": 158, "373": 218, "374": 87, "375": 243, "376": 251, "377": 2, "378": 181, "379": 11, "380": 193, "381": 234, "382": 245, "383": 222, "384": 18, "385": 114, "386": 10, "387": 112, "388": 156, "389": 184, "390": 71, "391": 193, "392": 179, "393": 209, "394": 199, "395": 225, "396": 129, "397": 8, "398": 175, "399": 164, "400": 26, "401": 168, "402": 252, "403": 112, "404": 193, "405": 11, "406": 9, "407": 188, "408": 5, "409": 236, "410": 218, "411": 28, "412": 208, "413": 9, "414": 56, "415": 72, "416": 153, "417": 191, "418": 84, "419": 57, "420": 231, "421": 2, "422": 26, "423": 5, "424": 118, "425": 18, "426": 36, "427": 89, "428": 62, "429": 218, "430": 77, "431": 69, "432": 96, "433": 92, "434": 235, "435": 235, "436": 24, "437": 38, "438": 33, "439": 70, "440": 78, "441": 237, "442": 109, "443": 111, "444": 98, "445": 198, "446": 236, "447": 187, "448": 155, "449": 251, "450": 227, "451": 158, "452": 136, "453": 214, "454": 36, "455": 177, "456": 244, "457": 21, "458": 164, "459": 207, "460": 193, "461": 103, "462": 235, "463": 87, "464": 97, "465": 214, "466": 157, "467": 109, "468": 190, "469": 117, "470": 183, "471": 146, "472": 211, "473": 3, "474": 143, "475": 248, "476": 154, "477": 162, "478": 250, "479": 61, "480": 90, "481": 34, "482": 118, "483": 121, "484": 112, "485": 101, "486": 29, "487": 135, "488": 143, "489": 230, "490": 222, "491": 90, "492": 191, "493": 194, "494": 172, "495": 203, "496": 227, "497": 150, "498": 61, "499": 55, "500": 26, "501": 8, "502": 10, "503": 6, "504": 0, "505": 20, "506": 0, "507": 0, "508": 184, "509": 237, "510": 34, "511": 32, "512": 253, "513": 102, "514": 60, "515": 113, "516": 54, "517": 156, "518": 74, "519": 198, "520": 84, "521": 240, "522": 157, "523": 92, "524": 64, "525": 94, "526": 8, "527": 97, "528": 85, "529": 239, "530": 193, "531": 74, "532": 148, "533": 244, "534": 119, "535": 178, "536": 109, "537": 118, "538": 19, "539": 62, "540": 43, "541": 30, "542": 147, "543": 121, "544": 42, "545": 32, "546": 183, "547": 50, "548": 221, "549": 165, "550": 196, "551": 94, "552": 54, "553": 19, "554": 51, "555": 251, "556": 107, "557": 11, "558": 4, "559": 96, "560": 240, "561": 142, "562": 4, "563": 216, "564": 143, "565": 40, "566": 102, "567": 194, "568": 79, "569": 134, "570": 61, "571": 180, "572": 39, "573": 97, "574": 228, "575": 134, "576": 9, "577": 94, "578": 50, "579": 8, "580": 10, "581": 6, "582": 0, "583": 21, "584": 0, "585": 0, "586": 184, "587": 238 } } ] } ] } ] } ]

Romerito007 commented 2 years ago

was trying to run this parser to check how to run the query WhatsappWebRequestAnalyzer

That tool didn't work for me, do you have another one which i can use? I'm using javascript but idk now to decode unit8bytes.

I only know these two tools.

Ased2235 commented 2 years ago

was trying to run this parser to check how to run the query WhatsappWebRequestAnalyzer

That tool didn't work for me, do you have another one which i can use? I'm using javascript but idk now to decode unit8bytes.

I only know these two tools.

I see, Any idea how I can convert bytes to string?

adarosci commented 2 years ago

was trying to run this parser to check how to run the query WhatsappWebRequestAnalyzer

That tool didn't work for me, do you have another one which i can use? I'm using javascript but idk now to decode unit8bytes.

I only know these two tools.

I see, Any idea how I can convert bytes to string?

@Ased2235 to converto byte array in string

var array []byte .... str := string(array)

Ased2235 commented 2 years ago

was trying to run this parser to check how to run the query WhatsappWebRequestAnalyzer

That tool didn't work for me, do you have another one which i can use? I'm using javascript but idk now to decode unit8bytes.

I only know these two tools.

I see, Any idea how I can convert bytes to string?

@Ased2235 to converto byte array in string

var array []byte .... str := string(array)

I already tried it but it's not working.

ayrokid commented 2 years ago

how to solve this? cc: @tulir

hrizal commented 2 years ago

You need to implement a function to get the order details by passing orderId go-whatsapp. I believe the ways of implementation are similar. Multi Device

I tried using the go-whatsapp idea image Implemented it this way, but it's resulting in timeout, some idea how to solve it? image image Att

@Romerito007

It's not tested yet but i think it's something like this

func (cli *Client) GetOrderdetails(smax_id, pid, token string) {

  attrs := waBinary.Attrs{
      "smax_id": smax_id,
  }
  orderNode, err := cli.sendIQ(infoQuery{
      Namespace: "fb:thrift_i",
      Type:      "get",
      To:        types.ServerJID,
      ID:        cli.generateRequestID(),
      Attrs:     attrs,
      Content: []waBinary.Node{{
          Tag: "order",
          Attrs: waBinary.Attrs{
              "op": "get",
              "id": pid,
          },
          Content: []waBinary.Node{
              {
                  Tag:     "token",
                  Content: []byte(token),
              },
              {
                  Tag: "image_dimensions",
                  Content: []waBinary.Node{
                      {
                          Tag:     "width",
                          Content: []byte("88"),
                      }, {
                          Tag:     "height",
                          Content: []byte("88"),
                      },
                  },
              },
          },
      }},
  })

}

What is smax_id ? i got unknown field 'attrs' in struct literal of type infoQuery

Has anyone succeeded in getting a detailed order?

Romerito007 commented 2 years ago

See if that helps!

implement getOrder on legacy

implement fetching product catalog + order details on MD

Romerito007 commented 2 years ago

Function to fetch product catalog and order item details. Add smax_id properties in infoQuery struct

func (cli *Client) GetCatalog(jid types.JID, limit int) (*waBinary.Node, error) {
    catalogNode, err := cli.sendIQ(infoQuery{
        Namespace: "w:biz:catalog",
        Type:      "get",
        To:        types.ServerJID,
        Content: []waBinary.Node{
            {
                Tag: "product_catalog",
                Attrs: waBinary.Attrs{
                    "jid":               jid,
                    "allow_shop_source": true,
                },
                Content: []waBinary.Node{
                    {
                        Tag:     "limit",
                        Attrs:   nil,
                        Content: []byte("10"),
                    },
                    {
                        Tag:     "width",
                        Attrs:   nil,
                        Content: []byte("100"),
                    }, {
                        Tag:     "height",
                        Attrs:   nil,
                        Content: []byte("100"),
                    },
                },
            },
        },
    })
    fmt.Println(catalogNode.XMLString())
    return catalogNode, err
}
func (cli *Client) GetOrderDetails(id, orderId, tokenBase64 string) (*waBinary.Node, error) {
    detailsNode, err := cli.sendIQ(infoQuery{
        Namespace: "fb:thrift_iq",
        Type:      "get",
        To:        types.ServerJID,
        SmaxId:    id,
        Content: []waBinary.Node{
            {
                Tag: "order",
                Attrs: waBinary.Attrs{
                    "op": "get",
                    "id": orderId,
                },
                Content: []waBinary.Node{
                    {
                        Tag:   "image_dimensions",
                        Attrs: nil,
                        Content: []waBinary.Node{
                            {
                                Tag:     "width",
                                Attrs:   nil,
                                Content: []byte("100"),
                            }, {
                                Tag:     "height",
                                Attrs:   nil,
                                Content: []byte("100"),
                            },
                        },
                    },
                    {
                        Tag:     "token",
                        Attrs:   nil,
                        Content: []byte(tokenBase64),
                    },
                },
            },
        },
    })
    fmt.Println(detailsNode.XMLString())
    return detailsNode, err
}

Order details.

hajsf commented 2 years ago

Function to fetch product catalog and order item details

Any thought what it is not working with me, I even tried same order id and token from your results, but got an error after long time of waiting!

        id := "718623112830121"
        token := "AR7n3JWSCzAAN+eAY/hX/D/ak4fZ+pFRlieHmuNV1GcDtw=="
        fmt.Println("id:", id, "token:", token)

        details, err := global.Cli.GetOrderDetails("5", id, token)
        if err != nil {
            fmt.Println("Error:", err)
        } else {
            fmt.Println(*details)
        }

Bash

PS D:\WhatsApp> go run github.io/hajsf/whatsapp
id: 718623112830121 token: AR7n3JWSCzAAN+eAY/hX/D/ak4fZ+pFRlieHmuNV1GcDtw==
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x18 pc=0x7ff63491de2d]

goroutine 1 [running]:
go.mau.fi/whatsmeow/binary.(*Node).contentString(0x0)
        D:/Development/gopath/pkg/mod/go.mau.fi/whatsmeow@v0.0.0-20220329131721-9f73bc00d158/binary/xml.go:66 +0x4d
go.mau.fi/whatsmeow/binary.(*Node).XMLString(0x0)
        D:/Development/gopath/pkg/mod/go.mau.fi/whatsmeow@v0.0.0-20220329131721-9f73bc00d158/binary/xml.go:26 +0x33
go.mau.fi/whatsmeow.(*Client).GetOrderDetails(0x7ff634e571e0?, {0x7ff634d83166, 0x1}, {0x7ff634d884a0, 0xf}, {0x7ff634da213c, 0x30})
        D:/Development/gopath/pkg/mod/go.mau.fi/whatsmeow@v0.0.0-20220329131721-9f73bc00d158/orderdetails.go:48 +0x525
main.main()
        D:/WhatsApp/main.go:158 +0xcb0
exit status 2

The changes I made to the whatsmeow code are:

package whatsmeow

import (
    "fmt"

    waBinary "go.mau.fi/whatsmeow/binary"
    "go.mau.fi/whatsmeow/types"
)

func (cli *Client) GetOrderDetails(id, orderId, tokenBase64 string) (*waBinary.Node, error) {
    detailsNode, err := cli.sendIQ(infoQuery{
        Namespace: "fb:thrift_iq",
        Type:      "get",
        To:        types.ServerJID,
        SmaxId:    id,
        Content: []waBinary.Node{
            {
                Tag: "order",
                Attrs: waBinary.Attrs{
                    "op": "get",
                    "id": orderId,
                },
                Content: []waBinary.Node{
                    {
                        Tag:   "image_dimensions",
                        Attrs: nil,
                        Content: []waBinary.Node{
                            {
                                Tag:     "width",
                                Attrs:   nil,
                                Content: []byte("100"),
                            }, {
                                Tag:     "height",
                                Attrs:   nil,
                                Content: []byte("100"),
                            },
                        },
                    },
                    {
                        Tag:     "token",
                        Attrs:   nil,
                        Content: []byte(tokenBase64),
                    },
                },
            },
        },
    })
    fmt.Println(detailsNode.XMLString())
    return detailsNode, err
}

And

type infoQuery struct {
    Namespace string
    Type      infoQueryType
    To        types.JID
    Target    types.JID
    ID        string
    SmaxId    string
    Content   interface{}

    Timeout time.Duration
    Context context.Context
}

The orderdetails.go:48 is:

fmt.Println(detailsNode.XMLString())

I disabled that line, and got:

PS D:\WhatsApp> go run github.io/hajsf/whatsapp
id: 718623112830121 token: AR7n3JWSCzAAN+eAY/hX/D/ak4fZ+pFRlieHmuNV1GcDtw==
Error: info query timed out
Romerito007 commented 2 years ago

You need to have an order to get the details.

Add attrs["smax_Id"] = query.SmaxId in this function

hajsf commented 2 years ago

You need to have an order to get the detail

I made it as:

func (cli *Client) sendIQAsync(query infoQuery) (<-chan *waBinary.Node, error) {

    attrs := waBinary.Attrs{
        "id":      query.ID,
        "xmlns":   query.Namespace,
        "type":    string(query.Type),
        "smax_Id": query.SmaxId,
    }

}

And got:

PS D:\WhatsApp> go run github.io/hajsf/whatsapp
id: 718623112830121 token: AR7n3JWSCzAAN+eAY/hX/D/ak4fZ+pFRlieHmuNV1GcDtw==
Error: websocket disconnected before info query returned response
hajsf commented 2 years ago

Function to fetch product catalog and order item details.

Can you pls check your code with my below data, for some reason I'm not getting the required output:

id: 1161725727959481 token: AR6duMDDW0tAjzlJQe7ck4eI2Fm7bC4w8O/Np32y1wdPeA==
Romerito007 commented 2 years ago

Function to fetch product catalog and order item details.

Can you pls check your code with my below data, for some reason I'm not getting the required output:

id: 1161725727959481 token: AR6duMDDW0tAjzlJQe7ck4eI2Fm7bC4w8O/Np32y1wdPeA==

Captura de tela de 2022-05-04 09-58-19

hajsf commented 2 years ago

Function to fetch product catalog and order item details.

Strange, why not coming with me, can you please share the modified files as gist, may I made something wrong there.

Romerito007 commented 2 years ago

Function to fetch product catalog and order item details.

Strange, why not coming with me, can you please share the modified files as gist, may I made something wrong there.

type infoQuery struct {
    Namespace string
    Type      infoQueryType
    To        types.JID
    Target    types.JID
    ID        string
    SmaxId    string
    Content   interface{}

    Timeout time.Duration
    Context context.Context
}
func (cli *Client) sendIQAsyncDebug(query infoQuery) (<-chan *waBinary.Node, []byte, error) {
    if len(query.ID) == 0 {
        query.ID = cli.generateRequestID()
    }
    waiter := cli.waitResponse(query.ID)
    attrs := waBinary.Attrs{
        "id":    query.ID,
        "xmlns": query.Namespace,
        "type":  string(query.Type),
    }
    if len(query.SmaxId) > 0 {
        attrs["smax_id"] = query.SmaxId
    }
    if !query.To.IsEmpty() {
        attrs["to"] = query.To
    }
    if !query.Target.IsEmpty() {
        attrs["target"] = query.Target
    }
    data, err := cli.sendNodeDebug(waBinary.Node{
        Tag:     "iq",
        Attrs:   attrs,
        Content: query.Content,
    })
    if err != nil {
        cli.cancelResponse(query.ID, waiter)
        return nil, data, err
    }
    return waiter, data, nil
}
func (cli *Client) GetOrderDetails(smaxid, orderId, tokenBase64 string) (*waBinary.Node, error) {
    detailsNode, err := cli.sendIQ(infoQuery{
        Namespace: "fb:thrift_iq",
        Type:      "get",
        To:        types.ServerJID,
        SmaxId:    smaxid,
        Content: []waBinary.Node{
            {
                Tag: "order",
                Attrs: waBinary.Attrs{
                    "op": "get",
                    "id": orderId,
                },
                Content: []waBinary.Node{
                    {
                        Tag:   "image_dimensions",
                        Attrs: nil,
                        Content: []waBinary.Node{
                            {
                                Tag:     "width",
                                Attrs:   nil,
                                Content: []byte("100"),
                            }, {
                                Tag:     "height",
                                Attrs:   nil,
                                Content: []byte("100"),
                            },
                        },
                    },
                    {
                        Tag:     "token",
                        Attrs:   nil,
                        Content: []byte(tokenBase64),
                    },
                },
            },
        },
    })
    fmt.Println(detailsNode.XMLString())
    return detailsNode, err
}
hajsf commented 2 years ago

Function to fetch product catalog and order item details.

Thanks. Trying to convert them to struct, so started as:

        id := *evt.Message.OrderMessage.OrderId
        token := *evt.Message.OrderMessage.Token
        itemCount := *evt.Message.OrderMessage.ItemCount
        var i int32 = 0
        for i < itemCount {
            fmt.Println("lineID", i, "id:", id, "token:", token)
            details, err := global.Cli.GetOrderDetails(fmt.Sprint(i), id, token)
            if err != nil {
                fmt.Println("Error:", err)
            } else {
                fmt.Println(details.XMLString())
            }
            i++
        }

But it hanged, and gave Error: info query timed out

Tried a dummy number as line id to be:

details, err := global.Cli.GetOrderDetails("5", id, token)

Then it gave the correct output multiple item (= i)

hrizal commented 2 years ago

Function to fetch product catalog and order item details.

Thanks. Trying to convert them to struct, so started as:

      id := *evt.Message.OrderMessage.OrderId
      token := *evt.Message.OrderMessage.Token
      itemCount := *evt.Message.OrderMessage.ItemCount
      var i int32 = 0
      for i < itemCount {
          fmt.Println("lineID", i, "id:", id, "token:", token)
          details, err := global.Cli.GetOrderDetails(fmt.Sprint(i), id, token)
          if err != nil {
              fmt.Println("Error:", err)
          } else {
              fmt.Println(details.XMLString())
          }
          i++
      }

But it hanged, and gave Error: info query timed out

Tried a dummy number as line id to be:

details, err := global.Cli.GetOrderDetails("5", id, token)

Then it gave the correct output multiple item (= i)

id is orderId from first response. you will have items product from detailorder as much as itemcount so, to call orderdetail, once only

hrizal commented 2 years ago

for me its work ! thanks @Romerito007

i change sendIQAsync on request.go, add parameter smax_id

func (cli *Client) sendIQAsync(query infoQuery) (<-chan *waBinary.Node, error) {
    if len(query.ID) == 0 {
        query.ID = cli.generateRequestID()
    }
    waiter := cli.waitResponse(query.ID)
    attrs := waBinary.Attrs{
        "id":    query.ID,
        "xmlns": query.Namespace,
        "type":  string(query.Type),
    }
    if len(query.SmaxId) > 0 {
        attrs["smax_id"] = query.SmaxId
    }
    if !query.To.IsEmpty() {
        attrs["to"] = query.To
    }
    if !query.Target.IsEmpty() {
        attrs["target"] = query.Target
    }
    err := cli.sendNode(waBinary.Node{
        Tag:     "iq",
        Attrs:   attrs,
        Content: query.Content,
    })
    if err != nil {
        cli.cancelResponse(query.ID, waiter)
        return nil, err
    }
    return waiter, nil
}

then for GetOrderDetails function, it is like this because SmaxId is always fix as '5' for SmaxId, so i make it static

func (cli *Client) GetOrderDetails(orderId, tokenBase64 string) (*waBinary.Node, error) {   
    detailsNode, err := cli.sendIQ(infoQuery{
        Namespace: "fb:thrift_iq",
        Type:      "get",
        To:        types.ServerJID,
        SmaxId:    "5",
        Content: []waBinary.Node{
            {
                Tag: "order",
                Attrs: waBinary.Attrs{
                    "op": "get",
                    "id": orderId,
                },
                Content: []waBinary.Node{
                    {
                        Tag:   "image_dimensions",
                        Attrs: nil,
                        Content: []waBinary.Node{
                            {
                                Tag:     "width",
                                Attrs:   nil,
                                Content: []byte("100"),
                            }, {
                                Tag:     "height",
                                Attrs:   nil,
                                Content: []byte("100"),
                            },
                        },
                    },
                    {
                        Tag:     "token",
                        Attrs:   nil,
                        Content: []byte(tokenBase64),
                    },
                },
            },
        },
    })
    fmt.Println(detailsNode.XMLString())    
    return detailsNode, err
}
hrizal commented 2 years ago

next problem is unmarshal the result, always fail when trying it (because image url ?)

    type OrderDetailData struct {
        XMLName xml.Name `xml:"iq"`
        From    string   `xml:"from,attr"`
        ID      string   `xml:"id,attr"`
        Type    string   `xml:"type,attr"`
        Order   struct {
            CreationTs string `xml:"creation_ts,attr"`
            ID         string `xml:"id,attr"`
            Product    []struct {
                ID         string `xml:"id"`
                RetailerID string `xml:"retailer_id"`
                Image      struct {
                    URL  string `xml:"url"`
                    ID   string `xml:"id"`
                } `xml:"image"`
                Price    string `xml:"price"`
                Currency string `xml:"currency"`
                Name     string `xml:"name"`
                Quantity string `xml:"quantity"`
            } `xml:"product"`
            Catalog struct {
                ID   string `xml:"id"`
            } `xml:"catalog"`
            Price struct {
                Subtotal    string `xml:"subtotal"`
                Currency    string `xml:"currency"`
                Total       string `xml:"total"`
                PriceStatus string `xml:"price_status"`
            } `xml:"price"`
        } `xml:"order"`
    } 
hajsf commented 2 years ago

because image url ?

Yes, I found it, the xml fragment contains an element url which contains a url with multiple parameters in its query string portion, separated by ampersands &.

This symbol has special semantics in xml in initiating an entity reference (kind of a symbolic constant) - you cannot use it in isolation.

To solve it, we have 3 options:

  1. Write the url as a CDATA section (the contents of which are considered a literal, Syntax: <![CDATA[...]]>)
  2. Replace all occurrences of & with &amp; something like:

    re := regexp.MustCompile("&")
    Str := "&amp;"
    contents := re.ReplaceAllString(details, Str)
    
    iq := &Iq{}
    
    err := xml.Unmarshal([]byte(contents), &iq)
    if err != nil {
        panic(err)
    }

    Here is the playground: https://go.dev/play/p/sqQJQog98Ug

  3. Creating a Decoder instance and turning off Strict mode, as:
    d := xml.NewDecoder(bytes.NewReader([]byte(contents)))
    d.Strict = false
    err := d.Decode(&iq)
    if err != nil {
    panic(err)
    }
    fmt.Printf("%v\n", iq.Order)

Here is the playground of it: https://go.dev/play/p/xtnyRfknUW1

package main

import (
    "bytes"
    "encoding/xml"
    "fmt"
)

type catalog struct {
    Id string `xml:"id"`
}

type price struct {
    Subtotal    int    `xml:"subtotal"`
    Currency    string `xml:"currency"`
    Total       int    `xml:"total"`
    PriceStatus string `xml:"price_status"`
}

type image struct {
    Url string `xml:"url"`
    Id  int    `xml:"id"`
}

type product struct {
    Id         int    `xml:"id"`
    RetailerId int    `xml:"retailer_id"`
    Image      image  `xml:"image"`
    Price      int    `xml:"price"`
    Currency   string `xml:"currency"`
    Name       string `xml:"name"`
    Quantity   int    `xml:"quantity"`
}

type order struct {
    Product product `xml:"product"`
    Catalog catalog `xml:"catalog"`
    Price   price   `xml:"price"`
}

type Iq struct {
    XMLName xml.Name `xml:"iq"`
    Order   order    `xml:"order"`
}

func main() {
    contents := `<iq from="s.whatsapp.net" id="162.120-3" type="result">
  <order creation_ts="1651703902" id="1046755402590219">
    <product>
      <id>8312993582051445</id>
      <retailer_id>291</retailer_id>
      <image>
        <url>https://mmg.whatsapp.net/v/t45.5328-4/279646282_7510595942346471_4295336878174066544_n.jpg?stp=dst-jpg_p100x100&ccb=1-5&_nc_sid=c48759&_nc_ohc=OMyHhkGxzRoAX8Dn93Q&_nc_ad=z-m&_nc_cid=0&_nc_ht=mmg.whatsapp.net&oh=01_AVw_0loIIuK1LP-n5OL1hdpRmNYhAiUjLGk20FCclgNXCA&oe=62774C93</url>
        <id>7510595939013138</id>
      </image>
      <price>5000</price>
      <currency>SAR</currency>
      <name>coffee</name>
      <quantity>1</quantity>
    </product>
    <catalog><id>326185462964376</id></catalog>
    <price>
      <subtotal>5000</subtotal>
      <currency>SAR</currency>
      <total>5000</total>
      <price_status>provided</price_status>
    </price>
  </order>
</iq>`

    iq := &Iq{}

    d := xml.NewDecoder(bytes.NewReader([]byte(contents)))
    d.Strict = false
    err := d.Decode(&iq)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%v\n", iq.Order)
}

Again, thanks a lot to @Romerito007 https://github.com/Romerito007 and everyone else contributed at solving this issue at https://stackoverflow.com/a/72120398/2441637 and at https://forum.golangbridge.org/t/how-can-i-convert-xml-to-struct/27374/4?u=hyousef

@tulir can you update this to the repository, I think it is a required option.

hrizal commented 2 years ago

correction, retailer_id type is string

hajsf commented 2 years ago

retailer_id type is string

Thanks, I'll fix it in my code

hajsf commented 2 years ago

@hrizal did you manage the

details, err := cli.GetOrderDetails(SmaxId, id, token)

In your code I see you fixed it as "5" which worked in my code as well, but I think it is related to the number of lines in the PO! @Romerito007 any help

hrizal commented 2 years ago

i think smax_id related to query structure not to number of order (PO is Product Order ?)

Romerito007 commented 2 years ago

i think smax_id related to query structure not to number of order (PO is Product Order ?)

I think it has to do with the structure.

Order Detatils

Catalog Collection

Diden05 commented 2 years ago

Hello everyone, did someone create a product, update, delete?

Diden05 commented 2 years ago

still interesting here https://github.com/tulir/whatsmeow/discussions/198

@Romerito007 Didn't see how it works?