From 5a61fb0ce8b5fa9b8497124975066752210935fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tr=C3=AD=20H=E1=BA=A3i?= Date: Thu, 24 Oct 2024 16:56:48 +0700 Subject: [PATCH 1/3] implement mock APIs for delivery service --- .env | 20 +++- delivery/pom.xml | 45 +++++++++ .../com/yas/delivery/DeliveryApplication.java | 2 +- .../yas/delivery/config/SecurityConfig.java | 48 ++++++++++ .../yas/delivery/config/SwaggerConfig.java | 24 +++++ .../controller/DeliveryController.java | 37 +++++++ .../yas/delivery/model/ShipmentProvider.java | 17 ++++ .../delivery/model/ShipmentServiceType.java | 17 ++++ .../yas/delivery/service/DeliveryService.java | 96 +++++++++++++++++++ .../viewmodel/CalculateFeesPostVm.java | 9 ++ .../delivery/viewmodel/CheckoutItemVm.java | 9 ++ .../yas/delivery/viewmodel/ShipmentFeeVm.java | 6 ++ .../viewmodel/ShipmentProviderVm.java | 4 + .../viewmodel/ShipmentServiceTypeVm.java | 5 + .../src/main/resources/application.properties | 13 +++ nginx/templates/default.conf.template | 3 + 16 files changed, 353 insertions(+), 2 deletions(-) create mode 100644 delivery/src/main/java/com/yas/delivery/config/SecurityConfig.java create mode 100644 delivery/src/main/java/com/yas/delivery/config/SwaggerConfig.java create mode 100644 delivery/src/main/java/com/yas/delivery/model/ShipmentProvider.java create mode 100644 delivery/src/main/java/com/yas/delivery/model/ShipmentServiceType.java create mode 100644 delivery/src/main/java/com/yas/delivery/viewmodel/CalculateFeesPostVm.java create mode 100644 delivery/src/main/java/com/yas/delivery/viewmodel/CheckoutItemVm.java create mode 100644 delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentFeeVm.java create mode 100644 delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentProviderVm.java create mode 100644 delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentServiceTypeVm.java diff --git a/.env b/.env index a8511c7314..43a5283f6b 100644 --- a/.env +++ b/.env @@ -82,10 +82,28 @@ YAS_SERVICES_INVENTORY=http://inventory/inventory YAS_SERVICES_RATING=http://rating/rating YAS_SERVICES_SAMPLE_DATA=http://sampledata/sampledata YAS_SERVICES_RECOMMENDATION=http://recommendation/recommendation +YAS_SERVICES_DELIVERY=http://delivery/delivery + SERVER_PORT=80 # Swagger UI -URLS=[{ url: 'http://api.yas.local/product/v3/api-docs', name: 'Product' },{ url: 'http://api.yas.local/media/v3/api-docs', name: 'Media' },{ url: 'http://api.yas.local/customer/v3/api-docs', name: 'Customer' },{ url: 'http://api.yas.local/cart/v3/api-docs', name: 'Cart'},{ url: 'http://api.yas.local/rating/v3/api-docs', name: 'Rating' }, { url: 'http://api.yas.local/order/v3/api-docs', name: 'Order'},{ url: 'http://api.yas.local/payment/v3/api-docs', name: 'Payment'},{ url: 'http://api.yas.local/payment-paypal/v3/api-docs', name: 'Payment-paypal'},{ url: 'http://api.yas.local/location/v3/api-docs', name: 'Location'}, { url: 'http://api.yas.local/inventory/v3/api-docs', name: 'Inventory'},{ url: 'http://api.yas.local/tax/v3/api-docs', name: 'Tax' },{ url: 'http://api.yas.local/promotion/v3/api-docs', name: 'Promotion'},{ url: 'http://api.yas.local/search/v3/api-docs', name: 'Search'}, { url: 'http://api.yas.local/webhook/v3/api-docs', name: 'Webhook'}] +URLS='[ + { url: "http://api.yas.local/product/v3/api-docs", name: "Product" }, + { url: "http://api.yas.local/media/v3/api-docs", name: "Media" }, + { url: "http://api.yas.local/customer/v3/api-docs", name: "Customer" }, + { url: "http://api.yas.local/cart/v3/api-docs", name: "Cart" }, + { url: "http://api.yas.local/rating/v3/api-docs", name: "Rating" }, + { url: "http://api.yas.local/order/v3/api-docs", name: "Order" }, + { url: "http://api.yas.local/payment/v3/api-docs", name: "Payment" }, + { url: "http://api.yas.local/payment-paypal/v3/api-docs", name: "Payment-paypal" }, + { url: "http://api.yas.local/location/v3/api-docs", name: "Location" }, + { url: "http://api.yas.local/inventory/v3/api-docs", name: "Inventory" }, + { url: "http://api.yas.local/tax/v3/api-docs", name: "Tax" }, + { url: "http://api.yas.local/promotion/v3/api-docs", name: "Promotion" }, + { url: "http://api.yas.local/search/v3/api-docs", name: "Search" }, + { url: "http://api.yas.local/webhook/v3/api-docs", name: "Webhook" }, + { url: "http://api.yas.local/delivery/v3/api-docs", name: "Delivery" } +]' # Start all service when run docker compose up COMPOSE_FILE=docker-compose.yml:docker-compose.search.yml:docker-compose.o11y.yml diff --git a/delivery/pom.xml b/delivery/pom.xml index 45f4720bc7..bd11ab242d 100644 --- a/delivery/pom.xml +++ b/delivery/pom.xml @@ -21,4 +21,49 @@ nashtech-garage_yas-delivery + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + + + org.springframework.boot + spring-boot-starter-validation + + + com.yas + common-library + ${revision} + + + com.yas + common-library + ${revision} + tests + test-jar + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.jacoco + jacoco-maven-plugin + + + + diff --git a/delivery/src/main/java/com/yas/delivery/DeliveryApplication.java b/delivery/src/main/java/com/yas/delivery/DeliveryApplication.java index f521563579..b5dcd75ca0 100644 --- a/delivery/src/main/java/com/yas/delivery/DeliveryApplication.java +++ b/delivery/src/main/java/com/yas/delivery/DeliveryApplication.java @@ -3,7 +3,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -@SpringBootApplication +@SpringBootApplication(scanBasePackages = {"com.yas.delivery", "com.yas.commonlibrary"}) public class DeliveryApplication { public static void main(String[] args) { SpringApplication.run(DeliveryApplication.class, args); diff --git a/delivery/src/main/java/com/yas/delivery/config/SecurityConfig.java b/delivery/src/main/java/com/yas/delivery/config/SecurityConfig.java new file mode 100644 index 0000000000..3fd356a864 --- /dev/null +++ b/delivery/src/main/java/com/yas/delivery/config/SecurityConfig.java @@ -0,0 +1,48 @@ +package com.yas.delivery.config; + +import java.util.Collection; +import java.util.Map; +import java.util.stream.Collectors; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.converter.Converter; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +public class SecurityConfig { + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + + return http + .authorizeHttpRequests(auth -> auth + .requestMatchers("/actuator/prometheus", "/actuator/health/**", + "/swagger-ui", "/swagger-ui/**", "/error", "/v3/api-docs/**").permitAll() + .requestMatchers("/storefront/**").permitAll() + .requestMatchers("/backoffice/**").hasRole("ADMIN") + .anyRequest().authenticated()) + .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults())) + .build(); + } + + @Bean + public JwtAuthenticationConverter jwtAuthenticationConverterForKeycloak() { + Converter> jwtGrantedAuthoritiesConverter = jwt -> { + Map> realmAccess = jwt.getClaim("realm_access"); + Collection roles = realmAccess.get("roles"); + return roles.stream() + .map(role -> new SimpleGrantedAuthority("ROLE_" + role)) + .collect(Collectors.toList()); + }; + + var jwtAuthenticationConverter = new JwtAuthenticationConverter(); + jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter); + + return jwtAuthenticationConverter; + } +} diff --git a/delivery/src/main/java/com/yas/delivery/config/SwaggerConfig.java b/delivery/src/main/java/com/yas/delivery/config/SwaggerConfig.java new file mode 100644 index 0000000000..b73ed038e2 --- /dev/null +++ b/delivery/src/main/java/com/yas/delivery/config/SwaggerConfig.java @@ -0,0 +1,24 @@ +package com.yas.delivery.config; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.security.OAuthFlow; +import io.swagger.v3.oas.annotations.security.OAuthFlows; +import io.swagger.v3.oas.annotations.security.OAuthScope; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityScheme; +import io.swagger.v3.oas.annotations.servers.Server; + +@OpenAPIDefinition(info = @Info(title = "Delivery Service API", description = "Delivery API documentation", + version = "1.0"), + security = @SecurityRequirement(name = "oauth2_bearer"), + servers = {@Server(url = "${server.servlet.context-path}", description = "Default Server URL")}) +@SecurityScheme(name = "oauth2_bearer", type = SecuritySchemeType.OAUTH2, + flows = @OAuthFlows(authorizationCode = + @OAuthFlow(authorizationUrl = "${springdoc.oauthflow.authorization-url}", + tokenUrl = "${springdoc.oauthflow.token-url}", scopes = { + @OAuthScope(name = "openid", description = "openid") + }))) +public class SwaggerConfig { +} diff --git a/delivery/src/main/java/com/yas/delivery/controller/DeliveryController.java b/delivery/src/main/java/com/yas/delivery/controller/DeliveryController.java index 90454b12c2..d485e2753f 100644 --- a/delivery/src/main/java/com/yas/delivery/controller/DeliveryController.java +++ b/delivery/src/main/java/com/yas/delivery/controller/DeliveryController.java @@ -1,7 +1,44 @@ package com.yas.delivery.controller; +import com.yas.delivery.service.DeliveryService; +import com.yas.delivery.viewmodel.CalculateFeesPostVm; +import com.yas.delivery.viewmodel.ShipmentFeeVm; +import com.yas.delivery.viewmodel.ShipmentProviderVm; +import com.yas.delivery.viewmodel.ShipmentServiceTypeVm; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController +@RequiredArgsConstructor public class DeliveryController { + private final DeliveryService deliveryService; + + @GetMapping("/storefront/shipment/providers") + public ResponseEntity> getShipmentProviders() { + List shipmentProviders = deliveryService.getShipmentProviders(); + return ResponseEntity.ok(shipmentProviders); + } + + @GetMapping("/storefront/shipment/providers/{shipmentProviderId}/service-types") + public ResponseEntity> getShipmentServiceTypes(@PathVariable String shipmentProviderId, + @RequestParam + String recipientAddressId) { + List shipmentServiceTypes = + deliveryService.getShipmentServiceTypes(shipmentProviderId, recipientAddressId); + return ResponseEntity.ok(shipmentServiceTypes); + } + + @PostMapping("/storefront/shipment/calculate") + public ResponseEntity> calculateShipmentFees( + @RequestBody CalculateFeesPostVm calculateFeePostVm) { + List shipmentFees = deliveryService.calculateShipmentFees(calculateFeePostVm); + return ResponseEntity.ok(shipmentFees); + } } diff --git a/delivery/src/main/java/com/yas/delivery/model/ShipmentProvider.java b/delivery/src/main/java/com/yas/delivery/model/ShipmentProvider.java new file mode 100644 index 0000000000..944a5242fd --- /dev/null +++ b/delivery/src/main/java/com/yas/delivery/model/ShipmentProvider.java @@ -0,0 +1,17 @@ +package com.yas.delivery.model; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@lombok.Getter +@lombok.Setter +@Builder +public class ShipmentProvider { + private String id; + private String name; + private List serviceTypes; +} diff --git a/delivery/src/main/java/com/yas/delivery/model/ShipmentServiceType.java b/delivery/src/main/java/com/yas/delivery/model/ShipmentServiceType.java new file mode 100644 index 0000000000..8fd1ffc9f0 --- /dev/null +++ b/delivery/src/main/java/com/yas/delivery/model/ShipmentServiceType.java @@ -0,0 +1,17 @@ +package com.yas.delivery.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@lombok.Getter +@lombok.Setter +@Builder +public class ShipmentServiceType { + private String id; + private String name; + private double cost; + private double tax; +} diff --git a/delivery/src/main/java/com/yas/delivery/service/DeliveryService.java b/delivery/src/main/java/com/yas/delivery/service/DeliveryService.java index 6ac53153ca..f6c4611848 100644 --- a/delivery/src/main/java/com/yas/delivery/service/DeliveryService.java +++ b/delivery/src/main/java/com/yas/delivery/service/DeliveryService.java @@ -1,7 +1,103 @@ package com.yas.delivery.service; +import com.yas.commonlibrary.exception.NotFoundException; +import com.yas.delivery.model.ShipmentProvider; +import com.yas.delivery.model.ShipmentServiceType; +import com.yas.delivery.viewmodel.CalculateFeesPostVm; +import com.yas.delivery.viewmodel.ShipmentFeeVm; +import com.yas.delivery.viewmodel.ShipmentProviderVm; +import com.yas.delivery.viewmodel.ShipmentServiceTypeVm; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; import org.springframework.stereotype.Service; @Service public class DeliveryService { + private static final List shipmentProviders; + + static { + ShipmentProvider fedexProvider = new ShipmentProvider(); + fedexProvider.setId("FEDEX"); + fedexProvider.setName("Fedex"); + List fedexServiceTypes = Arrays.asList( + ShipmentServiceType.builder() + .id("FEDEX_INTERNATIONAL_PRIORITY") + .name("FedEx International Priority") + .cost(20.0) + .tax(2.0) + .build(), + ShipmentServiceType.builder() + .id("INTERNATIONAL_ECONOMY") + .name("FedEx International Economy") + .cost(30.0) + .tax(3.0) + .build() + ); + fedexProvider.setServiceTypes(fedexServiceTypes); + + ShipmentProvider ghnProvider = new ShipmentProvider(); + ghnProvider.setId("GHN"); + ghnProvider.setName("Giao Hang Nhanh"); + List ghnServiceTypes = Arrays.asList( + ShipmentServiceType.builder() + .id("53322") + .name("Hang nhe") + .cost(10.0) + .tax(1.0) + .build(), + ShipmentServiceType.builder() + .id("100039") + .name("Hang nang") + .cost(15.0) + .tax(1.5).build() + ); + ghnProvider.setServiceTypes(ghnServiceTypes); + + shipmentProviders = Arrays.asList(fedexProvider, ghnProvider); + } + + public List getShipmentProviders() { + return shipmentProviders.stream().map(shipmentProvider -> + new ShipmentProviderVm(shipmentProvider.getId(), shipmentProvider.getName()) + ).toList(); + } + + public List getShipmentServiceTypes(String shipmentProviderId, + String recipientAddressId) { + ShipmentProvider shipmentProvider = + findShipmentProviderById(shipmentProviderId) + .orElseThrow(() -> new NotFoundException("Invalid shipment provider")); + + return shipmentProvider.getServiceTypes() + .stream() + .map(serviceType -> + new ShipmentServiceTypeVm(serviceType.getId(), serviceType.getName())) + .toList(); + } + + public List calculateShipmentFees(CalculateFeesPostVm calculateFeePostVm) { + ShipmentProvider shipmentProvider = + findShipmentProviderById(calculateFeePostVm.shipmentProviderId()) + .orElseThrow(() -> new NotFoundException("Invalid shipment provider")); + + ShipmentServiceType shipmentServiceType = shipmentProvider.getServiceTypes() + .stream() + .filter(serviceType -> serviceType.getId().equals(calculateFeePostVm.shipmentServiceTypeId())) + .findFirst() + .orElseThrow(() -> new NotFoundException("Invalid shipment service type")); + + return calculateFeePostVm + .checkoutItems() + .stream() + .map(checkoutItemVm -> + new ShipmentFeeVm(checkoutItemVm.id(), shipmentServiceType.getCost(), shipmentServiceType.getTax())) + .toList(); + } + + private Optional findShipmentProviderById(String shipmentProviderId) { + return shipmentProviders.stream() + .filter(provider -> provider.getId().equals(shipmentProviderId)) + .findFirst(); + } } diff --git a/delivery/src/main/java/com/yas/delivery/viewmodel/CalculateFeesPostVm.java b/delivery/src/main/java/com/yas/delivery/viewmodel/CalculateFeesPostVm.java new file mode 100644 index 0000000000..9106491a04 --- /dev/null +++ b/delivery/src/main/java/com/yas/delivery/viewmodel/CalculateFeesPostVm.java @@ -0,0 +1,9 @@ +package com.yas.delivery.viewmodel; + +import java.util.List; + +public record CalculateFeesPostVm(String shipmentProviderId, + String shipmentServiceTypeId, + String recipientAddressId, + List checkoutItems) { +} diff --git a/delivery/src/main/java/com/yas/delivery/viewmodel/CheckoutItemVm.java b/delivery/src/main/java/com/yas/delivery/viewmodel/CheckoutItemVm.java new file mode 100644 index 0000000000..9f50d774cd --- /dev/null +++ b/delivery/src/main/java/com/yas/delivery/viewmodel/CheckoutItemVm.java @@ -0,0 +1,9 @@ +package com.yas.delivery.viewmodel; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; + +public record CheckoutItemVm(@NotNull String id, + @NotNull String productId, + @NotNull @Min(1) Integer quantity) { +} diff --git a/delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentFeeVm.java b/delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentFeeVm.java new file mode 100644 index 0000000000..14cb94196b --- /dev/null +++ b/delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentFeeVm.java @@ -0,0 +1,6 @@ +package com.yas.delivery.viewmodel; + +public record ShipmentFeeVm(String checkoutItemId, + Double shipmentCost, + Double shipmentTax) { +} diff --git a/delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentProviderVm.java b/delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentProviderVm.java new file mode 100644 index 0000000000..dd7921a074 --- /dev/null +++ b/delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentProviderVm.java @@ -0,0 +1,4 @@ +package com.yas.delivery.viewmodel; + +public record ShipmentProviderVm(String id, + String name) {} diff --git a/delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentServiceTypeVm.java b/delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentServiceTypeVm.java new file mode 100644 index 0000000000..fdaa72aa5a --- /dev/null +++ b/delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentServiceTypeVm.java @@ -0,0 +1,5 @@ +package com.yas.delivery.viewmodel; + +public record ShipmentServiceTypeVm(String id, + String name) { +} diff --git a/delivery/src/main/resources/application.properties b/delivery/src/main/resources/application.properties index b657efe9cb..85540d3f35 100644 --- a/delivery/src/main/resources/application.properties +++ b/delivery/src/main/resources/application.properties @@ -1,7 +1,18 @@ +server.port=8095 server.servlet.context-path=/delivery + spring.application.name=delivery +spring.threads.virtual.enabled=true + +management.tracing.sampling.probability=1.0 +management.endpoints.web.exposure.include=prometheus +management.metrics.distribution.percentiles-histogram.http.server.requests=true +management.metrics.tags.application=${spring.application.name} + logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}] +spring.security.oauth2.resourceserver.jwt.issuer-uri=http://identity/realms/Yas + # swagger-ui custom path springdoc.swagger-ui.path=/swagger-ui springdoc.packagesToScan=com.yas.delivery @@ -9,3 +20,5 @@ springdoc.swagger-ui.oauth.use-pkce-with-authorization-code-grant=true springdoc.swagger-ui.oauth.client-id=swagger-ui springdoc.oauthflow.authorization-url=http://identity/realms/Yas/protocol/openid-connect/auth springdoc.oauthflow.token-url=http://identity/realms/Yas/protocol/openid-connect/token + +cors.allowed-origins=* diff --git a/nginx/templates/default.conf.template b/nginx/templates/default.conf.template index 71fca5ce3e..b955cc3b27 100644 --- a/nginx/templates/default.conf.template +++ b/nginx/templates/default.conf.template @@ -57,6 +57,9 @@ server { location /recommendation/ { proxy_pass http://recommendation; } + location /delivery/ { + proxy_pass http://host.docker.internal:8095; # temporary value for current development, will be replaced once the delivery service is dockerized + } } server { From 12a82d474a209e9f0bac27c680118752e509bfc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tr=C3=AD=20H=E1=BA=A3i?= Date: Fri, 25 Oct 2024 09:08:24 +0700 Subject: [PATCH 2/3] add javadoc for mocked services --- .../yas/delivery/service/DeliveryService.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/delivery/src/main/java/com/yas/delivery/service/DeliveryService.java b/delivery/src/main/java/com/yas/delivery/service/DeliveryService.java index f6c4611848..ece1b90222 100644 --- a/delivery/src/main/java/com/yas/delivery/service/DeliveryService.java +++ b/delivery/src/main/java/com/yas/delivery/service/DeliveryService.java @@ -57,12 +57,24 @@ public class DeliveryService { shipmentProviders = Arrays.asList(fedexProvider, ghnProvider); } + /** + * Retrieves a list of available shipment providers. + * + * @return a list of {@link ShipmentProviderVm} representing the available shipment providers. + */ public List getShipmentProviders() { return shipmentProviders.stream().map(shipmentProvider -> new ShipmentProviderVm(shipmentProvider.getId(), shipmentProvider.getName()) ).toList(); } + /** + * Retrieves the available shipment service types for a given shipment provider and recipient address. + * + * @param shipmentProviderId the ID of the shipment provider. + * @param recipientAddressId the ID of the recipient's address. + * @return a list of {@link ShipmentServiceTypeVm} representing the available shipment service types. + */ public List getShipmentServiceTypes(String shipmentProviderId, String recipientAddressId) { ShipmentProvider shipmentProvider = @@ -76,6 +88,12 @@ public List getShipmentServiceTypes(String shipmentProvid .toList(); } + /** + * Calculates the shipment fees for the given shipment provider and service type based on checkout items. + * + * @param calculateFeePostVm the view model containing the necessary data for fee calculation. + * @return a list of {@link ShipmentFeeVm} representing the calculated shipment fees for each checkout item. + */ public List calculateShipmentFees(CalculateFeesPostVm calculateFeePostVm) { ShipmentProvider shipmentProvider = findShipmentProviderById(calculateFeePostVm.shipmentProviderId()) From b2ced13f9a5e909eb6fea33e5a429b6f205db0fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Tr=C3=AD=20H=E1=BA=A3i?= Date: Tue, 29 Oct 2024 15:34:27 +0700 Subject: [PATCH 3/3] remove get services API and update calculate fee API --- .../controller/DeliveryController.java | 12 -- .../delivery/model/ShipmentServiceType.java | 1 + .../yas/delivery/service/DeliveryService.java | 107 ++++++++++-------- .../viewmodel/CalculateFeesPostVm.java | 1 - .../yas/delivery/viewmodel/ShipmentFeeVm.java | 10 +- 5 files changed, 72 insertions(+), 59 deletions(-) diff --git a/delivery/src/main/java/com/yas/delivery/controller/DeliveryController.java b/delivery/src/main/java/com/yas/delivery/controller/DeliveryController.java index d485e2753f..569de0b8fe 100644 --- a/delivery/src/main/java/com/yas/delivery/controller/DeliveryController.java +++ b/delivery/src/main/java/com/yas/delivery/controller/DeliveryController.java @@ -4,15 +4,12 @@ import com.yas.delivery.viewmodel.CalculateFeesPostVm; import com.yas.delivery.viewmodel.ShipmentFeeVm; import com.yas.delivery.viewmodel.ShipmentProviderVm; -import com.yas.delivery.viewmodel.ShipmentServiceTypeVm; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @@ -26,15 +23,6 @@ public ResponseEntity> getShipmentProviders() { return ResponseEntity.ok(shipmentProviders); } - @GetMapping("/storefront/shipment/providers/{shipmentProviderId}/service-types") - public ResponseEntity> getShipmentServiceTypes(@PathVariable String shipmentProviderId, - @RequestParam - String recipientAddressId) { - List shipmentServiceTypes = - deliveryService.getShipmentServiceTypes(shipmentProviderId, recipientAddressId); - return ResponseEntity.ok(shipmentServiceTypes); - } - @PostMapping("/storefront/shipment/calculate") public ResponseEntity> calculateShipmentFees( @RequestBody CalculateFeesPostVm calculateFeePostVm) { diff --git a/delivery/src/main/java/com/yas/delivery/model/ShipmentServiceType.java b/delivery/src/main/java/com/yas/delivery/model/ShipmentServiceType.java index 8fd1ffc9f0..1ce0911385 100644 --- a/delivery/src/main/java/com/yas/delivery/model/ShipmentServiceType.java +++ b/delivery/src/main/java/com/yas/delivery/model/ShipmentServiceType.java @@ -14,4 +14,5 @@ public class ShipmentServiceType { private String name; private double cost; private double tax; + private String expectedDeliveryTime; } diff --git a/delivery/src/main/java/com/yas/delivery/service/DeliveryService.java b/delivery/src/main/java/com/yas/delivery/service/DeliveryService.java index ece1b90222..0d100bfffc 100644 --- a/delivery/src/main/java/com/yas/delivery/service/DeliveryService.java +++ b/delivery/src/main/java/com/yas/delivery/service/DeliveryService.java @@ -4,9 +4,12 @@ import com.yas.delivery.model.ShipmentProvider; import com.yas.delivery.model.ShipmentServiceType; import com.yas.delivery.viewmodel.CalculateFeesPostVm; +import com.yas.delivery.viewmodel.CheckoutItemVm; import com.yas.delivery.viewmodel.ShipmentFeeVm; import com.yas.delivery.viewmodel.ShipmentProviderVm; -import com.yas.delivery.viewmodel.ShipmentServiceTypeVm; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -17,6 +20,16 @@ public class DeliveryService { private static final List shipmentProviders; static { + // Initialize shipment providers and service types + ShipmentProvider fedexProvider = buildFedexProvider(); + ShipmentProvider upsProvider = buildUPSProvider(); + + shipmentProviders = Arrays.asList(fedexProvider, upsProvider); + } + + private static ShipmentProvider buildFedexProvider() { + ZonedDateTime now = ZonedDateTime.now(); + ShipmentProvider fedexProvider = new ShipmentProvider(); fedexProvider.setId("FEDEX"); fedexProvider.setName("Fedex"); @@ -26,35 +39,44 @@ public class DeliveryService { .name("FedEx International Priority") .cost(20.0) .tax(2.0) + .expectedDeliveryTime(now.plusDays(1).format(DateTimeFormatter.ISO_INSTANT)) .build(), ShipmentServiceType.builder() .id("INTERNATIONAL_ECONOMY") .name("FedEx International Economy") .cost(30.0) .tax(3.0) + .expectedDeliveryTime(now.plusDays(3).format(DateTimeFormatter.ISO_INSTANT)) .build() ); fedexProvider.setServiceTypes(fedexServiceTypes); + return fedexProvider; + } + + private static ShipmentProvider buildUPSProvider() { + ZonedDateTime now = ZonedDateTime.now(); - ShipmentProvider ghnProvider = new ShipmentProvider(); - ghnProvider.setId("GHN"); - ghnProvider.setName("Giao Hang Nhanh"); - List ghnServiceTypes = Arrays.asList( + ShipmentProvider upsProvider = new ShipmentProvider(); + upsProvider.setId("UPS"); + upsProvider.setName("UPS"); + List upsServiceTypes = Arrays.asList( ShipmentServiceType.builder() - .id("53322") - .name("Hang nhe") + .id("07") + .name("UPS Worldwide Express") .cost(10.0) .tax(1.0) + .expectedDeliveryTime(now.plusDays(5).format(DateTimeFormatter.ISO_INSTANT)) .build(), ShipmentServiceType.builder() - .id("100039") - .name("Hang nang") + .id("11") + .name("UPS Standard") .cost(15.0) - .tax(1.5).build() + .expectedDeliveryTime(now.plusDays(7).format(DateTimeFormatter.ISO_INSTANT)) + .tax(1.5) + .build() ); - ghnProvider.setServiceTypes(ghnServiceTypes); - - shipmentProviders = Arrays.asList(fedexProvider, ghnProvider); + upsProvider.setServiceTypes(upsServiceTypes); + return upsProvider; } /** @@ -69,27 +91,7 @@ public List getShipmentProviders() { } /** - * Retrieves the available shipment service types for a given shipment provider and recipient address. - * - * @param shipmentProviderId the ID of the shipment provider. - * @param recipientAddressId the ID of the recipient's address. - * @return a list of {@link ShipmentServiceTypeVm} representing the available shipment service types. - */ - public List getShipmentServiceTypes(String shipmentProviderId, - String recipientAddressId) { - ShipmentProvider shipmentProvider = - findShipmentProviderById(shipmentProviderId) - .orElseThrow(() -> new NotFoundException("Invalid shipment provider")); - - return shipmentProvider.getServiceTypes() - .stream() - .map(serviceType -> - new ShipmentServiceTypeVm(serviceType.getId(), serviceType.getName())) - .toList(); - } - - /** - * Calculates the shipment fees for the given shipment provider and service type based on checkout items. + * Calculates the shipment fees for the given shipment provider based on checkout items. * * @param calculateFeePostVm the view model containing the necessary data for fee calculation. * @return a list of {@link ShipmentFeeVm} representing the calculated shipment fees for each checkout item. @@ -99,18 +101,33 @@ public List calculateShipmentFees(CalculateFeesPostVm calculateFe findShipmentProviderById(calculateFeePostVm.shipmentProviderId()) .orElseThrow(() -> new NotFoundException("Invalid shipment provider")); - ShipmentServiceType shipmentServiceType = shipmentProvider.getServiceTypes() - .stream() - .filter(serviceType -> serviceType.getId().equals(calculateFeePostVm.shipmentServiceTypeId())) - .findFirst() - .orElseThrow(() -> new NotFoundException("Invalid shipment service type")); + List shipmentFees = new ArrayList<>(); + + for (CheckoutItemVm checkoutItem : calculateFeePostVm.checkoutItems()) { + shipmentFees.addAll(calculateShipmentFeesForCheckoutItem(shipmentProvider, checkoutItem)); + } + return shipmentFees; + } - return calculateFeePostVm - .checkoutItems() - .stream() - .map(checkoutItemVm -> - new ShipmentFeeVm(checkoutItemVm.id(), shipmentServiceType.getCost(), shipmentServiceType.getTax())) - .toList(); + private List calculateShipmentFeesForCheckoutItem(ShipmentProvider shipmentProvider, + CheckoutItemVm checkoutItem) { + + // To make the response more dynamic, we calculate the shipment fees by multiplying the cost and tax with + // the quantity of the checkout item. + // The actual calculation should be based on the actual business logic. + return shipmentProvider.getServiceTypes().stream() + .map(serviceType -> + ShipmentFeeVm.builder() + .checkoutItemId(checkoutItem.id()) + .shipmentProviderId(shipmentProvider.getId()) + .shipmentProviderName(shipmentProvider.getName()) + .shipmentServiceTypeId(serviceType.getId()) + .shipmentServiceTypeName(serviceType.getName()) + .shipmentCost(serviceType.getCost() * checkoutItem.quantity()) + .shipmentTax(serviceType.getTax() * checkoutItem.quantity()) + .expectedDeliveryTime(serviceType.getExpectedDeliveryTime()) + .build() + ).toList(); } private Optional findShipmentProviderById(String shipmentProviderId) { diff --git a/delivery/src/main/java/com/yas/delivery/viewmodel/CalculateFeesPostVm.java b/delivery/src/main/java/com/yas/delivery/viewmodel/CalculateFeesPostVm.java index 9106491a04..d5c07ca117 100644 --- a/delivery/src/main/java/com/yas/delivery/viewmodel/CalculateFeesPostVm.java +++ b/delivery/src/main/java/com/yas/delivery/viewmodel/CalculateFeesPostVm.java @@ -3,7 +3,6 @@ import java.util.List; public record CalculateFeesPostVm(String shipmentProviderId, - String shipmentServiceTypeId, String recipientAddressId, List checkoutItems) { } diff --git a/delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentFeeVm.java b/delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentFeeVm.java index 14cb94196b..8961d67118 100644 --- a/delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentFeeVm.java +++ b/delivery/src/main/java/com/yas/delivery/viewmodel/ShipmentFeeVm.java @@ -1,6 +1,14 @@ package com.yas.delivery.viewmodel; +import lombok.Builder; + +@Builder public record ShipmentFeeVm(String checkoutItemId, + String shipmentProviderId, + String shipmentProviderName, + String shipmentServiceTypeId, + String shipmentServiceTypeName, Double shipmentCost, - Double shipmentTax) { + Double shipmentTax, + String expectedDeliveryTime) { }