Skip to content

OM-318: gestión de reclamos de productos - #108

Merged
SebaKisser merged 12 commits into
devfrom
OM-318
Apr 18, 2026
Merged

SebaKisser merged 12 commits into
devfrom
OM-318

Conversation

@leoAchu16

@leoAchu16 leoAchu16 commented Apr 17, 2026 •

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

Notas de Lanzamiento

  • New Features

    • Nuevo sistema de reportes para reseñas y productos con motivos específicos, estados (incl. IN_PROGRESS) y control para evitar duplicados.
    • Endpoints para listar, filtrar, paginar y actualizar reportes desde panel/API para administradores y vendedores; cierre de reportes requiere notas.
  • Bug Fixes

    • Validaciones y permisos reforzados para acceso y modificaciones de reportes; transiciones de estado validadas.
  • Tests

    • Suite de pruebas unitarias para servicios de reportes (casos de roles, transiciones y paginación).
  • Documentation

    • Esquemas y documentación API actualizados para reportes.

@coderabbitai

coderabbitai Bot commented Apr 17, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@leoAchu16 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 39 minutes and 19 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 39 minutes and 19 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 93d124eb-92db-4313-a0b0-2e2cff94ed7b

📥 Commits

Reviewing files that changed from the base of the PR and between 17eb256 and ac03bed.

📒 Files selected for processing (2)
  • src/modules/global/reports/product/product-report.service.js
  • tests/unit/report/product-report.test.js
📝 Walkthrough

Walkthrough

Se agregan enums y tablas de reportes (productos y reviews) en migraciones y schema Prisma; se incorporan rutas, controlador y servicios para listar, filtrar y actualizar reportes de productos con validaciones de rol, restricciones por tienda y reglas de transición de estado.

Changes

Cohort / File(s) Summary
Migraciones de Base de Datos
prisma/migrations/20260417000531_add_reports_tables/migration.sql, prisma/migrations/20260417115654_add_in_progress_report_status/migration.sql
Crea enums (ReviewReportReason, ReportStatus, ProductReportReason), tablas ReviewReports y ProductReports con FKs, índice único en reviews; agrega valor IN_PROGRESS a ReportStatus.
Prisma Schema
prisma/schema.prisma
Añade modelos ReviewReports y ProductReports, enums y nuevas relaciones en Users, Products, ProductReviews y Orders; incluye constraint único para reports de reviews.
Aplicación / Rutas
src/app.js, src/modules/global/reports/product/product-report.routes.js
Registra router en /api/reports y define endpoints autenticados: GET /products, GET /products/filtered (con paginación) y PUT /products/:reportId.
Controlador
src/modules/global/reports/product/product-report.controller.js
Agrega handlers getProductsReports, getProductsReportsFiltered, updateProductReport — validan autenticación, parsean inputs y delegan a servicios; errores se pasan a next.
Servicio de Reportes de Productos
src/modules/global/reports/product/product-report.service.js
Implementa lógica de permisos (ADMIN/SELLER), consultas base con includes anidados, filtrado por store, validación de transiciones de report_status, requisito de notes para cierre, y endpoints paginados con conteo/meta.
Documentación / Swagger
src/config/swagger.config.js, src/docs/schemas/commerce/product-report.schema.js, src/docs/schemas/index.js
Añade esquemas OpenAPI para ProductReport y ProductReportUpdated; incorpora export y merge en configuración Swagger.
Tests
tests/unit/report/product-report.test.js
Agrega suite de tests unitarios (Vitest) que mockean Prisma y validan flujos y reglas de negocio para los tres servicios principales.

Sequence Diagram(s)

sequenceDiagram
    participant Cliente
    participant Controlador
    participant Servicio
    participant BaseDeDatos

    Cliente->>Controlador: PUT /api/reports/products/:reportId\n{ report_status, notes }
    Controlador->>Controlador: validar req.user.id_user
    Controlador->>Servicio: updateProductReportService(userId, reportId, payload)
    Servicio->>BaseDeDatos: users.findUnique(id)
    BaseDeDatos-->>Servicio: user
    Servicio->>BaseDeDatos: stores.findUnique(fk_user)
    BaseDeDatos-->>Servicio: store
    Servicio->>BaseDeDatos: productReports.findFirst(filter por reportId y store)
    BaseDeDatos-->>Servicio: report
    Servicio->>Servicio: validar transición y requerir notes si cierra
    Servicio->>BaseDeDatos: productReports.update({...report_status, notes, resolved_by?, resolved_at?})
    BaseDeDatos-->>Servicio: updatedReport
    Servicio-->>Controlador: updatedReport
    Controlador-->>Cliente: HTTP 200 { updatedReport }
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • CrisNAC
  • Benjakr04
  • Andoumeda

Poem

🐰 Salté entre enums y tablas a cuidar,
abrí rutas y servicios para vigilar,
admin y seller pueden el flujo llevar,
notas y estados listos para cerrar,
¡brinco feliz, vengo a celebrar! 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed El título es específico y descriptivo: 'OM-318: gestión de reclamos de productos' alude claramente al cambio principal (adición de funcionalidad de gestión de reportes de productos), aunque está en español y sigue un patrón con ID de tarea (OM-318). Hay una pequeña discrepancia entre el título 'reclamos' y las tablas/servicios 'reports', pero se refieren al mismo dominio conceptual.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch OM-318

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
src/modules/global/reports/product/product-report.service.js (1)

141-145: Validar explícitamente que report_status venga en el body.

Si el cliente omite report_status, allowed.includes(undefined) devuelve false y el usuario ve un mensaje poco útil tipo "No podés pasar de PENDING a undefined...". Conviene validar arriba que report_status sea un valor del enum antes del chequeo de transición, con un mensaje claro (ValidationError("report_status es requerido y debe ser uno de: ...")).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/global/reports/product/product-report.service.js` around lines
141 - 145, Before checking allowed.includes(report_status) validate that
report_status is present and is one of the allowed enum values: if missing or
not in the enum throw a ValidationError with a clear message like "report_status
es requerido y debe ser uno de: ..." ; update the validation near the block that
throws ValidationError (references: report_status, allowed, currentStatus,
ValidationError) so the explicit enum check runs first and returns the clearer
error before evaluating transition rules.
src/modules/global/reports/product/product-report.controller.js (1)

8-71: Chequeo de autenticación redundante y con formato de error inconsistente.

Los tres handlers replican el mismo bloque if (!req.user?.id_user) return res.status(401).json(...). Como las rutas ya corren el middleware authenticate antes del controller, req.user debería estar garantizado; si no lo está, es un bug del middleware y conviene fallar de forma uniforme. Además, este res.status(401).json(...) inline bypassa el errorHandler central y usa un shape distinto ({ success, message }) al resto de errores del sistema (AppError + errorHandler).

Sugerencia: eliminar el chequeo (confiar en el middleware) o, si se quiere mantener defensa en profundidad, lanzar un UnauthorizedError vía next() para que errorHandler uniformice la respuesta.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/global/reports/product/product-report.controller.js` around lines
8 - 71, The three controller functions getProductsReports, updateProductReport,
and getProductsReportsFiltered contain redundant inline authentication checks
that bypass the central error handler; remove the repeated if
(!req.user?.id_user) { return res.status(401)... } blocks and either trust the
authenticate middleware or, for defense-in-depth, replace each inline response
with next(new UnauthorizedError('Usuario autenticado requerido')) (or the
project's equivalent AppError/Unauthorized error constructor) so the centralized
errorHandler produces a consistent error shape.
src/modules/global/reports/product/product-report.routes.js (1)

7-7: mergeParams: true innecesario.

Este router se monta en /api/reports (ver src/app.js línea 77), que no es una ruta con parámetros padres. mergeParams solo tiene sentido cuando el router se anida bajo una ruta con :params que se quieran heredar. Podés quitarlo para evitar ruido semántico.

♻️ Cambio sugerido
-const router = Router({ mergeParams: true });
+const router = Router();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/global/reports/product/product-report.routes.js` at line 7,
Elimina la opción innecesaria mergeParams en la declaración del router:
sustituye la creación de router que usa Router({ mergeParams: true }) por una
creación simple Router() (identifica la línea con la variable router y la
llamada a Router). Asegurate de revisar rápidamente que ninguna lógica en este
archivo (rutas dentro de product-report.routes.js) dependa de parámetros
heredados antes de removerla; si no hay dependencia, quitar mergeParams reduce
ruido semántico.
prisma/migrations/20260417000531_add_reports_tables/migration.sql (1)

28-44: Considerá agregar índices sobre columnas FK y sobre el hot path de listado.

Postgres no crea índices automáticamente sobre columnas de FK. Dado que el servicio consulta ProductReports filtrando por status y ordenando por created_at DESC, y que los joins se harán por fk_product, fk_reporter y fk_order, sería conveniente agregar índices desde el schema de Prisma (por ejemplo @@index([fk_product]), @@index([fk_reporter]), @@index([fk_order]), y un @@index([status, created_at]) para acelerar el listado paginado). Lo mismo aplica a ReviewReports (FKs fk_product_review, fk_reporter, resolved_by).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@prisma/migrations/20260417000531_add_reports_tables/migration.sql` around
lines 28 - 44, Agregar índices para acelerar joins y listados: en el modelo
ProductReports añade índices para fk_product, fk_reporter y fk_order (p. ej.
@@index([fk_product]), @@index([fk_reporter]), @@index([fk_order])) y un índice
compuesto para el hot path de listado @@index([status, created_at]) para
paginación/ordenamiento; hacer cambios análogos en el modelo ReviewReports
creando @@index([fk_product_review]), @@index([fk_reporter]),
@@index([resolved_by]) y un @@index([status, created_at]) si aplica. Estos
índices corresponden a las columnas y modelos ProductReports (id_product_report,
fk_product, fk_reporter, fk_order, status, created_at) y ReviewReports
(fk_product_review, fk_reporter, resolved_by, status, created_at) en el schema
de Prisma.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/modules/global/reports/product/product-report.service.js`:
- Around line 198-204: The filter validation in
getProductsReportsFilteredService rejects the new IN_PROGRESS enum because
allowedStatuses only contains ["PENDING","RESOLVED","REJECTED"]; update the
allowedStatuses array to include "IN_PROGRESS" and ensure the ValidationError
message (the join of allowedStatuses) reflects the updated list; verify
references to report_status and the related updateProductReportService flow
still accept IN_PROGRESS as a valid intermediate state.
- Around line 10-48: Declare BASE_QUERY as a local constant (e.g., add "const
BASE_QUERY = { ... }") to avoid ReferenceError; remove or replace the invalid
"store" selection inside BASE_QUERY and instead include the store via the
product relation (e.g., use product.select.store or nest product.select to
select store fields) because ProductReports has no direct store relation; update
any filters that use fk_store (references to fk_store in where clauses inside
functions like the store-scoped queries) to filter through the product relation
(e.g., where: { product: { fk_store: store.id_store } }) since ProductReports
doesn't have fk_store; and add "IN_PROGRESS" to the allowedStatuses array so it
matches the ReportStatus enum.
- Around line 35-48: El servicio está usando un campo/relación inexistente
(fk_store / store) en el modelo ProductReports; actualiza BASE_QUERY y todos los
where/filters para usar la relación product en su lugar: eliminar el select raiz
"store" y anidar ese select dentro de product.select (incluyendo store: {
select: { id_store, name } }), y reemplazar cualquier filtro que use fk_store
(en getProductsReportsService, updateProductReportService,
getProductsReportsFilteredService) por product: { fk_store: <valor> } (es decir
aplicar el filtro sobre ProductReports.product.fk_store). Asegúrate de ajustar
BASE_QUERY, el select del filtrado y las cláusulas where mencionadas para
referenciar product en vez de store.

---

Nitpick comments:
In `@prisma/migrations/20260417000531_add_reports_tables/migration.sql`:
- Around line 28-44: Agregar índices para acelerar joins y listados: en el
modelo ProductReports añade índices para fk_product, fk_reporter y fk_order (p.
ej. @@index([fk_product]), @@index([fk_reporter]), @@index([fk_order])) y un
índice compuesto para el hot path de listado @@index([status, created_at]) para
paginación/ordenamiento; hacer cambios análogos en el modelo ReviewReports
creando @@index([fk_product_review]), @@index([fk_reporter]),
@@index([resolved_by]) y un @@index([status, created_at]) si aplica. Estos
índices corresponden a las columnas y modelos ProductReports (id_product_report,
fk_product, fk_reporter, fk_order, status, created_at) y ReviewReports
(fk_product_review, fk_reporter, resolved_by, status, created_at) en el schema
de Prisma.

In `@src/modules/global/reports/product/product-report.controller.js`:
- Around line 8-71: The three controller functions getProductsReports,
updateProductReport, and getProductsReportsFiltered contain redundant inline
authentication checks that bypass the central error handler; remove the repeated
if (!req.user?.id_user) { return res.status(401)... } blocks and either trust
the authenticate middleware or, for defense-in-depth, replace each inline
response with next(new UnauthorizedError('Usuario autenticado requerido')) (or
the project's equivalent AppError/Unauthorized error constructor) so the
centralized errorHandler produces a consistent error shape.

In `@src/modules/global/reports/product/product-report.routes.js`:
- Line 7: Elimina la opción innecesaria mergeParams en la declaración del
router: sustituye la creación de router que usa Router({ mergeParams: true })
por una creación simple Router() (identifica la línea con la variable router y
la llamada a Router). Asegurate de revisar rápidamente que ninguna lógica en
este archivo (rutas dentro de product-report.routes.js) dependa de parámetros
heredados antes de removerla; si no hay dependencia, quitar mergeParams reduce
ruido semántico.

In `@src/modules/global/reports/product/product-report.service.js`:
- Around line 141-145: Before checking allowed.includes(report_status) validate
that report_status is present and is one of the allowed enum values: if missing
or not in the enum throw a ValidationError with a clear message like
"report_status es requerido y debe ser uno de: ..." ; update the validation near
the block that throws ValidationError (references: report_status, allowed,
currentStatus, ValidationError) so the explicit enum check runs first and
returns the clearer error before evaluating transition rules.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 22294b8f-d3a3-4757-bc2c-f8f7fe2feddc

📥 Commits

Reviewing files that changed from the base of the PR and between ad5f053 and a68ac53.

📒 Files selected for processing (7)
  • prisma/migrations/20260417000531_add_reports_tables/migration.sql
  • prisma/migrations/20260417115654_add_in_progress_report_status/migration.sql
  • prisma/schema.prisma
  • src/app.js
  • src/modules/global/reports/product/product-report.controller.js
  • src/modules/global/reports/product/product-report.routes.js
  • src/modules/global/reports/product/product-report.service.js

Comment thread src/modules/global/reports/product/product-report.service.js Outdated
Comment thread src/modules/global/reports/product/product-report.service.js Outdated
Comment thread src/modules/global/reports/product/product-report.service.js

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/modules/global/reports/product/product-report.service.js (1)

141-149: Validación explícita de report_status mejoraría el mensaje de error.

Si el consumidor no envía report_status (o envía un valor fuera del enum, como "FOO"), se lanza el error genérico de transición indicando "No podés pasar de PENDING a undefined", lo cual resulta confuso para el cliente. Considerar validar presencia y pertenencia al enum ReportStatus antes de evaluar la transición, reutilizando la lista allowedStatuses que ya se usa en getProductsReportsFilteredService.

♻️ Refactor sugerido
+  const allowedStatuses = ["PENDING", "IN_PROGRESS", "RESOLVED", "REJECTED"];
+  if (!report_status || !allowedStatuses.includes(report_status)) {
+    throw new ValidationError(
+      `Estado inválido. Los valores permitidos son: ${allowedStatuses.join(", ")}`
+    );
+  }
+
   const currentStatus = report.report_status;
   const allowed = allowedTransitions[currentStatus];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/global/reports/product/product-report.service.js` around lines
141 - 149, Validate that report_status is present and a valid enum value before
checking allowedTransitions: in the block using currentStatus,
allowedTransitions and allowed (and throwing ValidationError), first check if
report_status is undefined/null and throw ValidationError like "report_status is
required" and then check membership using the existing allowedStatuses array
(the same list used by getProductsReportsFilteredService); if report_status is
not in allowedStatuses throw a ValidationError listing allowedStatuses, only
after those checks perform the existing transition check (if
(!allowed.includes(report_status)) ...) to yield the clearer transition error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/modules/global/reports/product/product-report.service.js`:
- Around line 141-149: Validate that report_status is present and a valid enum
value before checking allowedTransitions: in the block using currentStatus,
allowedTransitions and allowed (and throwing ValidationError), first check if
report_status is undefined/null and throw ValidationError like "report_status is
required" and then check membership using the existing allowedStatuses array
(the same list used by getProductsReportsFilteredService); if report_status is
not in allowedStatuses throw a ValidationError listing allowedStatuses, only
after those checks perform the existing transition check (if
(!allowed.includes(report_status)) ...) to yield the clearer transition error.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0f30260f-32ea-4a07-93f9-b6d9159c3772

📥 Commits

Reviewing files that changed from the base of the PR and between a68ac53 and 726f68a.

📒 Files selected for processing (2)
  • src/modules/global/reports/product/product-report.routes.js
  • src/modules/global/reports/product/product-report.service.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/modules/global/reports/product/product-report.routes.js

@CrisNAC

CrisNAC commented Apr 18, 2026

Copy link
Copy Markdown
Owner

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Apr 18, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@CrisNAC

CrisNAC commented Apr 18, 2026

Copy link
Copy Markdown
Owner

@CodeRabbit help

@coderabbitai

coderabbitai Bot commented Apr 18, 2026

Copy link
Copy Markdown
Contributor

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
  • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
  • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve merge conflict to automatically resolve merge conflicts.
  • @coderabbitai autofix to automatically fix issues identified in unresolved review comments.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit configuration file (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/modules/global/reports/product/product-report.service.js (1)

64-85: Evitá listados sin límite.

Ambos findMany devuelven todos los reclamos activos. Si el volumen crece, este endpoint puede volverse pesado; conviene reutilizar el flujo paginado o aplicar un límite por defecto.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/global/reports/product/product-report.service.js` around lines 64
- 85, Las llamadas a prisma.productReports.findMany (tanto la rama ADMIN como la
SELLER) usan BASE_QUERY pero no aplican paginación ni límite por defecto; cambia
ambas invocaciones para reutilizar el flujo paginado o imponer límites seguros:
agrega parámetros de paginación (p. ej. take/skip o cursor) a las llamadas a
prisma.productReports.findMany y/o extiende BASE_QUERY para incluir valores por
defecto (limit/take y offset/skip) si no vienen desde la request. Asegúrate de
aplicar la misma lógica de paginado cuando construyas la consulta para SELLER
(la que extiende BASE_QUERY con product.fk_store) y documenta/propaga los
parámetros de paginado desde la función que ejecuta estas ramas.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/modules/global/reports/product/product-report.service.js`:
- Around line 151-166: Validate that notes is a string before calling trim():
check typeof notes === "string" (or convert non-null values to String only after
verifying) and if notes is provided but not a string, throw a ValidationError
(using the existing ValidationError symbol) with a 400-friendly message; then
use notes.trim() safely in both the mandatory-note check that gates
RESOLVED/REJECTED and in the prisma.productReports.update data spread (the
variables report_status, notes, resolvedReportId and
prisma.productReports.update are the places to change). Ensure the logic still
enforces non-empty trimmed notes for closed statuses and only includes notes in
data when a valid trimmed string exists.
- Around line 116-170: The status transition is vulnerable to race conditions
because you read with prisma.productReports.findFirst and later update with
prisma.productReports.update using only id_product_report; ensure the
read+validation+write is atomic by either wrapping the logic in a Prisma
transaction ($transaction) or by making the update conditional on the current
status (add report_status: currentStatus to the where clause on the update that
uses resolvedReportId), so only the row still in currentStatus is modified
(refer to currentStatus, report_status, resolvedReportId,
prisma.productReports.findFirst and prisma.productReports.update).

---

Nitpick comments:
In `@src/modules/global/reports/product/product-report.service.js`:
- Around line 64-85: Las llamadas a prisma.productReports.findMany (tanto la
rama ADMIN como la SELLER) usan BASE_QUERY pero no aplican paginación ni límite
por defecto; cambia ambas invocaciones para reutilizar el flujo paginado o
imponer límites seguros: agrega parámetros de paginación (p. ej. take/skip o
cursor) a las llamadas a prisma.productReports.findMany y/o extiende BASE_QUERY
para incluir valores por defecto (limit/take y offset/skip) si no vienen desde
la request. Asegúrate de aplicar la misma lógica de paginado cuando construyas
la consulta para SELLER (la que extiende BASE_QUERY con product.fk_store) y
documenta/propaga los parámetros de paginado desde la función que ejecuta estas
ramas.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 68c0e9c4-a98a-4da1-bd8b-2aad948cb0f0

📥 Commits

Reviewing files that changed from the base of the PR and between 726f68a and 5010e54.

📒 Files selected for processing (1)
  • src/modules/global/reports/product/product-report.service.js

Comment on lines +116 to +170
const report = await prisma.productReports.findFirst({
where: {
id_product_report: resolvedReportId,
status: true,
product: {
fk_store: store.id_store,
},
},
});

if (!report) throw new NotFoundError("Reporte no encontrado");

// No se puede modificar un reporte ya cerrado
if (report.report_status === "RESOLVED" || report.report_status === "REJECTED")
throw new ValidationError("Este reporte ya fue cerrado y no puede modificarse");

// Validar transiciones permitidas
// PENDING -> IN_PROGRESS
// IN_PROGRESS -> RESOLVED
// IN_PROGRESS -> REJECTED
const allowedTransitions = {
PENDING: ["IN_PROGRESS"],
IN_PROGRESS: ["RESOLVED", "REJECTED"],
};

const currentStatus = report.report_status; // estado actual del reporte
const allowed = allowedTransitions[currentStatus]; // estados permitidos para el siguiente estado

// si el nuevo estado no esta en los permitidos, lanza error
if (!allowed.includes(report_status)) {
throw new ValidationError(
`No podés pasar de ${currentStatus} a ${report_status}. Transiciones permitidas: ${allowed.join(", ")}`
);
}

// Notas obligatorias al cerrar el reporte
if (["RESOLVED", "REJECTED"].includes(report_status) && !notes?.trim()) {
throw new ValidationError(
report_status === "RESOLVED"
? "Debés agregar una nota explicando cómo se resolvió el reclamo"
: "Debés agregar una nota explicando por qué se rechazó el reclamo"
);
}

const isClosed = ["RESOLVED", "REJECTED"].includes(report_status);

const updatedReport = await prisma.productReports.update({
where: { id_product_report: resolvedReportId },
data: {
report_status,
...(notes && { notes: notes.trim() }),
...(isClosed && {
resolved_by: resolvedUserId,
resolved_at: new Date(),
}),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verifica si el flujo sigue separado en read -> update por id, sin update condicional/transacción.
rg -nP 'productReports\.(findFirst|updateMany|update)\(|\$transaction|report_status:\s*currentStatus' -C4 src/modules/global/reports/product/product-report.service.js

Repository: CrisNAC/BackendMarketplace

Length of output: 661


🏁 Script executed:

#!/bin/bash
# Get complete function context - lines before and after the snippet
sed -n '100,180p' src/modules/global/reports/product/product-report.service.js

Repository: CrisNAC/BackendMarketplace

Length of output: 2729


🏁 Script executed:

#!/bin/bash
# Search for transaction usage around this function
rg -n '\$transaction|prisma\.' src/modules/global/reports/product/product-report.service.js | head -30

Repository: CrisNAC/BackendMarketplace

Length of output: 904


🏁 Script executed:

#!/bin/bash
# Get the exact update block to see all where/data conditions
sed -n '162,180p' src/modules/global/reports/product/product-report.service.js

Repository: CrisNAC/BackendMarketplace

Length of output: 570


🏁 Script executed:

#!/bin/bash
# Get the function name and full context - look for async function declaration
sed -n '90,120p' src/modules/global/reports/product/product-report.service.js

Repository: CrisNAC/BackendMarketplace

Length of output: 1279


🏁 Script executed:

#!/bin/bash
# Search for export/function declaration around line 100
rg -n 'export|async.*resolveReport|function' src/modules/global/reports/product/product-report.service.js | head -20

Repository: CrisNAC/BackendMarketplace

Length of output: 396


🏁 Script executed:

#!/bin/bash
# Get the end of the function and see where it closes
sed -n '162,200p' src/modules/global/reports/product/product-report.service.js

Repository: CrisNAC/BackendMarketplace

Length of output: 1393


🏁 Script executed:

#!/bin/bash
# Check for any prisma.$transaction usage in the file
rg -n '\$transaction' src/modules/global/reports/product/product-report.service.js

Repository: CrisNAC/BackendMarketplace

Length of output: 52


🏁 Script executed:

#!/bin/bash
# Check for schema constraints on productReports related to state transitions
fd schema.prisma -o cat {} | rg -A50 'model ProductReports|model productReports' | head -80

Repository: CrisNAC/BackendMarketplace

Length of output: 195


🏁 Script executed:

#!/bin/bash
# Find the schema.prisma file
fd -name 'schema.prisma' -o cat -n {} \; 2>/dev/null | head -200

Repository: CrisNAC/BackendMarketplace

Length of output: 52


🏁 Script executed:

#!/bin/bash
# Search for ProductReport/productReports model in prisma schema
find . -name 'schema.prisma' -o -name '*.prisma' | xargs grep -A30 'model.*[Pp]roduct[Rr]eports' 2>/dev/null

Repository: CrisNAC/BackendMarketplace

Length of output: 1683


Hacé atómica la transición de estado de los reportes.

El flujo es vulnera­ble a race conditions: dos requests concurrentes pueden leer el reporte en estado IN_PROGRESS, ambas pasar la validación, y luego ambas ejecutar el update. La última escritura gana, violando la regla de "no modificar reportes cerrados".

Línea 162, el update solo filtra por id_product_report. Necesitá agregar la condición report_status: currentStatus en la cláusula where, o envolver todo en una transacción Prisma que incluya el read + validación + update como operación atómica:

where: { 
  id_product_report: resolvedReportId,
  report_status: currentStatus  // o envolver con $transaction
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/global/reports/product/product-report.service.js` around lines
116 - 170, The status transition is vulnerable to race conditions because you
read with prisma.productReports.findFirst and later update with
prisma.productReports.update using only id_product_report; ensure the
read+validation+write is atomic by either wrapping the logic in a Prisma
transaction ($transaction) or by making the update conditional on the current
status (add report_status: currentStatus to the where clause on the update that
uses resolvedReportId), so only the row still in currentStatus is modified
(refer to currentStatus, report_status, resolvedReportId,
prisma.productReports.findFirst and prisma.productReports.update).

Comment thread src/modules/global/reports/product/product-report.service.js Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants