From 20cd775b085ae013bda6c27b6b9c192901ecbc35 Mon Sep 17 00:00:00 2001 From: Wasiu Idowu Date: Thu, 14 Nov 2024 08:22:26 +0100 Subject: [PATCH 1/3] chore: remove annotation Remove @Valid annotation from service layer method. --- .../codeplanks/home360/service/ListingEnquiryServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/codeplanks/home360/service/ListingEnquiryServiceImpl.java b/src/main/java/com/codeplanks/home360/service/ListingEnquiryServiceImpl.java index 0c018e3..d7d2bce 100644 --- a/src/main/java/com/codeplanks/home360/service/ListingEnquiryServiceImpl.java +++ b/src/main/java/com/codeplanks/home360/service/ListingEnquiryServiceImpl.java @@ -34,7 +34,7 @@ public class ListingEnquiryServiceImpl implements ListingEnquiryService { private final AuthenticationUtils authenticationUtils; @Override - public ListingEnquiry makeEnquiry(@Valid ListingEnquiryDTO enquiryRequest) { + public ListingEnquiry makeEnquiry(ListingEnquiryDTO enquiryRequest) { if (authenticationUtils.isAuthenticated()) { Integer userId = userService.extractUserId(); enquiryRequest.setUserId(userId); From 33235d80c354635cd3c9628073f1f33c91fd7b14 Mon Sep 17 00:00:00 2001 From: Wasiu Idowu Date: Sat, 30 Nov 2024 17:55:49 +0100 Subject: [PATCH 2/3] Add UnsupportedEncodingException to method signature. --- .../java/com/codeplanks/home360/service/EmailServiceImpl.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/codeplanks/home360/service/EmailServiceImpl.java b/src/main/java/com/codeplanks/home360/service/EmailServiceImpl.java index 340308c..5bec074 100644 --- a/src/main/java/com/codeplanks/home360/service/EmailServiceImpl.java +++ b/src/main/java/com/codeplanks/home360/service/EmailServiceImpl.java @@ -1,9 +1,9 @@ package com.codeplanks.home360.service; -import com.codeplanks.home360.service.EmailService; import jakarta.mail.MessagingException; import jakarta.mail.internet.MimeMessage; +import java.io.UnsupportedEncodingException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.mail.javamail.JavaMailSender; @@ -13,8 +13,6 @@ import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; -import java.io.UnsupportedEncodingException; - @Service public class EmailServiceImpl implements EmailService { private final JavaMailSender mailSender; From 01157c3512f7bf2399a29c20ccecdaf8b58c54cf Mon Sep 17 00:00:00 2001 From: Wasiu Idowu Date: Sat, 30 Nov 2024 18:00:56 +0100 Subject: [PATCH 3/3] feat: show listings statistics This feature gives statistical information about the following 1. total listings 2. rented listings 3. total income 4. Yearly income broken down by monthly earnins 5. Yearly listings broken down by monthly listing This gives the agent an overview of their performance. --- .../home360/controller/ListingController.java | 10 ++ .../listing/AggregateListingStatistics.java | 14 ++ .../home360/domain/listing/MonthlyIncome.java | 17 +++ .../domain/listing/MonthlyListings.java | 21 +++ .../home360/service/ListingServiceImpl.java | 136 +++++++++++++++++- 5 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/codeplanks/home360/domain/listing/AggregateListingStatistics.java create mode 100644 src/main/java/com/codeplanks/home360/domain/listing/MonthlyIncome.java create mode 100644 src/main/java/com/codeplanks/home360/domain/listing/MonthlyListings.java diff --git a/src/main/java/com/codeplanks/home360/controller/ListingController.java b/src/main/java/com/codeplanks/home360/controller/ListingController.java index 8f4d8bc..e7836bf 100644 --- a/src/main/java/com/codeplanks/home360/controller/ListingController.java +++ b/src/main/java/com/codeplanks/home360/controller/ListingController.java @@ -15,6 +15,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import java.util.List; import lombok.RequiredArgsConstructor; +import org.bson.Document; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; @@ -308,4 +309,13 @@ public ResponseEntity> updateTakenListing( updatedListing.setStatus(HttpStatus.OK); return new ResponseEntity<>(updatedListing, HttpStatus.OK); } + + @GetMapping("/listing-statistics") + public ResponseEntity> getListingStatistics() { + SuccessDataResponse response = new SuccessDataResponse<>(); + response.setData(listingService.getAggregateListingStats()); + response.setMessage("Statistics data retrieved successfully"); + response.setStatus(HttpStatus.OK); + return new ResponseEntity<>(response, HttpStatus.OK); + } } diff --git a/src/main/java/com/codeplanks/home360/domain/listing/AggregateListingStatistics.java b/src/main/java/com/codeplanks/home360/domain/listing/AggregateListingStatistics.java new file mode 100644 index 0000000..54bac4b --- /dev/null +++ b/src/main/java/com/codeplanks/home360/domain/listing/AggregateListingStatistics.java @@ -0,0 +1,14 @@ +package com.codeplanks.home360.domain.listing; + +import lombok.Data; + +import java.util.List; + +@Data +public class AggregateListingStatistics { + private Integer total_listings; + private Integer rented_listings; + private Integer total_income; + private List income; + private List listings; +} diff --git a/src/main/java/com/codeplanks/home360/domain/listing/MonthlyIncome.java b/src/main/java/com/codeplanks/home360/domain/listing/MonthlyIncome.java new file mode 100644 index 0000000..48ecaaa --- /dev/null +++ b/src/main/java/com/codeplanks/home360/domain/listing/MonthlyIncome.java @@ -0,0 +1,17 @@ +package com.codeplanks.home360.domain.listing; + +import java.util.Map; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class MonthlyIncome { + private int year; + private Map months; + + @Override + public String toString() { + return "MonthlyIncome{" + "year=" + year + ", months=" + months + '}'; + } +} diff --git a/src/main/java/com/codeplanks/home360/domain/listing/MonthlyListings.java b/src/main/java/com/codeplanks/home360/domain/listing/MonthlyListings.java new file mode 100644 index 0000000..1eb399c --- /dev/null +++ b/src/main/java/com/codeplanks/home360/domain/listing/MonthlyListings.java @@ -0,0 +1,21 @@ +package com.codeplanks.home360.domain.listing; + +import lombok.Getter; +import lombok.Setter; + +import java.util.Map; + +@Getter +@Setter +public class MonthlyListings { + private int year; + private Map months; + + @Override + public String toString() { + return "MonthlyListings{" + + "year=" + year + + ", months=" + months + + '}'; + } +} diff --git a/src/main/java/com/codeplanks/home360/service/ListingServiceImpl.java b/src/main/java/com/codeplanks/home360/service/ListingServiceImpl.java index 657ac9c..89727bc 100644 --- a/src/main/java/com/codeplanks/home360/service/ListingServiceImpl.java +++ b/src/main/java/com/codeplanks/home360/service/ListingServiceImpl.java @@ -7,15 +7,20 @@ import com.codeplanks.home360.exception.UnAuthorizedException; import com.codeplanks.home360.repository.ListingRepository; import java.time.LocalDateTime; +import java.util.Arrays; import java.util.List; import java.util.Objects; import lombok.RequiredArgsConstructor; +import org.bson.BsonNull; +import org.bson.Document; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; +import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.security.access.AccessDeniedException; import org.springframework.stereotype.Service; @@ -27,6 +32,7 @@ public class ListingServiceImpl implements ListingService { private final ListingRepository listingRepository; private final UserServiceImpl userService; + @Autowired MongoTemplate mongoTemplate; Logger logger = LoggerFactory.getLogger(ListingServiceImpl.class); @@ -37,7 +43,6 @@ public Listing createListing(ListingDTO request) { throw new UnAuthorizedException( "You are not authorized to create a listing." + " Please confirm your email to proceed."); } - ; Listing listing = Listing.builder() @@ -153,4 +158,133 @@ public Listing updateRentedListing(RentUpdate rentUpdate) { return savedListing; } + + public Document getAggregateListingStats() { + Integer userId = userService.extractUserId(); + List pipeline = Arrays.asList(new Document("$match", + new Document("agent_id", userId)), + new Document("$facet", + new Document("totalListings", Arrays.asList(new Document("$count", "total_count"))) + .append("rentedListings", Arrays.asList(new Document("$match", + new Document("rented", true)), + new Document("$count", "total_rented"))) + .append("totalIncome", Arrays.asList(new Document("$match", + new Document("rented", true)), + new Document("$group", + new Document("_id", + new BsonNull()) + .append("total_income", + new Document("$sum", + new Document("$add", Arrays.asList("$cost.annual_rent", "$cost.agent_fee", "$cost.caution_fee", "$cost.agreement_fee"))))))) + .append("income", Arrays.asList(new Document("$match", + new Document("rented", true)), + new Document("$addFields", + new Document("total_income", + new Document("$add", Arrays.asList("$cost.annual_rent", "$cost.agent_fee", "$cost.caution_fee", "$cost.agreement_fee")))), + new Document("$group", + new Document("_id", + new Document("year", + new Document("$year", "$created_at")) + .append("month", + new Document("$month", "$created_at"))) + .append("total_income", + new Document("$sum", "$total_income"))), + new Document("$group", + new Document("_id", "$_id.year") + .append("months", + new Document("$push", + new Document("k", + new Document("$arrayElemAt", Arrays.asList(Arrays.asList("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"), + new Document("$subtract", Arrays.asList("$_id.month", 1L))))) + .append("v", "$total_income")))), + new Document("$addFields", + new Document("months", + new Document("$mergeObjects", Arrays.asList(new Document("$arrayToObject", + new Document("$map", + new Document("input", + new Document("$range", Arrays.asList(0L, + new Document("$cond", Arrays.asList(new Document("$eq", Arrays.asList("$_id", + new Document("$year", + new java.util.Date()))), + new Document("$month", + new java.util.Date()), 12L))))) + .append("as", "i") + .append("in", + new Document("k", + new Document("$arrayElemAt", Arrays.asList(Arrays.asList("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"), "$$i"))) + .append("v", 0L)))), + new Document("$arrayToObject", "$months"))))), + new Document("$addFields", + new Document("months", + new Document("$map", + new Document("input", + new Document("$objectToArray", "$months")) + .append("as", "m") + .append("in", + new Document("name", "$$m.k") + .append( + "amount", "$$m.v"))))), + new Document("$project", + new Document("_id", 0L) + .append("year", "$_id") + .append("months", 1L)))) + .append("listings", Arrays.asList(new Document("$group", + new Document("_id", + new Document("year", + new Document("$year", "$created_at")) + .append("month", + new Document("$month", "$created_at"))) + .append("count", + new Document("$sum", 1L))), + new Document("$group", + new Document("_id", "$_id.year") + .append("months", + new Document("$push", + new Document("k", + new Document("$arrayElemAt", Arrays.asList(Arrays.asList("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"), + new Document("$subtract", Arrays.asList("$_id.month", 1L))))) + .append("v", "$count")))), + new Document("$addFields", + new Document("months", + new Document("$mergeObjects", Arrays.asList(new Document("$arrayToObject", + new Document("$map", + new Document("input", + new Document("$range", Arrays.asList(0L, + new Document("$cond", Arrays.asList(new Document("$eq", Arrays.asList("$_id", + new Document("$year", + new java.util.Date()))), + new Document("$month", + new java.util.Date()), 12L))))) + .append("as", "i") + .append("in", + new Document("k", + new Document("$arrayElemAt", Arrays.asList(Arrays.asList("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"), "$$i"))) + .append("v", 0L)))), + new Document("$arrayToObject", "$months"))))), + new Document("$addFields", + new Document("months", + new Document("$map", + new Document("input", + new Document("$objectToArray", "$months")) + .append("as", "m") + .append("in", + new Document("name", "$$m.k") + .append( + "amount", "$$m.v"))))), + new Document("$project", + new Document("_id", 0L) + .append("year", "$_id") + .append("months", 1L))))), + new Document("$project", + new Document("total_listings", + new Document("$arrayElemAt", Arrays.asList("$totalListings.total_count", 0L))) + .append("rented_listings", + new Document("$arrayElemAt", Arrays.asList("$rentedListings.total_rented", 0L))) + .append("total_income", + new Document("$arrayElemAt", Arrays.asList("$totalIncome.total_income", 0L))) + .append("income", "$income") + .append("listings", "$listings"))); + + return mongoTemplate.getDb().getCollection("listings").aggregate(pipeline).first(); + } }