Commit 8e280738 authored by Shanelle Valencia's avatar Shanelle Valencia

Merge branch 'AFP-134' into 'dev'

🔀 [AFP-134]  Add paginated & filtered orders endpoint (@asegers)

See merge request !46
parents ab7415fe 613bd984
Pipeline #1752 failed with stage
in 38 seconds
package com.afp.ordermanagement.config;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
@Configuration
public class MongoConfig {
@Value("${spring.data.mongodb.database}")
public String databaseName;
@Bean
public SimpleReactiveMongoDatabaseFactory reactiveMongoDbFactory() {
MongoClient mongoClient = MongoClients.create();
return new SimpleReactiveMongoDatabaseFactory(mongoClient, databaseName);
}
@Bean
public ReactiveMongoTemplate reactiveMongoTemplate() throws Exception {
ReactiveMongoTemplate mongoTemplate = new ReactiveMongoTemplate(reactiveMongoDbFactory());
return mongoTemplate;
}
}
package com.afp.ordermanagement.controller;
import com.afp.ordermanagement.model.OrderStatus;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
public class AllOrdersRequestBody {
public Pagination pagination;
public Date date;
public Search search;
public Status status;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Pagination {
public int page, size;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Date {
public long start, end;
public DateFilter filter;
}
public enum DateFilter {
orderCreatedAt, orderUpdatedAt
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Search {
public SearchBy by;
public String query;
}
public enum SearchBy {
id, customerEmailAddress, orderTrackingCode
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Status {
public boolean received, fulfilled, cancelled;
public List<OrderStatus> getTruthyStatuses() {
List<OrderStatus> truthyStatuses = new ArrayList<>();
if (received) truthyStatuses.add(OrderStatus.RECEIVED);
if (fulfilled) truthyStatuses.add(OrderStatus.FULFILLED);
if (cancelled) truthyStatuses.add(OrderStatus.CANCELLED);
return truthyStatuses;
}
}
}
\ No newline at end of file
......@@ -5,6 +5,9 @@ import com.afp.ordermanagement.reactivekafkaservice.Receiver;
import com.afp.ordermanagement.reactivekafkaservice.Sender;
import com.afp.ordermanagement.service.EmailService;
import com.afp.ordermanagement.service.OrderService;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
......@@ -12,6 +15,8 @@ import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import static java.util.Objects.isNull;
@RestController
@RequestMapping("/api")
@CrossOrigin
......@@ -46,13 +51,17 @@ public class OrderController {
});
}
@GetMapping("/orders")
@CrossOrigin
public Flux<Order> getAllOrders(){
public Flux<Order> getAllOrders() {
return orderService.getAllOrders();
}
@PostMapping("/orders/filtered")
@CrossOrigin
public Flux<Order> getFilteredOrders(@RequestBody AllOrdersRequestBody reqBody) {
return orderService.getQueriedOrders(reqBody);
}
@GetMapping("/orders/{orderId}")
@CrossOrigin
......
......@@ -4,11 +4,8 @@ import com.afp.ordermanagement.model.Order;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import org.springframework.stereotype.Repository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Repository
public interface OrderRepository extends ReactiveMongoRepository<Order, String> {
Flux<Order> findByCustomerId(String customerId);
}
......@@ -40,7 +40,9 @@ public class OrderSeeder {
static private Stream<String> CUSTOMER_USERNAMES = Stream.of(
"nrobinson", "rsara", "agannamaneni", "rsayannagari", // Superiors
"ccottier", "kmuldoon", "nmoosapet", "spangburn", "xlu", // ECom Team
"asegers", "dbhuller", "earndt", "kkaminski", "svalencia", "vivaddadhi" // OMan Team
"asegers", "dbhuller", "earndt", "kkaminski", "svalencia", "vivaddadhi", // OMan Team
"kliew", "sburney", "banderson", "jwu", "jlam", // PPI team
"pfonzin", "alpinto", "dyong" // WMan team
);
// Create order seeds as soon as app is up and running
......@@ -57,22 +59,31 @@ public class OrderSeeder {
.insert(generateOrder(email))
.subscribe();
});
IntStream.range(0, 21).forEach(n -> {
String email = faker.internet().emailAddress();
orderRepository
.insert(generateOrder(email))
.subscribe();
});
}
}
private Order generateOrder(String email){
OrderStatus randStatus = OrderStatus.values()[faker.number().numberBetween(0, 2)]; // exclusive range
OrderStatus randStatus = OrderStatus.values()[faker.number().numberBetween(0, 3)]; // exclusive range
Order order = new Order(randStatus);
order.setOrderTrackingCode(faker.number().digits(27));
long unixTime = System.currentTimeMillis();
order.setOrderCreatedAt(unixTime);
order.setOrderUpdatedAt(unixTime);
long millisecondsInADay = 86400 * 1000;
long currentUnixTime = System.currentTimeMillis();
long createdAt = faker.number().numberBetween(currentUnixTime - (millisecondsInADay * 25), currentUnixTime);
order.setOrderCreatedAt(createdAt);
long updatedAt = faker.number().numberBetween(createdAt, createdAt + (millisecondsInADay * 10));
order.setOrderUpdatedAt(updatedAt);
order.setCustomerId(faker.number().digits(12));
order.setCustomerEmailAddress(email);
// Order items
int randOrderCount = faker.number().numberBetween(1, 10);
int randOrderCount = faker.number().numberBetween(1, 19);
List<Item> orderItems = IntStream
.range(0, randOrderCount)
.mapToObj(n -> generateItem())
......
package com.afp.ordermanagement.service;
import com.afp.ordermanagement.model.Item;
import com.afp.ordermanagement.controller.AllOrdersRequestBody;
import com.afp.ordermanagement.model.Order;
import com.afp.ordermanagement.model.OrderStatus;
import com.afp.ordermanagement.repository.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import static java.util.Objects.isNull;
@Service
public class OrderService {
......@@ -19,6 +26,9 @@ public class OrderService {
@Autowired
OrderRepository orderRepository;
@Autowired
ReactiveMongoTemplate reactiveMongoTemplate;
public Mono<Order> createOrder(Order newOrder){
System.out.println("here");
String defaultOrderTrackingCode = "N/A";
......@@ -37,6 +47,43 @@ public class OrderService {
return orderRepository.findAll();
}
public Flux<Order> getQueriedOrders(AllOrdersRequestBody requestBody){
Query query = new Query();
// ---- pagination & sort ----
int page = requestBody.pagination.page, size = requestBody.pagination.size;
Sort sortByLastUpdated = Sort.by("orderUpdatedAt").descending();
Pageable pagination = PageRequest.of(page, size, sortByLastUpdated);
query.with(pagination);
// ---- date ----
long startDate = requestBody.date.start, endDate = requestBody.date.end;
AllOrdersRequestBody.DateFilter dateFilter = requestBody.date.filter;
if (startDate > 0 && endDate > 0 && startDate <= endDate) {
if (!isNull(dateFilter)) {
query.addCriteria(Criteria.where(dateFilter.toString()).gte(startDate).lte(endDate));
} else {
Criteria dateCriteria = Criteria.where("orderCreatedAt").gte(startDate).lte(endDate)
.orOperator(Criteria.where("orderUpdatedAt").gte(startDate).lte(endDate));
query.addCriteria(dateCriteria);
}
}
// ---- search ----
String queryText = requestBody.search.query;
if (!isNull(queryText) && !queryText.trim().isEmpty()) {
String searchByStr = requestBody.search.by.toString();
Criteria searchCriteria = Criteria.where(searchByStr).regex("^" + queryText);
query.addCriteria(searchCriteria);
}
// ---- status ----
List<OrderStatus> truthyStatuses = requestBody.status.getTruthyStatuses();
if (!truthyStatuses.isEmpty()) {
Criteria statusCriteria = Criteria.where("orderStatus").in(truthyStatuses);
query.addCriteria(statusCriteria);
}
return reactiveMongoTemplate.find(query, Order.class);
}
public Mono<Order> getOrderById(String orderId) {
return orderRepository.findById(orderId);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment