package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" "os" "strings" "time" ) type Capture struct { ID string `json:"id"` Status string `json:"status"` PurchaseUnits []struct { Payments struct { Captures []struct { ID string `json:"id"` Status string `json:"status"` Amount struct { CurrencyCode string `json:"currency_code"` Value string `json:"value"` } `json:"amount"` CreateTime time.Time `json:"create_time"` } `json:"captures"` } `json:"payments"` } `json:"purchase_units"` Payer struct { Name struct { GivenName string `json:"given_name"` Surname string `json:"surname"` } `json:"name"` EmailAddress string `json:"email_address"` Phone struct { PhoneType string `json:"phone_type"` PhoneNumber struct { NationalNumber string `json:"national_number"` } `json:"phone_number"` } `json:"phone"` Address struct { CountryCode string `json:"country_code"` } `json:"address"` } `json:"payer"` } func Token() (string, error) { req, err := http.NewRequest("POST", os.Getenv("BASE_URL")+"/v1/oauth2/token", strings.NewReader(`grant_type=client_credentials`)) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.SetBasicAuth(os.Getenv("CLIENT_ID"), os.Getenv("CLIENT_SECRET")) raw, err := http.DefaultClient.Do(req) if err != nil { return "", fmt.Errorf("Error sending request: %v", err) } defer raw.Body.Close() var response struct { AccessToken string `json:"access_token"` } if err := json.NewDecoder(raw.Body).Decode(&response); err != nil { return "", fmt.Errorf("Error decoding response: %v", err) } return response.AccessToken, nil } func CreateOrder(w http.ResponseWriter, r *http.Request) { token, err := Token() if err != nil { http.Error(w, "Failed to get access token", http.StatusInternalServerError) return } type Amount struct { CurrencyCode string `json:"currency_code"` Value string `json:"value"` } type PurchaseUnits struct { Amount Amount `json:"amount"` } type Address struct { CountryCode string `json:"country_code"` } type Paypal struct { Address Address `json:"address"` } type PaymentSource struct { Paypal Paypal `json:"paypal"` } type ApplicationContext struct { ShippingPreference string `json:"shipping_preference"` } type Order struct { Intent string `json:"intent"` PurchaseUnits []PurchaseUnits `json:"purchase_units"` PaymentSource PaymentSource `json:"payment_source"` ApplicationContext ApplicationContext `json:"application_context"` } // This payload will fill out defaults in PayPal // checkout window (CR code, no shipping, etc) order := Order{ Intent: "CAPTURE", PurchaseUnits: []PurchaseUnits{{Amount: Amount{ CurrencyCode: "USD", Value: os.Getenv("PRICE"), }}}, PaymentSource: PaymentSource{Paypal: Paypal{Address: Address{ CountryCode: "CR", }}}, ApplicationContext: ApplicationContext{ ShippingPreference: "NO_SHIPPING", }, } payload, err := json.Marshal(order) req, err := http.NewRequest("POST", os.Getenv("BASE_URL")+"/v2/checkout/orders", bytes.NewBuffer(payload)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+token) raw, err := http.DefaultClient.Do(req) if err != nil { http.Error(w, "Failed to send request", http.StatusInternalServerError) return } defer raw.Body.Close() var response struct { ID string `json:"id"` } if err := json.NewDecoder(raw.Body).Decode(&response); err != nil { http.Error(w, "Failed to decode response", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(response) return } func CaptureOrder(w http.ResponseWriter, r *http.Request) { info, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "Failed to read request body", http.StatusInternalServerError) return } var cart struct { Directory string `json:"directory"` EditorData json.RawMessage `json:"editor_data"` } err = json.Unmarshal(info, &cart) if err != nil { http.Error(w, "Failed to parse request body", http.StatusBadRequest) return } directory := cart.Directory editorData := cart.EditorData if err != nil { http.Error(w, "Failed to parse request body", http.StatusBadRequest) return } path := strings.TrimPrefix(r.URL.Path, "/api/orders/") parts := strings.Split(path, "/") orderID := parts[0] if orderID == "" { http.Error(w, "Failed to get orderID from client URL", http.StatusInternalServerError) return } token, err := Token() if err != nil { http.Error(w, "Failed to get access token", http.StatusInternalServerError) return } req, err := http.NewRequest("POST", os.Getenv("BASE_URL")+"/v2/checkout/orders/"+orderID+"/capture", nil) req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Content-Type", "application/json") raw, err := http.DefaultClient.Do(req) if err != nil { http.Error(w, "Failed to send request", http.StatusInternalServerError) return } defer raw.Body.Close() body, err := io.ReadAll(raw.Body) if err != nil { http.Error(w, "Failed to read response body", http.StatusInternalServerError) return } var capture Capture if err := json.Unmarshal(body, &capture); err != nil { http.Error(w, "Failed to decode response into capture", http.StatusInternalServerError) return } var receipt = struct { PurchaseUnits []struct { Payments struct { Captures []struct { ID string `json:"id"` Status string `json:"status"` } `json:"captures"` } `json:"payments"` } `json:"purchase_units"` }{} if err := json.Unmarshal(body, &receipt); err != nil { http.Error(w, "Failed to decode response into receipt", http.StatusInternalServerError) return } RegisterSite(capture, directory, editorData) w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(receipt); err != nil { http.Error(w, "Failed to encode response", http.StatusInternalServerError) return } return }