Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions business.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright (c) 2025 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package whatsmeow

import (
"context"
"fmt"
"strconv"

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

// GetOrderDetails fetches the details of a specific order using its ID and token.
// Both token and orderID are found in the OrderMessage.
func (cli *Client) GetOrderDetails(ctx context.Context, orderID, tokenBase64 string) (*types.OrderDetails, error) {
resp, err := cli.sendIQ(ctx, infoQuery{
Namespace: "fb:thrift_iq",
Type: iqGet,
SMaxID: "5",
To: types.ServerJID,
Content: []waBinary.Node{{
Tag: "order",
Attrs: waBinary.Attrs{
"op": "get",
"id": orderID,
},
Content: []waBinary.Node{
{
Tag: "image_dimensions",
Content: []waBinary.Node{
{Tag: "width", Content: []byte("100")},
{Tag: "height", Content: []byte("100")},
},
},
{Tag: "token", Content: []byte(tokenBase64)},
},
}},
})
if err != nil {
return nil, fmt.Errorf("failed to send order IQ: %w", err)
}

orderNode, ok := resp.GetOptionalChildByTag("order")
if !ok {
return nil, &ElementMissingError{Tag: "order", In: "response to order query"}
}

return parseOrderDetailsNode(orderNode)
}

// Helper to get the string content of a child node.
func getStringChild(node waBinary.Node, tag string) string {
child, ok := node.GetOptionalChildByTag(tag)
if !ok {
return ""
}
content, _ := child.Content.([]byte)
return string(content)
}
Comment on lines +56 to +64
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not the right place for a helper like this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what should be done?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should i keep this scoped to the order-details parser instead ??

func parseOrderDetailsNode(orderNode waBinary.Node) (*types.OrderDetails, error) {
	getStringChild := func(node waBinary.Node, tag string) string {
		child, ok := node.GetOptionalChildByTag(tag)
		if !ok {
			return ""
		}
		content, _ := child.Content.([]byte)
		return string(content)
	}

	ag := orderNode.AttrGetter()
}


func parseOrderDetailsNode(orderNode waBinary.Node) (*types.OrderDetails, error) {
ag := orderNode.AttrGetter()
details := &types.OrderDetails{
ID: ag.String("id"),
CreatedAt: ag.UnixTime("creation_ts"),
}
if err := ag.Error(); err != nil {
return nil, err
}

// Parse Price
priceNode, ok := orderNode.GetOptionalChildByTag("price")
if ok {
subtotal, _ := strconv.ParseInt(getStringChild(priceNode, "subtotal"), 10, 64)
total, _ := strconv.ParseInt(getStringChild(priceNode, "total"), 10, 64)
details.Price = types.OrderPrice{
Subtotal: subtotal,
Total: total,
Currency: getStringChild(priceNode, "currency"),
PriceStatus: getStringChild(priceNode, "price_status"),
}
}

// Parse Catalog ID
catalogNode, ok := orderNode.GetOptionalChildByTag("catalog")
if ok {
details.CatalogID = getStringChild(catalogNode, "id")
}

// Parse Products
for _, productNode := range orderNode.GetChildrenByTag("product") {
price, _ := strconv.ParseInt(getStringChild(productNode, "price"), 10, 64)
quantity, _ := strconv.Atoi(getStringChild(productNode, "quantity"))

product := types.OrderProduct{
ID: getStringChild(productNode, "id"),
Price: price,
Currency: getStringChild(productNode, "currency"),
Name: getStringChild(productNode, "name"),
Quantity: quantity,
}

// Parse Product Image
if imageNode, ok := productNode.GetOptionalChildByTag("image"); ok {
product.ImageID = getStringChild(imageNode, "id")
product.ImageURL = getStringChild(imageNode, "url")
}

// Parse Variant Info
if variantNode, ok := productNode.GetOptionalChildByTag("variant_info"); ok {
product.VariantInfo.Properties = getStringChild(variantNode, "properties")
}

details.Products = append(details.Products, product)
}

return details, nil
}
39 changes: 39 additions & 0 deletions types/business.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) 2025 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package types

import "time"

type OrderDetails struct {
ID string `json:"id"`
CreatedAt time.Time `json:"created_at"`
CatalogID string `json:"catalog_id,omitempty"`
Price OrderPrice `json:"price"`
Products []OrderProduct `json:"products"`
}

type OrderProduct struct {
ID string `json:"id"`
ImageID string `json:"image_id,omitempty"`
ImageURL string `json:"image_url,omitempty"`
Price int64 `json:"price"`
Currency string `json:"currency"`
Name string `json:"name"`
Quantity int `json:"quantity"`
VariantInfo VariantInfo `json:"variant_info,omitempty"`
}

type VariantInfo struct {
Properties string `json:"properties,omitempty"`
}

type OrderPrice struct {
Subtotal int64 `json:"subtotal"`
Total int64 `json:"total"`
Currency string `json:"currency"`
PriceStatus string `json:"price_status,omitempty"`
}
Loading