From f68c0079485237c431019a380c3924ab3eb5b4c6 Mon Sep 17 00:00:00 2001 From: Diego Rocha Cerqueira Date: Fri, 16 Feb 2024 04:32:37 -0300 Subject: [PATCH] ebooks mais vendidos --- phase_4/app/api/dao/ebookDAO.py | 34 ++++++- phase_4/app/api/database/database.py | 4 +- phase_4/app/api/models/ebook.py | 9 ++ phase_4/app/api/routers/ebook.py | 26 +++-- phase_4/app/api/services/EbookService.py | 5 + .../app/webapp/app/(internal)/autor/page.tsx | 53 +++++----- script2.0.sql | 98 +++++++++++++++++++ 7 files changed, 192 insertions(+), 37 deletions(-) create mode 100644 script2.0.sql diff --git a/phase_4/app/api/dao/ebookDAO.py b/phase_4/app/api/dao/ebookDAO.py index ef5901a1..16fb9fef 100644 --- a/phase_4/app/api/dao/ebookDAO.py +++ b/phase_4/app/api/dao/ebookDAO.py @@ -1,5 +1,6 @@ from models.ebook import ( AuthorEbookDTO, + BestSellerEbookDTO, CatalogEbookDTO, Ebook, EbookDTO, @@ -126,4 +127,35 @@ def getEbookById(id): db.execute(query, [id]) data = db.fetchone() ebookModel = EbookShowupDTO(**data) - return ebookModel \ No newline at end of file + return ebookModel + + def getBestSellers(id = None): + ebooks = [] + parametro = [] + with DB() as db: + if(id): + query = """select ebook.idEBook, ebook.nome, sum(itempedido.valorUnitario) as faturamento, ebook.preco, count(itempedido.idEBook) as qtd_pedido from ebook + inner join itempedido on itempedido.idEBook = ebook.idEBook + where ebook.idAutor = %s + group by itempedido.idEBook + order by qtd_pedido desc + limit 10""" + parametro = [id] + else: + query = """select ebook.idEBook, ebook.nome, sum(itempedido.valorUnitario) as faturamento, ebook.preco, count(itempedido.idEBook) as qtd_pedido from ebook + inner join itempedido on itempedido.idEBook = ebook.idEBook + group by itempedido.idEBook + order by qtd_pedido + limit 10""" + db.execute(query, parametro) + data = db.fetchall() + for ebook in data: + ebookModel = BestSellerEbookDTO(**ebook) + + db.execute("""select genero.nome from genero + right join generoebook on genero.idGenero = generoebook.idGenero + right join ebook on generoebook.idEBook = ebook.idEBook where ebook.idEBook = %s""", [ebookModel.id]) + generos = db.fetchall() + ebookModel.genres = [genero["nome"] for genero in generos] + ebooks.append(ebookModel) + return ebooks \ No newline at end of file diff --git a/phase_4/app/api/database/database.py b/phase_4/app/api/database/database.py index f0c68810..9c9c66f9 100644 --- a/phase_4/app/api/database/database.py +++ b/phase_4/app/api/database/database.py @@ -3,9 +3,9 @@ # Configurações de conexão com o banco de dados settings = { "user": "root", - "password": "root", + "password": "abobora", "port": 3306, - "host": "livrum_database", # Endereço do servidor MySQL + "host": "localhost", # Endereço do servidor MySQL "database": "livrum", # Nome do banco de dados "raise_on_warnings": True, } diff --git a/phase_4/app/api/models/ebook.py b/phase_4/app/api/models/ebook.py index 097bc578..134039fd 100644 --- a/phase_4/app/api/models/ebook.py +++ b/phase_4/app/api/models/ebook.py @@ -104,6 +104,15 @@ def __init__(self, **kwargs): self.sinopse = kwargs.get("sinopse") self.motivo_recusa = kwargs.get("motivoRejeicao") +class BestSellerEbookDTO: + def __init__(self, **kwargs): + self.id = kwargs.get("idEBook") + self.name = kwargs.get("nome") + self.price = kwargs.get("preco") + self.sold = kwargs.get("qtd_pedido") + self.revenue = kwargs.get("faturamento") + self.genres = [] + class ReproveEbookDTO(BaseModel): id: int reason: str diff --git a/phase_4/app/api/routers/ebook.py b/phase_4/app/api/routers/ebook.py index c7d40e7f..734416a9 100644 --- a/phase_4/app/api/routers/ebook.py +++ b/phase_4/app/api/routers/ebook.py @@ -11,6 +11,8 @@ access = security.UserHasAccess([UserType.AUTHOR]) +access2 = security.UserHasAccess([UserType.AUTHOR, UserType.ADMIN]) + @router.get("/search", description="Get ebooks by optional filters") def searchWithOptionalFilters( @@ -35,7 +37,8 @@ def get(): @router.get("/{id}", description="Get an ebook by its ID") -def get(id: int): +def get(id: int, + user: Annotated[User, Depends(access)],): ebook = EbookService.getEbookById(id) return ebook @@ -48,26 +51,31 @@ def add( @router.put("/approve/{id}", description="approve an ebook") -def approve(id: str): +def approve(id: str, + user: Annotated[User, Depends(access)],): return EbookService.approveEbook(id) @router.put("/repprove", description="repprove an ebook") -def approve(reproveEbook: ReproveEbookDTO): +def approve(reproveEbook: ReproveEbookDTO, + user: Annotated[User, Depends(access)],): return EbookService.repproveEbook(reproveEbook) @router.put("/disable/{id}", description="approve an ebook") -def approve(id: str): +def approve(id: str, + user: Annotated[User, Depends(access)],): return EbookService.disableEbook(id) @router.patch("/{id}", description="Update an ebook's field") -def patch(id: int): +def patch(id: int, + user: Annotated[User, Depends(access)],): return {"message": "Update ebook", "id": id} @router.get("/download/{id}", description="download an ebook") -def download(id: str): +def download(id: str, + user: Annotated[User, Depends(access)],): result = EbookService.downloadEbook(id) if result is None: @@ -76,3 +84,9 @@ def download(id: str): "O PDF do Ebook não está disponível, por favor, tente novamente mais tarde", ) return result + +@router.get("/private/best-sellers", description="get best sellers ebooks") +def getBestSellers(user: Annotated[User, Depends(access2)], id=None): + print(user.idUsuario) + idAutor = id if id is not None else user.idUsuario + return EbookService.getBestSellers(idAutor) \ No newline at end of file diff --git a/phase_4/app/api/services/EbookService.py b/phase_4/app/api/services/EbookService.py index c6249bf3..c0889225 100644 --- a/phase_4/app/api/services/EbookService.py +++ b/phase_4/app/api/services/EbookService.py @@ -89,3 +89,8 @@ def downloadEbook(id: int): if file_path.is_file(): return FileResponse(file_path, filename=id + ".pdf") return None + def getBestSellers(id = None): + try: + return EbookDAO.getBestSellers(id) + except Exception as ex: + print("Erro ao buscar Ebooks para Autor com id:", id, ex) diff --git a/phase_4/app/webapp/app/(internal)/autor/page.tsx b/phase_4/app/webapp/app/(internal)/autor/page.tsx index bab17945..586136b4 100644 --- a/phase_4/app/webapp/app/(internal)/autor/page.tsx +++ b/phase_4/app/webapp/app/(internal)/autor/page.tsx @@ -2,7 +2,7 @@ import { theme } from "@/app/theme"; import { Card, Select, Typography } from "@mui/material"; -import { useEffect, useState } from "react"; +import { SetStateAction, useEffect, useState } from "react"; import Grid from "@mui/material/Unstable_Grid2/Grid2"; import DashboardCard from "@/app/components/DashboardCard"; import { Book, MonetizationOn, Sell } from "@mui/icons-material"; @@ -10,16 +10,35 @@ import { VisualizationChart, getFakeData } from "@/app/components/VisualizationC import { PopularityTable } from "@/app/components/PopularityTable"; import { EbookTableItem, EbooksTable } from "@/app/components/EbooksTable"; import { TableSelect } from "@/app/components/TableSelect"; +import useRequest from "@/app/services/requester"; +import { useUser } from "@/app/context"; export default function Page() { const username = "Almir"; + const { user, updateUser } = useUser(); const [data, setData] = useState([]); + const [items, setItems] = useState([] as Array) + const [itemsWithoutSearch, setItemsWithoutSearch] = useState([] as Array) + const [categories, setCategories] = useState([]); + + const requester = useRequest(); useEffect(() => { setData(getFakeData()); + requester.get("/ebook/private/best-sellers") + .then((response: { data: SetStateAction; }) => { + let aux = response.data as EbookTableItem[]; + setItems(response.data); + setItemsWithoutSearch(response.data); + let cat = [...new Set(aux.flatMap(item => item.genres)) as any].map(genre => ({ title: genre, value: genre }));; + setCategories(cat as any); + }) + .catch((err) => {console.log(err)}); }, []); + + const cards = [ { header: "Faturamento", @@ -48,31 +67,6 @@ export default function Page() { '#', 'Nome', 'Categoria', 'Preço', 'Vendidos (und)', "Faturamento" ]; - const items: Array = [ - { - id: 5, - name: 'Teste', - price: 51.47, - sold: 557, - revenue: 557 * 51.47, - genres: ['Adventure', 'Terror', 'Comedy'] - }, { - id: 15, - name: 'Teste', - price: 51.47, - sold: 557, - revenue: 557 * 51.47, - genres: ['Adventure', 'Terror', 'Comedy'] - } - ]; - - const categories = [ - { - value: 4, - title: 'Terror' - } - ]; - const mostSold = [ { id: 10, @@ -85,7 +79,7 @@ export default function Page() { - Bem-vindo, {username} + Bem-vindo, {user.nome} @@ -113,7 +107,10 @@ export default function Page() { { - console.log(e) + + let itemsFiltered = itemsWithoutSearch.filter((item) => item.genres.includes(e as any)); + + setItems(itemsFiltered); }} /> diff --git a/script2.0.sql b/script2.0.sql new file mode 100644 index 00000000..9b964a08 --- /dev/null +++ b/script2.0.sql @@ -0,0 +1,98 @@ + -- Script de inserção com 7 registros na tabela cliente +INSERT INTO cliente (idUsuario, cpf, dataNascimento, endereco, telefone) +VALUES + (10, '11111111111', '1990-01-01', 'Rua A, 123', '123456789'), + (2, '22222222222', '1991-02-02', 'Rua B, 456', '987654321'), + (3, '33333333333', '1992-03-03', 'Rua C, 789', '456789123'), + (4, '44444444444', '1993-04-04', 'Rua D, 101', '789123456'), + (8, '55555555555', '1994-05-05', 'Rua E, 112', '321654987'), + (6, '66666666666', '1995-06-06', 'Rua F, 113', '654987321'), + (7, '77777777777', '1996-07-07', 'Rua G, 114', '987321654'); + + +-- Script de inserção com 50 registros na tabela pedido +INSERT INTO pedido (meioPagamento, data, status, idCliente) +VALUES + ('pix', '2022-01-01', 'approved', 10), + ('credito', '2022-01-02', 'pending', 2), + ('pix', '2022-01-03', 'approved', 3), + ('credito', '2022-01-04', 'pending', 4), + ('pix', '2022-01-05', 'approved', 8), + ('credito', '2022-01-06', 'pending', 6), + ('pix', '2022-01-07', 'approved', 7), + ('credito', '2022-01-08', 'pending', 10), + ('pix', '2022-01-09', 'approved', 2), + ('credito', '2022-01-10', 'pending', 3), + ('pix', '2022-01-11', 'approved', 4), + ('credito', '2022-01-12', 'pending', 8), + ('pix', '2022-01-13', 'approved', 6), + ('credito', '2022-01-14', 'pending', 7), + ('pix', '2022-01-15', 'approved', 10), + ('credito', '2022-01-16', 'pending', 2), + ('pix', '2022-01-17', 'approved', 3), + ('credito', '2022-01-18', 'pending', 4), + ('pix', '2022-01-19', 'approved', 8), + ('credito', '2022-01-20', 'pending', 6), + ('pix', '2022-01-21', 'approved', 7), + ('credito', '2022-01-22', 'pending', 10), + ('pix', '2022-01-23', 'approved', 2), + ('credito', '2022-01-24', 'pending', 3), + ('pix', '2022-01-25', 'approved', 4), + ('credito', '2022-01-26', 'pending', 8), + ('pix', '2022-01-27', 'approved', 6), + ('credito', '2022-01-28', 'pending', 7), + ('pix', '2022-01-29', 'approved', 10), + ('credito', '2022-01-30', 'pending', 2), + ('pix', '2022-01-31', 'approved', 3), + ('credito', '2022-02-01', 'pending', 4), + ('pix', '2022-02-02', 'approved', 8), + ('credito', '2022-02-03', 'pending', 6), + ('pix', '2022-02-04', 'approved', 7), + ('credito', '2022-02-05', 'pending', 10), + ('pix', '2022-02-06', 'approved', 2), + ('credito', '2022-02-07', 'pending', 3), + ('pix', '2022-02-08', 'approved', 4), + ('credito', '2022-02-09', 'pending', 8), + ('pix', '2022-02-10', 'approved', 6), + ('credito', '2022-02-11', 'pending', 7), + ('pix', '2022-02-12', 'approved', 10), + ('credito', '2022-02-13', 'pending', 2), + ('pix', '2022-02-14', 'approved', 3), + ('credito', '2022-02-15', 'pending', 4), + ('pix', '2022-02-16', 'approved', 8), + ('credito', '2022-02-17', 'pending', 6), + ('pix', '2022-02-18', 'approved', 7), + ('credito', '2022-02-19', 'pending', 10), + ('pix', '2022-02-20', 'approved', 2); + +-- Script de inserção com 100 registros na tabela cupom +INSERT INTO cupom (idUsuario, nome, status, porcentagem, dataExpiracao, criadoEm, modificadoEM) +SELECT + -- Gera valores aleatórios entre 1 e 20 para idUsuario (presumindo a existência de registros em autor com idUsuario entre 1 e 20) + ROUND(RAND() * 19 + 1), + CONCAT('cupom', ROUND(RAND() * 100000)), -- Gera um nome de cupom único + -- Gera um status aleatório entre active, inactive e expired + CASE WHEN RAND() < 0.7 THEN 'active' WHEN RAND() < 0.9 THEN 'inactive' ELSE 'expired' END, + ROUND(RAND() * 30, 2), -- Gera uma porcentagem aleatória entre 0 e 30 + -- Gera uma data de expiração aleatória nos próximos 30 dias + DATE_ADD(CURDATE(), INTERVAL ROUND(RAND() * 30) DAY), + CURRENT_TIMESTAMP, + NULL +FROM + -- Este bloco FROM é apenas um truque para repetir a instrução SELECT 100 vezes + (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) AS counter +LIMIT 100; + + +-- Script de inserção com 100 registros na tabela itempedido +INSERT INTO itempedido (idCupom, idEBook, idPedido, valorUnitario, valorTotal) +SELECT + NULL, -- Coluna idCupom + ROUND(RAND() * 19 + 1), -- Gera valores aleatórios entre 1 e 20 para idEBook + ROUND(RAND() * 45 + 105), -- Gera valores aleatórios entre 105 e 150 para idPedido + ROUND(RAND() * 100, 2), -- Valor Unitário aleatório entre 0 e 100 + ROUND(RAND() * 100, 2) -- Valor Total aleatório entre 0 e 100 +FROM + -- Este bloco FROM é apenas um truque para repetir a instrução SELECT 100 vezes + (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) AS counter +LIMIT 100;