For a rental company, we need to set up deferred payment.
When a user rents an item we must lock $25 on his credit card (a deposit).
He will be charged $1 per hour. If he returns his item within 5 hours, he will be charged $5. After 25 hours we consider the item lost and it is charged the full price $25.
At the time of the customer payment validation we should show a $1 bill (not a $25 bill).
We managed to implement this on Apple Pay with pkdeferredpaymentsummaryitem.
Do you have any idea how to implement this with Stripe Pay?
For the moment here is our code:
public PaymentIntent createCapturePaymentIntent(String amount, String currency, String customerId,
String paymentMethodId, String description) throws Exception {
Map < String, Object > params = new HashMap < > ();
params.put("amount", amount);
params.put("currency", currency);
params.put("customer", customerId);
if (null != paymentMethodId) {
params.put("payment_method", paymentMethodId);
}
params.put("description", description);
// params.put("confirm", "true");
params.put("capture_method", "manual");
LoggerHelper.mdc("stripe", "createCapturePaymentIntent body ==> {}", JacksonUtils.toJson(params));
PaymentIntent paymentIntent = null;
try {
paymentIntent = PaymentIntent.create(params, requestOptions);
} catch (CardException e) {
LoggerHelper.mdc("stripe", "createCapturePaymentIntent error ==> {}: {}", e.getCode(), e.getMessage());
String paymentIntentId = e.getStripeError().getPaymentIntent().getId();
paymentIntent = PaymentIntent.retrieve(paymentIntentId, requestOptions);
}
LoggerHelper.mdc("stripe", "createCapturePaymentIntent result ==> {}", JSON.toJson(paymentIntent));
return paymentIntent;
}
But the user is shown a $25 bill instead of a $1 one:
Apple Pay Documentation: pkdeferredpaymentsummaryitem
Edit: Do you think creating a $1 payment with the option setup_future_usage set to off_session is a good idea to achieve our goal?
Since your customers agree to your certain terms and condition, your app UI can display $1 on the frontend and while in the background, you'll deduct the full $25. This should solve it if stripe doesn't have the API method to do that
Related
I want to fetch Merchant Name from Bank Transaction SMS. For this I used following regx;
Pattern.compile("(?i)(?:\\sat\\s|in\\*)([A-Za-z0-9]*\\s?-?\\s?[A-Za-z0-9]*\\s?-?\\.?)")
Its works fine with those SMS which contains at / in but what if SMS contains other than this two words.
For example, SMS is like ;
Dear Customer, You have made a Debit Card purchase of INR1,600.00 on
30 Jan. Info.VPS*AGGARWAL SH.
Then how to fetch AGGARWAL SH from above SMS?
You can use this below code to fetch Merchant Name from String
private void extractMerchantNameFromSMS(){
try{
String mMessage= "Dear Customer, You have made a Debit Card purchase of INR1,600.00 on 30 Jan. Info.VPS*AGGARWAL SH.";
Pattern regEx = Pattern.compile("(?i)(?:\\sInfo.\\s*)([A-Za-z0-9*]*\\s?-?\\s?[A-Za-z0-9*]*\\s?-?\\.?)");
// Find instance of pattern matches
Matcher m = regEx.matcher(mMessage);
if(m.find()){
String mMerchantName = m.group();
mMerchantName = mMerchantName.replaceAll("^\\s+|\\s+$", "");//trim from start and end
mMerchantName = mMerchantName.replace("Info.","");
FileLog.e(TAG, "MERCHANT NAME : "+mMerchantName);
}else{
FileLog.e(TAG, "MATCH NOTFOUND");
}
}catch(Exception e){
FileLog.e(TAG, e.toString());
}
}
This question might be silly but I'm not able to achieve this. I have a payment device that I'm connected via bluetooth to my app. For the device to display currency code, I need to pass a string, like this :
String codeForPaymendDevice = "978";
This "978" basically sends "EUR" currency code and displays on the screen of the payment device. (The device's library maps and handles this). In my app, when the user makes a purchase in EUR currency, it should compare with "978(EUR)" and if both matches, it should parse codeForPaymentDevice. I'm not able to do this because I cannot compare "EUR" with 978 (as my code doesn't know 978 is EUR, only the payment device knows 978 is EUR).
What I need to do is, map "978" to "EUR" code and then compare transaction.getCurrencyCode() with the mapped variable and then parse it.
private SaleRequest buildTransactionRequest(Transaction transaction) {
final SaleRequest tr = new SaleRequest();
BigDecimal amount = getAmountPaid();
String codeForPaymentDevice = "978";
String formattedAmount;
try {
if (!transaction.getCurrencyCode().equalsIgnoreCase(CREW_CURRENCY)) {
formattedAmount = AirFiApplication
.getPriceFormatter(AirFiApplication.getCurrency(transaction.getCurrencyCode())).format(amount);
// transaction.getCurrencyCode = EUR
tr.setCurrency(codeForPaymentDevice); // TODO remove hardcoding
}
} catch (MPosValueException e) {
LOG.error("Error while building transaction request due to {}", e.getLocalizedMessage());
}
return tr;
}
You can create a Map with some key (for now I have used currency code) with the value you need to pass as the value.
Map<String, String> map = new HashMap<>();
map.put("EUR", "978");
map.put("INR", "979");
map.put("USD", "980");
map.put("AED", "981");
...
In your code,
tr.setCurrency(map.get(transaction.getCurrencyCode()));
I want something like
objectid id name lastname pic
hx5w887 1 name1 lastname1 pic1
lops4wus 2 name2 lastname2 pic2
zh7w8sa 3 name3 lastname3 pic3
I don't want to change the objectId, just I want that field and every time I save an object increment in 1. I am searched a lot in google, about this, it is no possible at least you can something with Cloud Parse code, but I do not know how to make this function, I don't know if "Increment" can help me with this, and I do not know how to run the function anyway.
Parse.Cloud.afterSave("counter", function(request) {
var nameId = request.object.get("name").id;
var Name = Parse.Object.extend("Name");
var query = new Parse.Query(Name);
query.get(nameId).then(function(post) {
post.increment("idkey",+1);
post.save();
}, function(error) {
throw "Got an error " + error.code + " : " + error.message;
});
});
I deploy and
call the function in Android
ParseCloud.callFunctionInBackground("counter", new HashMap<String, Object>(), new FunctionCallback<String>() {
// #Override
public void done(String result, ParseException e) {
if (e == null) {
} else {
// handleError();
}
}
});
But nothing happens, what can be the problem? Sorry my bad english.
You can use ParseCloud 'beforeSave' functionality.
You can declare a code which will run before saving a new object of a specific class.
In this code you query for your class items, order it and get the first item (the highest value) then you can the next value (highest +1) to the new saved object.
For more info you can take a look at Parse documentation and in this thread (it is not in java but it is very similar)
EDIT: Since Parse is not longer is now an open source might be that things have changed.
I am apologize for this type Question. I am first time use Cloud Code in parse so I have No idea how to get data in parse through Cloud code. If any idea then suggest me. I have check many example but I have not found in my problem.
My parse data base is like this..
userId game1score game2score game3score gender
xcvgfs1 300 200 100 man
sfdgdh 500 600 300 man
like this parse data base many user are playing game and score the game.
My problem is how to get all user score in game1score ya other game score and compare to current user score and find the Rank of current user.
Thanks for helping..
Call the cloud code function is like this in my activity..
Map<String, String> map = new HashMap<String, String>();
map.put(" game1score", "300");
ParseCloud.callFunctionInBackground("check_duplicate",map,new FunctionCallback<Object>() {
#Override
public void done(Object o, ParseException e) {
if(e==null){
Log.e("String",""+o) ;
}else{
Log.e("error",e.getMessage()) ;
}
}
});
return always null or 0
As far as I understand from your explanation, you want to extract the rank number of current user via using the Parse Score table where you record 3 different game scores (gameScore1, gameScore2, gameScore3). You have already write the Cloud code trigger function. So the cloud code that you can use is below;
Parse.Cloud.define("rank", function(request, status)
{
var result = [];
var processRankCallback = function(res) {
result = result.concat(res);
if (res.length === 1000)
{
process(res[res.length-1].id);
return;
}
//All object that is greater than the given user score
status.success(result.length);
}
var processRank = function(skip)
{
var query = new Parse.Query("Score");
var userScore = request.params.userScore;
var gameType = request.params.gameType;
if (skip) query.greaterThan("objectId", skip);
query.limit(1000);
query.ascending("objectId");
query.find().then(function querySuccess(res)
{
var innerResult = [];
for(var i = 0 ; i < res.length;i++)
{
//var gameScore1 = res[i].get("gameScore1");
//var gameScore2 = res[i].get("gameScore2");
//var gameScore3 = res[i].get("gameScore3");
//var total = gameScore1+gameScore2+gameScore3;
var total = res[i].get(gameType);
if(userScore < total) innerResult.push(res[i]);
}
processRankCallback(innerResult);
}, function queryFailed(reason)
{
status.error("Error:" + error.code + " Message" + error.message);
});
}
processRank(false);
});
Actually, finding the rank means that query the Score table and count the entry where the game scores all total is larger than your current user total game score. To implement this you can use the countQuery however Parse countQuery can fail or show incorrect result when your table entry is larger than 1000. So, instead of using count query, you can walk through the entire table and find all entries that have larger game score than your current user. In above code, I assume that you have 3 different game scores and all have valid number (not undefined). You can modify the code for your own purposes. The end result will generate a number which is actually the number of entry in Score table that has larger game score total than your current user game scores total.
For example I have a Score table with column gameScore1 and 3 entries where the scores are 600, 200 and 100. I call the Cloud function with below parameters hash table;
HashMap<String, String> params = new HashMap<String, String>();
params.put("userScore", "150");
params.put("gameType", "gameScore1");
//Call Parse cloud function
The response will be 2 which actually means that there are two entries that has gameScore1 which is larger than 150. Hope this helps.
Regards.
I am implementing in-app purchases for an app with support for several countries.
The In-App Billing Version 3 API claims that:
No currency conversion or formatting is necessary: prices are reported
in the user's currency and formatted according to their locale.
This is actually true, since skuGetDetails() takes care of all necessary formatting. The response includes a field called price, which contains the
Formatted price of the item, including its currency sign. The price does not include tax.
However, I need the ISO 4217 currency code (retrievable if I know the store locale) and the actual non-formatted price (optimally in a float or decimal variable) so I can do further processing and analysis myself.
Parsing the return of skuGetDetails() is not a reliable idea, because many countries share the same currency symbols.
How can I get the ISO 4217 currency code and non-formatted price of an in-app purchase with the In-App Billing Version 3 API?
Full information can be found here, but essentially in August 2014 this was resolved with:
The getSkuDetails() method
This method returns product details for a list of product IDs. In the response Bundle sent by Google Play, the query results are stored in a String ArrayList mapped to the DETAILS_LIST key. Each String in the details list contains product details for a single product in JSON format. The fields in the JSON string with the product details are summarized below
price_currency_code ISO 4217 currency code for price. For example, if price is specified in British pounds sterling, price_currency_code is "GBP".
price_amount_micros Price in micro-units, where 1,000,000 micro-units equal one unit of the currency. For example, if price is "€7.99", price_amount_micros is "7990000".
You can't, this is currently not supported. There is a feature request for it, but it may or may not get implemented.
https://code.google.com/p/marketbilling/issues/detail?id=93
You can. You need to modify SkuDetails.java like below.
Steps:
Check their sample app for in-app billing.
Modify the SkuDetails.java file as follows:
import org.json.JSONException; import org.json.JSONObject;
/**
* Represents an in-app product's listing details.
*/
public class SkuDetails {
String mItemType;
String mSku;
String mType;
int mPriceAmountMicros;
String mPriceCurrencyCode;
String mPrice;
String mTitle;
String mDescription;
String mJson;
public SkuDetails(String jsonSkuDetails) throws JSONException {
this(IabHelper.ITEM_TYPE_INAPP, jsonSkuDetails);
}
public SkuDetails(String itemType, String jsonSkuDetails) throws JSONException {
mItemType = itemType;
mJson = jsonSkuDetails;
JSONObject o = new JSONObject(mJson);
mSku = o.optString("productId");
mType = o.optString("type");
mPrice = o.optString("price");
mPriceAmountMicros = o.optInt("price_amount_micros");
mPriceCurrencyCode = o.optString("price_currency_code");
mTitle = o.optString("title");
mDescription = o.optString("description");
}
public String getSku() { return mSku; }
public String getType() { return mType; }
public String getPrice() { return mPrice; }
public String getTitle() { return mTitle; }
public String getDescription() { return mDescription; }
public int getPriceAmountMicros() { return mPriceAmountMicros; }
public String getPriceCurrencyCode() { return mPriceCurrencyCode; }
#Override
public String toString() {
return "SkuDetails:" + mJson;
}
}
Here is my workaround :)
private static Locale findLocale(String price) {
for (Locale locale : Locale.getAvailableLocales()){
try {
Currency currency = Currency.getInstance(locale);
if (price.endsWith(currency.getSymbol()))
return locale;
}catch (Exception e){
}
}
return null;
}
Usage:
Locale locale = findLocale(price);
String currency = Currency.getInstance(locale).getCurrencyCode();
double priceClean = NumberFormat.getCurrencyInstance(locale).parse(price).doubleValue();
Very simple. SKU returns the currency code ("price_currency_code" field). With that code you can retrieve the symbol using the Currency class.
See the code attached:
String currencyCode = skuObj.getString("price_currency_code");
currencySymbol = Currency.getInstance(currencyCode).getSymbol();
Here's a complete code:
ArrayList<String> skuList = new ArrayList<>();
skuList.add("foo");
skuList.add("bar");
final String[] prices = new String[skuList.size()];
Bundle querySkus = new Bundle();
querySkus.putStringArrayList("ITEM_ID_LIST", skuList);
Bundle skuDetails = _appActivity.mService.getSkuDetails(3, _appActivity.getPackageName(), "inapp", querySkus);
int response = skuDetails.getInt("RESPONSE_CODE");
if(response == 0) {
ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");
int i = 0;
for (String thisResponse : responseList) {
JSONObject object = new JSONObject(thisResponse);
String sku = object.getString("productId");
final String priceCurrency = object.getString("price_currency_code");
String priceAmountMicros = object.getString("price_amount_micros");
float priceAmount = Float.parseFloat(priceAmountMicros) / 1000000.0f;
String price = priceAmount + " " + priceCurrency;
if(skuList.contains(sku)){
prices[i] = price;
i++;
}
}
}
From documentation:
price_currency_code ISO 4217 currency code for price. For example, if
price is specified in British pounds sterling, price_currency_code is
"GBP".
price_amount_micros Price in micro-units, where 1,000,000 micro-units
equal one unit of the currency. For example, if price is "€7.99",
price_amount_micros is "7990000". This value represents the localized,
rounded price for a particular currency.
Now you just have to divide price_amount_micros by a 1000000 and concatenate it with currency.
You can check this
The Android developers in select countries can now offer apps for sale in multiple currencies through Google Wallet Merchant Center. To sell your apps in additional currencies, you will need to set the price of the app in each country/currency. A list of supported countries/currencies is available in our help center.
If you make an app available in local currency, Google Play customers will only see the app for sale in that currency. Customers will be charged in their local currency, but payment will be issued in the currency set in your Google Wallet Merchant Center account.
Another hardcoded workaround is to price items for countries with the same symbol, differently by a cent or so. When you retrieve the price of the item from google play upon purchasing and you know the retrieved currency symbol is one which is used in many countries ie. $. You then have a log of different prices on your backend server and correlate the purchase price with a specific country.