Google Pay Implementaion On The Web [closed] - javascript

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I want to add the google pay buy now button on my website, I used the below documentation for reference.
https://codelabs.developers.google.com/codelabs/pay-web-checkout/index.html?index=..%2F..index#0
and everything works fine and here is the code that I created.
<div id="buy-now"></div>
<script async
src="https://pay.google.com/gp/p/js/pay.js"
onload="onGooglePayLoaded()">
</script>
<script>
let googlePayClient;
const baseCardPaymentMethod = {
type: 'CARD',
parameters: {
allowedCardNetworks: ['VISA','MASTERCARD'],
allowedAuthMethods: ['PAN_ONLY','CRYPTOGRAM_3DS']
}
};
const googlePayBaseConfiguration = {
apiVersion: 2,
apiVersionMinor: 0,
allowedPaymentMethods: [baseCardPaymentMethod]
};
function onGooglePayLoaded() {
googlePayClient = new google.payments.api.PaymentsClient({
environment: 'TEST'
});
// check compatability
googlePayClient.isReadyToPay(googlePayBaseConfiguration)
.then(function(response) {
if(response.result) {
createAndAddButton();
} else {
alert("Unable to pay using Google Pay");
}
}).catch(function(err) {
console.error("Error determining readiness to use Google Pay: ", err);
});
}
function createAndAddButton() {
const googlePayButton = googlePayClient.createButton({
// currently defaults to black if default or omitted
buttonColor: 'default',
// defaults to long if omitted
buttonType: 'long',
onClick: onGooglePaymentsButtonClicked
});
document.getElementById('buy-now').appendChild(googlePayButton);
}
function onGooglePaymentsButtonClicked() {
// TODO: Perform transaction
const tokenizationSpecification = {
type: 'PAYMENT_GATEWAY',
parameters: {
gateway: 'example',
gatewayMerchantId: 'gatewayMerchantId'
}
};
const cardPaymentMethod = {
type: 'CARD',
tokenizationSpecification: tokenizationSpecification,
parameters: {
allowedCardNetworks: ['VISA','MASTERCARD'],
allowedAuthMethods: ['PAN_ONLY','CRYPTOGRAM_3DS'],
billingAddressRequired: true,
billingAddressParameters: {
format: 'FULL',
phoneNumberRequired: true
}
}
};
const transactionInfo = {
totalPriceStatus: 'FINAL',
totalPrice: '123.45',
currencyCode: 'USD'
};
const merchantInfo = {
merchantId: 'BCR2DN6TRPZNDYLL', Only in PRODUCTION
merchantName: 'Example Merchant Name'
};
const paymentDataRequest = Object.assign({}, googlePayBaseConfiguration, {
allowedPaymentMethods: [cardPaymentMethod],
transactionInfo: transactionInfo,
merchantInfo: merchantInfo
});
googlePayClient
.loadPaymentData(paymentDataRequest)
.then(function(paymentData) {
processPayment(paymentData);
}).catch(function(err) {
// Log error: { statusCode: CANCELED || DEVELOPER_ERROR }
});
}
function processPayment(paymentData) {
// TODO: Send a POST request to your processor with the payload
// https://us-central1-devrel-payments.cloudfunctions.net/google-pay-server
// Sorry, this is out-of-scope for this codelab.
return new Promise(function(resolve, reject) {
// #todo pass payment token to your gateway to process payment
const paymentToken = paymentData.paymentMethodData.tokenizationData.token;
console.log('mock send token ' + paymentToken + ' to payment processor');
setTimeout(function() {
console.log('mock response from processor');
alert('done');
console.log(paymentData);
resolve({});
}, 800);
});
}
</script>
I am familiar with PHP and Ruby and I don't want to use third-party payment gateways for tokenization specification want to do it with the DIRECT method. I don't know what to do next and how to compare the token after payment success and don't have any idea about tokenization specification with the DIRECT method help me.
thanks, everyone.

If you're doing a web integration, consider using the Google Pay components. There's a React version if using React, and a Web Component version for most of the other frameworks.
As for DIRECT integration, it is strongly discouraged due to additional compliance obligations. From https://developers.google.com/pay/api/web/reference/request-objects#direct:
Key Point: The Direct integration allows merchants to decrypt the Google Pay response on their servers. To qualify, you must be Payments Card Industry (PCI) Data Security Standard (DSS) Level 1 compliant. Your servers also need to have the required infrastructure to securely handle users' payment credentials.
Third parties that supply gateway or processing services on behalf of actual merchants aren't eligible to use the Direct integration. For questions about your integration as a payment service provider, contact us.
If you don't meet the necessary prerequisites, we recommend that you use a supported gateway to receive a payment token.
Out of interest, why don't you want to use a payment gateway?
If you still feel like you need DIRECT integration, resources on how to decrypt the token can be found at: https://developers.google.com/pay/api/web/guides/resources/payment-data-cryptography.
I don't know what to do next and how to compare the token after payment success and don't have any idea about tokenization specification with the DIRECT method help me.
You need to generate a public/private key pair and register the public key with the Google Pay console. You'll also need to update the tokenizationSpecification to include the public key (example below)
"tokenizationSpecification": {
"type": "DIRECT",
"parameters": {
"protocolVersion": "ECv2",
"publicKey": "BOdoXP1aiNp.....kh3JUhiSZKHYF2Y="
}
}
how to compare the token after payment success
Google Pay won't handle the payment, you will. You'll need to decrypt the payment token and get the payment details and process the payment yourself.
DIRECT integration is a more difficult integration process, so I would strongly encourage exploring other alternatives first and only consider this if you cannot use a payment gateway.

Related

Custom Ecwid App not appearing at the checkout page

I am new to the Ecwid platform and I am building a custom courier app for dropshipping. I am using the Ecwid SDK JS file of version 1.2.8 https://djqizrxa6f10j.cloudfront.net/ecwid-sdk/js/1.2.8/ecwid-app.js. The issue now is, when I get to the storefront checkout page, as indicated by Ecwid developers API documentation, there should be a callback sent to my URL, in which I am not getting.
EcwidApp.init({
app_id: "app_id",
autoloadedflag: true,
autoheight: true
});
EcwidApp.ready();
window.localStorage.setItem("show_ec_logs", "true");
let storeData = EcwidApp.getPayload();
let storeId = storeData.store_id;
let accessToken = storeData.access_token;
let language = storeData.lang;
let viewMode = storeData.view_mode;
if (storeData.app_state !== undefined) {
var appState = storeData.app_state;
}
const initialConfig = {
private: {
merchantId: "app_id",
APIsecret: "app_secret_token",
endpointUrl: "https://ecwid-droppa-shipping.herokuapp.com",
instructionTitle: "Droppa Instruction Title",
globalShippingRate: "true",
freeShippingRate: "true",
installed: "yes"
},
profile: this.storeProfileInformation(storeId, accessToken)
};
EcwidApp.setAppStorage(initialConfig.profile, function (value) {
console.log('Private User Preferences Saved:', value);
});
EcwidApp.getAppStorage('installed', function (value) {
console.log(`Installed Application: ${value}`);
});
/**
* #description - Display the Ecwid User's Store's information
* #param {*} store_id
* #param {*} private_token ?
* #returns
*/
async function storeProfileInformation(store_id, private_token) {
return await fetch(`https://app.ecwid.com/api/v3/${store_id}/profile?token=${private_token}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept-Encoding': 'gzi'
},
mode: 'cors',
})
.then((res) => res.json())
.then((response) => response)
.catch((errors) => console.log(errors));
}
Is there a way to get the app to appear at the checkout page? And I have all the scopes loaded on my app in the Ecwid dashboard.
This is Harvel from Ecwid API team.
I am new to the Ecwid platform and I am building a custom courier app
for dropshipping. Is there a way to get the app to appear at the
checkout page?
The code you sent is the code for the Merchant App settings, it loads in the Ecwid Admin.
In order to develop a custom courier app and display its shipping rates at the checkout page, you should have your own server that will receive requests from Ecwid, send requests to the 3rd party service and then back to Ecwid.
Once Ecwid receives the shipping rates from your app, these shipping rates will be visible at the checkout page and customers will be able to choose them.
So, step-by-step and how it will work:
Develop your own server; Ecwid sends data to your server (shipping
URL);
Your server processes data and sends it to the 3rd party
service;
3rd party services sends shipping rates back to your
server;
Your server sends shipping rates to Ecwid (they will be
visible at the checkout page).
Shipping request example - https://api-docs.ecwid.com/reference/add-shipping-method#request-details.
Response with shipping rates example - https://api-docs.ecwid.com/reference/add-shipping-method#respond-with-shipping-rates.

MS teams bot JS - create conversation

I need to proactivly create conversation on channel in msteams. So i looked for examples but didn't find any examples of realy proactive conversation creation. All examples include first of all handling message, and creating conversation using context.
To be more accurate i have facebook, whatsapp, and web widget. Users write for example from facebook, i get message through fb webhook and i need to create new thread ( block with replies inside channel ) and only after that, someone who will answer in channel using thread block and i'll get message.
As i understood i need to bootstrap conversation object and use adapter.createConversation({ ...convFields }), but for example i don't have serviceUrl.
// i am using adapter from examples
new BotFrameworkAdapter({
appId: id,
appPassword: password
});
// then i have something like that in examples
const conversationParameters = {
isGroup: true,
channelData: {
channel: {
id: 'msteams'
}
},
activity: 'dsada'
};
const connectorClient = this.adapter.createConnectorClient(
context.activity.serviceUrl // i don't have context to get that serviceUrl, because i must do it first, not handle message and create thread after that.
);
const conversationResourceResponse = await connectorClient.conversations.createConversation(
conversationParameters as any
);
const conversationReference = TurnContext.getConversationReference(
context.activity // same here, i don't have context
);
conversationReference.conversation.id = conversationResourceResponse.id;
return [conversationReference, conversationResourceResponse.activityId];
In order to prevent (or at least hinder) spam, your bot can only send proactive messages to channels or group chats where it is already installed. In that instance you'll need to store the necessary information from the conversationUpdate membersAdded event you'll receive.
For 1:1 chats, it is possible to create a new conversation with a user, however your bot needs to know the Id of the user in order to do so. Typically this is achieved by retrieving the roster of a group chat or team where your bot is installed.
Essentially, it isn't possible to send a completely proactive message - the bot needs to be installed and/or have some amount of information about where it is sending the message previously.
Assuming you can achieve the correct permissions, it is possible to proactively install your bot. See this article for more details on that approach: https://learn.microsoft.com/en-us/graph/teams-proactive-messaging
Even though it is in C#, you may find this sample helpful as it demonstrates the minimal amount of information required in order to send proactive messages to each type of destination (which is the same across languages): https://github.com/clearab/teamsProactiveMessaging.
The relevant file is below:
public class MessageSender : IMessageSender
{
private ConnectorClient conClient;
private string serviceUrl;
public MessageSender(string serviceUrl, string id, string password)
{
MicrosoftAppCredentials.TrustServiceUrl(serviceUrl);
conClient = new ConnectorClient(new Uri(serviceUrl), id, password);
}
public async Task<ResourceResponse> SendOneToOneMessage(string conversationId, Activity activity)
{
return await conClient.Conversations.SendToConversationAsync(conversationId, activity);
}
public async Task<ConversationResourceResponse> CreateOneToOneConversation(string userId, string tenantId)
{
var members = new List<ChannelAccount>()
{
new ChannelAccount
{
Id = userId
}
};
ConversationParameters conParams = new ConversationParameters
{
Members = members,
TenantId = tenantId
};
return await this.conClient.Conversations.CreateConversationAsync(conParams);
}
public async Task<ConversationResourceResponse> CreateAndSendChannelMessage(string channelId, Activity activity)
{
ConversationParameters conParams = new ConversationParameters
{
ChannelData = new TeamsChannelData
{
Channel = new ChannelInfo(channelId)
},
Activity = activity
};
ConversationResourceResponse response = await this.conClient.Conversations.CreateConversationAsync(conParams);
return response;
}
public async Task<ResourceResponse> SendReplyToConversationThread(string threadId, Activity activity)
{
return await this.conClient.Conversations.SendToConversationAsync(threadId, activity);
}
}

There are no accepted cards available for use with this merchant - Google Pay

I am trying to integrate Google Pay web into my website but when i click "pay with googlepay" its shows the below error:
There are no accepted cards available for use with this merchant.
When i read documentation it says you can add example as merchant for testing, I just wanted to use test environment but still its not working.
Here is the code that i am using:
const allowedAuthMethods = ['PAN_ONLY','CRYPTOGRAM_3DS'] ;
const baseCardPaymentMethod = {
type: 'CARD',
parameters: {
allowedCardNetworks: allowedNetworks,
allowedAuthMethods: allowedAuthMethods
}
};
const googlePayBaseConfiguration = {
apiVersion: 2,
apiVersionMinor: 0,
allowedPaymentMethods: [baseCardPaymentMethod]
};
/**
* Holds the Google Pay client used to call the different methods available
* through the API.
* #type {PaymentsClient}
* #private
*/
let googlePayClient;
/**
* Defines and handles the main operations related to the integration of
* Google Pay. This function is executed when the Google Pay library script has
* finished loading.
*/
function onGooglePayLoaded() {
googlePayClient = new google.payments.api.PaymentsClient({
environment: 'TEST'
});
googlePayClient.isReadyToPay(googlePayBaseConfiguration)
.then(function(response) {
if(response.result) {
createAndAddButton();
} else {
alert("Unable to pay using Google Pay");
}
}).catch(function(err) {
console.error("Error determining readiness to use Google Pay: ", err);
});
}
/**
* Handles the creation of the button to pay with Google Pay.
* Once created, this button is appended to the DOM, under the element
* 'buy-now'.
*/
function createAndAddButton() {
const googlePayButton = googlePayClient.createButton({
// currently defaults to black if default or omitted
buttonColor: 'default',
// defaults to long if omitted
buttonType: 'long',
onClick: onGooglePaymentsButtonClicked
});
document.getElementById('buy-now').appendChild(googlePayButton);
}
/**
* Handles the click of the button to pay with Google Pay. Takes
* care of defining the payment data request to be used in order to load
* the payments methods available to the user.
*/
function onGooglePaymentsButtonClicked() {
const tokenizationSpecification = {
type: 'PAYMENT_GATEWAY',
parameters: {
gateway: 'example',
gatewayMerchantId: 'exampleGatewayMerchantId'
}
};
const cardPaymentMethod = {
type: 'CARD',
tokenizationSpecification: tokenizationSpecification,
parameters: {
allowedCardNetworks: ['VISA','MASTERCARD'],
allowedAuthMethods: ['PAN_ONLY','CRYPTOGRAM_3DS'],
billingAddressRequired: true,
billingAddressParameters: {
format: 'FULL',
phoneNumberRequired: true
}
}
};
const transactionInfo = {
totalPriceStatus: 'FINAL',
totalPrice: '123.45',
currencyCode: 'USD',
countryCode: 'US'
};
const merchantInfo = {
merchantId: '01234567890123456789', //Only in PRODUCTION
merchantName: 'Example Merchant Name'
};
const paymentDataRequest = Object.assign({}, googlePayBaseConfiguration, {
allowedPaymentMethods: [cardPaymentMethod],
transactionInfo: transactionInfo,
merchantInfo: merchantInfo
});
googlePayClient
.loadPaymentData(paymentDataRequest)
.then(function(paymentData) {
processPayment(paymentData);
}).catch(function(err) {
// Log error: { statusCode: CANCELED || DEVELOPER_ERROR }
});
}
function processPayment(paymentData) {
// TODO: Send a POST request to your processor with the payload
// https://us-central1-devrel-payments.cloudfunctions.net/google-pay-server
// Sorry, this is out-of-scope for this codelab.
return new Promise(function(resolve, reject) {
// #todo pass payment token to your gateway to process payment
const paymentToken = paymentData.paymentMethodData.tokenizationData.token;
console.log('mock send token ' + paymentToken + ' to payment processor');
setTimeout(function() {
console.log('mock response from processor');
alert('done');
resolve({});
}, 800);
});
} ```
There are no accepted cards available for use with this merchant.
This message means that the current Google user doesn't have any cards that are compatible with the payment options that the merchant has provided. Specifically allowedCardNetworks and allowedAuthMethods.
Here is a JSFiddle that I created based on your snippet: https://jsfiddle.net/aumg6ncb/
This is what I get back after clicking on the button:
If You are using Testing mode:-
I think You used testing card on your Chrome browser or Google Wallet
When testing Google Pay you should have a real card saved in your Chrome browser or Google Wallet, and have your test API keys/test Google Pay environment active. The real card does not get charged, and Google passes a test card during the checkout flow instead of a real card. Our normal test cards do not work with Google Pay when the user tries to save them in Chrome

Getting PUT routes to work in Angular

I'm seeking some wisdom from the Angular community. I am working on a simple project using the MEAN stack. I have set up my back-end api and everything is working as expected. Using Postman, I observe expected behavior for both a GET and PUT routes to retrieve/update a single value - a high score - which is saved in it's own document in its own collection in a MongoDB. So far so good.
Where things go off track is when trying to access the PUT api endpoint from within Angular. Accessing the GET endpoint is no problem, and retrieving and displaying data works smoothly. However, after considerable reading and searching, I am stll unable to properly access the PUT endpoint and update the high score data when that event is triggered by gameplay. Below are the snippets of code that I believe to be relevant for reference.
BACK-END CODE:
SCHEMA:
const _scoreSchema = {
name: { type: String, required: true },
value: { type: Number, "default": 0 }
};
ROUTES:
router
.route('/api/score/:highScore')
.put(scoreController.setHighScore);
CONTROLLER:
static setHighScore(req, res) {
scoreDAO
.setHighScore(req.params.highScore)
.then(highScore => res.status(200).json(highScore))
.catch(error => res.status(400).json(error));
}
DAO:
scoreSchema.statics.setHighScore = (value) => {
return new Promise((resolve, reject) => {
score
.findOneAndUpdate(
{"name": "highScore"},
{$set: {"value": value} }
)
.exec(function(err, response) {
err ? reject(err)
: resolve(response);
});
});
}
ANGULAR CODE:
CONTROLLER:
private _updateHighScore(newHighScore): void {
console.log('score to be updated to:', newHighScore)
this._gameService
.updateHighScore(newHighScore);
}
SERVICE:
updateHighScore(newHighScore: Number): Observable<any> {
console.log(newHighScore);
let url = '/api/score/' + newHighScore;
let _scoreStringified = JSON.stringify({value: newHighScore});
let headers = new Headers();
headers.append("Content-Type", "application/json");
return this._http
.put(url , _scoreStringified, {headers})
.map((r) => r.json());
}
Note that the console.log(newHighScore) in the last block of code above correctly prints the value of the new high score to be updated, it's just not being written to the database.
The conceptual question with PUT routes in angular is this: If the api is already set up such that it receives all the information it needs to successfully update the database (via the route param) why is it required to supply all of this information again in the Angular .put() function? It seems like reinventing the wheel and not really utilizing the robust api endpoint that was already created. Said differently, before digging into the docs, I naively was expecting something like .put(url) to be all that was required to call the api, so what is the missing link in my logic?
Thanks!

Parse-server social login

I am developing application based on Parse-server and I want to offer social login. I found this guide in the documentation http://docs.parseplatform.org/js/guide/#linking-users.
I started to implement the social login by google. I did following steps:
1) I added following lines to the ParseServer settings
var api = new ParseServer({
...
auth:{
google: {}
},
...
});
2) I did the authentication by hello.js on the client side (call user._linkWith function on login)
hello.init({
google: 'My Google id'
});
hello.on('auth.login', function(auth) {
// Call user information, for the given network
hello(auth.network).api('me').then(function(r) {
const user = new Parse.User();
user._linkWith(auth.network, auth.authResponse).then(function(user){
console.log('You are logged in successfully.');
});
});
});
When I debugged it, I found that it fails in _linkWith() function, when provider object is preparing. Object AuthProviders, which should store all providers, is empty. Because of it the statement provider = authProviders['google']; leads to undefined. Invoking provider.authenticate(...); leads to error "Cannot read property 'authenticate' of undefined"
What am I missing or what am I doing wrong?
Thanks for all your answers.
Honza
Did you register the authenticationProvider? You can find examples in our unit tests on how to do so:
https://github.com/parse-community/parse-server/blob/5813fd0bf8350a97d529e5e608e7620b2b65fd0c/spec/AuthenticationAdapters.spec.js#L139
I also got this error and looked at the _linkWith(provider, options) source code. It checks if options has an authData field (which in turn should contain id and credentials). If so, it uses options.authData. Otherwise it falls back on looking up a previously registered authentication provider mentioned in the previous answer.
This is a fragment of the code I'm using:
const authData = {
"id": profile.getId(),
"id_token": id_token
}
const options = {
"authData": authData
}
const user = new Parse.User();
user._linkWith('google', options).then(function(user) {
console.log('Successful user._linkWith(). returned user=' + JSON.stringify(user))
}, function(error) {
console.log('Error linking/creating user: ' + error)
alert('Error linking/creating user: ' + error)
// TODO handle error
})

Categories

Resources