mirror of
https://github.com/tavo-wasd-gh/conex-builder.git
synced 2025-06-07 04:03:29 -06:00
subscriptions in progress
This commit is contained in:
parent
59ea41ed74
commit
38c6523fbf
3 changed files with 179 additions and 4 deletions
117
main.go
117
main.go
|
@ -28,6 +28,47 @@ type OrderData struct {
|
||||||
} `json:"purchase_units"`
|
} `json:"purchase_units"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SubscriptionData struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
// StatusUpdateTime time.Time `json:"status_update_time"`
|
||||||
|
PlanID string `json:"plan_id"`
|
||||||
|
PlanOverridden bool `json:"plan_overridden"`
|
||||||
|
// StartTime time.Time `json:"start_time"`
|
||||||
|
Quantity string `json:"quantity"`
|
||||||
|
ShippingAmount struct {
|
||||||
|
CurrencyCode string `json:"currency_code"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
} `json:"shipping_amount"`
|
||||||
|
Subscriber struct {
|
||||||
|
Name struct {
|
||||||
|
GivenName string `json:"given_name"`
|
||||||
|
Surname string `json:"surname"`
|
||||||
|
} `json:"name"`
|
||||||
|
EmailAddress string `json:"email_address"`
|
||||||
|
PayerID string `json:"payer_id"`
|
||||||
|
ShippingAddress struct {
|
||||||
|
Name struct {
|
||||||
|
FullName string `json:"full_name"`
|
||||||
|
} `json:"name"`
|
||||||
|
Address struct {
|
||||||
|
AddressLine1 string `json:"address_line_1"`
|
||||||
|
AddressLine2 string `json:"address_line_2"`
|
||||||
|
AdminArea2 string `json:"admin_area_2"`
|
||||||
|
AdminArea1 string `json:"admin_area_1"`
|
||||||
|
PostalCode string `json:"postal_code"`
|
||||||
|
CountryCode string `json:"country_code"`
|
||||||
|
} `json:"address"`
|
||||||
|
} `json:"shipping_address"`
|
||||||
|
} `json:"subscriber"`
|
||||||
|
// CreateTime time.Time `json:"create_time"`
|
||||||
|
Links []struct {
|
||||||
|
Href string `json:"href"`
|
||||||
|
Rel string `json:"rel"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
} `json:"links"`
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
baseURL = "https://api-m.sandbox.paypal.com"
|
baseURL = "https://api-m.sandbox.paypal.com"
|
||||||
)
|
)
|
||||||
|
@ -42,6 +83,7 @@ func main() {
|
||||||
// Handlers
|
// Handlers
|
||||||
http.HandleFunc("/api/orders", CreateOrder)
|
http.HandleFunc("/api/orders", CreateOrder)
|
||||||
http.HandleFunc("/api/orders/", CaptureOrder)
|
http.HandleFunc("/api/orders/", CaptureOrder)
|
||||||
|
http.HandleFunc("/api/paypal/create-subscription", CreateSubscription)
|
||||||
http.Handle("/", http.FileServer(http.Dir("./public")))
|
http.Handle("/", http.FileServer(http.Dir("./public")))
|
||||||
|
|
||||||
// Channel to listen for signals
|
// Channel to listen for signals
|
||||||
|
@ -178,5 +220,80 @@ func CaptureOrder(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
if err := json.NewEncoder(w).Encode(result); err != nil {
|
if err := json.NewEncoder(w).Encode(result); err != nil {
|
||||||
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
|
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CreateSubscription(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("asked to create sub")
|
||||||
|
|
||||||
|
planID := os.Getenv("PLAN_ID")
|
||||||
|
returnUrl := "https://suckless.org"
|
||||||
|
cancelUrl := "https://suckless.org"
|
||||||
|
|
||||||
|
log.Printf("This is the planid: %s", planID)
|
||||||
|
|
||||||
|
token, err := Token()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Failed to get access token", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("This is the token: %s", token)
|
||||||
|
|
||||||
|
body := map[string]interface{}{
|
||||||
|
"plan_id": planID,
|
||||||
|
"application_context": map[string]string{
|
||||||
|
"shipping_preference": "NO_SHIPPING",
|
||||||
|
"return_url": returnUrl,
|
||||||
|
"cancel_url": cancelUrl,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
jsonData, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Creating request")
|
||||||
|
req, err := http.NewRequest("POST", baseURL+"/v1/billing/subscriptions", bytes.NewBuffer(jsonData))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Failed to create request", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("Authorization", "Bearer "+token)
|
||||||
|
req.Header.Set("Accept", "application/json")
|
||||||
|
req.Header.Set("Prefer", "return=representation")
|
||||||
|
|
||||||
|
log.Printf("Sending request")
|
||||||
|
client := &http.Client{}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Failed to send request", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
log.Printf("Request sent")
|
||||||
|
|
||||||
|
// Create an instance of AutoGenerated
|
||||||
|
// var result SubscriptionData
|
||||||
|
var result map[string]interface{}
|
||||||
|
|
||||||
|
// Decode the response into the AutoGenerated struct
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||||
|
http.Error(w, "Failed to decode response", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("Raw JSON Response: %v", result)
|
||||||
|
|
||||||
|
// Now, `result` contains the entire structured response
|
||||||
|
// You can send the whole `result` back to the client, or you can selectively send fields.
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
if err := json.NewEncoder(w).Encode(result); err != nil {
|
||||||
|
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
log.Printf("sent response to client")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -145,6 +145,63 @@ window.paypal_order.Buttons({
|
||||||
},
|
},
|
||||||
}).render("#paypal-button-container-order");
|
}).render("#paypal-button-container-order");
|
||||||
|
|
||||||
|
window.paypal_subscribe.Buttons({
|
||||||
|
style: { shape: 'pill', color: 'black', layout: 'vertical', label: 'subscribe' },
|
||||||
|
async createSubscription() {
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/paypal/create-subscription", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ userAction: "SUBSCRIBE_NOW" }),
|
||||||
|
});
|
||||||
|
const data = await response.json();
|
||||||
|
if (data?.id) {
|
||||||
|
resultMessage(`Successful subscription with ID ${data.id}...<br><br>`);
|
||||||
|
return data.id;
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
{ callback: "createSubscription", serverResponse: data },
|
||||||
|
JSON.stringify(data, null, 2),
|
||||||
|
);
|
||||||
|
// (Optional) The following hides the button container and shows a message about why checkout can't be initiated
|
||||||
|
const errorDetail = data?.details?.[0];
|
||||||
|
resultMessage(
|
||||||
|
`Could not initiate PayPal Subscription...<br><br>${
|
||||||
|
errorDetail?.issue || ""
|
||||||
|
} ${errorDetail?.description || data?.message || ""} ` +
|
||||||
|
(data?.debug_id ? `(${data.debug_id})` : ""),
|
||||||
|
{ hideButtons: true },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const approvalUrl = data.links.find(link => link.rel === "approve").href;
|
||||||
|
window.location.href = approvalUrl;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
resultMessage(
|
||||||
|
`Could not initiate PayPal Subscription...<br><br>${error}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onApprove(data) {
|
||||||
|
/*
|
||||||
|
No need to activate manually since SUBSCRIBE_NOW is being used.
|
||||||
|
Learn how to handle other user actions from our docs:
|
||||||
|
https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_create
|
||||||
|
*/
|
||||||
|
if (data.orderID) {
|
||||||
|
resultMessage(
|
||||||
|
`You have successfully subscribed to the plan. Your subscription id is: ${data.subscriptionID}`,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
resultMessage(
|
||||||
|
`Failed to activate the subscription: ${data.subscriptionID}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}).render("#paypal-button-container-subscribe"); // Renders the PayPal button
|
||||||
|
|
||||||
// Example function to show a result to the user. Your site's UI library can be used instead.
|
// Example function to show a result to the user. Your site's UI library can be used instead.
|
||||||
function resultMessage(message) {
|
function resultMessage(message) {
|
||||||
const container = document.querySelector("#checkout");
|
const container = document.querySelector("#checkout");
|
||||||
|
|
|
@ -29,10 +29,10 @@
|
||||||
src="https://www.paypal.com/sdk/js?client-id=AcCW43LI1S6lLQgtLkF4V8UOPfmXcqXQ8xfEl41hRuMxSskR2jkWNwQN6Ab1WK7E2E52GNaoYBHqgIKd&components=buttons&enable-funding=card&disable-funding=paylater,venmo"
|
src="https://www.paypal.com/sdk/js?client-id=AcCW43LI1S6lLQgtLkF4V8UOPfmXcqXQ8xfEl41hRuMxSskR2jkWNwQN6Ab1WK7E2E52GNaoYBHqgIKd&components=buttons&enable-funding=card&disable-funding=paylater,venmo"
|
||||||
data-namespace="paypal_order"
|
data-namespace="paypal_order"
|
||||||
></script>
|
></script>
|
||||||
<!-- <script -->
|
<script
|
||||||
<!-- src="" -->
|
src="https://www.paypal.com/sdk/js?client-id=AcCW43LI1S6lLQgtLkF4V8UOPfmXcqXQ8xfEl41hRuMxSskR2jkWNwQN6Ab1WK7E2E52GNaoYBHqgIKd&components=buttons&vault=true&intent=subscription&enable-funding=card&disable-funding=paylater"
|
||||||
<!-- data-namespace="paypal_subscribe" -->
|
data-namespace="paypal_subscribe"
|
||||||
<!-- ></script> -->
|
></script>
|
||||||
</head>
|
</head>
|
||||||
<form action="submit.php" id="mainForm" method="post">
|
<form action="submit.php" id="mainForm" method="post">
|
||||||
<div class="banner" style="background-image: url(/static/banner.jpg);">
|
<div class="banner" style="background-image: url(/static/banner.jpg);">
|
||||||
|
@ -82,6 +82,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="paypal-button-container">
|
<div id="paypal-button-container">
|
||||||
<div id="paypal-button-container-order"></div>
|
<div id="paypal-button-container-order"></div>
|
||||||
|
<div id="paypal-button-container-subscribe"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue