NextJs Stripe Subscription with subscription end date - next.js

I have generated some products in stripe configured as recurring payment and i can subscribe to them without problem.
I would like to know if it is possible from the same call that is made to generate the subscription it is possible to indicate the end date of this subscription.
Researching the documentation I see that they talk about "cancel_at" but I can't find where to indicate this parameter in the call. I haven't been able to locate any examples either.
const session = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
line_items: [
{
price: "price_1LaMHQH4AS5eXWlNhznAR7JA",
quantity: 1
},
],
mode: 'subscription',
success_url:`${req.headers.origin}/public/payment?success=true`,
cancel_url: `${req.headers.origin}/public/payment?cancelled=true`
});

You cannot provide an end date for a Subscription in a Checkout Session.
What you can do instead is to listen for the checkout.session.completed webhook event. This event will contain the subscription id and upon receipt of the event, you can make a request to update that Subscription's cancel_at.

Related

Can I use "dataLayer" code to capture "purchase" events from backend of website when batch processing orders / membership fees?

Is it possible to use dataLayer code on my website to capture monthly membership plan fees? My website processes this automatically and charges my customers credit card, so would I be able to have my developer add this code so when each customer's credit card is charged this dataLayer will execute?
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: "purchase",
ecommerce: {
transaction_id: "{invoice_id}",
value: {billable_amount},
currency: "USD",
items: [
{
item_id: "{invoice_id}",
item_name: "Membership Plan Fee",
price: {billable_amount}
}]
}
});
</script>
Would this also work if I batch process orders on the backend of my website, where a similar dataLayer would fire for each order that is processed?
Would I need to add GTM tracking code to the admin/backend of my website for this to work?
Thank you!
I ended up finding what I need to use to accomplish this; I guess Google calls it Measurement Protocols for sending events server-to-server.
Measurement Protocols - Sending Events Server to Server

WooCommerce REST API: Gateway does not support admin changing the payment method on a Subscription

I am using WooCommerce Subscription REST API to extend the subscription of the user. The problem that I have is that when I want to update expire time I get this error:
Gateway does not support admin changing the payment method on a Subscription
Does someone know where is the problem?
I am using the following code to update the subscription expire time:
return $this->guzzleClient->request('PUT', 'wp-json/wc/v1/subscriptions/'.$id, [
'json' => [
'end_date' => $endDate->toDateTimeString(),
'status' => 'active',
]
]);
We ran into a similar issue. Instead of passing the whole subscription object back, we instead only passed the necessary information (in our case we wanted to add to the coupon_lines field).
Our resulting payload looked like:
{
coupon_lines: [
{
code: "sample-code",
amount: "10.00"
}
]
}

How to properly configure Amplify Analytics?

I need some help understanding how to configure AWS Pinpoint analytics in Amplify. I'm currently using Amplify for Auth and have it configured like this in my index.js file:
export const configureAmplify = () => {
window.LOG_LEVEL="DEBUG"
Hub.listen('auth', data => handleAmplifyHubEvent(data))
Hub.listen('analytics', data => handleAmplifyHubEvent(data))
Amplify.configure({
Auth: {
identityPoolId: "redacted",
region: "us-west-2",
userPoolId: "redacted",
userPoolWebClientId: "redacted",
mandatorySignIn: false,
cookieStorage: {
domain: process.env.NODE_ENV === 'development' ? "localhost" : "redacted",
path: '/',
expires: 1,
secure: false
}
}
})
}
To add Analytics, I started by adding this to my configureAmplify() function:
Analytics: {
disabled: false,
autoSessionRecord: true,
AWSPinpoint: {
appId: 'redacted',
region: 'us-east-1',
endpointId: `wgc-default`,
bufferSize: 1000,
flushInterval: 5000, // 5s
flushSize: 100,
resendLimit: 5
}
}
Upon user sign-in or refresh from cookie storage I called
Analytics.updateEndpoint({
address: user.attributes.email, // The unique identifier for the recipient. For example, an address could be a device token, email address, or mobile phone number.
attributes: {
},
channelType: 'EMAIL', // The channel type. Valid values: APNS, GCM
optOut: 'ALL',
userId: user.attributes.sub,
userAttributes: {
}
})
After doing this, it seems to me that the data in the Pinpoint console is not accurate. For example, there are currently 44 sessions displayed when no endpoint filter is applied. If I add an endpoint filter by userAttributes: userId then no matter which ID I select, it shows all 44 sessions associated with that user. I suspect that is because the EndpointID is established at startup, and is not changed by the updateEndpoint call.
I have also tried omitting the Analytics key when I initially configure Amplify, and then calling Analytics.configure() after the user is signed in. With this approach, I can construct a user-specific endpointId. However, I think that doing it this way will mean that I don't capture any of the Authentication events (sign-in, sign-up, auth failure), because Analytics is not configured until after they occur.
So my question is what is the proper timing for configuring Amplify Analytics? How can I accurately capture session, auth and custom events, AND uniquely identify them by user id?
It's not necessary to assign a custom endpoint id, amplify will handle it automatically and all events will be tracked per device. Instead, if you really need it, update the endpoint with the userId after sign-in.
The advantage of adding the userId is that all the endpointIds of a user are automatically associated to that userId, thus when you update a user's attribute, it will be synchronized across the endpoints.
As you are using Cognito, Amazon Cognito can add user IDs and attributes to your endpoints automatically. For the endpoint user ID value, Amazon Cognito assigns the sub value that's assigned to the user in the user pool. To learn about adding users with Amazon Cognito, see Using Amazon Pinpoint Analytics with Amazon Cognito User Pools in the Amazon Cognito Developer Guide.

Error trying to test tokenized payments

CONTEXT
I'm writing a custom checkout process using tokenized payments inside a WebView since I need to use payments outside US.
I'm using this code, based on this facebook guide, to ask for the user's credit card info.
const saveThis = this
MessengerExtensions.requestPaymentCredentials(
function success(name, email, cardType, cardLastFourDigits, shippingAddress) {
console.log('success getting user payment info', cardLastFourDigits)
saveThis.printAsyncData(cardType)
},
function error(err, errorMessage) {
console.log('error trying to get user payment info', errorMessage)
saveThis.printAsyncData(errorMessage)
},
['CONTACT_NAME', 'CONTACT_EMAIL', 'CONTACT_PHONE', 'SHIPPING_ADDRESS']
);
CONSIDERATIONS
saveThis.printAsyncData() function is a workaround to log the
output in mobile devices so I can debug the code, since payments
don't work using the Messenger web client.
I'm testing this chatbot with my facebook account which is the one having the chatbot's Administrator role.
Administrator user returns the profile property is_payment_enabled: true
OUTPUT
I'm getting the following error: "An unexpected error has occured.24002". In the facebook's error reference, 24002 means "Payment request cannot be processed due to missing privacy url".
QUESTION
Does that mean that I have to provide a privacy policy URL to test payments even when I'm using the Administrator's chatbot account in a testing environment??
UPDATE
As suggested, I implemented the updated WebView payment code as follows:
const methodData = [{
supportedMethods: ['fb'], //only 'fb' is supported
data: {
merchantTitle: 'Merchant name', // optional, defaults to the Facebook Page name
merchantImageUrl: 'imageURL', //optional, defaults to the app icon
confirmationText: 'Thank you!', // optional, defaults to "Thank you for your payment"
merchantFBPageId: '28636603843****', // page id with onboarded payment method. Need to be the same with the page id in thread or messenger extension
termsUrl: 'https://www.facebook.com/' // Merchant payment privacy terms and conditions.
}
}]
const paymentDetails = {
displayItems: [ //array of items being charged for
{
label: 'T-shirt',
amount: {
currency: 'USD',
value : '15.00'
}
}
],
total: {
label: 'Total', // defaults to "Total"
amount: {
currency: 'USD',
value : '16.23'
}
},
shippingOptions: [ // Optional. Array of options for user to select
{
id: 'free-shipping', // custom ID
label: 'Free shipping in US', //human-readable name
amount: {currency: 'USD', value: '0.00'},
selected: true
}
]
}
const additionalOptions = {
requestShipping: false, // If shipping is required. If true, handle shippingoptionchange and shippingaddresschange events.
requestPayerName: true, // Name of the payer sent with the final response
requestPayerEmail: true, // Email address, same as above
requestPayerPhone: false // Phone number, same as above
}
let request = new this.messengerExtensions.PaymentRequest(
methodData, // array of payment methods and their setup
paymentDetails, // array of items, total, shipping options
additionalOptions, // request shipping information, payee email address, etc
);
request.canMakePayment()
.then(response => {
this.printAsyncData(response + ' from canMakePayment')
if (response === true) {
// proceed
} else {
// something went wrong, e.g. invalid `displayItems` configuration
// or the device does not run a
// recent enough version of the Facebook app
}
})
.catch(error => {
this.printAsyncData(error+' error from canMakePayment')
// an error such as `InvalidStateError`
// if a payment is already in process
});
This suggested implementation returns the variable response as false. Each configuration variable is copied from this link. I changed the MerchantPageID with the PageID I found on my Chatbot's fb page > Information, so I don't think this could be the problem. I checked the Messenger's version of my Android device and is the latest, being the 147.0.0.25.86 one.
I even tried to implement the payment dialog as follows just to see how it behaves.
request.show().then(response => {
// Process the payment if using tokenized payments.
// Process the confirmation if using Stripe/PayPal
this.printAsyncData(response)
// paymentResponse.complete('success').then(() => {
// // cleanup UI, log, etc
// });
}).catch(error => this.printAsyncData(error+'from show()'));
Payment dialog pops over nicely. It shows user's name and email but under the METHOD PAYMENT header it shows a loading spinner indefinitely. Moreover, .show() never triggers the callback thus not allowing to print its response on the line before paymentResponse.complete('success').
UPDATE 2
I've got the supported features with the following code to try to get some clue of what I'm missing
const saveThis = this
MessengerExtensions.getSupportedFeatures(function success(result) {
var features = result.supported_features;
saveThis.printAsyncData(features)
}, function error(err, errorMessage) {
saveThis.printAsyncData(errorMessage)
});
This is the output on my android messenger client:
["sharing_broadcast","sharing_direct", "sharing_open_graph", "permissions", "thread_context", "context", "sharing_media_template"]
There is no "payments" as it should be, based on this reference
Yes, but since you are just testing it can be any URL. Once you submit your bot for approval it will need to point to a real privacy policy.
You are also using the deprecated version of payments. For webview payments you should use PaymentRequest which is explained here:
https://developers.facebook.com/docs/messenger-platform/payments/webview-payments

How to approach Redux + Microservices intercommunication

We are implementing an auction cloud service, that will receive orders, from an external API service on demand. Each received order is a 1:1 to an auction.
We can have more than 2000 orders (auctions) per day.
we have decided to use Microservices + Redux to separate concerns between orders and auctions.
Bellow are the explanation of each service.
External API
Enternal API is just a website that pushes orders to our Order Service and receive updates from our Order service we have no control over it.
Order service
Orders has a bunch of information (properties) that the client (mobile app) use to get information to decide on joining an auction. for example, this is how an order can look like:
{
id: 123,
description: 'Some description',
salePrice: 0,
minPrice: 1000,
openPrice: 500,
status: 'active',
address: 'Some address',
file: '.../some-file.pdf',
client: 'Joe Doe',
notes: 'Some notes',
createdAt: '12345678',
pending: false,
postpone: false,
...moreproperties
}
In the order service the orders can be updated (address, name, openPrice, minPrice, status, etc) by the server at any time before the auction starts via the actions bellow.
{ type: LOAD_ORDERS, orders }
{ type: PEND_ORDER, id }
{ type: POSTPONE_ORDER, id }
{ type: SET_ORDER_AUCTION, id, auction, salePrice }
{ type: UPDATE_ORDER, id, properties }
Auction Service
An auction object in this service can look like this:
{
id: 'abcd',
orderId: 123456,
increment: 1,
outBid: { agentId: 'b1', price: 545 },
bestBid:{agentId: 'b2', price: 550 },
openPrice: 500,
currentPrice: 550,
status: 'started'
startedByAgent: 'a1'
}
Auctions can be updated by these actions:
{ type: JOIN_AUCTION, id, agentId, type }
{ type: START_AUCTION, id, agentId }
{ type: PLACE_BID, id, agentId, price }
{ type: END_AUCTION, id, agentId }
API Service
It works just as gateway between front end app and the microservices. Receive and dispatch requests from clients (mobiles) to Order Service or Auction Service in form of actions.
Workflow:
1 - External API push orders of the day to Order Service via LOAD_ORDERS also a CREATE_AUCTIONS action is dispatched to the Action Service to create an auction for each order.
2 - User open mobile app and get the list of orders of the day with details including open prices from Order Service.
3 - User join an specific order
- API Service creates a bidder agent that will place bids.
- API Service send a join action via JOIN_AUCTION to join an auction on the Auction Service
4 - An auctioneer agent starts the auction and bidding starts.
5 - Joined bidder agents starts to place bids via PLACE_BID action on Auction Service.
6 - When auction is over the auctioneer agent ends the auction by dispatching END_AUCTION.
7 - When auction ends sale price and auction details (via object) are send to the Order Service via the SET_ORDER_AUCTION.
8 - The Order Service handle the SET_ORDER_AUCTION and update the order state with the final salePrice and the auction object and then wait for payment.
9 - Once payment info is received from the client then it is submitted to the External Service by Order Service
My questions are:
Is the workflow above a reasonable approach for using Microservices + Redux and updating each service state?
It is ok to dispatch actions from a microservice to another when using redux microservices? My question is because when using microservices + event sourcing + CQRS, services intercommunication are not recommended but instead using a Sagas that work as intermediate service that convert events to commands.
My other question is where to put business logic (validation), for example a bidder cannot send bid if auction is not started or its already ended, a bidder cannot send a bid if he/she has not joined the auction yet. Were to put this logic? in action, middleware or reducers? and how to handle errors back to clients?
In general what are some best practices when it comes to Microservices + Redux?
What are pros and cons of using Microservices + Redux vs Microservices + Event sourcing + CQRS?
Sorry for the long post, I just need some orientation here because I cannot find any documentation about this topic and I am not sure if I am approaching this right.
Any advice would be appreciated!!!
I think this questions is way off the guidelines.
Nevertheless, I'd say write your own redux middleware to integrate your microservices; the API is very simple:
store => next => action => {
let result = next(action)
return result
}
In the most outer function (store =>) you can add microservice listerner and dispatch actions via the store reference.
In the innermost function (action =>) you can react to actions in the redux app by sending requests to your microservices.

Resources