taler-go

Utility functions in Go language
Log | Files | Refs | LICENSE

commit b4025837dad5952e60c31cc16b83498d1e4f33ba
parent 95f0f59f1e462cf543cd3acf335f08630dd84a1d
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date:   Tue, 19 Jul 2022 14:05:50 +0200

refactor merchant

Diffstat:
Apkg/merchant/merchant.go | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 157 insertions(+), 0 deletions(-)

diff --git a/pkg/merchant/merchant.go b/pkg/merchant/merchant.go @@ -0,0 +1,157 @@ +package merchant + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + + "taler.net/taler-go.git/pkg/util" +) + +type PostOrderRequest struct { + // The order must at least contain the minimal + // order detail, but can override all. + order MinimalOrderDetail + + // If set, the backend will then set the refund deadline to the current + // time plus the specified delay. If it's not set, refunds will not be + // possible. + RefundDelay int64 `json:"refund_delay,omitempty"` + + // Specifies the payment target preferred by the client. Can be used + // to select among the various (active) wire methods supported by the instance. + PaymentTarget string `json:"payment_target,omitempty"` + + // Specifies that some products are to be included in the + // order from the inventory. For these inventory management + // is performed (so the products must be in stock) and + // details are completed from the product data of the backend. + // FIXME: Not sure we actually need this for now + //InventoryProducts []MinimalInventoryProduct `json:"inventory_products,omitempty"` + + // Specifies a lock identifier that was used to + // lock a product in the inventory. Only useful if + // inventory_products is set. Used in case a frontend + // reserved quantities of the individual products while + // the shopping cart was being built. Multiple UUIDs can + // be used in case different UUIDs were used for different + // products (i.e. in case the user started with multiple + // shopping sessions that were combined during checkout). + LockUuids []string `json:"lock_uuids"` + + // Should a token for claiming the order be generated? + // False can make sense if the ORDER_ID is sufficiently + // high entropy to prevent adversarial claims (like it is + // if the backend auto-generates one). Default is 'true'. + CreateToken bool `json:"create_token,omitempty"` +} + +type MinimalOrderDetail struct { + // Amount to be paid by the customer. + Amount string + + // Short summary of the order. + Summary string +} + +// NOTE: Part of the above but optional +type FulfillmentMetadata struct { + // See documentation of fulfillment_url in ContractTerms. + // Either fulfillment_url or fulfillment_message must be specified. + FulfillmentUrl string `json:"fulfillment_url,omitempty"` + + // See documentation of fulfillment_message in ContractTerms. + // Either fulfillment_url or fulfillment_message must be specified. + FulfillmentMessage string `json:"fulfillment_message,omitempty"` +} + +type PostOrderResponse struct { + // Order ID of the response that was just created. + OrderId string `json:"order_id"` +} + +type PostOrderResponseToken struct { + // Token that authorizes the wallet to claim the order. + // Provided only if "create_token" was set to 'true' + // in the request. + Token string +} + +type CheckPaymentStatusResponse struct { + // Status of the order + OrderStatus string `json:"order_status"` +} + +type CheckPaymentPaytoResponse struct { + // Status of the order + TalerPayUri string `json:"taler_pay_uri"` +} + +type Merchant struct { + + // The host of this merchant + BaseUrlPrivate string + + // The access token to use for the private API + AccessToken string +} + +func NewMerchant(merchBaseUrlPrivate string, merchAccessToken string) Merchant { + return Merchant{ + BaseUrlPrivate: merchBaseUrlPrivate, + AccessToken: merchAccessToken, + } +} + +func (m *Merchant) IsOrderPaid(orderId string) (string, error) { + var orderPaidResponse CheckPaymentStatusResponse + var paytoResponse CheckPaymentPaytoResponse + resp, err := http.Get(m.BaseUrlPrivate + "/private/orders/" + orderId) + if nil != err { + return "", err + } + defer resp.Body.Close() + if http.StatusOK != resp.StatusCode { + message := fmt.Sprintf("Expected response code %d. Got %d", http.StatusOK, resp.StatusCode) + return "", errors.New(message) + } + respData, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + err = json.NewDecoder(bytes.NewReader(respData)).Decode(&orderPaidResponse) + if err != nil { + return "", err + } + if orderPaidResponse.OrderStatus != "paid" { + err = json.NewDecoder(bytes.NewReader(respData)).Decode(&paytoResponse) + return paytoResponse.TalerPayUri, err + } + return "", nil +} + +func (m *Merchant) AddNewOrder(cost util.Amount) (string, error) { + var newOrder PostOrderRequest + var orderDetail MinimalOrderDetail + var orderResponse PostOrderResponse + orderDetail.Amount = cost.String() + // FIXME get from cfg + orderDetail.Summary = "This is an order to a TalDir registration" + newOrder.order = orderDetail + reqString, _ := json.Marshal(newOrder) + resp, err := http.Post(m.BaseUrlPrivate+"/private/orders", "application/json", bytes.NewBuffer(reqString)) + + if nil != err { + return "", err + } + defer resp.Body.Close() + if http.StatusOK != resp.StatusCode { + message := fmt.Sprintf("Expected response code %d. Got %d", http.StatusOK, resp.StatusCode) + return "", errors.New(message) + } + err = json.NewDecoder(resp.Body).Decode(&orderResponse) + return orderResponse.OrderId, err +}