killbill-uncached

Details

diff --git a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
index 2ff19b9..63fc93a 100644
--- a/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
+++ b/api/src/main/java/com/ning/billing/payment/api/PaymentApi.java
@@ -61,7 +61,10 @@ public interface PaymentApi {
    
    public List<PaymentMethod> getPaymentMethods(final Account account, final boolean withPluginDetail)
     throws PaymentApiException;
-   
+
+   public PaymentMethod getPaymentMethodById(final UUID paymentMethodId)
+   throws PaymentApiException;
+
    public PaymentMethod getPaymentMethod(final Account account, final UUID paymentMethodId, final boolean withPluginDetail)
    throws PaymentApiException;
    
diff --git a/api/src/main/java/com/ning/billing/util/dao/ObjectType.java b/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
index 196cc19..b961b39 100644
--- a/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
+++ b/api/src/main/java/com/ning/billing/util/dao/ObjectType.java
@@ -23,7 +23,8 @@ public enum ObjectType {
     INVOICE("invoice"),
     PAYMENT("payment"),
     RECURRING_INVOICE_ITEM("recurring_invoice_item"),
-    SUBSCRIPTION("subscription");
+    SUBSCRIPTION("subscription"),
+    PAYMENT_METHOD("payment method");
 
     private final String objectName;
     ObjectType(String objectName) {
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentMethodJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentMethodJson.java
index b9a554f..8f6c71b 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentMethodJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentMethodJson.java
@@ -15,42 +15,66 @@
  */
 package com.ning.billing.jaxrs.json;
 
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.ning.billing.account.api.Account;
 import com.ning.billing.payment.api.PaymentMethod;
 import com.ning.billing.payment.api.PaymentMethodPlugin;
+import com.ning.billing.payment.api.PaymentMethodPlugin.PaymentMethodKVInfo;
 
 public class PaymentMethodJson {
 
     private final String paymentMethodId;
     private final String accountId;
-    private final Boolean isActive;
+    private final Boolean isDefault;
     private final String pluginName;
     private final PaymentMethodPluginDetailJson pluginInfo;
 
     @JsonCreator
     public PaymentMethodJson(@JsonProperty("paymentMethodId") String paymentMethodId,
             @JsonProperty("accountId") String accountId,
-            @JsonProperty("isActive") Boolean isActive,
+            @JsonProperty("isDefault") Boolean isDefault,
             @JsonProperty("pluginName") String pluginName,
             @JsonProperty("pluginInfo") PaymentMethodPluginDetailJson pluginInfo) {
         super();
         this.paymentMethodId = paymentMethodId;
         this.accountId = accountId;
-        this.isActive = isActive;
+        this.isDefault = isDefault;
         this.pluginName = pluginName;
         this.pluginInfo = pluginInfo;
     }
+    
+    public static PaymentMethodJson toPaymentMethodJson(Account account, PaymentMethod in) {
+
+        final boolean isDefault = account.getPaymentMethodId() != null && account.getPaymentMethodId().equals(in.getId());
+        PaymentMethodPluginDetailJson detail = null;
+        if (in.getPluginDetail() != null) {
+            List<PaymentMethodProperties> properties = null;
+            if (in.getPluginDetail().getProperties() != null) {
+                properties = new ArrayList<PaymentMethodJson.PaymentMethodProperties>(Collections2.transform(in.getPluginDetail().getProperties(), new Function<PaymentMethodKVInfo,PaymentMethodProperties>() {
+                    @Override
+                    public PaymentMethodProperties apply(PaymentMethodKVInfo input) {
+                        return new PaymentMethodProperties(input.getKey(), input.getValue().toString(), input.getIsUpdatable());
+                    }
+                }));
+                detail = new PaymentMethodPluginDetailJson(in.getPluginDetail().getExternalPaymentMethodId(), properties);
+            }
+        }
+        return new PaymentMethodJson(in.getId().toString(), account.getId().toString(), isDefault, in.getPluginName(), detail);
+    }
 
     public PaymentMethod toPaymentMethod() {
         return new PaymentMethod() {
             @Override
             public Boolean isActive() {
-                return isActive;
+                return true;
             }
             @Override
             public String getPluginName() {
@@ -58,11 +82,11 @@ public class PaymentMethodJson {
             }
             @Override
             public UUID getId() {
-                return UUID.fromString(paymentMethodId);
+                return paymentMethodId != null ? UUID.fromString(paymentMethodId) : null;
             }
             @Override
             public UUID getAccountId() {
-                return UUID.fromString(accountId);
+                return accountId != null ? UUID.fromString(accountId) : null;
             }
             @Override
             public PaymentMethodPlugin getPluginDetail() {
@@ -106,8 +130,9 @@ public class PaymentMethodJson {
         return accountId;
     }
 
-    public Boolean getIsActive() {
-        return isActive;
+    @JsonProperty("isDefault")
+    public Boolean isDefault() {
+        return isDefault;
     }
 
     public String getPluginName() {
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
index dc38f73..d83c164 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AccountResource.java
@@ -38,11 +38,11 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
 
 import com.ning.billing.util.api.CustomFieldUserApi;
 import com.ning.billing.util.dao.ObjectType;
 
-import org.skife.config.Default;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -75,9 +75,7 @@ import com.ning.billing.jaxrs.util.TagHelper;
 import com.ning.billing.payment.api.Payment;
 import com.ning.billing.payment.api.PaymentApi;
 import com.ning.billing.payment.api.PaymentApiException;
-import com.ning.billing.payment.api.PaymentInfoEvent;
 import com.ning.billing.payment.api.PaymentMethod;
-import com.ning.billing.util.api.TagDefinitionApiException;
 
 import com.ning.billing.util.api.TagUserApi;
 
@@ -297,15 +295,16 @@ public class AccountResource extends JaxRsResourceBase {
             @QueryParam(QUERY_PAYMENT_METHOD_IS_DEFAULT) @DefaultValue("false") final Boolean isDefault,
             @HeaderParam(HDR_CREATED_BY) final String createdBy,
             @HeaderParam(HDR_REASON) final String reason,
-            @HeaderParam(HDR_COMMENT) final String comment) {
+            @HeaderParam(HDR_COMMENT) final String comment,
+            @javax.ws.rs.core.Context UriInfo uriInfo) {
 
         try {
+            
             PaymentMethod data = json.toPaymentMethod();
             Account account = accountApi.getAccountById(data.getAccountId());
             
-            // STEPH we might want an API to retrieve a single PaymentMethod based on ID
-            /* UUID paymentMethodId = */ paymentApi.addPaymentMethod(data.getPluginName(), account, isDefault, data.getPluginDetail(), context.createContext(createdBy, reason, comment));
-            return uriBuilder.buildResponse(AccountResource.class, "getPaymentMethods", account.getId());
+            UUID paymentMethodId = paymentApi.addPaymentMethod(data.getPluginName(), account, isDefault, data.getPluginDetail(), context.createContext(createdBy, reason, comment));
+            return uriBuilder.buildResponse(PaymentMethodResource.class, "getPaymentMethod", paymentMethodId, uriInfo.getBaseUri().toString());
         } catch (AccountApiException e) {
             final String error = String.format("Failed to create account %s", json);
             log.info(error, e);
@@ -319,18 +318,24 @@ public class AccountResource extends JaxRsResourceBase {
         }
     }
     
-
     @GET
-    @Path("/{accountId:\\w+-\\w+-\\w+-\\w+-\\w+}/" + PAYMENT_METHODS)
+    @Path("/{accountId:" + UUID_PATTERN + "}/" + PAYMENT_METHODS)
     @Produces(APPLICATION_JSON)
     public Response getPaymentMethods(@PathParam("accountId") String accountId,
             @QueryParam(QUERY_PAYMENT_METHOD_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
             @QueryParam(QUERY_PAYMENT_LAST4_CC) final String last4CC,
             @QueryParam(QUERY_PAYMENT_NAME_ON_CC) final String nameOnCC) {
+            
         try {
-            Account account = accountApi.getAccountById(UUID.fromString(accountId));
+            final Account account = accountApi.getAccountById(UUID.fromString(accountId));
             List<PaymentMethod> methods = paymentApi.getPaymentMethods(account, withPluginInfo);
-            return Response.status(Status.OK).entity(methods).build();
+            List<PaymentMethodJson> json = new ArrayList<PaymentMethodJson>(Collections2.transform(methods, new Function<PaymentMethod, PaymentMethodJson>() {
+                @Override
+                public PaymentMethodJson apply(PaymentMethod input) {
+                    return PaymentMethodJson.toPaymentMethodJson(account, input);
+                }
+            }));
+            return Response.status(Status.OK).entity(json).build();
         } catch (PaymentApiException e) {
             return Response.status(Status.NOT_FOUND).build();
         } catch (AccountApiException e) {
@@ -338,6 +343,28 @@ public class AccountResource extends JaxRsResourceBase {
         }
     }
     
+    @PUT
+    @Consumes(APPLICATION_JSON)
+    @Produces(APPLICATION_JSON)
+    @Path("/{accountId:" + UUID_PATTERN + "}/" + PAYMENT_METHODS + "/{paymentMethodId:" + UUID_PATTERN + "}/" + PAYMENT_METHODS_DEFAULT_PATH_POSTFIX)    
+    public Response setDefaultPaymentMethod(@PathParam("accountId") final String accountId,
+            @PathParam("paymentMethodId") final String paymentMethodId,            
+            @HeaderParam(HDR_CREATED_BY) final String createdBy,
+            @HeaderParam(HDR_REASON) final String reason,
+            @HeaderParam(HDR_COMMENT) final String comment) {
+        try {
+            final Account account = accountApi.getAccountById(UUID.fromString(accountId));
+            paymentApi.setDefaultPaymentMethod(account, UUID.fromString(paymentMethodId), context.createContext(createdBy, reason, comment));
+            return Response.status(Status.OK).build();
+        } catch (AccountApiException e) {
+            return Response.status(Status.BAD_REQUEST).build();
+        } catch (PaymentApiException e) {
+            return Response.status(Status.NOT_FOUND).build();
+        } catch (IllegalArgumentException e) {
+            return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+        }
+    }
+    
     /****************************      TAGS     ******************************/
     @GET
     @Path(CUSTOM_FIELD_URI)
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
index 2b4d6a9..fbf052f 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
@@ -61,8 +61,7 @@ public interface JaxrsResource {
 	public static final String QUERY_PAYMENT_METHOD_PLUGIN_INFO = "plugin_info";
 	public static final String QUERY_PAYMENT_METHOD_IS_DEFAULT = "is_default";
 	
-	
-	
+		
 	
 	public static final String ACCOUNTS = "accounts";  
     public static final String ACCOUNTS_PATH = PREFIX + "/" + ACCOUNTS;
@@ -73,7 +72,7 @@ public interface JaxrsResource {
     public static final String SUBSCRIPTIONS = "subscriptions";     
     public static final String SUBSCRIPTIONS_PATH = PREFIX + "/" + SUBSCRIPTIONS;
 
-    public static final String TAG_DEFINITIONS = "tag_definitions";     
+    public static final String TAG_DEFINITIONS = "tagDefinitions";     
     public static final String TAG_DEFINITIONS_PATH = PREFIX + "/" + TAG_DEFINITIONS;
 
     public static final String INVOICES = "invoices";     
@@ -83,6 +82,9 @@ public interface JaxrsResource {
     public static final String PAYMENTS_PATH = PREFIX + "/" + PAYMENTS;    
 
     public static final String PAYMENT_METHODS = "paymentMethods";     
+    public static final String PAYMENT_METHODS_PATH  = PREFIX + "/" + PAYMENT_METHODS;
+    public static final String PAYMENT_METHODS_DEFAULT_PATH_POSTFIX = "setDefault";
+    
     
     public static final String CREDITS = "credits";
     public static final String CREDITS_PATH = PREFIX + "/" + CREDITS;
@@ -91,7 +93,7 @@ public interface JaxrsResource {
     public static final String CHARGEBACKS_PATH = PREFIX + "/" + CHARGEBACKS;
 
     public static final String TAGS = "tags";
-    public static final String CUSTOM_FIELDS = "custom_fields";
+    public static final String CUSTOM_FIELDS = "customFields";
     
     public static final String CATALOG = "catalog";
     public static final String CATALOG_PATH = PREFIX + "/" + CATALOG;
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentMethodResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentMethodResource.java
new file mode 100644
index 0000000..14ac19b
--- /dev/null
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentMethodResource.java
@@ -0,0 +1,154 @@
+/* 
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+package com.ning.billing.jaxrs.resources;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import java.util.List;
+import java.util.UUID;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.ning.billing.ErrorCode;
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountApiException;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.jaxrs.json.AccountJson;
+import com.ning.billing.jaxrs.json.PaymentMethodJson;
+import com.ning.billing.jaxrs.util.Context;
+import com.ning.billing.jaxrs.util.JaxrsUriBuilder;
+import com.ning.billing.jaxrs.util.TagHelper;
+import com.ning.billing.payment.api.PaymentApi;
+import com.ning.billing.payment.api.PaymentApiException;
+import com.ning.billing.payment.api.PaymentMethod;
+import com.ning.billing.util.api.CustomFieldUserApi;
+import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.dao.ObjectType;
+
+@Singleton
+@Path(JaxrsResource.PAYMENT_METHODS_PATH)
+public class PaymentMethodResource extends JaxRsResourceBase {
+
+    private static final Logger log = LoggerFactory.getLogger(PaymentMethodResource.class);
+    
+    private final PaymentApi paymentApi;
+    private final AccountUserApi accountApi;
+    private final Context context;
+    
+    @Inject
+    public PaymentMethodResource(final JaxrsUriBuilder uriBuilder, final AccountUserApi accountApi,
+            final PaymentApi paymentApi, final TagUserApi tagUserApi, final TagHelper tagHelper,
+            final CustomFieldUserApi customFieldUserApi, final Context context) {
+        super(uriBuilder, tagUserApi, tagHelper, customFieldUserApi);
+        this.paymentApi = paymentApi;
+        this.accountApi = accountApi;
+        this.context = context;
+    }
+    
+    
+    
+    @GET
+    @Path("/{paymentMethodId:" + UUID_PATTERN + "}")    
+    @Produces(APPLICATION_JSON)
+    public Response getPaymentMethod(@PathParam("paymentMethodId") final String paymentMethodId,
+            @QueryParam(QUERY_PAYMENT_METHOD_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo) {
+        try {
+            PaymentMethod paymentMethod = paymentApi.getPaymentMethodById(UUID.fromString(paymentMethodId));
+            final Account account = accountApi.getAccountById(paymentMethod.getAccountId());  
+            if (withPluginInfo) {
+                paymentMethod = paymentApi.getPaymentMethod(account, paymentMethod.getId(), true);
+            }
+            PaymentMethodJson json = PaymentMethodJson.toPaymentMethodJson(account, paymentMethod);
+
+            return Response.status(Status.OK).entity(json).build();
+        } catch (AccountApiException e) {
+            return Response.status(Status.NO_CONTENT).build();            
+        } catch (PaymentApiException e) { 
+            return Response.status(Status.NO_CONTENT).entity("PaymentMethod does not exist").build();
+        }
+    }
+
+
+    @PUT
+    @Consumes(APPLICATION_JSON)
+    @Produces(APPLICATION_JSON)
+    @Path("/{paymentMethodId:" + UUID_PATTERN + "}")
+    public Response updatePaymentMethod(final PaymentMethodJson json,
+            @PathParam("paymentMethodId") final String paymentMethodId,
+            @HeaderParam(HDR_CREATED_BY) final String createdBy,
+            @HeaderParam(HDR_REASON) final String reason,
+            @HeaderParam(HDR_COMMENT) final String comment) {
+        try {
+
+            final PaymentMethod input = json.toPaymentMethod();            
+            final PaymentMethod paymentMethod = paymentApi.getPaymentMethodById(UUID.fromString(paymentMethodId));
+ 
+            final Account account = accountApi.getAccountById(paymentMethod.getAccountId());
+
+            paymentApi.updatePaymentMethod(account, paymentMethod.getId(), input.getPluginDetail());
+            return getPaymentMethod(paymentMethod.getId().toString(), false);
+        } catch (PaymentApiException e) { 
+            return Response.status(Status.NO_CONTENT).entity("PaymentMethod does not exist").build();                          
+        } catch (AccountApiException e) {
+            return Response.status(Status.NO_CONTENT).build();              
+        } catch (IllegalArgumentException e) {
+            return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+        }
+    }
+    
+    @DELETE
+    @Produces(APPLICATION_JSON)
+    @Path("/{paymentMethodId:" + UUID_PATTERN + "}")
+    public Response deletePaymentMethod(@PathParam("paymentMethodId") final String paymentMethodId,
+            @HeaderParam(HDR_CREATED_BY) final String createdBy,
+            @HeaderParam(HDR_REASON) final String reason,
+            @HeaderParam(HDR_COMMENT) final String comment) {
+        try {
+
+            final PaymentMethod paymentMethod = paymentApi.getPaymentMethodById(UUID.fromString(paymentMethodId));            
+            final Account account = accountApi.getAccountById(paymentMethod.getAccountId());            
+            paymentApi.deletedPaymentMethod(account, UUID.fromString(paymentMethodId), context.createContext(createdBy, reason, comment));
+            return Response.status(Status.OK).build();
+        } catch (PaymentApiException e) { 
+            return Response.status(Status.NO_CONTENT).entity("PaymentMethod does not exist").build();                          
+        } catch (AccountApiException e) {
+            return Response.status(Status.NO_CONTENT).build();              
+        } catch (IllegalArgumentException e) {
+            return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+        }
+    }
+
+    @Override
+    protected ObjectType getObjectType() {
+        return ObjectType.PAYMENT_METHOD;
+    }
+}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
index 88b2de7..a55f952 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/SubscriptionResource.java
@@ -235,7 +235,7 @@ public class SubscriptionResource extends JaxRsResourceBase {
     public Response cancelSubscriptionPlan(final @PathParam("subscriptionId") String subscriptionId,
             @QueryParam(QUERY_REQUESTED_DT) final String requestedDate,
             @QueryParam(QUERY_CALL_COMPLETION) @DefaultValue("false") final Boolean callCompletion,
-            @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("3") final long timeoutSec,
+            @QueryParam(QUERY_CALL_TIMEOUT) @DefaultValue("5") final long timeoutSec,
             @HeaderParam(HDR_CREATED_BY) final String createdBy,
             @HeaderParam(HDR_REASON) final String reason,
             @HeaderParam(HDR_COMMENT) final String comment) {
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/JaxrsUriBuilder.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/JaxrsUriBuilder.java
index 0917106..c291d95 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/JaxrsUriBuilder.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/JaxrsUriBuilder.java
@@ -24,15 +24,33 @@ import com.ning.billing.jaxrs.resources.JaxrsResource;
 
 public class JaxrsUriBuilder {
 
+    public Response buildResponse(final Class<? extends JaxrsResource> theClass, final String getMethodName, final Object objectId) {
+        URI uri = UriBuilder.fromPath(objectId.toString()).build();
+        Response.ResponseBuilder ri = Response.created(uri);
+        return ri.entity(new Object() {
+            @SuppressWarnings(value = "all")
+            public URI getUri() {
+                final URI newUriFromResource = UriBuilder.fromResource(theClass).path(theClass, getMethodName).build(objectId);
+                return newUriFromResource;
+            }
+        }).build();
+    }
+
 	
-	public Response buildResponse(final Class<? extends JaxrsResource> theClass, final String getMethodName, final Object objectId) {
-		URI uri = UriBuilder.fromPath(objectId.toString()).build();
-		Response.ResponseBuilder ri = Response.created(uri);
-		return ri.entity(new Object() {
-			@SuppressWarnings(value = "all")
-			public URI getUri() {
-				return UriBuilder.fromResource(theClass).path(theClass, getMethodName).build(objectId);
-			}
-		}).build();
-	}
+    public Response buildResponse(final Class<? extends JaxrsResource> theClass, final String getMethodName, final Object objectId, String baseUri) {
+        
+        // Let's build a n absolute location for cross resources
+        // See Jersey ContainerResponse.setHeaders
+        StringBuilder tmp  = new StringBuilder(baseUri.substring(0, baseUri.length() - 1));
+        tmp.append(UriBuilder.fromResource(theClass).path(theClass, getMethodName).build(objectId).toString());
+        final URI newUriFromResource = UriBuilder.fromUri(tmp.toString()).build();
+        Response.ResponseBuilder ri = Response.created(newUriFromResource);
+        return ri.entity(new Object() {
+            @SuppressWarnings(value = "all")
+            public URI getUri() {
+                
+                return newUriFromResource;
+            }
+        }).build();
+    }
 }
diff --git a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
index 2d94661..8c0ecf5 100644
--- a/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/com/ning/billing/payment/api/DefaultPaymentApi.java
@@ -118,6 +118,11 @@ public class DefaultPaymentApi implements PaymentApi {
         return methodProcessor.getPaymentMethods(account, withPluginDetail);
     }
 
+    public PaymentMethod getPaymentMethodById(final UUID paymentMethodId)
+    throws PaymentApiException {
+        return methodProcessor.getPaymentMethodById(paymentMethodId);        
+    }
+
     @Override
     public PaymentMethod getPaymentMethod(final Account account, UUID paymentMethod, boolean withPluginDetail)
         throws PaymentApiException {
diff --git a/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
index 5ff43dc..41b79a4 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
@@ -159,11 +159,20 @@ public class PaymentMethodProcessor extends ProcessorBase {
         return getPaymentMethodInternal(paymentMethodModels, account.getId(), account.getExternalKey(), withPluginDetail);
     }
 
+    public PaymentMethod getPaymentMethodById(UUID paymentMethodId)
+    throws PaymentApiException {
+        PaymentMethodModelDao paymentMethodModel = paymentDao.getPaymentMethod(paymentMethodId);
+        if (paymentMethodModel == null) {
+            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId); 
+        }
+        return new DefaultPaymentMethod(paymentMethodModel, null);
+    }
+    
     public PaymentMethod getPaymentMethod(Account account, UUID paymentMethodId, boolean withPluginDetail) 
     throws PaymentApiException {
         PaymentMethodModelDao paymentMethodModel = paymentDao.getPaymentMethod(paymentMethodId);
         if (paymentMethodModel == null) {
-            return null;
+            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_PAYMENT_METHOD, paymentMethodId);             
         }
         List<PaymentMethod> result =  getPaymentMethodInternal(Collections.singletonList(paymentMethodModel), account.getId(), account.getExternalKey(), withPluginDetail);
         return (result.size() == 0) ? null : result.get(0); 
diff --git a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentMethodSqlDao.sql.stg b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentMethodSqlDao.sql.stg
index 27640a6..62a0501 100644
--- a/payment/src/main/resources/com/ning/billing/payment/dao/PaymentMethodSqlDao.sql.stg
+++ b/payment/src/main/resources/com/ning/billing/payment/dao/PaymentMethodSqlDao.sql.stg
@@ -19,20 +19,20 @@ insertPaymentMethod() ::= <<
 
 markPaymentMethodAsDeleted() ::= <<
     UPDATE payment_methods 
-    SET is_active = false
+    SET is_active = 0
     WHERE  id = :id;
 >>
 
 getPaymentMethod() ::= <<
     SELECT <paymentMethodFields()>
       FROM payment_methods
-    WHERE id = :id;
+    WHERE id = :id AND is_active = 1;
 >>
 
 getPaymentMethods() ::= <<
     SELECT <paymentMethodFields()>
       FROM payment_methods
-    WHERE account_id = :accountId;
+    WHERE account_id = :accountId AND is_active = 1;
 >>
 
 getRecordId() ::= <<
diff --git a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
index 00390e0..eb99b14 100644
--- a/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/com/ning/billing/payment/dao/TestPaymentDao.java
@@ -15,6 +15,7 @@
  */
 package com.ning.billing.payment.dao;
 
+import static junit.framework.Assert.assertNull;
 import static org.testng.Assert.assertEquals;
 
 import java.io.IOException;
@@ -23,6 +24,8 @@ import java.math.RoundingMode;
 import java.util.List;
 import java.util.UUID;
 
+import junit.framework.Assert;
+
 import org.apache.commons.io.IOUtils;
 import org.joda.time.DateTime;
 import org.skife.config.ConfigurationObjectFactory;
@@ -260,5 +263,11 @@ public class TestPaymentDao {
         assertEquals(savedMethod.isActive(), isActive);
         assertEquals(savedMethod.getExternalId(), externalPaymentId);
         
+        paymentDao.deletedPaymentMethod(paymentMethodId);
+        
+        PaymentMethodModelDao deletedPaymentMethod = paymentDao.getPaymentMethod(paymentMethodId);
+        assertNull(deletedPaymentMethod);
+        
+        
     }
 }
diff --git a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
index 68b2f28..68ac725 100644
--- a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
+++ b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
@@ -30,6 +30,8 @@ import com.ning.billing.jaxrs.resources.AccountResource;
 import com.ning.billing.jaxrs.resources.BundleResource;
 import com.ning.billing.jaxrs.resources.CatalogResource;
 import com.ning.billing.jaxrs.resources.InvoiceResource;
+import com.ning.billing.jaxrs.resources.PaymentMethodResource;
+import com.ning.billing.jaxrs.resources.PaymentResource;
 import com.ning.billing.jaxrs.resources.SubscriptionResource;
 import com.ning.billing.jaxrs.resources.TagResource;
 import com.ning.billing.jaxrs.util.KillbillEventHandler;
@@ -70,6 +72,8 @@ public class KillbillServerModule extends AbstractModule
         bind(InvoiceResource.class).asEagerSingleton();
         bind(TagResource.class).asEagerSingleton();
         bind(CatalogResource.class).asEagerSingleton();
+        bind(PaymentMethodResource.class).asEagerSingleton();        
+        bind(PaymentResource.class).asEagerSingleton();                
         bind(KillbillEventHandler.class).asEagerSingleton();
     }
 
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
index 324adbd..9fe5ade 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
@@ -17,7 +17,9 @@ package com.ning.billing.jaxrs;
 
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
 
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -46,8 +48,11 @@ import com.ning.billing.jaxrs.json.BundleJsonNoSubscriptions;
 import com.ning.billing.jaxrs.json.CustomFieldJson;
 import com.ning.billing.jaxrs.json.InvoiceJsonSimple;
 import com.ning.billing.jaxrs.json.PaymentJsonSimple;
+import com.ning.billing.jaxrs.json.PaymentMethodJson;
+import com.ning.billing.jaxrs.json.PaymentMethodJson.PaymentMethodPluginDetailJson;
 import com.ning.billing.jaxrs.json.SubscriptionJsonNoEvents;
 import com.ning.billing.jaxrs.json.TagDefinitionJson;
+import com.ning.billing.payment.api.PaymentMethod;
 import com.ning.http.client.Response;
 
 
@@ -145,13 +150,100 @@ public class TestAccount extends TestJaxrsBase {
         Assert.assertEquals(objFromJson.getBundles().get(0).getSubscriptions().get(0).getEvents().size(), 2);        
     }
 
+	
+
+    @Test(groups="slow", enabled=true)
+    public void testAccountPaymentMethods() throws Exception {
+
+        AccountJson accountJson = createAccount("qwerty", "ytrewq", "qwerty@yahoo.com");
+        assertNotNull(accountJson);
+        
+        String uri = JaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAccountId() + "/" + JaxrsResource.PAYMENT_METHODS;
+        PaymentMethodJson paymentMethodJson = getPaymentMethodJson(accountJson.getAccountId(), getPaymentMethodCCProperties());
+        String baseJson = mapper.writeValueAsString(paymentMethodJson);
+        Map<String, String> queryParams = new HashMap<String, String>();
+        queryParams.put(JaxrsResource.QUERY_PAYMENT_METHOD_IS_DEFAULT, "true");
+    
+        Response response = doPost(uri, baseJson, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
+        assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+        String locationCC = response.getHeader("Location");
+        Assert.assertNotNull(locationCC);
+
+        // Retrieves by Id based on Location returned
+        response = doGetWithUrl(locationCC, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+        baseJson = response.getResponseBody();
+        PaymentMethodJson paymentMethodCC = mapper.readValue(baseJson, PaymentMethodJson.class);
+        assertTrue(paymentMethodCC.isDefault());
+        //
+        // Add another payment method
+        //
+        uri = JaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAccountId() + "/" + JaxrsResource.PAYMENT_METHODS;
+        paymentMethodJson = getPaymentMethodJson(accountJson.getAccountId(), getPaymentMethodPaypalProperties());
+        baseJson = mapper.writeValueAsString(paymentMethodJson);
+    
+        response = doPost(uri, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
+
+        String locationPP = response.getHeader("Location");
+        assertNotNull(locationPP);
+        response = doGetWithUrl(locationPP, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+        baseJson = response.getResponseBody();
+        PaymentMethodJson paymentMethodPP = mapper.readValue(baseJson, PaymentMethodJson.class);
+        assertFalse(paymentMethodPP.isDefault());
+        
+        //
+        // FETCH ALL PAYMENT METHODS
+        //
+        queryParams = new HashMap<String, String>();
+        queryParams.put(JaxrsResource.QUERY_PAYMENT_METHOD_PLUGIN_INFO, "true");
+        response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+        baseJson = response.getResponseBody();
+        List<PaymentMethodJson> paymentMethods = mapper.readValue(baseJson, new TypeReference<List<PaymentMethodJson>>() {});
+        assertEquals(paymentMethods.size(), 2);
+        
+        
+        //
+        // CHANGE DEFAULT
+        //
+        uri = JaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAccountId() + "/" + JaxrsResource.PAYMENT_METHODS +  "/" + paymentMethodPP.getPaymentMethodId() + "/" + JaxrsResource.PAYMENT_METHODS_DEFAULT_PATH_POSTFIX;      
+        response = doPut(uri, "{}", DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+
+        response = doGetWithUrl(locationPP, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+        baseJson = response.getResponseBody();
+        PaymentMethodJson paymentMethodPPDefault = mapper.readValue(baseJson, PaymentMethodJson.class);
+        assertTrue(paymentMethodPPDefault.isDefault());
+        
+        //
+        // DELETE NON DEFAULT PM
+        //
+        uri = JaxrsResource.PAYMENT_METHODS_PATH  + "/" + paymentMethodCC.getPaymentMethodId();
+        response = doDelete(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+
+        //
+        // FETCH ALL PAYMENT METHODS
+        //
+        uri = JaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAccountId() + "/" + JaxrsResource.PAYMENT_METHODS;        
+        queryParams = new HashMap<String, String>();
+        queryParams.put(JaxrsResource.QUERY_PAYMENT_METHOD_PLUGIN_INFO, "true");
+        response = doGet(uri, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
+        baseJson = response.getResponseBody();
+        paymentMethods = mapper.readValue(baseJson, new TypeReference<List<PaymentMethodJson>>() {});
+        assertEquals(paymentMethods.size(), 1);
+    }
 
     @Test(groups="slow", enabled=true)
     public void testAccountPayments() throws Exception {
 
         clock.setTime(new DateTime(2012, 4, 25, 0, 3, 42, 0));
 
-
         AccountJson accountJson = createAccountWithDefaultPaymentMethod("ermenehildo", "shtyrgfhwe", "ermenehildo@yahoo.com");
         assertNotNull(accountJson);
 
@@ -176,16 +268,6 @@ public class TestAccount extends TestJaxrsBase {
         Assert.assertEquals(objFromJson.size(), 3);
     }
 
-
-
-
-
-
-
-    protected String getRootPath() {
-        return JaxrsResource.ACCOUNTS_PATH;
-    }
-
 	@Test(groups="slow", enabled=true)
 	public void testTags() throws Exception {
 	    //Create Tag definition
@@ -196,7 +278,7 @@ public class TestAccount extends TestJaxrsBase {
 	        
 	    Map<String, String> queryParams = new HashMap<String, String>();
         queryParams.put(JaxrsResource.QUERY_TAGS, input.getName());
-        String uri = getRootPath() + "/" + JaxrsResource.TAGS + "/" + UUID.randomUUID().toString();
+        String uri = JaxrsResource.ACCOUNTS_PATH + "/" + JaxrsResource.TAGS + "/" + UUID.randomUUID().toString();
 	    response = doPost(uri, null, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
 
         assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
@@ -222,7 +304,7 @@ public class TestAccount extends TestJaxrsBase {
         customFields.add(new CustomFieldJson("3", "value3"));  
         String baseJson = mapper.writeValueAsString(customFields);
 
-        String uri = getRootPath() + "/" + JaxrsResource.CUSTOM_FIELDS + "/" + UUID.randomUUID().toString();
+        String uri = JaxrsResource.ACCOUNTS_PATH + "/" + JaxrsResource.CUSTOM_FIELDS + "/" + UUID.randomUUID().toString();
         Response response = doPost(uri, baseJson, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
         assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
 
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
index 7df9c44..d7f9f27 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
@@ -24,6 +24,7 @@ import java.util.Collections;
 import java.util.EventListener;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.UUID;
@@ -51,7 +52,7 @@ import org.testng.annotations.BeforeSuite;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.datatype.joda.JodaModule;
-import com.google.common.collect.Lists;
+
 import com.google.inject.Module;
 import com.ning.billing.account.glue.AccountModule;
 import com.ning.billing.analytics.setup.AnalyticsModule;
@@ -87,6 +88,7 @@ import com.ning.billing.util.glue.TagStoreModule;
 import com.ning.http.client.AsyncCompletionHandler;
 import com.ning.http.client.AsyncHttpClient;
 import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder;
+import com.ning.http.client.AsyncHttpClientConfig;
 import com.ning.http.client.ListenableFuture;
 import com.ning.http.client.Response;
 import com.ning.jetty.core.CoreConfig;
@@ -94,10 +96,10 @@ import com.ning.jetty.core.server.HttpServer;
 
 public class TestJaxrsBase {
 
-    private final static String PLUGIN_NAME = "noop";
+    protected final static String PLUGIN_NAME = "noop";
 
     // STEPH
-    protected static final int DEFAULT_HTTP_TIMEOUT_SEC =  500000; // 5;
+    protected static final int DEFAULT_HTTP_TIMEOUT_SEC =  6000; // 5;
 
     protected static final Map<String, String> DEFAULT_EMPTY_QUERY = new HashMap<String, String>();
 
@@ -245,7 +247,7 @@ public class TestJaxrsBase {
     @BeforeClass(groups="slow")
     public void setupClass() throws IOException {
         loadConfig();
-        httpClient = new AsyncHttpClient();
+        httpClient = new AsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(DEFAULT_HTTP_TIMEOUT_SEC * 1000).build());
         mapper = new ObjectMapper();
         mapper.registerModule(new JodaModule());
         mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
@@ -323,10 +325,35 @@ public class TestJaxrsBase {
         }
     }
 
-    private PaymentMethodJson getPaymentJson(String accountId) {
-        
-        PaymentMethodProperties properties = new PaymentMethodProperties("whatever", "zero", false);
-        PaymentMethodPluginDetailJson info = new PaymentMethodPluginDetailJson(null, Collections.singletonList(properties));
+    
+    protected List<PaymentMethodProperties> getPaymentMethodCCProperties() {
+        List<PaymentMethodProperties> properties = new ArrayList<PaymentMethodJson.PaymentMethodProperties>();
+        properties.add(new PaymentMethodProperties("type", "CreditCard", false));
+        properties.add(new PaymentMethodProperties("cardType", "Visa", false));
+        properties.add(new PaymentMethodProperties("cardHolderName", "Mr Sniff", false));
+        properties.add(new PaymentMethodProperties("expirationDate", "2015-08", false));        
+        properties.add(new PaymentMethodProperties("maskNumber", "3451", false));
+        properties.add(new PaymentMethodProperties("address1", "23, rue des cerisiers", false));
+        properties.add(new PaymentMethodProperties("address2", "", false));
+        properties.add(new PaymentMethodProperties("city", "Toulouse", false));        
+        properties.add(new PaymentMethodProperties("country", "France", false));
+        properties.add(new PaymentMethodProperties("postalCode", "31320", false));
+        properties.add(new PaymentMethodProperties("state", "Midi-Pyrenees", false));
+        return properties;
+    }
+    
+    
+  protected List<PaymentMethodProperties> getPaymentMethodPaypalProperties() {
+        List<PaymentMethodProperties> properties = new ArrayList<PaymentMethodJson.PaymentMethodProperties>();
+        properties.add(new PaymentMethodProperties("type", "CreditCard", false));
+        properties.add(new PaymentMethodProperties("email", "zouzou@laposte.fr", false));
+        properties.add(new PaymentMethodProperties("baid", "23-8787d-R", false));
+        return properties;
+    }
+    
+    
+    protected PaymentMethodJson getPaymentMethodJson(String accountId, List<PaymentMethodProperties> properties) {
+        PaymentMethodPluginDetailJson info = new PaymentMethodPluginDetailJson(null, properties);
         return new PaymentMethodJson(null, accountId, true, PLUGIN_NAME, info);
     }
     
@@ -335,7 +362,7 @@ public class TestJaxrsBase {
         AccountJson input = createAccount(name, key, email);
         
         final String uri = JaxrsResource.ACCOUNTS_PATH + "/" + input.getAccountId() + "/" + JaxrsResource.PAYMENT_METHODS;
-        PaymentMethodJson paymentMethodJson = getPaymentJson(input.getAccountId());
+        PaymentMethodJson paymentMethodJson = getPaymentMethodJson(input.getAccountId(), null);
         String baseJson = mapper.writeValueAsString(paymentMethodJson);
         Map<String, String> queryParams = new HashMap<String, String>();
         queryParams.put(JaxrsResource.QUERY_PAYMENT_METHOD_IS_DEFAULT, "true");
@@ -344,7 +371,6 @@ public class TestJaxrsBase {
         Assert.assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
 
         
-        
         queryParams = new HashMap<String, String>();
         queryParams.put(JaxrsResource.QUERY_EXTERNAL_KEY, input.getExternalKey());
         response = doGet(JaxrsResource.ACCOUNTS_PATH, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
@@ -511,6 +537,8 @@ public class TestJaxrsBase {
         for (Entry<String, String> q : queryParams.entrySet()) {
             builder.addQueryParameter(q.getKey(), q.getValue());
         }
+        
+
         return builder;
     }