Skip to content

fix(BE-122/123/124/125): vendor delete, license race fix, request DTOs, paginated findAll - #1368

Merged
yusuftomilola merged 26 commits into
DistinctCodes:mainfrom
devzakari-sketch:fix/BE-122-123-124-125-vendors-licenses-dtos-pagination
Aug 26, 2026
Merged

fix(BE-122/123/124/125): vendor delete, license race fix, request DTOs, paginated findAll#1368
yusuftomilola merged 26 commits into
DistinctCodes:mainfrom
devzakari-sketch:fix/BE-122-123-124-125-vendors-licenses-dtos-pagination

Conversation

@devzakari-sketch

Copy link
Copy Markdown
Contributor

Summary

This PR addresses four backend issues (BE-122, BE-123, BE-124, BE-125).


BE-122 - VendorsService missing delete()

  • Added delete(id) to VendorsService with a guard that rejects removal when the vendor is referenced by any non-received PurchaseOrder.
  • Wired DELETE /vendors/:id into VendorsController (returns 204 on success, 400 if open POs exist, 404 if not found).
  • Updated VendorsModule to register the PurchaseOrder repository.

BE-123 - LicensesService.assign() race condition

  • Wrapped the check-and-increment in a TypeORM transaction using pessimistic_write lock on the License row, ensuring two concurrent �ssign() calls against a single remaining seat cannot both succeed.
  • DataSource injected via constructor to support the transactional manager pattern.

BE-124 - Unvalidated �ny bodies in controllers

  • Created CreateBranchDto / UpdateBranchDto for BranchesController.
  • Created CreateVendorDto / UpdateVendorDto for VendorsController.
  • Created CreatePurchaseOrderDto for PurchaseOrdersController.
  • Created CreateTransferDto for TransfersController.
  • All DTOs use class-validator decorators, consistent with the existing CreateLicenseDto pattern.
  • Updated all affected controller routes to use the new typed DTOs.

BE-125 - Unpaginated findAll() in 5 services

  • Updated indAll() in BranchesService, VendorsService, PurchaseOrdersService, TransfersService, and DepartmentsService to accept PaginationQueryDto and return the standard PaginatedResponse envelope (items, otal, page, limit, otalPages).
  • Added search filtering via ILIKE on the primary text column (name for branches/vendors/departments, poNumber for purchase orders).
  • Updated all five corresponding controller GET / routes to forward @query() query: PaginationQueryDto.

closes #1264
closes #1265
closes #1266
closes #1267

@vercel

vercel Bot commented Aug 25, 2026

Copy link
Copy Markdown

@devzakari-sketch is attempting to deploy a commit to the naijabuz's projects Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Aug 25, 2026

Copy link
Copy Markdown

@devzakari-sketch Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

…-pagination

Resolve import/method conflicts against DistinctCodes#1361 (branches delete, PO
cancel, transfers cancel/complete) and DistinctCodes#1363 (JwtAuthGuard on
branches/departments/purchase-orders/transfers/vendors) - all
additive, combined both sides. purchase-orders.service.ts findAll
now paginates AND still eager-loads lineItems (was dropped by the
pagination rewrite otherwise).

Also fixes a compile bug: create-purchase-order.dto.ts imported and
used @isMin(0), which does not exist in class-validator (the correct
decorator is @min, as already used elsewhere in this exact repo's
pagination.dto.ts). Renamed to @min(0).

@yusuftomilola yusuftomilola left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed. Real, valuable fixes:

  • License seat over-allocation race condition (BE-123): assign() previously read seatsUsed/seatsTotal, then wrote, with no lock in between — two concurrent requests could both pass the check and over-allocate seats. Now wrapped in a DB transaction with a pessimistic write lock on the license row. Correct fix for a real concurrency bug.
  • Vendor delete (BE-122) now blocks deletion when the vendor has an open (non-RECEIVED) purchase order, returning a clear 400 with the PO number. Minor note for a follow-up: it treats CANCELLED POs as 'open' too (only excludes RECEIVED), so a vendor with only cancelled POs can't be deleted even though nothing is actually pending — not harmful (fails safe), just overly strict.
  • Real DTOs (BE-124) replacing @Body() dto: any across branches/purchase-orders/transfers/vendors, plus consistent pagination (BE-125) across branches/departments/purchase-orders/transfers/vendors list endpoints.

Found and fixed one compile bug before merging: create-purchase-order.dto.ts imported and used @IsMin(0) from class-validator, which has no such export (the correct decorator is @Min, as already used in this exact repo's own pagination.dto.ts). Renamed to @Min(0).

Also resolved conflicts against #1361 (branch delete, PO cancel, transfer cancel/complete) and #1363 (JwtAuthGuard everywhere) — all additive, kept both sides. Note: purchase-orders.service.ts's paginated findAll now also keeps eager-loading lineItems, which the pagination rewrite would otherwise have silently dropped from the list endpoint.

Approving.

@yusuftomilola
yusuftomilola merged commit 26b4fa9 into DistinctCodes:main Aug 26, 2026
6 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment