refatorando a arquitetura
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"controle-de-estoque/internal/service"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// App representa a aplicação de linha de comando.
|
||||
// Ele faz o papel de "controller" + "router": lê a entrada do usuário,
|
||||
// decide qual ação executar e chama o service correspondente.
|
||||
type App struct {
|
||||
service *service.InventorySevice
|
||||
reader *bufio.Scanner
|
||||
}
|
||||
|
||||
func NewApp(s *service.InventorySevice) *App {
|
||||
return &App{
|
||||
service: s,
|
||||
reader: bufio.NewScanner(os.Stdin),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) Run() {
|
||||
for {
|
||||
ShowMenu()
|
||||
|
||||
if !a.reader.Scan() {
|
||||
return
|
||||
}
|
||||
input := strings.TrimSpace(a.reader.Text())
|
||||
|
||||
switch strings.ToLower(input) {
|
||||
case "1", "adicionar":
|
||||
a.handleAdd()
|
||||
case "2", "listar":
|
||||
a.handleList()
|
||||
case "3", "atualizar":
|
||||
a.handleUpdate()
|
||||
case "4", "deletar":
|
||||
a.handleDelete()
|
||||
case "0", "sair":
|
||||
fmt.Println("Saindo...")
|
||||
return
|
||||
default:
|
||||
fmt.Println("Opção inválida, tente novamente.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper para pedir e ler uma linha de texto do usuário.
|
||||
func (a *App) readLine(msg string) string {
|
||||
fmt.Print(msg)
|
||||
a.reader.Scan()
|
||||
return strings.TrimSpace(a.reader.Text())
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (a *App) handleAdd() {
|
||||
name := a.readLine("Nome do produto: ")
|
||||
category := a.readLine("Categoria do produto: ")
|
||||
priceStr := a.readLine("Preço: ")
|
||||
|
||||
price, err := strconv.ParseFloat(priceStr, 64)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Preço inválido.")
|
||||
return
|
||||
}
|
||||
|
||||
qtyStr := a.readLine("Quantidade: ")
|
||||
qty, err := strconv.Atoi(qtyStr)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Quantidade inválida.")
|
||||
return
|
||||
}
|
||||
|
||||
product, err := a.service.CreateProduct(name, category, price, qty)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Erro ao adicionar:", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Produto adicionado: #%d %s\n", product.ID, product.Name)
|
||||
}
|
||||
|
||||
func (a *App) handleList() {
|
||||
products := a.service.ListProducts()
|
||||
|
||||
if len(products) == 0 {
|
||||
fmt.Println("Nenhum produto cadastrado.")
|
||||
return
|
||||
}
|
||||
|
||||
for _, p := range products {
|
||||
fmt.Printf(
|
||||
"==============================================="+"\n"+
|
||||
"ID PRODUTO: %d"+"\n"+
|
||||
"NOME: %s"+"\n"+
|
||||
"CATEGORIA: %s"+"\n"+
|
||||
"PREÇO: %.2f"+"\n"+
|
||||
"QUANTIDADE: %d"+"\n"+
|
||||
"==============================================="+"\n",
|
||||
p.ID, p.Name, p.Category, p.Price, p.Quantity)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) handleUpdate() {
|
||||
idStr := a.readLine("Informe o Id do produto que deseja atualizar: ")
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
fmt.Println("ID inválido.")
|
||||
return
|
||||
}
|
||||
|
||||
field := a.readLine("Informe o campo que deseja atualizar (nome, categoria, preco, quantidade): ")
|
||||
value := a.readLine(fmt.Sprintf("Informe o novo valor para %s: ", field))
|
||||
|
||||
product, err := a.service.UpdateProduct(id, field, value)
|
||||
if err != nil {
|
||||
fmt.Println("Erro ao atualizar:", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Produto %d atualizado com sucesso!\n", product.ID)
|
||||
}
|
||||
|
||||
func (a *App) handleDelete() {
|
||||
idStr := a.readLine("Informe o Id do produto que deseja deletar: ")
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
fmt.Println("ID inválido.")
|
||||
return
|
||||
}
|
||||
|
||||
if err := a.service.DeleteProduct(id); err != nil {
|
||||
fmt.Println("Erro ao deletar:", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Produto %d deletado com sucesso!\n", id)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package cli
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ShowMenu() {
|
||||
fmt.Print(`
|
||||
============ CONTROLE DE ESTOQUE ==============
|
||||
ESCOLHA UMA DAS OPÇÕES:
|
||||
1 / adicionar - Adiciona o produto no estoque
|
||||
2 / listar - Lista todos os produtos do estoque
|
||||
3 / atualizar - Atualiza um produto do estoque
|
||||
4 / deletar - Deleta um produto do estoque
|
||||
0 / sair - Sair do programa
|
||||
=================================================
|
||||
Opção: `)
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package model
|
||||
|
||||
type Product struct {
|
||||
ID int
|
||||
Name string
|
||||
Category string
|
||||
Price float64
|
||||
Quantity int
|
||||
}
|
||||
|
||||
type ProductInput struct {
|
||||
Name string
|
||||
Category string
|
||||
Price float64
|
||||
Quantity int
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package inmemory
|
||||
|
||||
import (
|
||||
"controle-de-estoque/internal/model"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var ErrNotFound = errors.New("Produto não encontrado!")
|
||||
|
||||
type InventoryRepository struct {
|
||||
products map[int]*model.Product
|
||||
nextID int
|
||||
}
|
||||
|
||||
func NewInventorytRepository() *InventoryRepository {
|
||||
return &InventoryRepository{
|
||||
products: make(map[int]*model.Product),
|
||||
nextID: 1,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *InventoryRepository) Create(p *model.ProductInput) *model.Product {
|
||||
product := model.Product{
|
||||
ID: r.nextID,
|
||||
Name: p.Name,
|
||||
Category: p.Category,
|
||||
Price: p.Price,
|
||||
Quantity: p.Quantity,
|
||||
}
|
||||
|
||||
r.products[r.nextID] = &product
|
||||
|
||||
r.nextID++
|
||||
|
||||
return &product
|
||||
}
|
||||
|
||||
func (r *InventoryRepository) FindByID(id int) (*model.Product, error) {
|
||||
product, ok := r.products[id]
|
||||
|
||||
if !ok {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
return product, nil
|
||||
}
|
||||
|
||||
func (r *InventoryRepository) FindAll() map[int]*model.Product {
|
||||
return r.products
|
||||
}
|
||||
|
||||
func (r *InventoryRepository) Update(p *model.Product) error {
|
||||
if _, ok := r.products[p.ID]; !ok {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
r.products[p.ID] = p
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *InventoryRepository) Delete(id int) error {
|
||||
if _, ok := r.products[id]; !ok {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
delete(r.products, id)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package repository
|
||||
|
||||
import "controle-de-estoque/internal/model"
|
||||
|
||||
type InventoryRepository interface {
|
||||
Create(p *model.ProductInput) *model.Product
|
||||
FindByID(id int) (*model.Product, error)
|
||||
FindAll() map[int]*model.Product
|
||||
Update(p *model.Product) error
|
||||
Delete(id int) error
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"controle-de-estoque/internal/model"
|
||||
"controle-de-estoque/internal/repository"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type InventorySevice struct {
|
||||
repo repository.InventoryRepository
|
||||
}
|
||||
|
||||
func NewInventoryService(repo repository.InventoryRepository) *InventorySevice {
|
||||
return &InventorySevice{repo: repo}
|
||||
}
|
||||
|
||||
func (s *InventorySevice) CreateProduct(
|
||||
name string,
|
||||
category string,
|
||||
price float64,
|
||||
quantity int) (*model.Product, error) {
|
||||
if name == "" {
|
||||
return nil, errors.New("O nome é obrigatório")
|
||||
}
|
||||
|
||||
if quantity < 0 {
|
||||
return nil, errors.New("A quantidade não pode ser negativa!")
|
||||
}
|
||||
|
||||
productInput := &model.ProductInput{
|
||||
Name: name,
|
||||
Category: category,
|
||||
Price: price,
|
||||
Quantity: quantity,
|
||||
}
|
||||
|
||||
product := s.repo.Create(productInput)
|
||||
|
||||
return product, nil
|
||||
}
|
||||
|
||||
func (s *InventorySevice) ListProducts() map[int]*model.Product {
|
||||
return s.repo.FindAll()
|
||||
}
|
||||
|
||||
func (s *InventorySevice) GetProduct(id int) (*model.Product, error) {
|
||||
return s.repo.FindByID(id)
|
||||
}
|
||||
|
||||
func (s *InventorySevice) UpdateProduct(id int, field, value string) (*model.Product, error) {
|
||||
product, err := s.repo.FindByID(id)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch strings.ToLower(field) {
|
||||
case "nome", "name":
|
||||
product.Name = value
|
||||
case "categoria", "category":
|
||||
product.Category = value
|
||||
case "preco", "preço", "price":
|
||||
price, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return nil, errors.New("Preço inválido")
|
||||
}
|
||||
product.Price = price
|
||||
case "quantidade", "quantity":
|
||||
quantity, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return nil, errors.New("Quantidade inválida")
|
||||
}
|
||||
product.Quantity = quantity
|
||||
default:
|
||||
return nil, errors.New("Campo inválido")
|
||||
}
|
||||
|
||||
err = s.repo.Update(product)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return product, nil
|
||||
}
|
||||
|
||||
func (s *InventorySevice) DeleteProduct(id int) error {
|
||||
return s.repo.Delete(id)
|
||||
}
|
||||
Reference in New Issue
Block a user