killbill-memoizeit

server: implement audit logs for custom fields, tags and invoices Signed-off-by:

8/27/2013 2:01:29 PM

Details

diff --git a/beatrix/killbill-beatrix.iml b/beatrix/killbill-beatrix.iml
index cecfc16..c0c30bb 100644
--- a/beatrix/killbill-beatrix.iml
+++ b/beatrix/killbill-beatrix.iml
@@ -13,7 +13,6 @@
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-account:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
-    <orderEntry type="library" name="Maven: com.ning.billing.plugin:killbill-plugin-api-payment:0.3.0" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-invoice:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-junction:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-payment:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CustomFieldJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CustomFieldJson.java
index 8fc166b..637930c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CustomFieldJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/CustomFieldJson.java
@@ -16,32 +16,32 @@
 
 package com.ning.billing.jaxrs.json;
 
+import java.util.List;
+
 import javax.annotation.Nullable;
 
+import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.customfield.CustomField;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
-public class CustomFieldJson {
+public class CustomFieldJson extends JsonBase {
 
     private final String name;
     private final String value;
 
-    public CustomFieldJson() {
-        this(null, null);
-    }
-
     @JsonCreator
     public CustomFieldJson(@JsonProperty("name") @Nullable final String name,
-                           @JsonProperty("value") @Nullable final String value) {
+                           @JsonProperty("value") @Nullable final String value,
+                           @JsonProperty("auditLogs") @Nullable final List<AuditLogJson> auditLogs) {
+        super(auditLogs);
         this.name = name;
         this.value = value;
     }
 
-    public CustomFieldJson(final CustomField input) {
-        this.name = input.getFieldName();
-        this.value = input.getFieldValue();
+    public CustomFieldJson(final CustomField input, @Nullable final List<AuditLog> auditLogs) {
+        this(input.getFieldName(), input.getFieldValue(), toAuditLogJson(auditLogs));
     }
 
     public String getName() {
@@ -53,6 +53,15 @@ public class CustomFieldJson {
     }
 
     @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("CustomFieldJson{");
+        sb.append("name='").append(name).append('\'');
+        sb.append(", value='").append(value).append('\'');
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
     public boolean equals(final Object o) {
         if (this == o) {
             return true;
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceItemJsonSimple.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceItemJsonSimple.java
index d879d96..e0ac916 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceItemJsonSimple.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceItemJsonSimple.java
@@ -25,6 +25,7 @@ import org.joda.time.LocalDate;
 
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.util.audit.AuditLog;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -76,11 +77,15 @@ public class InvoiceItemJsonSimple extends JsonBase {
         this.currency = currency;
     }
 
-    public InvoiceItemJsonSimple(final InvoiceItem item) {
+    public InvoiceItemJsonSimple(final InvoiceItem item, @Nullable final List<AuditLog> auditLogs) {
         this(toString(item.getId()), toString(item.getInvoiceId()), toString(item.getLinkedItemId()),
              toString(item.getAccountId()), toString(item.getBundleId()), toString(item.getSubscriptionId()),
              item.getPlanName(), item.getPhaseName(), item.getDescription(), item.getStartDate(), item.getEndDate(),
-             item.getAmount(), item.getCurrency(), null);
+             item.getAmount(), item.getCurrency(), toAuditLogJson(auditLogs));
+    }
+
+    public InvoiceItemJsonSimple(final InvoiceItem input) {
+        this(input, null);
     }
 
     public String getInvoiceItemId() {
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonSimple.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonSimple.java
index ca64d84..987ae5c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonSimple.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonSimple.java
@@ -67,7 +67,7 @@ public class InvoiceJsonSimple extends JsonBase {
         this.accountId = accountId;
     }
 
-    public InvoiceJsonSimple(final Invoice input, final List<AuditLog> auditLogs) {
+    public InvoiceJsonSimple(final Invoice input, @Nullable final List<AuditLog> auditLogs) {
         this(input.getChargedAmount(), input.getCurrency().toString(), input.getCreditedAmount(), input.getRefundedAmount(),
              input.getId().toString(), input.getInvoiceDate(), input.getTargetDate(), String.valueOf(input.getInvoiceNumber()),
              input.getBalance(), input.getAccountId().toString(), toAuditLogJson(auditLogs));
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithItems.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithItems.java
index 52bae04..614adf1 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithItems.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/InvoiceJsonWithItems.java
@@ -20,6 +20,8 @@ import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.UUID;
 
 import javax.annotation.Nullable;
 
@@ -27,6 +29,7 @@ import org.joda.time.LocalDate;
 
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.util.audit.AuditLog;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -52,11 +55,11 @@ public class InvoiceJsonWithItems extends InvoiceJsonSimple {
         this.items = new ArrayList<InvoiceItemJsonSimple>(items);
     }
 
-    public InvoiceJsonWithItems(final Invoice input) {
-        super(input);
+    public InvoiceJsonWithItems(final Invoice input, @Nullable final List<AuditLog> invoiceAuditLogs, @Nullable final Map<UUID, List<AuditLog>> invoiceItemsAuditLogs) {
+        super(input, invoiceAuditLogs);
         this.items = new ArrayList<InvoiceItemJsonSimple>(input.getInvoiceItems().size());
         for (final InvoiceItem item : input.getInvoiceItems()) {
-            this.items.add(new InvoiceItemJsonSimple(item));
+            this.items.add(new InvoiceItemJsonSimple(item, invoiceItemsAuditLogs == null ? null : invoiceItemsAuditLogs.get(item.getId())));
         }
     }
 
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonSimple.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonSimple.java
index 8fcc682..04c5961 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonSimple.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/PaymentJsonSimple.java
@@ -83,7 +83,7 @@ public class PaymentJsonSimple extends JsonBase {
         this.extSecondPaymentIdRef = extSecondPaymentIdRef;
     }
 
-    public PaymentJsonSimple(final Payment src, final List<AuditLog> auditLogs) {
+    public PaymentJsonSimple(final Payment src, @Nullable final List<AuditLog> auditLogs) {
         this(src.getAmount(), src.getPaidAmount(), src.getAccountId().toString(), src.getInvoiceId().toString(),
              src.getId().toString(), src.getPaymentMethodId().toString(), src.getEffectiveDate(), src.getEffectiveDate(),
              src.getAttempts().size(), src.getCurrency().toString(), src.getPaymentStatus().toString(),
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/TagJson.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/TagJson.java
index 12581cb..7840747 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/json/TagJson.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/json/TagJson.java
@@ -40,8 +40,8 @@ public class TagJson extends JsonBase {
         this.tagDefinitionName = tagDefinitionName;
     }
 
-    public TagJson(final TagDefinition tagDefintion, @Nullable final List<AuditLog> auditLogs) {
-        this(tagDefintion.getId().toString(), tagDefintion.getName(), toAuditLogJson(auditLogs));
+    public TagJson(final TagDefinition tagDefinition, @Nullable final List<AuditLog> auditLogs) {
+        this(tagDefinition.getId().toString(), tagDefinition.getName(), toAuditLogJson(auditLogs));
     }
 
     public String getTagDefinitionId() {
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 eebe22b..f66bee1 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
@@ -482,8 +482,9 @@ public class AccountResource extends JaxRsResourceBase {
     @Path("/{accountId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
     @Produces(APPLICATION_JSON)
     public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id,
+                                    @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        return super.getCustomFields(UUID.fromString(id), context.createContext(request));
+        return super.getCustomFields(UUID.fromString(id), auditMode, context.createContext(request));
     }
 
     @POST
@@ -522,9 +523,9 @@ public class AccountResource extends JaxRsResourceBase {
     @Path("/{accountId:" + UUID_PATTERN + "}/" + TAGS)
     @Produces(APPLICATION_JSON)
     public Response getTags(@PathParam(ID_PARAM_NAME) final String id,
-                            @QueryParam(QUERY_AUDIT) @DefaultValue("false") final Boolean withAudit,
+                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException {
-        return super.getTags(UUID.fromString(id), withAudit, context.createContext(request));
+        return super.getTags(UUID.fromString(id), auditMode, context.createContext(request));
     }
 
     @POST
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
index d1d88e6..c25f7de 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/BundleResource.java
@@ -128,8 +128,9 @@ public class BundleResource extends JaxRsResourceBase {
     @Path("/{bundleId:" + UUID_PATTERN + "}/" + CUSTOM_FIELD_URI)
     @Produces(APPLICATION_JSON)
     public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id,
+                                    @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        return super.getCustomFields(UUID.fromString(id), context.createContext(request));
+        return super.getCustomFields(UUID.fromString(id), auditMode, context.createContext(request));
     }
 
     @POST
@@ -164,9 +165,9 @@ public class BundleResource extends JaxRsResourceBase {
     @Path("/{bundleId:" + UUID_PATTERN + "}/" + TAG_URI)
     @Produces(APPLICATION_JSON)
     public Response getTags(@PathParam(ID_PARAM_NAME) final String id,
-                            @QueryParam(QUERY_AUDIT) @DefaultValue("false") final Boolean withAudit,
+                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException {
-        return super.getTags(UUID.fromString(id), withAudit, context.createContext(request));
+        return super.getTags(UUID.fromString(id), auditMode, context.createContext(request));
     }
 
     @PUT
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/EntitlementResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/EntitlementResource.java
index 2e0c428..ae6d628 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/EntitlementResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/EntitlementResource.java
@@ -370,8 +370,9 @@ public class EntitlementResource extends JaxRsResourceBase {
     @Path(CUSTOM_FIELD_URI)
     @Produces(APPLICATION_JSON)
     public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id,
+                                    @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        return super.getCustomFields(UUID.fromString(id), context.createContext(request));
+        return super.getCustomFields(UUID.fromString(id), auditMode, context.createContext(request));
     }
 
     @POST
@@ -408,9 +409,9 @@ public class EntitlementResource extends JaxRsResourceBase {
     @Path(TAG_URI)
     @Produces(APPLICATION_JSON)
     public Response getTags(@PathParam(ID_PARAM_NAME) final String id,
-                            @QueryParam(QUERY_AUDIT) @DefaultValue("false") final Boolean withAudit,
+                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException {
-        return super.getTags(UUID.fromString(id), withAudit, context.createContext(request));
+        return super.getTags(UUID.fromString(id), auditMode, context.createContext(request));
     }
 
     @POST
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
index c3648e6..ff23fee 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/InvoiceResource.java
@@ -49,6 +49,7 @@ 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.catalog.api.Currency;
+import com.ning.billing.clock.Clock;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceApiException;
 import com.ning.billing.invoice.api.InvoiceItem;
@@ -70,11 +71,13 @@ import com.ning.billing.util.api.CustomFieldUserApi;
 import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.api.TagDefinitionApiException;
 import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.audit.AuditLogsForInvoices;
+import com.ning.billing.util.audit.AuditLogsForPayments;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.TenantContext;
-import com.ning.billing.clock.Clock;
 
 import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
 import com.google.inject.Inject;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
@@ -113,6 +116,7 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     public Response getInvoices(@QueryParam(QUERY_ACCOUNT_ID) final String accountId,
                                 @QueryParam(QUERY_INVOICE_WITH_ITEMS) @DefaultValue("false") final boolean withItems,
+                                @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                 @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException {
         final TenantContext tenantContext = context.createContext(request);
 
@@ -120,17 +124,22 @@ public class InvoiceResource extends JaxRsResourceBase {
         accountUserApi.getAccountById(UUID.fromString(accountId), tenantContext);
 
         final List<Invoice> invoices = invoiceApi.getInvoicesByAccount(UUID.fromString(accountId), tenantContext);
+        final AuditLogsForInvoices invoicesAuditLogs = auditUserApi.getAuditLogsForInvoices(invoices, auditMode.getLevel(), tenantContext);
+
         if (withItems) {
             final List<InvoiceJsonWithItems> result = new LinkedList<InvoiceJsonWithItems>();
             for (final Invoice invoice : invoices) {
-                result.add(new InvoiceJsonWithItems(invoice));
+                result.add(new InvoiceJsonWithItems(invoice,
+                                                    invoicesAuditLogs.getInvoiceAuditLogs().get(invoice.getId()),
+                                                    invoicesAuditLogs.getInvoiceItemsAuditLogs()));
             }
 
             return Response.status(Status.OK).entity(result).build();
         } else {
             final List<InvoiceJsonSimple> result = new LinkedList<InvoiceJsonSimple>();
             for (final Invoice invoice : invoices) {
-                result.add(new InvoiceJsonSimple(invoice));
+                result.add(new InvoiceJsonSimple(invoice,
+                                                 invoicesAuditLogs.getInvoiceAuditLogs().get(invoice.getId())));
             }
 
             return Response.status(Status.OK).entity(result).build();
@@ -142,12 +151,23 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     public Response getInvoice(@PathParam("invoiceId") final String invoiceId,
                                @QueryParam(QUERY_INVOICE_WITH_ITEMS) @DefaultValue("false") final boolean withItems,
+                               @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException {
-        final Invoice invoice = invoiceApi.getInvoice(UUID.fromString(invoiceId), context.createContext(request));
+        final TenantContext tenantContext = context.createContext(request);
+        final Invoice invoice = invoiceApi.getInvoice(UUID.fromString(invoiceId), tenantContext);
+        final AuditLogsForInvoices invoicesAuditLogs = auditUserApi.getAuditLogsForInvoices(ImmutableList.<Invoice>of(invoice),
+                                                                                            auditMode.getLevel(),
+                                                                                            tenantContext);
+
         if (invoice == null) {
             throw new InvoiceApiException(ErrorCode.INVOICE_NOT_FOUND, invoiceId);
         } else {
-            final InvoiceJsonSimple json = withItems ? new InvoiceJsonWithItems(invoice) : new InvoiceJsonSimple(invoice);
+            final InvoiceJsonSimple json = withItems ?
+                                           new InvoiceJsonWithItems(invoice,
+                                                                    invoicesAuditLogs.getInvoiceAuditLogs().get(invoice.getId()),
+                                                                    invoicesAuditLogs.getInvoiceItemsAuditLogs()) :
+                                           new InvoiceJsonSimple(invoice,
+                                                                 invoicesAuditLogs.getInvoiceAuditLogs().get(invoice.getId()));
             return Response.status(Status.OK).entity(json).build();
         }
     }
@@ -157,12 +177,23 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Produces(APPLICATION_JSON)
     public Response getInvoiceByNumber(@PathParam("invoiceNumber") final Integer invoiceNumber,
                                        @QueryParam(QUERY_INVOICE_WITH_ITEMS) @DefaultValue("false") final boolean withItems,
+                                       @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                        @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException {
-        final Invoice invoice = invoiceApi.getInvoiceByNumber(invoiceNumber, context.createContext(request));
+        final TenantContext tenantContext = context.createContext(request);
+        final Invoice invoice = invoiceApi.getInvoiceByNumber(invoiceNumber, tenantContext);
+        final AuditLogsForInvoices invoicesAuditLogs = auditUserApi.getAuditLogsForInvoices(ImmutableList.<Invoice>of(invoice),
+                                                                                            auditMode.getLevel(),
+                                                                                            tenantContext);
+
         if (invoice == null) {
             throw new InvoiceApiException(ErrorCode.INVOICE_NOT_FOUND, invoiceNumber);
         } else {
-            final InvoiceJsonSimple json = withItems ? new InvoiceJsonWithItems(invoice) : new InvoiceJsonSimple(invoice);
+            final InvoiceJsonSimple json = withItems ?
+                                           new InvoiceJsonWithItems(invoice,
+                                                                    invoicesAuditLogs.getInvoiceAuditLogs().get(invoice.getId()),
+                                                                    invoicesAuditLogs.getInvoiceItemsAuditLogs()) :
+                                           new InvoiceJsonSimple(invoice,
+                                                                 invoicesAuditLogs.getInvoiceAuditLogs().get(invoice.getId()));
             return Response.status(Status.OK).entity(json).build();
         }
     }
@@ -189,7 +220,7 @@ public class InvoiceResource extends JaxRsResourceBase {
 
         final Account account = accountUserApi.getAccountById(UUID.fromString(accountId), callContext);
 
-        final DateTime inputDateTime =  targetDateTime != null ? DATE_TIME_FORMATTER.parseDateTime(targetDateTime) : clock.getUTCNow();
+        final DateTime inputDateTime = targetDateTime != null ? DATE_TIME_FORMATTER.parseDateTime(targetDateTime) : clock.getUTCNow();
         final LocalDate inputDate = inputDateTime.toDateTime(account.getTimeZone()).toLocalDate();
 
         final Invoice generatedInvoice = invoiceApi.triggerInvoiceGeneration(UUID.fromString(accountId), inputDate, dryRun,
@@ -349,12 +380,15 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Path("/{invoiceId:" + UUID_PATTERN + "}/" + PAYMENTS)
     @Produces(APPLICATION_JSON)
     public Response getPayments(@PathParam("invoiceId") final String invoiceId,
+                                @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                 @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException {
-        final List<Payment> payments = paymentApi.getInvoicePayments(UUID.fromString(invoiceId), context.createContext(request));
+        final TenantContext tenantContext = context.createContext(request);
+        final List<Payment> payments = paymentApi.getInvoicePayments(UUID.fromString(invoiceId), tenantContext);
+        final AuditLogsForPayments auditLogsForPayments = auditUserApi.getAuditLogsForPayments(payments, auditMode.getLevel(), tenantContext);
 
         final List<PaymentJsonSimple> result = new ArrayList<PaymentJsonSimple>(payments.size());
         for (final Payment cur : payments) {
-            result.add(new PaymentJsonSimple(cur));
+            result.add(new PaymentJsonSimple(cur, auditLogsForPayments.getPaymentsAuditLogs().get(cur.getId())));
         }
 
         return Response.status(Status.OK).entity(result).build();
@@ -438,8 +472,9 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Path(CUSTOM_FIELD_URI)
     @Produces(APPLICATION_JSON)
     public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id,
+                                    @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        return super.getCustomFields(UUID.fromString(id), context.createContext(request));
+        return super.getCustomFields(UUID.fromString(id), auditMode, context.createContext(request));
     }
 
     @POST
@@ -474,9 +509,9 @@ public class InvoiceResource extends JaxRsResourceBase {
     @Path(TAG_URI)
     @Produces(APPLICATION_JSON)
     public Response getTags(@PathParam(ID_PARAM_NAME) final String id,
-                            @QueryParam(QUERY_AUDIT) @DefaultValue("false") final Boolean withAudit,
+                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException {
-        return super.getTags(UUID.fromString(id), withAudit, context.createContext(request));
+        return super.getTags(UUID.fromString(id), auditMode, context.createContext(request));
     }
 
     @POST
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java
index dafb1c5..e0ee06a 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxRsResourceBase.java
@@ -17,11 +17,9 @@
 package com.ning.billing.jaxrs.resources;
 
 import java.util.Collection;
-import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
-import java.util.concurrent.atomic.AtomicReference;
 
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
@@ -35,7 +33,6 @@ import org.joda.time.format.ISODateTimeFormat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.ning.billing.ErrorCode;
 import com.ning.billing.ObjectType;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
@@ -51,6 +48,7 @@ import com.ning.billing.util.api.CustomFieldUserApi;
 import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.api.TagDefinitionApiException;
 import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.audit.AuditLog;
 import com.ning.billing.util.callcontext.CallContext;
 import com.ning.billing.util.callcontext.TenantContext;
 import com.ning.billing.util.customfield.CustomField;
@@ -97,48 +95,20 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         return null;
     }
 
-    protected Response getTags(final UUID id, final boolean withAudit, final TenantContext context) throws TagDefinitionApiException {
-        final List<Tag> tags = tagUserApi.getTagsForObject(id, getObjectType(), context);
-        final Collection<UUID> tagIdList = (tags.size() == 0) ?
-                                           Collections.<UUID>emptyList() :
-                                           Collections2.transform(tags, new Function<Tag, UUID>() {
-                                               @Override
-                                               public UUID apply(final Tag input) {
-                                                   return input.getTagDefinitionId();
-                                               }
-                                           });
-
-        final AtomicReference<TagDefinitionApiException> theException = new AtomicReference<TagDefinitionApiException>();
-        final List<TagDefinition> tagDefinitionList = tagUserApi.getTagDefinitions(tagIdList, context);
-        final List<TagJson> result = ImmutableList.<TagJson>copyOf(Collections2.transform(tagIdList, new Function<UUID, TagJson>() {
-            @Override
-            public TagJson apply(final UUID input) {
-                try {
-                    final TagDefinition tagDefinition = findTagDefinitionFromId(tagDefinitionList, input);
-                    return new TagJson(input.toString(), tagDefinition.getName(), null);
-                } catch (TagDefinitionApiException e) {
-                    theException.set(e);
-                    return null;
-                }
-            }
-        }));
-        // Yackk..
-        if (theException.get() != null) {
-            throw theException.get();
+    protected Response getTags(final UUID taggedObjectId, final AuditMode auditMode, final TenantContext context) throws TagDefinitionApiException {
+        final List<Tag> tags = tagUserApi.getTagsForObject(taggedObjectId, getObjectType(), context);
+
+        final Collection<TagJson> result = new LinkedList<TagJson>();
+        for (final Tag tag : tags) {
+            final TagDefinition tagDefinition = tagUserApi.getTagDefinition(tag.getTagDefinitionId(), context);
+            // TODO PIERRE - Bulk API
+            final List<AuditLog> auditLogs = auditUserApi.getAuditLogs(tag.getId(), ObjectType.TAG, auditMode.getLevel(), context);
+            result.add(new TagJson(tagDefinition, auditLogs));
         }
 
         return Response.status(Response.Status.OK).entity(result).build();
     }
 
-    private TagDefinition findTagDefinitionFromId(final List<TagDefinition> tagDefinitionList, final UUID tagDefinitionId) throws TagDefinitionApiException {
-        for (TagDefinition cur : tagDefinitionList) {
-            if (cur.getId().equals(tagDefinitionId)) {
-                return cur;
-            }
-        }
-        throw new TagDefinitionApiException(ErrorCode.TAG_DEFINITION_DOES_NOT_EXIST, tagDefinitionId);
-    }
-
     protected Response createTags(final UUID id,
                                   final String tagList,
                                   final UriInfo uriInfo,
@@ -168,12 +138,14 @@ public abstract class JaxRsResourceBase implements JaxrsResource {
         return Response.status(Response.Status.OK).build();
     }
 
-    protected Response getCustomFields(final UUID id, final TenantContext context) {
+    protected Response getCustomFields(final UUID id, final AuditMode auditMode, final TenantContext context) {
         final List<CustomField> fields = customFieldUserApi.getCustomFieldsForObject(id, getObjectType(), context);
 
         final List<CustomFieldJson> result = new LinkedList<CustomFieldJson>();
         for (final CustomField cur : fields) {
-            result.add(new CustomFieldJson(cur));
+            // TODO PIERRE - Bulk API
+            final List<AuditLog> auditLogs = auditUserApi.getAuditLogs(cur.getId(), ObjectType.CUSTOM_FIELD, auditMode.getLevel(), context);
+            result.add(new CustomFieldJson(cur, auditLogs));
         }
 
         return Response.status(Response.Status.OK).entity(result).build();
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
index b4fdd69..71abd3c 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/PaymentResource.java
@@ -216,8 +216,9 @@ public class PaymentResource extends JaxRsResourceBase {
     @Path(CUSTOM_FIELD_URI)
     @Produces(APPLICATION_JSON)
     public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id,
+                                    @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) {
-        return super.getCustomFields(UUID.fromString(id), context.createContext(request));
+        return super.getCustomFields(UUID.fromString(id), auditMode, context.createContext(request));
     }
 
     @POST
@@ -252,9 +253,9 @@ public class PaymentResource extends JaxRsResourceBase {
     @Path(TAG_URI)
     @Produces(APPLICATION_JSON)
     public Response getTags(@PathParam(ID_PARAM_NAME) final String id,
-                            @QueryParam(QUERY_AUDIT) @DefaultValue("false") final Boolean withAudit,
+                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                             @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException {
-        return super.getTags(UUID.fromString(id), withAudit, context.createContext(request));
+        return super.getTags(UUID.fromString(id), auditMode, context.createContext(request));
     }
 
     @POST
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestCustomFieldJson.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestCustomFieldJson.java
index 8f68fed..97e9b64 100644
--- a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestCustomFieldJson.java
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestCustomFieldJson.java
@@ -29,14 +29,12 @@ public class TestCustomFieldJson extends JaxrsTestSuiteNoDB {
     public void testJson() throws Exception {
         final String name = UUID.randomUUID().toString();
         final String value = UUID.randomUUID().toString();
-        final CustomFieldJson customFieldJson = new CustomFieldJson(name, value);
+        final CustomFieldJson customFieldJson = new CustomFieldJson(name, value, null);
         Assert.assertEquals(customFieldJson.getName(), name);
         Assert.assertEquals(customFieldJson.getValue(), value);
+        Assert.assertNull(customFieldJson.getAuditLogs());
 
         final String asJson = mapper.writeValueAsString(customFieldJson);
-        Assert.assertEquals(asJson, "{\"name\":\"" + customFieldJson.getName() + "\"," +
-                                    "\"value\":\"" + customFieldJson.getValue() + "\"}");
-
         final CustomFieldJson fromJson = mapper.readValue(asJson, CustomFieldJson.class);
         Assert.assertEquals(fromJson, customFieldJson);
     }
diff --git a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestInvoiceJsonWithItems.java b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestInvoiceJsonWithItems.java
index ec9453b..b792e95 100644
--- a/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestInvoiceJsonWithItems.java
+++ b/jaxrs/src/test/java/com/ning/billing/jaxrs/json/TestInvoiceJsonWithItems.java
@@ -84,7 +84,7 @@ public class TestInvoiceJsonWithItems extends JaxrsTestSuiteNoDB {
         final InvoiceItem invoiceItem = createInvoiceItem();
         Mockito.when(invoice.getInvoiceItems()).thenReturn(ImmutableList.<InvoiceItem>of(invoiceItem));
 
-        final InvoiceJsonWithItems invoiceJsonWithItems = new InvoiceJsonWithItems(invoice);
+        final InvoiceJsonWithItems invoiceJsonWithItems = new InvoiceJsonWithItems(invoice, null, null);
         Assert.assertEquals(invoiceJsonWithItems.getAmount(), invoice.getChargedAmount());
         Assert.assertEquals(invoiceJsonWithItems.getInvoiceId(), invoice.getId().toString());
         Assert.assertEquals(invoiceJsonWithItems.getInvoiceDate(), invoice.getInvoiceDate());
diff --git a/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java b/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
index 04d8012..7f674fe 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
@@ -436,7 +436,11 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
     }
 
     protected InvoiceJsonSimple getInvoice(final String invoiceId) throws IOException {
-        return doGetInvoice(invoiceId, Boolean.FALSE, InvoiceJsonSimple.class);
+        return getInvoiceWithAudits(invoiceId, AuditLevel.NONE);
+    }
+
+    protected InvoiceJsonSimple getInvoiceWithAudits(final String invoiceId, final AuditLevel auditLevel) throws IOException {
+        return doGetInvoice(invoiceId, Boolean.FALSE, InvoiceJsonSimple.class, auditLevel);
     }
 
     protected InvoiceJsonSimple getInvoice(final Integer invoiceNumber) throws IOException {
@@ -444,14 +448,19 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
     }
 
     protected InvoiceJsonWithItems getInvoiceWithItems(final String invoiceId) throws IOException {
-        return doGetInvoice(invoiceId, Boolean.TRUE, InvoiceJsonWithItems.class);
+        return getInvoiceWithItemsWithAudits(invoiceId, AuditLevel.NONE);
+    }
+
+    protected InvoiceJsonWithItems getInvoiceWithItemsWithAudits(final String invoiceId, final AuditLevel auditLevel) throws IOException {
+        return doGetInvoice(invoiceId, Boolean.TRUE, InvoiceJsonWithItems.class, auditLevel);
     }
 
-    private <T> T doGetInvoice(final String invoiceId, final Boolean withItems, final Class<T> clazz) throws IOException {
+    private <T> T doGetInvoice(final String invoiceId, final Boolean withItems, final Class<T> clazz, final AuditLevel auditLevel) throws IOException {
         final String uri = JaxrsResource.INVOICES_PATH + "/" + invoiceId;
 
         final Map<String, String> queryParams = new HashMap<String, String>();
         queryParams.put(JaxrsResource.QUERY_INVOICE_WITH_ITEMS, withItems.toString());
+        queryParams.put(JaxrsResource.QUERY_AUDIT, auditLevel.toString());
 
         final Response response = doGet(uri, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
         Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
@@ -464,19 +473,28 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
     }
 
     protected List<InvoiceJsonSimple> getInvoicesForAccount(final String accountId) throws IOException {
-        return doGetInvoicesForAccount(accountId, Boolean.FALSE, new TypeReference<List<InvoiceJsonSimple>>() {});
+        return getInvoicesForAccountWithAudits(accountId, AuditLevel.NONE);
+    }
+
+    protected List<InvoiceJsonSimple> getInvoicesForAccountWithAudits(final String accountId, final AuditLevel auditLevel) throws IOException {
+        return doGetInvoicesForAccount(accountId, Boolean.FALSE, new TypeReference<List<InvoiceJsonSimple>>() {}, auditLevel);
     }
 
     protected List<InvoiceJsonWithItems> getInvoicesWithItemsForAccount(final String accountId) throws IOException {
-        return doGetInvoicesForAccount(accountId, Boolean.TRUE, new TypeReference<List<InvoiceJsonWithItems>>() {});
+        return getInvoicesWithItemsForAccountWithAudits(accountId, AuditLevel.NONE);
+    }
+
+    protected List<InvoiceJsonWithItems> getInvoicesWithItemsForAccountWithAudits(final String accountId, final AuditLevel auditLevel) throws IOException {
+        return doGetInvoicesForAccount(accountId, Boolean.TRUE, new TypeReference<List<InvoiceJsonWithItems>>() {}, auditLevel);
     }
 
-    private <T> List<T> doGetInvoicesForAccount(final String accountId, final Boolean withItems, final TypeReference<List<T>> clazz) throws IOException {
+    private <T> List<T> doGetInvoicesForAccount(final String accountId, final Boolean withItems, final TypeReference<List<T>> clazz, final AuditLevel auditLevel) throws IOException {
         final String invoicesURI = JaxrsResource.INVOICES_PATH;
 
         final Map<String, String> queryParams = new HashMap<String, String>();
         queryParams.put(JaxrsResource.QUERY_ACCOUNT_ID, accountId);
         queryParams.put(JaxrsResource.QUERY_INVOICE_WITH_ITEMS, withItems.toString());
+        queryParams.put(JaxrsResource.QUERY_AUDIT, auditLevel.toString());
 
         final Response invoicesResponse = doGet(invoicesURI, queryParams, DEFAULT_HTTP_TIMEOUT_SEC);
         assertEquals(invoicesResponse.getStatusCode(), Status.OK.getStatusCode());
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 239c4d3..af1e2c4 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
@@ -31,12 +31,14 @@ import org.testng.annotations.Test;
 
 import com.ning.billing.jaxrs.json.AccountJson;
 import com.ning.billing.jaxrs.json.AccountJsonWithBalance;
+import com.ning.billing.jaxrs.json.AuditLogJson;
 import com.ning.billing.jaxrs.json.CustomFieldJson;
 import com.ning.billing.jaxrs.json.PaymentJsonSimple;
 import com.ning.billing.jaxrs.json.PaymentMethodJson;
 import com.ning.billing.jaxrs.json.RefundJson;
 import com.ning.billing.jaxrs.json.TagJson;
 import com.ning.billing.jaxrs.resources.JaxrsResource;
+import com.ning.billing.util.api.AuditLevel;
 import com.ning.http.client.Response;
 
 import com.fasterxml.jackson.core.type.TypeReference;
@@ -280,10 +282,20 @@ public class TestAccount extends TestJaxrsBase {
         assertEquals(response.getStatusCode(), Status.CREATED.getStatusCode());
 
         // Retrieves all tags again
-        response = doGetWithUrl(accountTagsUrl, DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        response = doGetWithUrl(accountTagsUrl, ImmutableMap.<String, String>of(JaxrsResource.QUERY_AUDIT, AuditLevel.FULL.toString()), DEFAULT_HTTP_TIMEOUT_SEC);
         Assert.assertEquals(response.getStatusCode(), Status.OK.getStatusCode());
         final List<TagJson> tags2 = mapper.readValue(response.getResponseBody(), new TypeReference<List<TagJson>>() {});
         Assert.assertEquals(tags2, tags1);
+
+        // Verify audit logs
+        Assert.assertEquals(tags2.get(0).getAuditLogs().size(), 1);
+        final AuditLogJson auditLogJson = tags2.get(0).getAuditLogs().get(0);
+        Assert.assertEquals(auditLogJson.getChangeType(), "INSERT");
+        Assert.assertEquals(auditLogJson.getChangedBy(), createdBy);
+        Assert.assertEquals(auditLogJson.getReasonCode(), reason);
+        Assert.assertEquals(auditLogJson.getComments(), comment);
+        Assert.assertNotNull(auditLogJson.getChangeDate());
+        Assert.assertNotNull(auditLogJson.getUserToken());
     }
 
     @Test(groups = "slow")
@@ -292,9 +304,9 @@ public class TestAccount extends TestJaxrsBase {
         assertNotNull(accountJson);
 
         final List<CustomFieldJson> customFields = new LinkedList<CustomFieldJson>();
-        customFields.add(new CustomFieldJson("1", "value1"));
-        customFields.add(new CustomFieldJson("2", "value2"));
-        customFields.add(new CustomFieldJson("3", "value3"));
+        customFields.add(new CustomFieldJson("1", "value1", null));
+        customFields.add(new CustomFieldJson("2", "value2", null));
+        customFields.add(new CustomFieldJson("3", "value3", null));
         final String baseJson = mapper.writeValueAsString(customFields);
 
         final String uri = JaxrsResource.ACCOUNTS_PATH + "/" + accountJson.getAccountId() + "/" + JaxrsResource.CUSTOM_FIELDS;
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java b/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
index 69833e4..9dfb817 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestInvoice.java
@@ -22,15 +22,18 @@ import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
+import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.ning.billing.jaxrs.json.AccountJson;
+import com.ning.billing.jaxrs.json.AuditLogJson;
 import com.ning.billing.jaxrs.json.InvoiceItemJsonSimple;
 import com.ning.billing.jaxrs.json.InvoiceJsonSimple;
 import com.ning.billing.jaxrs.json.InvoiceJsonWithItems;
 import com.ning.billing.jaxrs.json.PaymentJsonSimple;
 import com.ning.billing.jaxrs.json.PaymentMethodJson;
 import com.ning.billing.payment.provider.ExternalPaymentProviderPlugin;
+import com.ning.billing.util.api.AuditLevel;
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNull;
@@ -44,8 +47,18 @@ public class TestInvoice extends TestJaxrsBase {
 
         final AccountJson accountJson = createAccountWithPMBundleAndSubscriptionAndWaitForFirstInvoice();
 
-        final List<InvoiceJsonSimple> invoices = getInvoicesForAccount(accountJson.getAccountId());
+        final List<InvoiceJsonSimple> invoices = getInvoicesForAccountWithAudits(accountJson.getAccountId(), AuditLevel.FULL);
         assertEquals(invoices.size(), 2);
+        for (final InvoiceJsonSimple invoiceJsonSimple : invoices) {
+            Assert.assertEquals(invoiceJsonSimple.getAuditLogs().size(), 1);
+            final AuditLogJson auditLogJson = invoiceJsonSimple.getAuditLogs().get(0);
+            Assert.assertEquals(auditLogJson.getChangeType(), "INSERT");
+            Assert.assertEquals(auditLogJson.getChangedBy(), "SubscriptionBaseTransition");
+            Assert.assertFalse(auditLogJson.getChangeDate().isBefore(initialDate));
+            Assert.assertNotNull(auditLogJson.getUserToken());
+            Assert.assertNull(auditLogJson.getReasonCode());
+            Assert.assertNull(auditLogJson.getComments());
+        }
 
         // Check we can retrieve an individual invoice
         final InvoiceJsonSimple invoiceJsonSimple = invoices.get(0);
@@ -187,8 +200,42 @@ public class TestInvoice extends TestJaxrsBase {
         adjustInvoiceItem(accountJson.getAccountId(), invoice.getInvoiceId(), invoiceItem.getInvoiceItemId(), null, null, null);
 
         // Verify the new invoice balance is zero
-        final InvoiceJsonSimple adjustedInvoice = getInvoice(invoice.getInvoiceId());
+        final InvoiceJsonWithItems adjustedInvoice = getInvoiceWithItemsWithAudits(invoice.getInvoiceId(), AuditLevel.FULL);
         assertEquals(adjustedInvoice.getAmount().compareTo(BigDecimal.ZERO), 0);
+
+        // Verify invoice audit logs
+        Assert.assertEquals(adjustedInvoice.getAuditLogs().size(), 1);
+        final AuditLogJson invoiceAuditLogJson = adjustedInvoice.getAuditLogs().get(0);
+        Assert.assertEquals(invoiceAuditLogJson.getChangeType(), "INSERT");
+        Assert.assertEquals(invoiceAuditLogJson.getChangedBy(), "SubscriptionBaseTransition");
+        Assert.assertNotNull(invoiceAuditLogJson.getChangeDate());
+        Assert.assertNotNull(invoiceAuditLogJson.getUserToken());
+        Assert.assertNull(invoiceAuditLogJson.getReasonCode());
+        Assert.assertNull(invoiceAuditLogJson.getComments());
+
+        Assert.assertEquals(adjustedInvoice.getItems().size(), 2);
+
+        // Verify invoice items audit logs
+
+        // The first item is the original item
+        Assert.assertEquals(adjustedInvoice.getItems().get(0).getAuditLogs().size(), 1);
+        final AuditLogJson itemAuditLogJson = adjustedInvoice.getItems().get(0).getAuditLogs().get(0);
+        Assert.assertEquals(itemAuditLogJson.getChangeType(), "INSERT");
+        Assert.assertEquals(itemAuditLogJson.getChangedBy(), "SubscriptionBaseTransition");
+        Assert.assertNotNull(itemAuditLogJson.getChangeDate());
+        Assert.assertNotNull(itemAuditLogJson.getUserToken());
+        Assert.assertNull(itemAuditLogJson.getReasonCode());
+        Assert.assertNull(itemAuditLogJson.getComments());
+
+        // The second one is the adjustment
+        Assert.assertEquals(adjustedInvoice.getItems().get(1).getAuditLogs().size(), 1);
+        final AuditLogJson adjustedItemAuditLogJson = adjustedInvoice.getItems().get(1).getAuditLogs().get(0);
+        Assert.assertEquals(adjustedItemAuditLogJson.getChangeType(), "INSERT");
+        Assert.assertEquals(adjustedItemAuditLogJson.getChangedBy(), createdBy);
+        Assert.assertEquals(adjustedItemAuditLogJson.getReasonCode(), reason);
+        Assert.assertEquals(adjustedItemAuditLogJson.getComments(), comment);
+        Assert.assertNotNull(adjustedItemAuditLogJson.getChangeDate());
+        Assert.assertNotNull(adjustedItemAuditLogJson.getUserToken());
     }
 
     @Test(groups = "slow")