Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust to orders #20

Merged
merged 1 commit into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
uses: aws-actions/amazon-ecr-login@v2

- name: Build, tag, and push docker image to Amazon ECR
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
#if: github.ref == 'refs/heads/main' && github.event_name == 'push'
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
ECR_REPOSITORY: ${{ vars.AWS_ECR_REPO_NAME }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import com.fiap.stock.application.domain.valueobjects.ProductCategory
import com.fiap.stock.application.driver.web.ProductAPI
import com.fiap.stock.application.driver.web.request.ProductComposeRequest
import com.fiap.stock.application.driver.web.request.ProductRequest
import com.fiap.stock.application.driver.web.request.ProductStockBatchChangeRequest
import com.fiap.stock.application.driver.web.response.ProductResponse
import com.fiap.stock.application.usecases.AdjustStockUseCase
import com.fiap.stock.application.usecases.AssembleProductsUseCase
import com.fiap.stock.application.usecases.LoadProductUseCase
import com.fiap.stock.application.usecases.SearchProductUseCase
Expand All @@ -17,29 +19,37 @@ class ProductController(
private val assembleProductsUseCase: AssembleProductsUseCase,
private val loadProductUseCase: LoadProductUseCase,
private val searchProductUseCase: SearchProductUseCase,
private val adjustStockUseCase: AdjustStockUseCase,
) : ProductAPI {
override fun getByProductNumber(productNumber: Long): ResponseEntity<ProductResponse> {
return loadProductUseCase.getByProductNumber(productNumber).let(::createResponse)
}

override fun findAll(): ResponseEntity<List<ProductResponse>> {
return loadProductUseCase.findAll().let(::respond)
}
override fun findAll(): ResponseEntity<List<ProductResponse>> =
loadProductUseCase.findAll().let(::respond)

override fun findByCategory(category: String): ResponseEntity<List<ProductResponse>> {
return loadProductUseCase.findByCategory(ProductCategory.fromString(category)).let(::respond)
}
override fun findAllByProductNumber(productNumbers: List<Long>): ResponseEntity<List<ProductResponse>> =
loadProductUseCase.findAllByProductNumber(productNumbers).let(::respond)

override fun searchByName(name: String): ResponseEntity<List<ProductResponse>> {
return searchProductUseCase.searchByName(name).let(::respond)
override fun incrementStockOfProducts(productStockBatchChangeRequest: ProductStockBatchChangeRequest): ResponseEntity<String> {
adjustStockUseCase.incrementStockOfProducts(productStockBatchChangeRequest.productNumberQuantityMap)
return ResponseEntity.ok().build()
}

override fun create(productRequest: ProductRequest): ResponseEntity<ProductResponse> {
val result =
assembleProductsUseCase.create(productRequest.toDomain(), productRequest.components).let(::createResponse)
return result
override fun decrementStockOfProducts(productStockBatchChangeRequest: ProductStockBatchChangeRequest): ResponseEntity<String> {
adjustStockUseCase.decrementStockOfProducts(productStockBatchChangeRequest.productNumberQuantityMap)
return ResponseEntity.ok().build()
}

override fun findByCategory(category: String): ResponseEntity<List<ProductResponse>> =
loadProductUseCase.findByCategory(ProductCategory.fromString(category)).let(::respond)

override fun searchByName(name: String): ResponseEntity<List<ProductResponse>> =
searchProductUseCase.searchByName(name).let(::respond)

override fun create(productRequest: ProductRequest): ResponseEntity<ProductResponse> =
assembleProductsUseCase.create(productRequest.toDomain(), productRequest.components).let(::createResponse)

override fun update(
productNumber: Long,
productRequest: ProductRequest,
Expand All @@ -48,22 +58,18 @@ class ProductController(
return assembleProductsUseCase.update(product, productRequest.components).let(::createResponse)
}

override fun delete(productNumber: Long): ResponseEntity<ProductResponse> {
return assembleProductsUseCase.delete(productNumber).let(::createResponse)
}
override fun delete(productNumber: Long): ResponseEntity<ProductResponse> =
assembleProductsUseCase.delete(productNumber).let(::createResponse)

override fun compose(productComposeRequest: ProductComposeRequest): ResponseEntity<ProductResponse> {
return assembleProductsUseCase.compose(
override fun compose(productComposeRequest: ProductComposeRequest): ResponseEntity<ProductResponse> =
assembleProductsUseCase.compose(
productComposeRequest.productNumber,
productComposeRequest.subItemsNumbers,
).let(::createResponse)
}

private fun createResponse(product: Product?): ResponseEntity<ProductResponse> {
return ResponseEntity.ok(product?.let { ProductResponse.fromDomain(product) })
}
private fun createResponse(product: Product?): ResponseEntity<ProductResponse> =
ResponseEntity.ok(product?.let { ProductResponse.fromDomain(product) })

private fun respond(products: List<Product>): ResponseEntity<List<ProductResponse>> {
return ResponseEntity.ok(products.map { ProductResponse.fromDomain(it) })
}
private fun respond(products: List<Product>): ResponseEntity<List<ProductResponse>> =
ResponseEntity.ok(products.map { ProductResponse.fromDomain(it) })
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import com.fiap.stock.application.StockApiApp
import com.fiap.stock.application.adapter.gateway.ComponentGateway
import com.fiap.stock.application.adapter.gateway.ProductGateway
import com.fiap.stock.application.adapter.gateway.StockGateway
import com.fiap.stock.application.adapter.gateway.TransactionalGateway
import com.fiap.stock.application.usecases.LoadComponentUseCase
import com.fiap.stock.application.services.ComponentService
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
import com.fiap.stock.application.services.ProductService
import com.fiap.stock.application.services.StockService
import com.fiap.stock.application.usecases.LoadProductUseCase

@Configuration
@ComponentScan(basePackageClasses = [StockApiApp::class])
Expand Down Expand Up @@ -42,9 +44,15 @@ class ServiceConfig {
}

@Bean
fun createStockService(stockRepository: StockGateway): StockService {
return StockService(stockRepository)
fun createStockService(
stockRepository: StockGateway,
loadProductUseCase: LoadProductUseCase,
transactionalGateway: TransactionalGateway,
): StockService {
return StockService(
stockRepository,
loadProductUseCase,
transactionalGateway,
)
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import com.fiap.stock.application.domain.valueobjects.ProductCategory

interface ProductGateway {
fun findAll(): List<Product>

fun findAllByProductNumber(productNumbers: List<Long>): List<Product>

fun findByProductNumber(productNumber: Long): Product?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,23 @@ class ProductGatewayImpl(
) : ProductGateway {
private val mapper: ProductMapper = Mappers.getMapper(ProductMapper::class.java)

override fun findAll(): List<Product> {
return productJpaRepository.findAll()
.map(mapper::toDomain)
}
override fun findAll(): List<Product> =
productJpaRepository.findAll().map(mapper::toDomain)

override fun findByProductNumber(productNumber: Long): Product? {
return productJpaRepository.findById(productNumber)
.map { mapper.toDomain(it) }
.orElse(null)
}
override fun findAllByProductNumber(productNumbers: List<Long>): List<Product> =
productJpaRepository.findAllById(productNumbers).map(mapper::toDomain)

override fun findByCategory(category: ProductCategory): List<Product> {
return productJpaRepository.findByCategoryIgnoreCase(category.toString())
.map { mapper.toDomain(it) }
}
override fun findByProductNumber(productNumber: Long): Product? =
productJpaRepository.findById(productNumber).map { mapper.toDomain(it) }.orElse(null)

override fun searchByName(name: String): List<Product> {
return productJpaRepository.findByNameContainingIgnoreCase(name)
.map(mapper::toDomain)
}
override fun findByCategory(category: ProductCategory): List<Product> =
productJpaRepository.findByCategoryIgnoreCase(category.toString()).map { mapper.toDomain(it) }

override fun create(product: Product): Product {
return persist(product.copy(number = null))
}
override fun searchByName(name: String): List<Product> =
productJpaRepository.findByNameContainingIgnoreCase(name).map(mapper::toDomain)

override fun create(product: Product): Product =
persist(product.copy(number = null))

override fun update(product: Product): Product {
val number =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.fiap.stock.application.driver.web

import com.fiap.stock.application.driver.web.request.ProductComposeRequest
import com.fiap.stock.application.driver.web.request.ProductRequest
import com.fiap.stock.application.driver.web.request.ProductStockBatchChangeRequest
import com.fiap.stock.application.driver.web.response.ProductResponse
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
Expand All @@ -19,6 +20,7 @@ import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam

@Tag(name = "produto", description = "Produtos")
@RequestMapping("/admin/products")
Expand All @@ -43,6 +45,71 @@ interface ProductAPI {
@GetMapping
fun findAll(): ResponseEntity<List<ProductResponse>>

@Operation(
summary = "Retorna todos os produtos identificados por número",
parameters = [
Parameter(
name = "x-admin-token",
required = true,
`in` = ParameterIn.HEADER,
schema = Schema(type = "string", defaultValue = "token"),
),
],
)
@ApiResponses(
value = [
ApiResponse(responseCode = "200", description = "Operação bem-sucedida"),
],
)
@GetMapping("/batch")
fun findAllByProductNumber(
@Parameter(description = "IDs de produtos") @RequestParam("numbers") productNumbers: List<Long>,
): ResponseEntity<List<ProductResponse>>

@Operation(
summary = "Incrementa estoque disponível para os produtos identificados",
parameters = [
Parameter(
name = "x-admin-token",
required = true,
`in` = ParameterIn.HEADER,
schema = Schema(type = "string", defaultValue = "token"),
),
],
)
@ApiResponses(
value = [
ApiResponse(responseCode = "200", description = "Operação bem-sucedida"),
],
)
@PostMapping("/batch/increment")
fun incrementStockOfProducts(
@Parameter(description = "Relações de produto e quantidade a incrementar")
@RequestBody productStockBatchChangeRequest: ProductStockBatchChangeRequest,
): ResponseEntity<String>

@Operation(
summary = "Decrementa estoque disponível para os produtos identificados",
parameters = [
Parameter(
name = "x-admin-token",
required = true,
`in` = ParameterIn.HEADER,
schema = Schema(type = "string", defaultValue = "token"),
),
],
)
@ApiResponses(
value = [
ApiResponse(responseCode = "200", description = "Operação bem-sucedida"),
],
)
@PostMapping("/batch/decrement")
fun decrementStockOfProducts(
@Parameter(description = "Relações de produto e quantidade a decrementar")
@RequestBody productStockBatchChangeRequest: ProductStockBatchChangeRequest,
): ResponseEntity<String>

@Operation(
summary = "Retorna produtos por categoria",
parameters = [
Expand Down Expand Up @@ -127,7 +194,7 @@ interface ProductAPI {
ApiResponse(responseCode = "500", description = "Erro não esperado"),
],
)
@PostMapping()
@PostMapping
fun create(
@Parameter(description = "Cadastro do produto") @RequestBody productRequest: ProductRequest,
): ResponseEntity<ProductResponse>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.fiap.stock.application.driver.web.request

data class ProductStockBatchChangeRequest(
val productNumberQuantityMap: Map<Long, Long>
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import com.fiap.stock.application.domain.entities.Product
import com.fiap.stock.application.domain.errors.ErrorType
import com.fiap.stock.application.domain.errors.SelfOrderManagementException
import com.fiap.stock.application.domain.valueobjects.ProductCategory
import com.fiap.stock.application.usecases.*
import com.fiap.stock.application.usecases.AssembleProductsUseCase
import com.fiap.stock.application.usecases.LoadComponentUseCase
import com.fiap.stock.application.usecases.LoadProductUseCase
import com.fiap.stock.application.usecases.RemoveProductUseCase
import com.fiap.stock.application.usecases.SearchProductUseCase
import org.slf4j.LoggerFactory

class ProductService(
Expand All @@ -18,25 +22,24 @@ class ProductService(
RemoveProductUseCase {
private val log = LoggerFactory.getLogger(javaClass)

override fun getByProductNumber(productNumber: Long): Product {
return productRepository.findByProductNumber(productNumber)
override fun getByProductNumber(productNumber: Long): Product =
productRepository.findByProductNumber(productNumber)
?: throw SelfOrderManagementException(
errorType = ErrorType.PRODUCT_NOT_FOUND,
message = "Product [$productNumber] not found",
)
}

override fun findAll(): List<Product> {
return productRepository.findAll()
}
override fun findAll(): List<Product> =
productRepository.findAll()

override fun findByCategory(category: ProductCategory): List<Product> {
return productRepository.findByCategory(category)
}
override fun findAllByProductNumber(productNumbers: List<Long>): List<Product> =
productRepository.findAllByProductNumber(productNumbers)

override fun searchByName(productName: String): List<Product> {
return productRepository.searchByName(productName.trim())
}
override fun findByCategory(category: ProductCategory): List<Product> =
productRepository.findByCategory(category)

override fun searchByName(productName: String): List<Product> =
productRepository.searchByName(productName.trim())

override fun create(
product: Product,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package com.fiap.stock.application.services

import com.fiap.stock.application.adapter.gateway.StockGateway
import com.fiap.stock.application.adapter.gateway.TransactionalGateway
import com.fiap.stock.application.domain.entities.Stock
import com.fiap.stock.application.domain.errors.ErrorType
import com.fiap.stock.application.domain.errors.SelfOrderManagementException
import com.fiap.stock.application.usecases.AdjustStockUseCase
import com.fiap.stock.application.usecases.LoadProductUseCase
import com.fiap.stock.application.usecases.LoadStockUseCase
import org.slf4j.LoggerFactory

class StockService(
private val stockRepository: StockGateway,
private val loadProductUseCase: LoadProductUseCase,
private val transactionalGateway: TransactionalGateway,
) : LoadStockUseCase,
AdjustStockUseCase {
private val log = LoggerFactory.getLogger(javaClass)
Expand Down Expand Up @@ -45,4 +49,24 @@ class StockService(
}
return stockRepository.update(stock.copy(quantity = stock.quantity - quantity))
}

override fun incrementStockOfProducts(productNumberQuantityMap: Map<Long, Long>) {
transactionalGateway.transaction {
productNumberQuantityMap.forEach{ (productId, quantity) ->
loadProductUseCase.getByProductNumber(productId).components.forEach { component ->
increment(component.number!!, quantity)
}
}
}
}

override fun decrementStockOfProducts(productNumberQuantityMap: Map<Long, Long>) {
transactionalGateway.transaction {
productNumberQuantityMap.forEach{ (productId, quantity) ->
loadProductUseCase.getByProductNumber(productId).components.forEach { component ->
decrement(component.number!!, quantity)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ interface AdjustStockUseCase {
fun increment(componentNumber: Long, quantity: Long): Stock

fun decrement(componentNumber: Long, quantity: Long): Stock

fun incrementStockOfProducts(productNumberQuantityMap: Map<Long, Long>)

fun decrementStockOfProducts(productNumberQuantityMap: Map<Long, Long>)
}
Loading
Loading