taler-go

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

merchant.go (5590B)


      1 package merchant
      2 
      3 import (
      4 	"bytes"
      5 	"encoding/json"
      6 	"errors"
      7 	"fmt"
      8 	"io/ioutil"
      9 	"net/http"
     10 
     11 	"github.com/schanzen/taler-go/pkg/util"
     12 )
     13 
     14 type PostOrderRequest struct {
     15 	// The order must at least contain the minimal
     16 	// order detail, but can override all.
     17 	Order MinimalOrderDetail `json:"order"`
     18 
     19 	// If set, the backend will then set the refund deadline to the current
     20 	// time plus the specified delay.  If it's not set, refunds will not be
     21 	// possible.
     22 	RefundDelay int64 `json:"refund_delay,omitempty"`
     23 
     24 	// Specifies the payment target preferred by the client. Can be used
     25 	// to select among the various (active) wire methods supported by the instance.
     26 	PaymentTarget string `json:"payment_target,omitempty"`
     27 
     28 	// Specifies that some products are to be included in the
     29 	// order from the inventory.  For these inventory management
     30 	// is performed (so the products must be in stock) and
     31 	// details are completed from the product data of the backend.
     32 	// FIXME: Not sure we actually need this for now
     33 	//InventoryProducts []MinimalInventoryProduct `json:"inventory_products,omitempty"`
     34 
     35 	// Specifies a lock identifier that was used to
     36 	// lock a product in the inventory.  Only useful if
     37 	// inventory_products is set.  Used in case a frontend
     38 	// reserved quantities of the individual products while
     39 	// the shopping cart was being built.  Multiple UUIDs can
     40 	// be used in case different UUIDs were used for different
     41 	// products (i.e. in case the user started with multiple
     42 	// shopping sessions that were combined during checkout).
     43 	LockUuids []string `json:"lock_uuids,omitempty"`
     44 
     45 	// Should a token for claiming the order be generated?
     46 	// False can make sense if the ORDER_ID is sufficiently
     47 	// high entropy to prevent adversarial claims (like it is
     48 	// if the backend auto-generates one). Default is 'true'.
     49 	CreateToken bool `json:"create_token,omitempty"`
     50 }
     51 
     52 type MinimalOrderDetail struct {
     53 	// Amount to be paid by the customer.
     54 	Amount string `json:"amount"`
     55 
     56 	// Short summary of the order.
     57 	Summary string `json:"summary"`
     58 
     59 	// See documentation of fulfillment_url in ContractTerms.
     60 	// Either fulfillment_url or fulfillment_message must be specified.
     61 	FulfillmentUrl string `json:"fulfillment_url"`
     62 }
     63 
     64 // NOTE: Part of the above but optional
     65 type FulfillmentMetadata struct {
     66 	// See documentation of fulfillment_url in ContractTerms.
     67 	// Either fulfillment_url or fulfillment_message must be specified.
     68 	FulfillmentUrl string `json:"fulfillment_url,omitempty"`
     69 
     70 	// See documentation of fulfillment_message in ContractTerms.
     71 	// Either fulfillment_url or fulfillment_message must be specified.
     72 	FulfillmentMessage string `json:"fulfillment_message,omitempty"`
     73 }
     74 
     75 type PostOrderResponse struct {
     76 	// Order ID of the response that was just created.
     77 	OrderId string `json:"order_id"`
     78 }
     79 
     80 type PostOrderResponseToken struct {
     81 	// Token that authorizes the wallet to claim the order.
     82 	// Provided only if "create_token" was set to 'true'
     83 	// in the request.
     84 	Token string
     85 }
     86 
     87 type CheckPaymentStatusResponse struct {
     88 	// Status of the order
     89 	OrderStatus string `json:"order_status"`
     90 }
     91 
     92 type CheckPaymentPaytoResponse struct {
     93 	// Status of the order
     94 	TalerPayUri string `json:"taler_pay_uri"`
     95 }
     96 
     97 type Merchant struct {
     98 
     99 	// The host of this merchant
    100 	BaseUrlPrivate string
    101 
    102 	// The access token to use for the private API
    103 	AccessToken string
    104 }
    105 
    106 func NewMerchant(merchBaseUrlPrivate string, merchAccessToken string) Merchant {
    107 	return Merchant{
    108 		BaseUrlPrivate: merchBaseUrlPrivate,
    109 		AccessToken:    merchAccessToken,
    110 	}
    111 }
    112 
    113 func (m *Merchant) IsOrderPaid(orderId string) (string, error) {
    114 	var orderPaidResponse CheckPaymentStatusResponse
    115 	var paytoResponse CheckPaymentPaytoResponse
    116 	client := &http.Client{}
    117 	req, _ := http.NewRequest("GET", m.BaseUrlPrivate+"/private/orders/"+orderId, nil)
    118 	req.Header.Set("Authorization", "Bearer secret-token:"+m.AccessToken)
    119 	resp, err := client.Do(req)
    120 	fmt.Println(req)
    121 	if nil != err {
    122 		return "", err
    123 	}
    124 	defer resp.Body.Close()
    125 	if http.StatusOK != resp.StatusCode {
    126 		message := fmt.Sprintf("Expected response code %d. Got %d", http.StatusOK, resp.StatusCode)
    127 		return "", errors.New(message)
    128 	}
    129 	respData, err := ioutil.ReadAll(resp.Body)
    130 	if err != nil {
    131 		return "", err
    132 	}
    133 	err = json.NewDecoder(bytes.NewReader(respData)).Decode(&orderPaidResponse)
    134 	if err != nil {
    135 		return "", err
    136 	}
    137 	if orderPaidResponse.OrderStatus != "paid" {
    138 		err = json.NewDecoder(bytes.NewReader(respData)).Decode(&paytoResponse)
    139 		return paytoResponse.TalerPayUri, err
    140 	}
    141 	return "", nil
    142 }
    143 
    144 func (m *Merchant) AddNewOrder(cost util.Amount, summary string, fulfillment_url string) (string, error) {
    145 	var newOrder PostOrderRequest
    146 	var orderDetail MinimalOrderDetail
    147 	var orderResponse PostOrderResponse
    148 	orderDetail.Amount = cost.String()
    149 	// FIXME get from cfg
    150 	orderDetail.Summary = summary
    151 	orderDetail.FulfillmentUrl = fulfillment_url
    152 	newOrder.Order = orderDetail
    153 	reqString, err := json.Marshal(newOrder)
    154 	if nil != err {
    155 		return "", err
    156 	}
    157 	client := &http.Client{}
    158 	req, _ := http.NewRequest(http.MethodPost, m.BaseUrlPrivate+"/private/orders", bytes.NewReader(reqString))
    159 	req.Header.Set("Authorization", "Bearer secret-token:"+m.AccessToken)
    160 	resp, err := client.Do(req)
    161 
    162 	if nil != err {
    163 		return "", err
    164 	}
    165 	defer resp.Body.Close()
    166 	if http.StatusOK != resp.StatusCode {
    167 		message := fmt.Sprintf("Expected response code %d. Got %d. With request %s", http.StatusOK, resp.StatusCode, reqString)
    168 		return "", errors.New(message)
    169 	}
    170 	err = json.NewDecoder(resp.Body).Decode(&orderResponse)
    171 	return orderResponse.OrderId, err
    172 }