github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/mobile/mysterium/payment_orders.go (about)

     1  /*
     2   * Copyright (C) 2021 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package mysterium
    19  
    20  import (
    21  	"encoding/json"
    22  	"strings"
    23  
    24  	"github.com/mysteriumnetwork/node/identity"
    25  	"github.com/mysteriumnetwork/node/pilvytis"
    26  	"github.com/mysteriumnetwork/payments/exchange"
    27  )
    28  
    29  // PaymentOrderResponse represents a payment order for mobile usage.
    30  type PaymentOrderResponse struct {
    31  	ID                string          `json:"id"`
    32  	Status            string          `json:"status"`
    33  	IdentityAddress   string          `json:"identity"`
    34  	ChannelAddress    string          `json:"channel_address"`
    35  	Gateway           string          `json:"gateway"`
    36  	ReceiveMYST       string          `json:"receive_myst"`
    37  	PayAmount         string          `json:"pay_amount"`
    38  	PayCurrency       string          `json:"pay_currency"`
    39  	Country           string          `json:"country"`
    40  	Currency          string          `json:"currency"`
    41  	ItemsSubTotal     string          `json:"items_sub_total"`
    42  	TaxRate           string          `json:"tax_rate"`
    43  	TaxSubTotal       string          `json:"tax_sub_total"`
    44  	OrderTotal        string          `json:"order_total"`
    45  	PublicGatewayData json.RawMessage `json:"public_gateway_data"`
    46  }
    47  
    48  func newPaymentOrderResponse(r pilvytis.GatewayOrderResponse) PaymentOrderResponse {
    49  	return PaymentOrderResponse{
    50  		ID:                r.ID,
    51  		Status:            r.Status.Status(),
    52  		IdentityAddress:   r.Identity,
    53  		ChannelAddress:    r.ChannelAddress,
    54  		Gateway:           r.GatewayName,
    55  		ReceiveMYST:       r.ReceiveMYST,
    56  		PayAmount:         r.PayAmount,
    57  		PayCurrency:       r.PayCurrency,
    58  		Country:           r.Country,
    59  		Currency:          r.Currency,
    60  		ItemsSubTotal:     r.ItemsSubTotal,
    61  		TaxRate:           r.TaxRate,
    62  		TaxSubTotal:       r.TaxSubTotal,
    63  		OrderTotal:        r.OrderTotal,
    64  		PublicGatewayData: r.PublicGatewayData,
    65  	}
    66  }
    67  
    68  // GetPaymentOrderRequest a request to get an order.
    69  type GetPaymentOrderRequest struct {
    70  	IdentityAddress string
    71  	ID              string
    72  }
    73  
    74  // GetPaymentGatewayOrder gets an order by ID.
    75  func (mb *MobileNode) GetPaymentGatewayOrder(req *GetPaymentOrderRequest) ([]byte, error) {
    76  	order, err := mb.pilvytis.GetPaymentGatewayOrder(identity.FromAddress(req.IdentityAddress), req.ID)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	res := newPaymentOrderResponse(*order)
    82  
    83  	return json.Marshal(res)
    84  }
    85  
    86  // GetPaymentGatewayOrderInvoice gets the invoice for an order.
    87  func (mb *MobileNode) GetPaymentGatewayOrderInvoice(req *GetPaymentOrderRequest) ([]byte, error) {
    88  	return mb.pilvytis.GetPaymentGatewayOrderInvoice(identity.FromAddress(req.IdentityAddress), req.ID)
    89  }
    90  
    91  // GatewaysResponse represents a respose which cointains gateways and their data.
    92  type GatewaysResponse struct {
    93  	Name         string              `json:"name"`
    94  	OrderOptions PaymentOrderOptions `json:"order_options"`
    95  	Currencies   []string            `json:"currencies"`
    96  }
    97  
    98  // PaymentOrderOptions are the suggested and minimum myst amount options for a gateway.
    99  type PaymentOrderOptions struct {
   100  	Minimum   float64   `json:"minimum"`
   101  	Suggested []float64 `json:"suggested"`
   102  }
   103  
   104  func newGatewayReponse(g []pilvytis.GatewaysResponse) []GatewaysResponse {
   105  	result := make([]GatewaysResponse, len(g))
   106  	for i, v := range g {
   107  		entry := GatewaysResponse{
   108  			Name: v.Name,
   109  			OrderOptions: PaymentOrderOptions{
   110  				Minimum:   v.OrderOptions.Minimum,
   111  				Suggested: v.OrderOptions.Suggested,
   112  			},
   113  			Currencies: v.Currencies,
   114  		}
   115  		result[i] = entry
   116  	}
   117  	return result
   118  }
   119  
   120  // GetGatewaysRequest request for GetGateways.
   121  type GetGatewaysRequest struct {
   122  	OptionsCurrency string
   123  }
   124  
   125  // GetGateways returns possible payment gateways.
   126  func (mb *MobileNode) GetGateways(req *GetGatewaysRequest) ([]byte, error) {
   127  	gateways, err := mb.pilvytis.GetPaymentGateways(exchange.Currency(req.OptionsCurrency))
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  
   132  	return json.Marshal(gateways)
   133  }
   134  
   135  // CreatePaymentGatewayOrderReq is used to create a new order.
   136  type CreatePaymentGatewayOrderReq struct {
   137  	IdentityAddress string
   138  	Gateway         string
   139  	MystAmount      string
   140  	AmountUSD       string
   141  	PayCurrency     string
   142  	Country         string
   143  	State           string
   144  	// GatewayCallerData is marshaled json that is accepting by the payment gateway.
   145  	GatewayCallerData []byte
   146  }
   147  
   148  // CreatePaymentGatewayOrder creates a payment order.
   149  func (mb *MobileNode) CreatePaymentGatewayOrder(req *CreatePaymentGatewayOrderReq) ([]byte, error) {
   150  	if req.Country == "" {
   151  		org := mb.locationResolver.GetOrigin()
   152  		req.Country = strings.ToUpper(org.Country)
   153  	}
   154  
   155  	order, err := mb.pilvytisOrderIssuer.CreatePaymentGatewayOrder(
   156  		pilvytis.GatewayOrderRequest{Identity: identity.FromAddress(req.IdentityAddress),
   157  			Gateway:     req.Gateway,
   158  			MystAmount:  req.MystAmount,
   159  			AmountUSD:   req.AmountUSD,
   160  			PayCurrency: req.PayCurrency,
   161  			Country:     req.Country,
   162  			State:       req.State,
   163  			CallerData:  req.GatewayCallerData,
   164  		},
   165  	)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  
   170  	res := newPaymentOrderResponse(*order)
   171  
   172  	return json.Marshal(res)
   173  }
   174  
   175  // ListOrdersRequest a request to list orders.
   176  type ListOrdersRequest struct {
   177  	IdentityAddress string
   178  }
   179  
   180  // ListPaymentGatewayOrders lists all payment orders.
   181  func (mb *MobileNode) ListPaymentGatewayOrders(req *ListOrdersRequest) ([]byte, error) {
   182  	orders, err := mb.pilvytis.GetPaymentGatewayOrders(identity.FromAddress(req.IdentityAddress))
   183  	if err != nil {
   184  		return nil, err
   185  	}
   186  
   187  	res := make([]PaymentOrderResponse, len(orders))
   188  
   189  	for i := range orders {
   190  		orderRes := newPaymentOrderResponse(orders[i])
   191  
   192  		res[i] = orderRes
   193  	}
   194  
   195  	return json.Marshal(orders)
   196  }
   197  
   198  // GatewayClientCallbackReq is the payload for GatewayClientCallback.
   199  type GatewayClientCallbackReq struct {
   200  	IdentityAddress     string
   201  	Gateway             string
   202  	GooglePurchaseToken string
   203  	GoogleProductID     string
   204  }
   205  
   206  // GatewayClientCallback triggers payment callback for google from client side.
   207  func (mb *MobileNode) GatewayClientCallback(req *GatewayClientCallbackReq) error {
   208  	payload := struct {
   209  		PurchaseToken   string `json:"purchase_token"`
   210  		GoogleProductID string `json:"google_product_id"`
   211  	}{
   212  		PurchaseToken:   req.GooglePurchaseToken,
   213  		GoogleProductID: req.GoogleProductID,
   214  	}
   215  	return mb.pilvytis.GatewayClientCallback(identity.FromAddress(req.IdentityAddress), req.Gateway, payload)
   216  }
   217  
   218  // OrderUpdatedCallbackPayload is the payload of OrderUpdatedCallback.
   219  type OrderUpdatedCallbackPayload struct {
   220  	OrderID     string
   221  	Status      string
   222  	PayAmount   string
   223  	PayCurrency string
   224  }
   225  
   226  // OrderUpdatedCallback is a callback when order status changes.
   227  type OrderUpdatedCallback interface {
   228  	OnUpdate(payload *OrderUpdatedCallbackPayload)
   229  }
   230  
   231  // RegisterOrderUpdatedCallback registers OrderStatusChanged callback.
   232  func (mb *MobileNode) RegisterOrderUpdatedCallback(cb OrderUpdatedCallback) {
   233  	_ = mb.eventBus.SubscribeAsync(pilvytis.AppTopicOrderUpdated, func(e pilvytis.AppEventOrderUpdated) {
   234  		payload := OrderUpdatedCallbackPayload{}
   235  		payload.OrderID = e.ID
   236  		payload.Status = e.Status.Status()
   237  		payload.PayAmount = e.PayAmount
   238  		payload.PayCurrency = e.PayCurrency
   239  		cb.OnUpdate(&payload)
   240  	})
   241  }
   242  
   243  // ExchangeRate returns MYST rate in quote currency.
   244  func (mb *MobileNode) ExchangeRate(quote string) (float64, error) {
   245  	return mb.pilvytis.GetMystExchangeRateFor(quote)
   246  }