PayPal REST API returns INVALID_CURRENCY_AMOUNT_FORMAT - spring-boot

response-code: 400 details: name: VALIDATION_ERROR message: Invalid request - see details details: [{
"field": "transactions.amount",
"issue": "Cannot construct instance of com.paypal.platform.payments.model.rest.common.Amount, >problem: INVALID_CURRENCY_AMOUNT_FORMAT"
}] debug-id: 86ad5783892c3 information-link: https://developer.paypal.com/docs/api/payments/#errors
package com.spring.soap.api;
#Configuration
public class PaypalConfig {
#Value("${paypal.client.id}")
private String clientId;
#Value("${paypal.client.secret}")
private String clientSecret;
#Value("${paypal.mode}")
private String mode;
#Bean
public Map<String,String> paypalSdkConfig(){
Map<String,String> configMap= new HashMap<>();
configMap.put("mode",mode);
return configMap;
}
#Bean
public OAuthTokenCredential oAuthTokenCredential() {
return new OAuthTokenCredential(clientId,clientSecret,paypalSdkConfig());
}
#Bean
public APIContext apiContext() throws PayPalRESTException {
APIContext context = new APIContext(oAuthTokenCredential().getAccessToken());
context.setConfigurationMap(paypalSdkConfig());
return context;
}
}
{
#Autowired
PaypalService service;
public static final String SUCCESS_URL = "pay/success";
public static final String CANCEL_URL = "pay/cancel";
#GetMapping("/")
public String home() {
return "home";
}
#PostMapping("/pay")
public String payment(#ModelAttribute("order") Order order) {
try {
Payment payment = service.createPayment(order.getPrice(), order.getCurrency(), order.getMethod(),
order.getIntent(), order.getDescription(), "http://localhost:9090/" + CANCEL_URL,
"http://localhost:9090/" + SUCCESS_URL);
for(Links link:payment.getLinks()) {
if(link.getRel().equals("approval_url")) {
return "redirect:"+link.getHref();
}
}
} catch (PayPalRESTException e) {
e.printStackTrace();
}
return "redirect:/";
}
#GetMapping(value = CANCEL_URL)
public String cancelPay() {
return "cancel";
}
#GetMapping(value = SUCCESS_URL)
public String successPay(#RequestParam("paymentId") String paymentId, #RequestParam("PayerID") String payerId) {
try {
Payment payment = service.executePayment(paymentId, payerId);
System.out.println(payment.toJSON());
if (payment.getState().equals("approved")) {
return "success";
}
} catch (PayPalRESTException e) {
System.out.println(e.getMessage());
}
return "redirect:/";
}
}
{
#Autowired
private APIContext apiContext;
public Payment createPayment(
Double total,
String currency,
String method,
String intent,
String description,
String cancelUrl,
String successUrl) throws PayPalRESTException{
Amount amount = new Amount();
amount.setCurrency(currency);
total = new BigDecimal(total).setScale(2, RoundingMode.HALF_UP).doubleValue();
amount.setTotal(String.format("%.2f", total));
Transaction transaction = new Transaction();
transaction.setDescription(description);
transaction.setAmount(amount);
List<Transaction> transactions = new ArrayList<>();
transactions.add(transaction);
Payer payer = new Payer();
payer.setPaymentMethod(method);
Payment payment = new Payment();
payment.setIntent(intent);
payment.setPayer(payer);
payment.setTransactions(transactions);
RedirectUrls redirectUrls = new RedirectUrls();
redirectUrls.setCancelUrl(cancelUrl);
redirectUrls.setReturnUrl(successUrl);
payment.setRedirectUrls(redirectUrls);
return payment.create(apiContext);
}
public Payment executePayment(String paymentId, String payerId) throws PayPalRESTException{
Payment payment = new Payment();
payment.setId(paymentId);
PaymentExecution paymentExecute = new PaymentExecution();
paymentExecute.setPayerId(payerId);
return payment.execute(apiContext, paymentExecute);
}
}

It would appear your locale is formatting decimals with a comma (,) as the decimal separator.
The PayPal API exclusively accepts numbers with a period (.) as the decimal separator

Take this line:
amount.setTotal(String.format("%.2f", total));
Change %.2f to %.3f. The final code should look like:
amount.setTotal(String.format("%.3f", total));

In my case I was sending the SubTotal on Details with a NON rounded value:
141.750
So I just round the value like this:
details.setSubtotal(subTotal.setScale(2, BigDecimal.ROUND_HALF_EVEN).toString());
(In other words)
141.75

Related

spring resttemplate request object not mapping to rest controller

i have below resttempalte which invokes rest controller of another service..
#Override
public ResponseEntity<String> callRestAPI(APIReqDataMO apiReqDataMO) {
String apiURL = URIGenerator.getAPIURL(apiReqDataMO);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<?> request = new HttpEntity<>(apiReqDataMO.getRequestObject(), headers);
ResponseEntity<String> httpRes = restTemplate.postForEntity(apiURL, request, String.class);
return httpRes;
}
and in my service i have controller, which consumes above request..
#RequestMapping(value = "/targetService/createUser", method = RequestMethod.POST, consumes = "application/json")
public String fuzzerServiceAge(UserMO userMO) {
System.out.println("---------------------age is -------------------------" + userMO.getAge());
if (userMO.getAge() > 0) {
System.out.println("error age greater than 0 ");
return "invalid user age";
} else if (userMO.getAge() == 0) {
return "invalid user age";
}
return "user added successfully";
}
when i try my test.. the age which i am pushing through rest template is not getting mapped..and i am getting age as 0 always in my system.out.. what could be wrong in my code... and is there anything missing from configuration perspective..
EDIT -
public class APIReqDataMO {
private String restAPIURL;
private Object[] pathParam;
private Object[] requestParam;
private String requestType;
private String paramType;
private Object requestObject;
public String getParamType() {
return paramType;
}
public void setParamType(String paramType) {
this.paramType = paramType;
}
public String getRequestType() {
return requestType;
}
public void setRequestType(String requestType) {
this.requestType = requestType;
}
public Object getRequestObject() {
return requestObject;
}
public void setRequestObject(Object requestObject) {
this.requestObject = requestObject;
}
public String getRestAPIURL() {
return restAPIURL;
}
public void setRestAPIURL(String restAPIURL) {
this.restAPIURL = restAPIURL;
}
public Object[] getPathParam() {
return pathParam;
}
public void setPathParam(Object[] pathParam) {
this.pathParam = pathParam;
}
public Object[] getRequestParam() {
return requestParam;
}
public void setRequestParam(Object[] requestParam) {
this.requestParam = requestParam;
}
}
controller
#PostMapping("/targetService/createUser")
public String fuzzerServiceAge(UserMO userMO) {
System.out.println("--------------------- age is -------------------------" + userMO.getAge());
if (userMO.getAge() > 0) {
// return ResponseEntity.ok("Hello World!");
} else if (userMO.getAge() == 0) {
System.out.println(" it is else block");
// return ResponseEntity.badRequest().build();
}
// return ResponseEntity.ok("user added successfully!");
return "user added successfully";
}
usermo
public class UserMO {
#JsonProperty("name")
private String name;
#JsonProperty("age")
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Issue
There is an issue in API implementation. You are creating POST API and when the user will invoke this API by passing UserMO in the request body then mapping won't happen because the #RequestBody annotation is missing.
#PostMapping("/targetService/createUser")
public String fuzzerServiceAge(UserMO userMO) {
System.out.println("--------------------- age is -------------------------" + userMO.getAge());
if (userMO.getAge() > 0) {
// return ResponseEntity.ok("Hello World!");
} else if (userMO.getAge() == 0) {
System.out.println(" it is else block");
// return ResponseEntity.badRequest().build();
}
// return ResponseEntity.ok("user added successfully!");
return "user added successfully";
}
Solution
If you are using #RestController annotation on top of the controller class then add #RequestBody annotation before UserMO userMO and try again.
Like this
#PostMapping("/targetService/createUser")
public String fuzzerServiceAge(#RequestBody UserMO userMO) {
//logic
}
if you are using #Controller annotation on top of the controller class then add #ResponseBody annotation on top of method fuzzerServiceAge() and #RequestBody annotation before UserMO userMO and try again.
Like this
#PostMapping("/targetService/createUser")
#ResponseBody
public String fuzzerServiceAge(#RequestBody UserMO userMO) {
//logic
}

how to change value after controller in spring RESTful

I want change data after #RestController class in Spring
I need to change the fields data based on the specified language.
example:
enum:
public enum Gender {
WOMAN, MAN, OTHER
}
the controller:
#RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
public User get(#PathVariable Long id) throws Exception {
log.debug("Entering get( id={} )", id);
User user = null;
try {
user = UserService.get(id);
} catch (Exception e) {
log.debug("Error occurred in get().", e);
throw e;
}
return user;
}
this output:
{
fisrtName: 'john',
lastName: 'doe',
gender: 'man'
}
change to this output:
{
fisrtName: 'john',
lastName: 'doe',
gender: 'homme'
}
I assume user.gender is a enum. Then you could add a custom Serializer and Deserializer to your JSON Mapper (hopefully Jackson).
#JsonComponent
public class TranslatedGenderJsonComponent {
public static class TranslatedGenderSerializer extends StdSerializer<Gender> {
public TranslatedGenderSerializer () {
super(Gender.class);
}
public void serialize(
Gender gender, JsonGenerator generator, SerializerProvider provider)
throws IOException, JsonProcessingException {
String translatedGender = myTranslateFunction(gender);
generator.writeString(translatedGender );
}
}
public static class TranslatedGenderDeserializer extends StdDeserializer<Gender> {
public TranslatedGenderDeserializer () {
super(Gender.class);
}
public Gender deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonToken currentToken = jp.getCurrentToken();
if (currentToken.equals(JsonToken.VALUE_STRING)) {
String text jp.getText().trim();
Gender gender = myInverseTranslateFunction(text);
return gender;
} else if (currentToken.equals(JsonToken.VALUE_NULL)) {
return getNullValue();
} else {
throw ctxt.mappingException(Gender.class);
}
}
}
}
This code is not tested, it is just written in the browser! (I am quite unsure with the deserializer/parser code.) But I hope it will guide you to a solution.
I changed code:
the controller:
#Autowired
GlobalMassengerAdvice globalMassenger;
#RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
public User get(#PathVariable Long id) throws Exception {
log.debug("Entering get( id={} )", id);
User user = null;
try {
user = userService.get(id);
String value = globalMassenger.getMessage(user.getGender().name());
user.setGender( value );
} catch (Exception e) {
log.debug("Error occurred in get().", e);
throw e;
}
return user;
}
I add new Class (GlobalMassengerAdvice):
#ControllerAdvice
public class GlobalMassengerAdvice {
#Autowired
private MessageSource messageSource;
public String getMessage(final String messageKey, final Object... messageParameters) {
Locale locale = LocaleContextHolder.getLocale();
String result = null;
try {
result = messageSource.getMessage(messageKey, messageParameters, locale);
} catch (NoSuchMessageException e) {
result = messageKey;
}
return result;
}
}

Spring boot paypal INVALID_RESOURCE_ID

I'm trying to implement PayPal's API, but as this is the first time im using it, I get some errors.
This is the code:
Controller
#PostMapping("/checkout/paypal")
public String checkout_paypal(#RequestParam(value = "id") Integer id) throws Exception {
Order order = orderServices.findOrderById(id);
try {
Payment payment = service.createPayment(order.getTotalPrice().doubleValue(), "EUR", "PAYPAL",
"ORDER", "Order id:"+order.getId(), "http://localhost:4200/checkout?id="+order.getId(),
"http://localhost:4200/checkout?id="+order.getId());
for(Links link:payment.getLinks()) {
if(link.getRel().equals("approval_url")) {
return "redirect:"+link.getHref();
}
}
} catch (PayPalRESTException e) {
e.printStackTrace();
}
System.out.println("Success");
return "Success";
}
#GetMapping("/successPaymentPaypal")
public String successPayment(#RequestParam(value = "id") Integer id,#RequestParam(value = "paymentId") String paymentId,#RequestParam(value = "PayerID") String PayerID) throws Exception {
System.out.println(id+" "+paymentId+" "+PayerID);
try {
Payment payment = service.executePayment(paymentId, PayerID);
if(payment.getState().equals("approved")){
Order order = orderServices.findOrderById(id);
order.setOrderState(OrderState.PAID);
orderServices.saveOrder(order);
return "success";
}
} catch (PayPalRESTException e) {
throw new Exception("Error occured while processing payment!");
}
return "Done";
}
Service
#Autowired
private APIContext apiContext;
public Payment createPayment(
Double total,
String currency,
String method,
String intent,
String description,
String cancelUrl,
String successUrl) throws PayPalRESTException {
Amount amount = new Amount();
amount.setCurrency(currency);
total = new BigDecimal(total).setScale(2, RoundingMode.HALF_UP).doubleValue();
amount.setTotal(String.format("%.2f", total));
Transaction transaction = new Transaction();
transaction.setDescription(description);
transaction.setAmount(amount);
List<Transaction> transactions = new ArrayList<>();
transactions.add(transaction);
Payer payer = new Payer();
payer.setPaymentMethod(method.toString());
Payment payment = new Payment();
payment.setIntent(intent.toString());
payment.setPayer(payer);
payment.setTransactions(transactions);
RedirectUrls redirectUrls = new RedirectUrls();
redirectUrls.setCancelUrl(cancelUrl);
redirectUrls.setReturnUrl(successUrl);
payment.setRedirectUrls(redirectUrls);
return payment.create(apiContext);
}
public Payment executePayment(String paymentId, String payerId) throws PayPalRESTException{
Payment payment = new Payment();
payment.setId(paymentId);
PaymentExecution paymentExecute = new PaymentExecution();
paymentExecute.setPayerId(payerId);
return payment.execute(apiContext, paymentExecute);
}
Config
#Value("${paypal.client.id}")
private String clientId;
#Value("${paypal.mode}")
private String paypalMode;
#Value("${paypal.client.secret}")
private String clientSecret;
#Bean
public Map<String, String> paypalSdkConfig(){
Map<String, String> sdkConfig = new HashMap<>();
sdkConfig.put("mode", paypalMode);
return sdkConfig;
}
#Bean
public OAuthTokenCredential authTokenCredential(){
return new OAuthTokenCredential(clientId, clientSecret, paypalSdkConfig());
}
#Bean
public APIContext apiContext() throws PayPalRESTException{
APIContext apiContext = new APIContext(authTokenCredential().getAccessToken());
apiContext.setConfigurationMap(paypalSdkConfig());
return apiContext;
}
This is the error:
Response code: 404 Error response: {"name":"INVALID_RESOURCE_ID","message":"Requested resource ID was not found.","information_link":"https://developer.paypal.com/docs/api/payments/#errors","debug_id":"c2dc1e86af7fe"}
The checkout/paypal dont give any error, and works well i think, it got me redirect to my frontend, where i make second request, but there is when error comes..
I really dont know what is the problem..
It appears you're integrating the old v1/payments API. You should instead integrate using the current v2/checkout/orders.
See the guide at https://developer.paypal.com/docs/checkout/reference/server-integration/
The best approval flow to pair it with is https://developer.paypal.com/demo/checkout/#/pattern/server
With v2/checkout/orders, always use intent:capture unless you have very specific and well-defined business reasons to add an intervening authorization step

Cannot remove attributes in ldap with spring ldap

we need to make a spring boot project that works with spring ldap.
every things is good.But when we remove a member from a group,the member deleted form group (i see it in debug mode in a Setmembers) but, in ldap(Oracle Internet Directory) that member exists!
Please help me!
//Group Entry
#Entry(objectClasses = {"top", "groupOfUniqueNames", "orclGroup"}, base = "cn=Groups")
public final class Group {
#Id
private Name dn;
#Attribute(name = "cn")
private String name;
private String description;
private String displayName;
#Attribute(name = "ou")
private String ou;
#Attribute(name = "uniqueMember")
private Set<Name> members;
public void addMember(Name newMember) {
members.add(newMember);
}
public void removeMember(Name member) {
members.remove(member);
}
//Custom LdapUtils
public class CustomLdapUtils {
private static final String GROUP_BASE_DN = "cn=Groups";
private static final String USER_BASE_DN = "cn=Users";
public Name buildGroupDn(String name) {
return LdapNameBuilder.newInstance(GROUP_BASE_DN)
.add("cn","Charts")
.add("cn",name)
.build();
}
private static final CsutomLdapUtils LDAP_UTILS = new CsutomLdapUtils ();
private CsutomLdapUtils () {
}
public Name buildPersonDn(String name) {
return LdapNameBuilder.newInstance(USER_BASE_DN)
.add("cn", name)
.build();
}
}
//Controller
#DeleteMapping(value = "/memberOfGroup", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> removeMemberFromGroup(#RequestBody Map<String,String> map) throws NamingException {
List<Group> groupToFind = ldapSearchGroupsService.getGroupByCn(map.get("groupName"));
List<User> userToFind = ldapSearchUserService.getAllUserByUserName(map.get("userName"));
if (groupToFind.isEmpty()) {
//TODO : Group no found!
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
for (Group group1 : groupToFind) {
group1.removeMember(userToFind.stream().findAny().get().getDn());
//ldapBindGroupService.deleteMemberFromGroup(group1);
DirContextOperations ctx = ldapTemplate.lookupContext(CustomLdapUtils.getInstance().buildGroupDn(map.get("groupName")));
ctx.removeAttributeValue("uniqueMember",map.get("userName"));
ctx.rebind(CustomLdapUtils.getInstance().buildGroupDn(map.get("groupName")),map.get("groupName"));
ldapTemplate.modifyAttributes(ctx);
}
return new ResponseEntity<>(HttpStatus.OK);
}
}
Is some problem in code? or need some methods?
Finally after several search and debug,i found the problem!
In each ldap env,after every changes,the directory must be commit and apply.
In above code,i implemented that,but not in true way!
Best way is here:
#DeleteMapping(value = "/membersOfGroup", consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> removeMemberFromGroup(#RequestBody Map<String,String> map) {
List<Group> groupToFind = ldapSearchGroupsService.getGroupByCn(map.get("groupName"));
List<User> userToFind = ldapSearchUserService.getAllUserByUserName(map.get("userName"));
if (groupToFind.isEmpty()) {
//TODO : Group no found!
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
for (Group group1 : groupToFind) {
group1.removeMember(userToFind.stream().findAny().get().getDn());
DirContextOperations ctx = ldapTemplate.lookupContext(CustomLdapUtils.getInstance().buildGroupDn(map.get("groupName")));
ctx.removeAttributeValue("member",CustomLdapUtils.getInstance().buildPersonDn(map.get("userName")));
//True way
ldapTemplate.update(group1);
}
return new ResponseEntity<>(HttpStatus.OK);
}
}

how does we enhance presistent class

AS I am new to JDO and datastore
I have set up a simple Google App Engine project based on Spring Framework to Perform Basic CRUD operation.
When I run my Application Its Show's
Persistent class "Class com.pandian.model.Customer does not seem to have been enhanced. You may want to rerun the enhancer and check for errors in the output." has no table in the database, but the operation requires it. Please check the specification of the MetaData for this class.
Customer
#PersistenceCapable
public class Customer {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private String name;
#Persistent
private String email;
#Persistent
private Date date;
public Key getKey() {
return key;
}
public void setKey(Key key) {
this.key = key;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Customer() {
super();
}
Controller
#Controller
#RequestMapping("/customer")
public class CustomerController {
#RequestMapping(value = "/add", method = RequestMethod.GET)
public String getAddCustomerPage(ModelMap model) {
return "add";
}
#RequestMapping(value = "/add", method = RequestMethod.POST)
public ModelAndView add(HttpServletRequest request, ModelMap model) {
String name = request.getParameter("name");
String email = request.getParameter("email");
Customer c = new Customer();
c.setName(name);
c.setEmail(email);
c.setDate(new Date());
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(c);
} finally {
pm.close();
}
return new ModelAndView("redirect:list");
}
#RequestMapping(value = "/update/{name}", method = RequestMethod.GET)
public String getUpdateCustomerPage(#PathVariable String name,
HttpServletRequest request, ModelMap model) {
PersistenceManager pm = PMF.get().getPersistenceManager();
Query q = pm.newQuery(Customer.class);
q.setFilter("name == nameParameter");
q.setOrdering("date desc");
q.declareParameters("String nameParameter");
try {
#SuppressWarnings("unchecked")
List<Customer> results = (List<Customer>) q.execute(name);
if (results.isEmpty()) {
model.addAttribute("customer", null);
} else {
model.addAttribute("customer", results.get(0));
}
} finally {
q.closeAll();
pm.close();
}
return "update";
}
#RequestMapping(value = "/update", method = RequestMethod.POST)
public ModelAndView update(HttpServletRequest request, ModelMap model) {
String name = request.getParameter("name");
String email = request.getParameter("email");
String key = request.getParameter("key");
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Customer c = pm.getObjectById(Customer.class, key);
c.setName(name);
c.setEmail(email);
c.setDate(new Date());
} finally {
pm.close();
}
// return to list
return new ModelAndView("redirect:list");
}
#RequestMapping(value = "/delete/{key}", method = RequestMethod.GET)
public ModelAndView delete(#PathVariable String key,
HttpServletRequest request, ModelMap model) {
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Customer c = pm.getObjectById(Customer.class, key);
pm.deletePersistent(c);
} finally {
pm.close();
}
PMF
public final class PMF {
private static final PersistenceManagerFactory pmfInstance = JDOHelper
.getPersistenceManagerFactory("transactions-optional");
private PMF() {
}
list//JSP
....
<%
if(request.getAttribute("customerList")!=null){
List<Customer> customers =
(List<Customer>)request.getAttribute("customerList");
if(!customers.isEmpty()){
for(Customer c : customers){
%>
<tr>
<td><%=c.getName() %></td>
<td><%=c.getEmail() %></td>
...
Any body help me out from this.....
When you looked at the AppEngine docs for using JDO, you would have come across
https://developers.google.com/eclipse/docs/appengine_orm
This tells you HOW to enhance classes for use with JDO.

Resources