-
Notifications
You must be signed in to change notification settings - Fork 0
Schema product ADDRESS, WAREHOUSE, PRODUCT(SPEC,VARINET,IMAGE), INVENTORY, USER DONE #7
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
Conversation
…e-based access control
…ded the spections inteh varint optional
|
Caution Review failedThe pull request is closed. WalkthroughThis update introduces a comprehensive B2B e-commerce platform backend for SaudiMart, including a robust SQL schema, full JPA entity models, repositories, services, and REST controllers for all core business domains: users, products, inventory, orders, contracts, payments, quotes, and credit management. Documentation and configuration files were also extensively expanded and improved. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Gateway
participant ProductService
participant AuthService
participant DB
Client->>Gateway: HTTP Request (e.g. GET /products)
alt Public endpoint (GET/OPTIONS /products or /categories)
Gateway-->>ProductService: Forward request (no auth)
ProductService->>DB: Query products/categories
ProductService-->>Gateway: Response
Gateway-->>Client: Response
else Authenticated endpoint
Gateway->>AuthService: Validate JWT
AuthService-->>Gateway: Auth result
Gateway-->>ProductService: Forward request (with auth)
ProductService->>DB: Query/Update
ProductService-->>Gateway: Response
Gateway-->>Client: Response
end
sequenceDiagram
participant Controller
participant Service
participant Repository
participant DB
Controller->>Service: create/update/get/delete Entity
Service->>Repository: save/find/delete Entity
Repository->>DB: SQL (CRUD)
DB-->>Repository: Result
Repository-->>Service: Entity/Entities
Service-->>Controller: Entity/Entities or Exception
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 62
🔭 Outside diff range comments (1)
MartProduct/src/main/java/com/saudiMart/Product/Controller/ProductsController.java (1)
72-72: Fix incorrect error message for successful updateThe response message says "Product not found" for a successful update operation, which is misleading.
- .body(new ResponseWrapper<>(200, "Product not found", updatedProduct)); + .body(new ResponseWrapper<>(200, "Successfully updated product", updatedProduct));
🧹 Nitpick comments (44)
MartAuth/src/main/java/com/saudiMart/Auth/Security/JwtRequestFilter.java (1)
61-61: Replace System.out.println with proper logging.Using
System.out.printlnfor debug output is not recommended in production code. Consider using a logger instead.- System.out.println("ITS FROM THE AUTH OPENEND POINT HERES THE PATH: " + request.getRequestURI()); + logger.debug("Bypassing JWT authentication for public endpoint: {}", request.getRequestURI());You'll need to add a logger field:
private static final Logger logger = LoggerFactory.getLogger(JwtRequestFilter.class);MartGateway/src/main/resources/application.yml (1)
29-29: Consider organizing the routing configuration for better maintainability.The expanded Path predicate correctly routes all the new endpoints to the product service, but the single long line makes it difficult to maintain and review.
Consider splitting into logical groups or multiple route configurations:
- id: product-service uri: lb://SAUDIMARTPRODUCT predicates: - - Path=/categories/**,/pricetiers/**,/productimages/**,/productspecifications/**,/productvariants/**,/products/**,/addresses/**,/contracts/**,/contractitems/**,/creditapplications/**,/inventory/**,/orderapprovals/**,/orders/**,/orderitems/**,/payments/**,/quotes/**,/quoteitems/**,/warehouses/** + - Path=/categories/**,/pricetiers/**,/productimages/**,/productspecifications/**,/productvariants/**,/products/** + + - id: product-service-business + uri: lb://SAUDIMARTPRODUCT + predicates: + - Path=/addresses/**,/contracts/**,/contractitems/**,/creditapplications/**,/inventory/**,/orderapprovals/**,/orders/**,/orderitems/**,/payments/**,/quotes/**,/quoteitems/**,/warehouses/**MartProduct/src/main/java/com/saudiMart/Product/Repository/UserRepository.java (1)
14-15: Consider using Spring Data auto-generated method instead of explicit JPQL.Spring Data JPA can automatically generate the
findByEmailmethod based on the method name, making the explicit@Queryannotation unnecessary. The current JPQL query is correct but redundant.- @Query("SELECT u FROM Users u WHERE u.email = ?1") Optional<Users> findByEmail(String email);This simplification reduces code and leverages Spring Data's convention-over-configuration approach.
MartProduct/src/main/java/com/saudiMart/Product/Security/GatewayAuthFilter.java (1)
34-34: Remove debug System.out.println statements.These debug print statements should be removed for production code or replaced with proper logging using a logger framework.
- System.out.println("ITS FROM THE PRODUCT OPENED ENDPOINT, HERE'S THE PATH: " + path); + // Public endpoint accessed- System.out.println("Hello! I am Pinged here"); + // Authenticated endpoint processingAlso applies to: 39-39
DatabasePath.md (2)
12-12: Fix grammar: Add missing article.Add the missing article "a" for better readability.
-4. `product_variants` - If product has variants (size, color, etc.) +4. `product_variants` - If a product has variants (size, color, etc.)
17-24: Add language specifications to code blocks.According to markdownlint, fenced code blocks should specify a language for proper syntax highlighting and accessibility.
-``` +```textApply this pattern to all code blocks in the file (lines 17, 102, 107, 112).
Also applies to: 102-104, 107-109, 112-114
MartProduct/src/main/java/com/saudiMart/Product/Service/UserService.java (2)
16-17: Consider using constructor injection instead of field injection.Constructor injection is preferred over field injection for better testability and immutability.
- @Autowired - private UserRepository userRepository; + private final UserRepository userRepository; + + public UserService(UserRepository userRepository) { + this.userRepository = userRepository; + }
19-21: Add @transactional annotation for consistency.For consistency with other read operations and to ensure proper transaction boundaries, consider adding
@Transactional(readOnly = true)to this method as well.+ @Transactional(readOnly = true) public List<Users> getAllUsers() { return userRepository.findAll(); }MartProduct/src/main/java/com/saudiMart/Product/Model/CreditApplication.java (1)
41-46: Add validation constraints for credit amounts.Consider adding validation to ensure credit amounts are positive and within reasonable bounds.
+ @DecimalMin(value = "0.01", message = "Requested limit must be positive") + @DecimalMax(value = "9999999999.99", message = "Requested limit exceeds maximum allowed") @NotNull @Column(name = "requested_limit", nullable = false, precision = 12, scale = 2) private BigDecimal requestedLimit; + @DecimalMin(value = "0.01", message = "Approved limit must be positive") + @DecimalMax(value = "9999999999.99", message = "Approved limit exceeds maximum allowed") @Column(name = "approved_limit", precision = 12, scale = 2) private BigDecimal approvedLimit;Don't forget to import the validation annotations:
+import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin;MartProduct/src/main/java/com/saudiMart/Product/Repository/OrderRepository.java (2)
21-21: Fix parameter naming inconsistency.The parameter naming is inconsistent:
BuyerUser(PascalCase) vssellerUser(camelCase). Follow Java naming conventions consistently.- List<Order> findByBuyerAndSeller(Users BuyerUser, Users sellerUser); + List<Order> findByBuyerAndSeller(Users buyerUser, Users sellerUser);
23-24: Consider using Spring Data JPA method derivation instead of custom JPQL.The custom JPQL query can be replaced with Spring Data's built-in method derivation for better maintainability.
- @Query("SELECT o FROM Order o WHERE o.createdAt BETWEEN :startDate AND :endDate") - List<Order> findByCreatedAtBetween(LocalDateTime startDate, LocalDateTime endDate); + List<Order> findByCreatedAtBetween(LocalDateTime startDate, LocalDateTime endDate);MartProduct/src/main/java/com/saudiMart/Product/Repository/QuoteItemRepository.java (1)
11-24: Repository design looks good with minor optimization suggestion.The repository follows Spring Data JPA conventions correctly and provides comprehensive query methods for QuoteItem retrieval. The dual approach of entity-based and ID-based queries offers flexibility for different use cases.
Consider adding
@Queryannotations for complex queries if performance becomes a concern, especially for the entity-based methods that might trigger additional lazy loading:+import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface QuoteItemRepository extends JpaRepository<QuoteItem, String> { + @Query("SELECT qi FROM QuoteItem qi WHERE qi.quote.id = :quoteId") + List<QuoteItem> findByQuoteIdOptimized(@Param("quoteId") String quoteId);MartProduct/src/main/java/com/saudiMart/Product/Service/OrderItemService.java (1)
15-86: Well-structured service with room for improvement.The service follows good patterns with proper error handling and null checks. The CRUD operations are comprehensive and the exception handling is consistent.
Consider these improvements:
- Add transaction management:
+import org.springframework.transaction.annotation.Transactional; @Service +@Transactional public class OrderItemService {
- Simplify the verbose update method using mapping:
+import org.springframework.beans.BeanUtils; public OrderItem updateOrderItem(String id, OrderItem orderItemDetails) throws ProductException { if (orderItemDetails == null) { throw new ProductException("Order item details cannot be null for update"); } OrderItem orderItem = orderItemRepository.findById(id) - .orElseThrow(() -> new ProductException("Order item not found with id: " + id)); - // Replace the verbose field updates with: - BeanUtils.copyProperties(orderItemDetails, orderItem, "id", "createdAt"); + BeanUtils.copyProperties(orderItemDetails, orderItem, + getNullPropertyNames(orderItemDetails)); return orderItemRepository.save(orderItem); }
- Add method-level transaction annotations for specific operations:
+@Transactional public OrderItem createOrderItem(OrderItem orderItem) throws ProductException { +@Transactional public OrderItem updateOrderItem(String id, OrderItem orderItemDetails) throws ProductException { +@Transactional public void deleteOrderItem(String id) throws ProductException {MartProduct/src/main/java/com/saudiMart/Product/Model/QuoteItem.java (1)
19-62: Well-designed entity with proper JPA mapping and validation.The entity demonstrates good practices with:
- Proper use of
BigDecimalfor monetary fields with precision/scale- Appropriate validation constraints
- Lazy loading for performance optimization
- Correct nullable configurations
Consider these enhancements:
- Add cascade configuration for better relationship management:
@NotNull -@ManyToOne(fetch = FetchType.LAZY) +@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH) @JoinColumn(name = "quote_id", nullable = false) private Quote quote;
- Add business logic validation for discount calculations:
+@PostLoad +@PrePersist +@PreUpdate +private void calculateTotalPrice() { + if (quotedPrice != null && quantity != null && discountPercent != null) { + BigDecimal itemTotal = quotedPrice.multiply(BigDecimal.valueOf(quantity)); + BigDecimal discountAmount = itemTotal.multiply(discountPercent.divide(BigDecimal.valueOf(100))); + this.totalPrice = itemTotal.subtract(discountAmount); + } +}
- Add audit trail support:
+import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +@EntityListeners(AuditingEntityListener.class) @Entity @Table(name = "quote_items") @Data public class QuoteItem { + + @CreatedDate + @Column(name = "created_at", updatable = false) + private LocalDateTime createdAt; + + @LastModifiedDate + @Column(name = "updated_at") + private LocalDateTime updatedAt;MartProduct/src/main/java/com/saudiMart/Product/Model/Warehouse.java (1)
40-43: Consider using LAZY fetch for address to improve performance.The
EAGERfetch strategy for the address relationship may cause unnecessary database queries when address details aren't needed. Unless address information is frequently accessed alongside warehouse data, consider usingLAZYfetching.- @ManyToOne(fetch = FetchType.EAGER) + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "address_id", nullable = false) private Address address;MartProduct/src/main/java/com/saudiMart/Product/Model/ContractItem.java (2)
27-39: Add fetch strategies to relationship mappings for better performance.The relationships are missing explicit fetch strategies, defaulting to
EAGERwhich may cause performance issues with unnecessary joins.@NotNull - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "contract_id", nullable = false) private Contract contract; @NotNull - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "product_id", nullable = false) private Products product; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "variant_id") private ProductVariant variant;
18-25: Consider adding lifecycle callbacks for audit trail consistency.Unlike other entities in the codebase, this entity lacks creation and update timestamp tracking. Consider adding audit fields for consistency.
+import java.time.LocalDateTime; +import jakarta.persistence.PrePersist; +import jakarta.persistence.PreUpdate; + @Column(name = "created_at", updatable = false) + private LocalDateTime createdAt; + + @Column(name = "updated_at") + private LocalDateTime updatedAt; + + @PrePersist + protected void onCreate() { + createdAt = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + updatedAt = LocalDateTime.now(); + }MartProduct/src/main/java/com/saudiMart/Product/Service/OrderApprovalService.java (1)
65-75: Consider adding validation to query methods.The query methods don't validate their parameters, which could lead to unexpected behavior.
public List<OrderApproval> getOrderApprovalsByOrder(Order order) { + if (order == null) { + throw new ProductException("Order cannot be null"); + } return orderApprovalRepository.findByOrder(order); } public List<OrderApproval> getOrderApprovalsByApprover(Users approver) { + if (approver == null) { + throw new ProductException("Approver cannot be null"); + } return orderApprovalRepository.findByApprover(approver); } public List<OrderApproval> getOrderApprovalsByStatus(OrderApprovalStatus status) { + if (status == null) { + throw new ProductException("Status cannot be null"); + } return orderApprovalRepository.findByStatus(status); }MartProduct/src/main/java/com/saudiMart/Product/Model/Contract.java (1)
47-49: Consider automatic contract number generation.The contract number field is marked as unique but there's no generation strategy. Consider implementing automatic generation to ensure uniqueness and consistency.
You might want to add a service method or entity lifecycle callback to generate contract numbers automatically:
@PrePersist protected void generateContractNumber() { if (contractNumber == null || contractNumber.isEmpty()) { // Generate unique contract number based on your business rules contractNumber = "CT-" + LocalDate.now().getYear() + "-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase(); } }MartProduct/src/main/java/com/saudiMart/Product/Model/ProductImage.java (1)
55-58: Consider using LocalDateTime for consistency.The entity uses
Timestampwhile other entities in the codebase useLocalDateTime. Consider standardizing for consistency.-import java.sql.Timestamp; +import java.time.LocalDateTime; -@Column(name = "created_at") -private Timestamp createdAt; +@Column(name = "created_at") +private LocalDateTime createdAt; @PrePersist protected void onCreate() { - createdAt = new Timestamp(System.currentTimeMillis()); + createdAt = LocalDateTime.now(); }MartProduct/src/main/java/com/saudiMart/Product/Model/Inventory.java (2)
38-48: Consider using LAZY fetching for better performance.All three relationships use
FetchType.EAGER, which could lead to performance issues and unnecessary data loading. Consider usingFetchType.LAZYas the default and explicitly fetch related entities when needed.- @ManyToOne(fetch = FetchType.EAGER) + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "product_id", nullable = false) private Products product; - @ManyToOne(fetch = FetchType.EAGER) + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "variant_id") private ProductVariant variant; - @ManyToOne(fetch = FetchType.EAGER) + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "warehouse_id", nullable = false) private Warehouse warehouse;
58-72: Use consistent timestamp types across entities.This entity uses
Timestampwhile other entities in the codebase useLocalDateTime(e.g.,Products.javalines 66-67,Warehouse.javalines 49-50). Consider usingLocalDateTimefor consistency.- @Column(name = "created_at", updatable = false) - private Timestamp createdAt; - - @Column(name = "updated_at") - private Timestamp updatedAt; + @Column(name = "created_at", updatable = false) + private LocalDateTime createdAt; + + @Column(name = "updated_at") + private LocalDateTime updatedAt; @PrePersist protected void onCreate() { - createdAt = new Timestamp(System.currentTimeMillis()); + createdAt = LocalDateTime.now(); } @PreUpdate protected void onUpdate() { - updatedAt = new Timestamp(System.currentTimeMillis()); + updatedAt = LocalDateTime.now(); }Don't forget to add the import:
+import java.time.LocalDateTime; -import java.sql.Timestamp;MartProduct/src/main/java/com/saudiMart/Product/Model/Quote.java (1)
81-83: Implement quote number generation or remove misleading comment.The comment suggests generating quoteNumber in @PrePersist, but no implementation is provided. This could lead to quotes without proper numbering.
Consider implementing automatic quote number generation:
@PrePersist protected void onCreate() { createdAt = LocalDateTime.now(); - // Consider generating quoteNumber here if not handled by the database default - // e.g., if using a different database or need application-level generation + if (quoteNumber == null || quoteNumber.isEmpty()) { + quoteNumber = generateQuoteNumber(); + } +} + +private String generateQuoteNumber() { + // Implement your quote numbering logic here + // e.g., "Q" + timestamp + random suffix + return "Q" + System.currentTimeMillis(); }Would you like me to help implement a more sophisticated quote numbering strategy?
MartProduct/src/main/java/com/saudiMart/Product/Model/OrderItem.java (1)
66-69: Reconsider total price validation constraint.The @DecimalMin(value = "0.01") constraint prevents totalPrice from being exactly zero, but legitimate business scenarios (promotional items, full discounts) might result in zero totals.
Consider using @PositiveOrZero instead:
@NotNull -@DecimalMin(value = "0.01", message = "Total price must be positive") +@PositiveOrZero(message = "Total price cannot be negative") @Column(name = "total_price", nullable = false, precision = 12, scale = 2) private BigDecimal totalPrice;Add the import:
+import jakarta.validation.constraints.PositiveOrZero;MartProduct/src/main/java/com/saudiMart/Product/Model/Address.java (1)
23-98: Consider adding business logic for default address management.Having multiple default addresses for the same user and address type could cause business logic issues. Consider adding validation or lifecycle callbacks to ensure only one default address per user per type.
Consider implementing business logic to handle default address constraints:
+@PrePersist +@PreUpdate +private void validateDefaultAddress() { + // Business logic to ensure only one default address per user per type + // This could be handled at the service layer or with database constraints +}Alternatively, handle this logic in the AddressService to ensure data consistency when setting default addresses.
MartProduct/src/main/java/com/saudiMart/Product/Service/QuoteItemService.java (1)
68-77: Remove or implement commented code.The commented code for updating relationships should either be implemented properly or removed to maintain code cleanliness.
MartProduct/src/main/java/com/saudiMart/Product/Service/ContractService.java (1)
33-34: Consider adding business validation logic.The comment suggests adding business logic validation, which would be beneficial for contract creation. Consider validating fields like date ranges, credit limits, and contract terms.
Example validation to add:
public Contract createContract(Contract contract) throws ProductException { if (contract == null) { throw new ProductException("Contract cannot be null"); } + // Validate date ranges + if (contract.getStartDate() != null && contract.getEndDate() != null && + contract.getStartDate().after(contract.getEndDate())) { + throw new ProductException("Start date cannot be after end date"); + } + // Validate credit limit + if (contract.getCreditLimit() != null && contract.getCreditLimit().compareTo(BigDecimal.ZERO) < 0) { + throw new ProductException("Credit limit cannot be negative"); + } return contractRepository.save(contract); }MartProduct/src/main/java/com/saudiMart/Product/Model/Category.java (1)
33-36: Consider making imageUrl optional for flexibility.The mandatory
imageUrlfield might be restrictive during category creation. Consider making it optional initially and requiring it only when the category becomes active.@Size(max = 255, message = "Image URL cannot exceed 255 characters") @Column(name = "image_url") -@NotBlank(message = "Image URL is mandatory") private String imageUrl;Alternatively, add validation in the service layer to require imageUrl only for active categories.
MartProduct/src/main/java/com/saudiMart/Product/Service/CreditApplicationService.java (2)
35-35: TODO: Implement the mentioned validation or business logicThe comment indicates that validation or business logic should be added before saving, but none is implemented. Consider adding validation for credit limits, buyer/seller relationships, or other business rules.
Would you like me to help implement validation logic for credit applications, such as:
- Validating requested credit limit ranges
- Checking buyer eligibility
- Ensuring buyer and seller are different entities
63-63: Consider using JPA lifecycle callbacks for timestamp managementInstead of manually setting
updatedAt, consider using JPA's@PreUpdatelifecycle callback in your entity class for automatic timestamp management.In your
CreditApplicationentity, add:@PreUpdate protected void onUpdate() { this.updatedAt = LocalDateTime.now(); }Then remove the manual timestamp update from the service.
MartProduct/src/main/java/com/saudiMart/Product/Service/CategoryService.java (1)
23-33: Consider simplifying the conditional logicWhile the logic is correct, the nested if-else structure could be simplified for better readability.
Consider using a more streamlined approach:
public List<Category> getAllActiveCategoriesByName(String name, Boolean isActive) { if (name == null && isActive == null) { return categoryRepository.findAll(); } if (name != null && isActive != null) { return categoryRepository.findByNameContainingIgnoreCaseAndIsActive(name, isActive); } return (name != null) ? categoryRepository.findByNameContainingIgnoreCase(name) : categoryRepository.findByIsActive(isActive); }MartProduct/src/main/java/com/saudiMart/Product/Controller/AddressController.java (1)
46-58: Consider using a global exception handler to reduce boilerplate code.The repetitive try-catch blocks in every method create unnecessary verbosity. A
@ControllerAdvicewith@ExceptionHandlermethods would centralize error handling and improve maintainability.Create a global exception handler:
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(ProductException.class) public ResponseEntity<ResponseWrapper<Void>> handleProductException(ProductException e) { return ResponseEntity.status(HttpStatus.NOT_FOUND) .body(new ResponseWrapper<>(HttpStatus.NOT_FOUND.value(), e.getMessage(), null)); } @ExceptionHandler(Exception.class) public ResponseEntity<ResponseWrapper<Void>> handleGenericException(Exception e) { // Log the exception details for debugging return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(new ResponseWrapper<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), "An error occurred: " + e.getMessage(), null)); } }Also applies to: 76-90, 92-105
MartProduct/src/main/java/com/saudiMart/Product/Model/Products.java (1)
52-52: Review the description field size constraint.The
@Size(max = 1000)constraint for description seems quite small for product descriptions in a B2B context. Consider if this limit is appropriate for your use case.Consider increasing the size limit or removing it entirely since the column is already defined as TEXT:
-@Size(max = 1000) +@Size(max = 5000)MartProduct/src/main/java/com/saudiMart/Product/Controller/WarehouseController.java (1)
33-37: Use consistent constructor injection pattern.The constructor correctly uses dependency injection, but there's a spacing inconsistency in the assignment.
Apply consistent formatting:
public WarehouseController(WarehouseService warehouseService, UserService userService) { this.warehouseService = warehouseService; - this.userService=userService; + this.userService = userService; }MartProduct/src/main/java/com/saudiMart/Product/Controller/QuoteController.java (1)
31-36: Fix inconsistent indentation.The indentation for the
userServicefield and constructor assignment is inconsistent.Apply consistent formatting:
-private final UserService userService; + private final UserService userService; @Autowired public QuoteController(QuoteService quoteService, UserService userService) { this.quoteService = quoteService; -this.userService = userService; + this.userService = userService; }MartProduct/src/main/java/com/saudiMart/Product/Controller/ContractItemController.java (2)
29-30: Consider using constructor injection instead of field injection.Constructor injection is preferred as it makes dependencies explicit, enables immutability, and facilitates testing.
Apply this diff to use constructor injection:
- @Autowired - private ContractItemService contractItemService; + private final ContractItemService contractItemService; + + public ContractItemController(ContractItemService contractItemService) { + this.contractItemService = contractItemService; + }
32-37: Remove unnecessary ProductException from method signature.The
getAllContractItems()service method doesn't appear to throwProductException, making this declaration unnecessary.- public ResponseEntity<ResponseWrapper<List<ContractItem>>> getAllContractItems() throws ProductException { + public ResponseEntity<ResponseWrapper<List<ContractItem>>> getAllContractItems() {MartProduct/src/main/java/com/saudiMart/Product/Controller/OrderItemController.java (1)
28-29: Use constructor injection for better testability.Field injection should be replaced with constructor injection.
- @Autowired - private OrderItemService orderItemService; + private final OrderItemService orderItemService; + + public OrderItemController(OrderItemService orderItemService) { + this.orderItemService = orderItemService; + }MartProduct/src/main/java/com/saudiMart/Product/Controller/CreditApplicationController.java (1)
137-143: Consider adding exception handling for invalid enum values.While Spring handles enum conversion, invalid status values will result in a generic 400 error. Consider adding exception handling for better error messages.
@GetMapping("/status/{status}") public ResponseEntity<ResponseWrapper<List<CreditApplication>>> getCreditApplicationsByStatus( @PathVariable CreditApplicationStatus status) { - List<CreditApplication> creditApplications = creditApplicationService.getCreditApplicationsByStatus(status); - return ResponseEntity.ok( - new ResponseWrapper<>(200, "Successfully retrieved credit applications by status", creditApplications)); + try { + List<CreditApplication> creditApplications = creditApplicationService.getCreditApplicationsByStatus(status); + return ResponseEntity.ok( + new ResponseWrapper<>(200, "Successfully retrieved credit applications by status", creditApplications)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ResponseWrapper<>(400, "Invalid status value", null)); + }MartProduct/src/main/java/com/saudiMart/Product/Controller/CategoryController.java (1)
33-45: Consider reversing the endpoint paths for better REST conventions.Having the filtered endpoint at the root path and the unfiltered at
/allis unconventional. Consider keeping the unfiltered endpoint at the root path and using query parameters for filtering on the same endpoint.You could combine both endpoints into one:
- @GetMapping("/all") - public ResponseEntity<ResponseWrapper<List<Category>>> getAllCategories() throws ProductException { - List<Category> categories = categoryService.getAllCategories(); - return ResponseEntity.ok(new ResponseWrapper<>(200, "All categories fetched successfully", categories)); - } - - @GetMapping - public ResponseEntity<ResponseWrapper<List<Category>>> getAllActiveCategoriesByName( - @RequestParam(required = false) String name, - @RequestParam(required = false) Boolean isActive) throws ProductException { - List<Category> categories = categoryService.getAllActiveCategoriesByName(name, isActive); + @GetMapping + public ResponseEntity<ResponseWrapper<List<Category>>> getCategories( + @RequestParam(required = false) String name, + @RequestParam(required = false) Boolean isActive) throws ProductException { + List<Category> categories; + if (name == null && isActive == null) { + categories = categoryService.getAllCategories(); + } else { + categories = categoryService.getAllActiveCategoriesByName(name, isActive); + } return ResponseEntity.ok(new ResponseWrapper<>(200, "Category fetched successfully", categories)); }MartProduct/src/main/java/com/saudiMart/Product/Service/ProductVariantService.java (1)
68-76: Consider optimizing the double save operation.The variant is saved twice - once to get an ID and again after setting images. Consider using cascade operations to save images automatically.
If the
ProductVariantentity has proper cascade settings on theimagesrelationship, you could eliminate the double save:- // Save the product variant first to get an ID - ProductVariant savedVariant = productVariantRepository.save(productVariant); - // Handle Product Images if (productVariant.getImages() != null) { - productVariant.getImages().forEach(image -> image.setVariant(savedVariant)); + productVariant.getImages().forEach(image -> image.setVariant(productVariant)); } - return productVariantRepository.save(savedVariant); + return productVariantRepository.save(productVariant);DB_schema.sql (1)
51-51: Consider using consistent primary key naming.The
warehousestable useswarehouse_idas the primary key name, while all other tables useid. Consider renaming toidfor consistency.- warehouse_id VARCHAR(36) PRIMARY KEY, + id VARCHAR(36) PRIMARY KEY,Note: This change would require updating all foreign key references from
warehouse_idtoid.MartProduct/src/main/java/com/saudiMart/Product/Service/ProductsService.java (1)
47-47: Remove or implement the commented code.Either remove this comment or implement image loading if it's needed.
- // product.setImages(productImageRepository.findByProduct(product));fixedDBSchema.md (1)
25-370: Excellent constraint design for data integrity.This schema includes comprehensive CHECK constraints that enforce business rules at the database level, including:
- Email format validation
- Prevention of self-trading
- Positive amount validations
- Date logic validations
- Percentage range validations
Consider adopting these constraints in the main schema.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (90)
DB_schema.sql(1 hunks)DatabaseDesign.md(10 hunks)DatabasePath.md(1 hunks)MartAuth/src/main/java/com/saudiMart/Auth/Security/JwtRequestFilter.java(1 hunks)MartAuth/src/main/java/com/saudiMart/Auth/Security/SecurityConfig.java(0 hunks)MartGateway/src/main/java/com/saudimart/Gateway/Security/SecurityConfig.java(1 hunks)MartGateway/src/main/java/com/saudimart/Gateway/Security/filter/JwtAuthenticationFilter.java(3 hunks)MartGateway/src/main/java/com/saudimart/Gateway/config/GatewayConfig.java(1 hunks)MartGateway/src/main/java/com/saudimart/Gateway/config/GatewayErrorWebExceptionHandler.java(1 hunks)MartGateway/src/main/resources/application.yml(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/AddressController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/CategoryController.java(3 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/ContractController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/ContractItemController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/CreditApplicationController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/InventoryController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/OrderApprovalController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/OrderController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/OrderItemController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/PaymentController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/PriceTierController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/ProductImageController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/ProductSpecificationController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/ProductVariantController.java(3 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/ProductsController.java(3 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/QuoteController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/QuoteItemController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Controller/WarehouseController.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/Address.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/Category.java(2 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/Contract.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/ContractItem.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/CreditApplication.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/Inventory.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/Order.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/OrderApproval.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/OrderItem.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/Payment.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/PriceTier.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/ProductImage.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/ProductSpecification.java(2 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/ProductVariant.java(2 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/Products.java(4 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/Quote.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/QuoteItem.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/Users.java(3 hunks)MartProduct/src/main/java/com/saudiMart/Product/Model/Warehouse.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/AddressRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/CategoryRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/ContractItemRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/ContractRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/CreditApplicationRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/InventoryRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/OrderApprovalRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/OrderItemRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/OrderRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/PaymentRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/PriceTierRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/ProductImageRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/ProductSpecificationRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/ProductVariantRepository.java(2 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/ProductsRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/QuoteItemRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/QuoteRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/UserRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Repository/WarehouseRepository.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Security/GatewayAuthFilter.java(3 hunks)MartProduct/src/main/java/com/saudiMart/Product/Security/SecurityConfig.java(2 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/AddressService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/CategoryService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/ContractItemService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/ContractService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/CreditApplicationService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/InventoryService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/OrderApprovalService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/OrderItemService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/OrderService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/PaymentService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/PriceTierService.java(2 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/ProductImageService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/ProductSpecificationService.java(2 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/ProductVariantService.java(2 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/ProductsService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/QuoteItemService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/QuoteService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/UserService.java(1 hunks)MartProduct/src/main/java/com/saudiMart/Product/Service/WarehouseService.java(1 hunks)MartProduct/src/main/resources/application.yaml(1 hunks)README.md(1 hunks)fixedDBSchema.md(1 hunks)
💤 Files with no reviewable changes (1)
- MartAuth/src/main/java/com/saudiMart/Auth/Security/SecurityConfig.java
🧰 Additional context used
🧬 Code Graph Analysis (14)
MartGateway/src/main/java/com/saudimart/Gateway/Security/SecurityConfig.java (2)
MartAuth/src/main/java/com/saudiMart/Auth/Security/SecurityConfig.java (1)
Configuration(20-59)MartProduct/src/main/java/com/saudiMart/Product/Security/SecurityConfig.java (1)
Configuration(25-72)
MartProduct/src/main/java/com/saudiMart/Product/Service/WarehouseService.java (1)
MartProduct/src/main/java/com/saudiMart/Product/Utils/ProductException.java (1)
ProductException(5-36)
MartProduct/src/main/java/com/saudiMart/Product/Model/ContractItem.java (4)
MartProduct/src/main/java/com/saudiMart/Product/Model/ProductVariant.java (1)
Entity(27-74)MartProduct/src/main/java/com/saudiMart/Product/Model/Products.java (1)
Entity(27-104)MartProduct/src/main/java/com/saudiMart/Product/Model/Contract.java (1)
Entity(25-92)MartProduct/src/main/java/com/saudiMart/Product/Model/Users.java (1)
Data(23-104)
MartProduct/src/main/java/com/saudiMart/Product/Controller/PaymentController.java (2)
MartProduct/src/main/java/com/saudiMart/Product/Service/PaymentService.java (1)
Service(14-84)MartProduct/src/main/java/com/saudiMart/Product/Utils/ProductException.java (1)
ProductException(5-36)
MartProduct/src/main/java/com/saudiMart/Product/Service/AddressService.java (2)
MartProduct/src/main/java/com/saudiMart/Product/Service/WarehouseService.java (1)
Service(14-68)MartProduct/src/main/java/com/saudiMart/Product/Utils/ProductException.java (1)
ProductException(5-36)
MartProduct/src/main/java/com/saudiMart/Product/Controller/InventoryController.java (4)
MartProduct/src/main/java/com/saudiMart/Product/Service/ProductsService.java (1)
Service(23-203)MartProduct/src/main/java/com/saudiMart/Product/Service/WarehouseService.java (1)
Service(14-68)MartProduct/src/main/java/com/saudiMart/Product/Service/InventoryService.java (1)
Service(16-82)MartProduct/src/main/java/com/saudiMart/Product/Utils/ProductException.java (1)
ProductException(5-36)
MartProduct/src/main/java/com/saudiMart/Product/Service/ContractService.java (1)
MartProduct/src/main/java/com/saudiMart/Product/Utils/ProductException.java (1)
ProductException(5-36)
MartProduct/src/main/java/com/saudiMart/Product/Service/QuoteService.java (1)
MartProduct/src/main/java/com/saudiMart/Product/Utils/ProductException.java (1)
ProductException(5-36)
MartProduct/src/main/java/com/saudiMart/Product/Model/Inventory.java (4)
MartProduct/src/main/java/com/saudiMart/Product/Model/ProductVariant.java (1)
Entity(27-74)MartProduct/src/main/java/com/saudiMart/Product/Model/Products.java (1)
Entity(27-104)MartProduct/src/main/java/com/saudiMart/Product/Model/Warehouse.java (1)
Entity(20-63)MartProduct/src/main/java/com/saudiMart/Product/Model/Users.java (1)
Data(23-104)
MartProduct/src/main/java/com/saudiMart/Product/Model/Quote.java (3)
MartProduct/src/main/java/com/saudiMart/Product/Model/Products.java (1)
Entity(27-104)MartProduct/src/main/java/com/saudiMart/Product/Model/QuoteItem.java (1)
Entity(19-62)MartProduct/src/main/java/com/saudiMart/Product/Model/Users.java (1)
Data(23-104)
MartProduct/src/main/java/com/saudiMart/Product/Model/Contract.java (1)
MartProduct/src/main/java/com/saudiMart/Product/Model/ContractItem.java (1)
Entity(18-61)
MartProduct/src/main/java/com/saudiMart/Product/Controller/OrderItemController.java (2)
MartProduct/src/main/java/com/saudiMart/Product/Service/OrderItemService.java (1)
Service(15-86)MartProduct/src/main/java/com/saudiMart/Product/Utils/ProductException.java (1)
ProductException(5-36)
MartProduct/src/main/java/com/saudiMart/Product/Service/ProductsService.java (4)
MartProduct/src/main/java/com/saudiMart/Product/Service/ProductVariantService.java (1)
Service(19-189)MartProduct/src/main/java/com/saudiMart/Product/Service/CategoryService.java (1)
Service(13-87)MartProduct/src/main/java/com/saudiMart/Product/Service/ProductSpecificationService.java (1)
Service(15-83)MartProduct/src/main/java/com/saudiMart/Product/Utils/ProductException.java (1)
ProductException(5-36)
MartProduct/src/main/java/com/saudiMart/Product/Controller/WarehouseController.java (2)
MartProduct/src/main/java/com/saudiMart/Product/Service/WarehouseService.java (1)
Service(14-68)MartProduct/src/main/java/com/saudiMart/Product/Utils/ProductException.java (1)
ProductException(5-36)
🪛 LanguageTool
DatabasePath.md
[uncategorized] ~12-~12: You might be missing the article “a” here.
Context: ...f needed):** 4. product_variants - If product has variants (size, color, etc.) 5. `pr...
(AI_EN_LECTOR_MISSING_DETERMINER_A)
README.md
[uncategorized] ~12-~12: A punctuation mark might be missing here.
Context: ...--------------------------------------- | | User Authentication | Login/Signu...
(AI_EN_LECTOR_MISSING_PUNCTUATION)
DatabaseDesign.md
[misspelling] ~20-~20: This word is normally spelled as one.
Context: ...ured B2B e-commerce platform with: - Multi-role user management (Buyers, Sellers, Adm...
(EN_COMPOUNDS_MULTI_ROLE)
[style] ~468-~468: Consider using a less common alternative to make your writing sound more unique and professional.
Context: ... LIMIT 1; ``` --- ## 🤝 Contributing Feel free to submit issues and enhancement requests!...
(FEEL_FREE_TO_STYLE_ME)
🪛 markdownlint-cli2 (0.17.2)
DatabasePath.md
17-17: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
102-102: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
107-107: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
112-112: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
🔇 Additional comments (86)
MartAuth/src/main/java/com/saudiMart/Auth/Security/JwtRequestFilter.java (1)
60-60: The regex pattern correctly implements the bypass logic.The updated regex pattern
^/(authen|actuator)(/.*)?$properly matches URIs starting with/authenor/actuator, which aligns with the security configuration changes mentioned in the summary.MartProduct/src/main/java/com/saudiMart/Product/Repository/AddressRepository.java (1)
10-12: Clean repository implementation following Spring Data JPA conventions.The repository interface is well-structured with a clear custom finder method that follows Spring Data naming conventions. The method signature will automatically generate the appropriate query to find addresses by user.
MartProduct/src/main/resources/application.yaml (4)
9-11: Database configuration defaults are appropriate for development.The default database configuration provides reasonable values for local development while allowing production environments to override via environment variables.
17-20: Redis configuration follows the same pattern as database config.Consistent approach with environment variables and development-friendly defaults.
23-25: JWT configuration provides sensible defaults.The JWT secret default is adequate for development, and token expiration times (1 day for access, 7 days for refresh) are reasonable. Ensure the JWT secret is properly configured in production environments.
30-30: Eureka configuration completes the service discovery setup.The default Eureka server URL aligns with standard local development setups.
MartProduct/src/main/java/com/saudiMart/Product/Repository/WarehouseRepository.java (1)
10-12: Consistent repository pattern with appropriate business logic.The WarehouseRepository follows the same clean pattern as AddressRepository, with a custom finder method that makes business sense for a marketplace where sellers manage multiple warehouses.
MartProduct/src/main/java/com/saudiMart/Product/Repository/PaymentRepository.java (1)
12-18: Well-structured repository with appropriate finder methods.The repository correctly follows Spring Data JPA conventions with clear method names that will be auto-implemented. The use of domain objects (
Order) and enums (PaymentStatus) as parameters is a good practice for type safety and maintainability.MartGateway/src/main/java/com/saudimart/Gateway/config/GatewayConfig.java (1)
10-13: Configuration Verified: GatewayErrorWebExceptionHandler is Properly ImplementedThe
GatewayErrorWebExceptionHandlerclass exists undercom.saudimart.Gateway.config, implementsErrorWebExceptionHandler, and overrides
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex)to map authentication failures to 401 and other errors to 500, writing a JSON response. The bean declared inGatewayConfigis correctly defined.Optional suggestion:
- For more robust JSON handling, consider using Jackson’s
ObjectMapperinstead of the customtoJsonmethod.MartGateway/src/main/java/com/saudimart/Gateway/Security/filter/JwtAuthenticationFilter.java (1)
37-38: Good refactoring to extract path and method variables.Extracting the path and method into local variables improves code readability and reusability. This is a clean improvement to the filter logic.
MartProduct/src/main/java/com/saudiMart/Product/Repository/QuoteRepository.java (1)
1-16: LGTM! Well-structured repository interface.The repository follows Spring Data JPA conventions correctly with appropriate query methods for finding quotes by status, seller, and buyer. The String ID type aligns with the UUID migration strategy.
MartProduct/src/main/java/com/saudiMart/Product/Repository/ProductVariantRepository.java (2)
13-13: LGTM! ID type migration properly implemented.The change from
LongtoStringID type is consistent with the UUID migration strategy mentioned in the PR objectives.
23-23: LGTM! Useful cascade deletion method added.The
deleteByProductmethod enables proper cleanup of product variants when a product is deleted, supporting referential integrity.MartProduct/src/main/java/com/saudiMart/Product/Repository/ProductsRepository.java (2)
14-14: LGTM! ID type migration properly implemented.The change from
LongtoStringID type is consistent with the UUID migration strategy.
16-17: LGTM! Parameter type correctly updated.The
findBySellerIdmethod parameter type change fromLongtoStringproperly aligns with the seller ID being a UUID string.MartProduct/src/main/java/com/saudiMart/Product/Repository/ProductSpecificationRepository.java (2)
12-12: LGTM! ID type migration properly implemented.The change from
LongtoStringID type is consistent with the UUID migration strategy.
20-20: LGTM! Useful cascade deletion method added.The
deleteByProductmethod enables proper cleanup of product specifications when a product is deleted, maintaining referential integrity.MartProduct/src/main/java/com/saudiMart/Product/Security/SecurityConfig.java (1)
36-37: Verify that public access to product endpoints is intentional.The configuration now allows unauthenticated GET and OPTIONS requests to
/products/**and/categories/**endpoints. This enables public browsing of products and categories, which is typical for e-commerce platforms.Please confirm this is the intended behavior and that no sensitive product information (like internal pricing, seller details, etc.) is exposed through these endpoints.
MartProduct/src/main/java/com/saudiMart/Product/Repository/ContractItemRepository.java (1)
1-21: Well-implemented repository interface following Spring Data JPA conventions.The repository correctly extends
JpaRepositorywith String ID type and declares appropriate query methods that follow Spring Data JPA naming conventions for automatic query derivation. The imports are clean and the structure is consistent with the domain model.MartProduct/src/main/java/com/saudiMart/Product/Repository/ContractRepository.java (1)
1-19: Repository implementation follows best practices.The repository interface is well-structured with appropriate query methods for filtering contracts by status, buyer, and seller. The use of
Contract.ContractStatusenum in thefindByStatusmethod indicates proper type safety for status filtering.MartProduct/src/main/java/com/saudiMart/Product/Security/GatewayAuthFilter.java (1)
31-32: Regex pattern for public GET/OPTIONS endpoints is correct
- ProductsController exposes GET at
/products,/products/{id},/products/seller/{sellerId},/products/seller/{sellerId}/available.- CategoryController exposes GET at
/categories/all,/categories(active), and/categories/{id}.- No other controllers expose GET/OPTIONS under
/productsor/categories, and/productspecificationsremains protected.No unintended endpoints are exposed by
^/(products|categories)(/.*)?$.README.md (1)
1-116: Excellent comprehensive documentation overhaul.The README has been transformed into a professional, well-structured document that provides clear project overview, architecture details, and implementation guidance. The database schema roadmap with dependency phases is particularly valuable for development planning.
MartProduct/src/main/java/com/saudiMart/Product/Repository/OrderItemRepository.java (1)
1-21: Clean repository implementation with useful query methods.The repository interface is well-designed with appropriate query methods, including a useful compound query method
findByOrderAndProductfor more specific filtering. The implementation follows Spring Data JPA best practices consistently.MartProduct/src/main/java/com/saudiMart/Product/Repository/OrderApprovalRepository.java (1)
1-22: LGTM! Well-structured repository interface.The repository follows Spring Data JPA best practices with proper method naming conventions, appropriate return types, and clean imports. The query methods will automatically generate correct SQL based on the method names.
DatabasePath.md (1)
1-116: Excellent documentation restructure!The operational workflow approach is much more practical than listing individual tables. This will help developers understand the dependencies and sequence of operations needed for different business processes.
MartProduct/src/main/java/com/saudiMart/Product/Service/UserService.java (1)
23-33: Good exception handling and transaction management.The exception handling with custom ProductException and read-only transactions are well implemented for the retrieval methods.
MartProduct/src/main/java/com/saudiMart/Product/Model/CreditApplication.java (1)
22-25: Well-designed entity with proper JPA practices.The entity demonstrates good JPA practices with appropriate annotations, lazy loading, and proper enum usage. The UUID primary key strategy and BigDecimal for financial data are excellent choices.
Also applies to: 76-78
MartProduct/src/main/java/com/saudiMart/Product/Repository/ProductImageRepository.java (2)
8-14: Repository refactoring looks correct.The transition from Products to ProductVariant association and the ID type change to String are well-implemented. The remaining method signature is appropriate for the new entity relationship.
12-12: Confirm ProductImage ID Type RefactoringAutomated searches did not reveal any remaining
Longreferences in theProductImagecontext. To ensure the change is complete, please manually verify:
- All
findByIdcalls (in services/controllers) now useStringIDs.- Any JSON (de)serialization or DTO mappings expect
Stringfor theidfield.- Custom JPQL/SQL queries or utility methods aren’t assuming numeric IDs.
MartProduct/src/main/java/com/saudiMart/Product/Repository/CategoryRepository.java (1)
12-21: LGTM! Well-designed repository enhancements.The changes effectively improve category search capabilities:
- Consistent UUID-based ID type migration
- Case-insensitive search methods enhance user experience
- Method naming follows Spring Data JPA conventions
- Good balance of filtering options (by name, active status, or both)
MartProduct/src/main/java/com/saudiMart/Product/Model/Payment.java (1)
25-98: LGTM! Excellent entity design with comprehensive validation.This Payment entity demonstrates several best practices:
- Proper UUID-based primary key generation
- Appropriate BigDecimal usage for financial amounts with correct precision/scale
- Comprehensive validation annotations ensuring data integrity
- Strategic database indexes on frequently queried columns
- Well-defined enums for type safety
- Proper timestamp management with JPA lifecycle callbacks
- Reasonable field size constraints and nullability settings
The entity is ready for production use.
MartProduct/src/main/java/com/saudiMart/Product/Model/ProductSpecification.java (1)
24-25: LGTM! Proper UUID migration and JSON serialization handling.The changes effectively address two important concerns:
- UUID-based ID generation maintains consistency with the broader entity refactoring
@JsonBackReferenceannotation prevents infinite recursion in bidirectional relationships during JSON serializationThe annotation name "product-specifications" clearly identifies the relationship context.
Also applies to: 30-30
MartProduct/src/main/java/com/saudiMart/Product/Model/Users.java (2)
25-28: Good database optimization with proper indexing.Adding indexes on frequently queried columns (
role) will improve query performance, especially for authentication and authorization operations.
29-29: Proper JSON serialization configuration.The
@JsonIgnorePropertiesannotation correctly handles Hibernate proxy issues during JSON serialization.MartProduct/src/main/java/com/saudiMart/Product/Repository/CreditApplicationRepository.java (1)
13-30: Excellent repository design with security considerations.The repository provides comprehensive query methods that cover all expected business use cases for credit application management. The inclusion of security-focused methods like
findByIdAndSellerandfindByIdAndBuyerdemonstrates proper authorization boundary enforcement at the data access layer.The query methods are well-designed:
- User role-based queries (
findByBuyer,findBySeller,findByReviewer)- Status-based filtering for workflow management
- Combined queries for complex business logic
- Security-aware ID queries for access control
MartProduct/src/main/java/com/saudiMart/Product/Model/OrderApproval.java (1)
20-63: LGTM! Well-designed approval entity with solid JPA practices.The
OrderApprovalentity demonstrates excellent design choices:
- UUID primary key strategy suitable for distributed systems
- Proper lazy loading for performance optimization
- Type-safe enum for approval status
- Appropriate default values and validation constraints
- Clean lifecycle management with
@PrePersistMartProduct/src/main/java/com/saudiMart/Product/Model/Warehouse.java (1)
20-63: LGTM! Well-structured warehouse entity with proper validation.The
Warehouseentity demonstrates good design practices:
- Appropriate UUID primary key strategy
- Proper validation constraints with
@NotNulland@Size- Sensible default values for
isActive- Clean lifecycle management with timestamp callbacks
- Correct relationship mappings
MartProduct/src/main/java/com/saudiMart/Product/Model/ContractItem.java (1)
41-61: LGTM! Excellent use of BigDecimal and validation constraints.The monetary and quantity fields demonstrate best practices:
BigDecimalfor precise monetary calculations- Comprehensive validation constraints with meaningful messages
- Appropriate precision and scale for database columns
- Sensible default values for
discountPercentandisActiveMartProduct/src/main/java/com/saudiMart/Product/Repository/PriceTierRepository.java (1)
13-22: LGTM! Repository refactoring aligns well with the domain model changes.The updates demonstrate good design decisions:
- Consistent use of
StringID type matching UUID strategy- Logical shift from
ProductstoProductVariantfor price tier relationships- Well-named query methods following Spring Data JPA conventions
- Useful filtering capabilities for business requirements
MartProduct/src/main/java/com/saudiMart/Product/Controller/PriceTierController.java (1)
34-58: LGTM! Clean controller implementation with consistent ID type migration.The controller properly implements the REST endpoints with:
- Consistent use of String IDs throughout all methods
- Proper HTTP method mappings
- Standardized response wrapper usage
- Appropriate exception handling
The migration from Long to String UUIDs is implemented correctly and consistently across all endpoints.
MartProduct/src/main/java/com/saudiMart/Product/Model/Contract.java (1)
89-91: LGTM! Well-designed enum for contract status.The ContractStatus enum covers all essential contract states and follows good naming conventions.
MartProduct/src/main/java/com/saudiMart/Product/Model/ProductImage.java (1)
29-35: LGTM! Proper ID migration and relationship refactoring.The changes correctly implement:
- UUID string primary key generation
- Updated relationship to ProductVariant for more granular image management
- Proper JSON serialization handling with
@JsonBackReferenceThe relationship change from Products to ProductVariant aligns well with the overall schema refactoring.
MartProduct/src/main/java/com/saudiMart/Product/Controller/ProductSpecificationController.java (1)
39-76: LGTM! Consistent and well-implemented controller.The controller properly implements:
- Consistent migration from Long to String IDs in all path variables
- Standard REST endpoint patterns with appropriate HTTP methods
- Proper status codes (201 for creation, 200 for other operations)
- Standardized response wrapper usage
- Comprehensive exception handling
The ID type migration is implemented correctly and consistently across all endpoints.
MartProduct/src/main/java/com/saudiMart/Product/Service/ContractItemService.java (1)
1-84: LGTM! Well-structured service implementation.The service follows established patterns in the codebase with proper CRUD operations, null validation, and exception handling. The selective field updates in the
updateContractItemmethod and the comment about not changing product/variant relationships during updates show good design consideration.MartProduct/src/main/java/com/saudiMart/Product/Controller/ProductVariantController.java (1)
38-39: LGTM! Consistent UUID migration.The changes from
LongtoStringID parameters align with the system-wide migration to UUID-based identifiers. The modifications are consistent across all affected methods and maintain the existing functionality.Also applies to: 57-57, 71-71
MartProduct/src/main/java/com/saudiMart/Product/Service/InventoryService.java (1)
1-82: LGTM! Well-implemented service following established patterns.The service correctly implements CRUD operations with proper null validation, exception handling using
ProductException, and selective field updates. The design decision to not modify relationships during updates (lines 67-69) is appropriate for inventory management.MartProduct/src/main/java/com/saudiMart/Product/Service/AddressService.java (1)
1-77: LGTM! Service implementation follows established patterns.The service correctly implements CRUD operations with proper null validation, exception handling, and selective field updates. The implementation is consistent with other services in the codebase like
WarehouseServiceand follows the project's established patterns for service layer design.MartProduct/src/main/java/com/saudiMart/Product/Model/OrderItem.java (1)
34-46: Specify LAZY fetch type for ManyToOne relationships.All ManyToOne relationships default to EAGER fetching, which can cause performance issues with N+1 queries when loading multiple order items.
Apply this diff:
@NotNull -@ManyToOne(fetch = FetchType.LAZY) +@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "order_id", nullable = false) private Order order; @NotNull -@ManyToOne(fetch = FetchType.LAZY) +@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "product_id", nullable = false) private Products product; -@ManyToOne(fetch = FetchType.LAZY) +@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "variant_id") private ProductVariant variant;Likely an incorrect or invalid review comment.
MartProduct/src/main/java/com/saudiMart/Product/Model/Address.java (1)
38-41: Specify LAZY fetch type for user relationship.The @manytoone relationship with Users defaults to EAGER fetching, which can cause performance issues when loading multiple addresses.
Apply this diff:
@NotNull -@ManyToOne(fetch = FetchType.LAZY) +@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id", nullable = false) private Users user;Likely an incorrect or invalid review comment.
MartProduct/src/main/java/com/saudiMart/Product/Model/ProductVariant.java (2)
35-37: Good migration to UUID identifiers.The change from Long to UUID String for the primary key is a good choice for distributed systems and provides better uniqueness guarantees.
45-47: Well-implemented bidirectional relationships.The JSON reference annotations (
@JsonManagedReferenceand@JsonBackReference) properly handle serialization of bidirectional relationships, preventing infinite recursion. The cascade operations ensure proper lifecycle management of child entities.Also applies to: 57-59
MartProduct/src/main/java/com/saudiMart/Product/Service/ContractService.java (1)
1-92: Well-implemented service following established patterns.The
ContractServicefollows the consistent CRUD pattern used throughout the application with proper error handling viaProductException. The selective field updates in theupdateContractmethod and the additional query methods for filtering by buyer, seller, and status provide good functionality.MartProduct/src/main/java/com/saudiMart/Product/Model/Category.java (2)
25-26: Good migration to UUID-based identifiers.The change from
LongtoStringID with UUID generation strategy aligns with the system-wide refactoring and provides better scalability and uniqueness guarantees.
21-21: Good addition for JSON serialization handling.The
@JsonIgnorePropertiesannotation properly handles Hibernate lazy initialization issues during JSON serialization.MartProduct/src/main/java/com/saudiMart/Product/Controller/PaymentController.java (1)
31-122: Well-structured REST controller with consistent patterns.The controller follows the established patterns with proper
ResponseWrapperusage, appropriate HTTP status codes, and comprehensive exception handling that distinguishes between domain-specificProductExceptionand generic exceptions.MartProduct/src/main/java/com/saudiMart/Product/Controller/InventoryController.java (1)
50-112: Comprehensive inventory management with good service integration.The controller provides excellent functionality for inventory management with well-integrated queries across products, variants, and warehouses. The seller inventory aggregation logic effectively combines data from multiple warehouses.
MartProduct/src/main/java/com/saudiMart/Product/Service/ProductImageService.java (1)
28-78: Good migration to String IDs and ProductVariant integration.The service properly migrates to UUID-based String IDs and integrates with
ProductVariantinstead ofProducts, aligning with the data model changes. The selective field updates in the update method are well-implemented.MartProduct/src/main/java/com/saudiMart/Product/Service/ProductSpecificationService.java (1)
64-71: LGTM! Well-implemented selective update patternThe selective update logic properly checks for non-null values before updating fields, preventing accidental overwrites with null values. This is a good practice for partial updates.
MartProduct/src/main/java/com/saudiMart/Product/Service/PriceTierService.java (2)
45-55: LGTM! Robust validation and filtering logicThe method properly validates the quantity parameter and correctly filters tiers based on quantity ranges, including proper handling of null
maxQuantityvalues.
97-100: Excellent business rule enforcementGreat implementation to prevent changing the associated product variant during updates. This maintains data integrity and prevents potential inconsistencies.
MartProduct/src/main/java/com/saudiMart/Product/Service/CategoryService.java (1)
53-56: Excellent duplicate prevention logicGreat implementation to check for existing categories with the same name before creating a new one. This prevents duplicate categories and maintains data integrity.
MartProduct/src/main/java/com/saudiMart/Product/Controller/ProductsController.java (1)
56-66: LGTM! Well-structured seller-specific endpointsThe new endpoints for retrieving products by seller ID and available products by seller ID are well-implemented and follow RESTful conventions.
MartProduct/src/main/java/com/saudiMart/Product/Controller/ProductImageController.java (1)
36-37: ID type changes align with UUID migration.The path variable type changes from
LongtoStringare consistent with the broader UUID adoption across the codebase.Also applies to: 51-52, 59-59
MartProduct/src/main/java/com/saudiMart/Product/Model/PriceTier.java (1)
24-58: Well-structured entity with proper validation and relationships.The entity refactoring is well-executed with:
- Clear field naming conventions
- Appropriate validation constraints
- Proper lazy loading and JSON serialization handling
- Good use of precision and scale for monetary values
MartProduct/src/main/java/com/saudiMart/Product/Controller/AddressController.java (1)
29-36: Use consistent dependency injection pattern and fix formatting.The controller uses constructor injection for
AddressServicebut field injection forUserService. Also, there's a missing space after the equals sign.private final AddressService addressService; private final UserService userService; -@Autowired public AddressController(AddressService addressService, UserService userService) { this.addressService = addressService; - this.userService=userService; + this.userService = userService; }Likely an incorrect or invalid review comment.
MartProduct/src/main/java/com/saudiMart/Product/Controller/ContractController.java (1)
38-93: Well-structured controller with proper service delegation.The controller methods are well-organized with:
- Clear endpoint mappings
- Proper HTTP status codes (201 for creation)
- Consistent response wrapping
- Good separation of concerns by delegating to service layer
MartProduct/src/main/java/com/saudiMart/Product/Model/Products.java (3)
38-39: Verify UUID generation strategy for production use.The
GenerationType.UUIDstrategy generates random UUIDs which may not be optimal for database performance due to their random nature causing index fragmentation.Consider using
@GeneratedValue(generator = "uuid2")with@GenericGeneratorfor more control, or evaluate if sequential UUIDs would be better for your use case:-@GeneratedValue(strategy = GenerationType.UUID) -private String id; +@GeneratedValue(generator = "uuid2") +@GenericGenerator(name = "uuid2", strategy = "uuid2") +private String id;
28-33: Good performance optimization with strategic indexing.The database indexes on
seller_id,category_id,sku, andavailablecolumns are well-chosen for common query patterns in a B2B e-commerce platform.
59-65: Back-References Verified – No Further Action Needed
Thecascade = CascadeType.ALLandorphanRemoval = truesettings onProducts(lines 59–65) are paired with correct back-reference annotations in both child models:
- MartProduct/src/main/java/com/saudiMart/Product/Model/ProductSpecification.java (line 30):
@JsonBackReference("product-specifications")- MartProduct/src/main/java/com/saudiMart/Product/Model/ProductVariant.java (line 42):
@JsonBackReference("product-variants")MartProduct/src/main/java/com/saudiMart/Product/Controller/WarehouseController.java (1)
59-72: Good exception handling pattern.The CRUD operations demonstrate consistent exception handling with appropriate HTTP status codes and response wrapping.
MartProduct/src/main/java/com/saudiMart/Product/Controller/QuoteController.java (1)
71-76: Good separation of concerns with filtered endpoints.The buyer and seller filtering endpoints correctly delegate user lookup to
UserServiceand maintain clean separation of responsibilities.MartProduct/src/main/java/com/saudiMart/Product/Controller/OrderApprovalController.java (1)
97-109: Good nested service integration.The order filtering endpoint correctly integrates with
OrderServiceto fetch the order entity before querying approvals, maintaining proper separation of concerns.MartProduct/src/main/java/com/saudiMart/Product/Controller/OrderController.java (1)
91-97: Excellent date range filtering implementation.The date range filtering endpoint with
LocalDateTimeparameters provides flexible querying capabilities for order analytics and reporting.MartProduct/src/main/java/com/saudiMart/Product/Controller/CreditApplicationController.java (1)
29-37: Excellent use of constructor injection!The controller properly uses constructor injection with final fields, which is the recommended approach for dependency injection.
MartProduct/src/main/java/com/saudiMart/Product/Controller/CategoryController.java (1)
48-48: ID type migration looks good.The change from
LongtoStringfor ID parameters is consistent with the UUID migration across the codebase.Also applies to: 63-63, 71-71
MartProduct/src/main/java/com/saudiMart/Product/Service/ProductVariantService.java (1)
148-188: Well-implemented price tier management!The price tier CRUD operations are properly implemented with appropriate validation and error handling.
DB_schema.sql (1)
112-121: Clarify the relationship between product images and variants.The comment on line 112 states that
product_idis not directly on ProductImage in the latest model, but theimage_urlis required whilevariant_idis nullable. This creates ambiguity about whether images belong to products or variants.Consider either:
- Making
variant_idNOT NULL if images should only belong to variants- Adding
product_idcolumn if images can belong to either products or variants- Creating separate tables for product-level and variant-level images
MartProduct/src/main/java/com/saudiMart/Product/Service/ProductsService.java (5)
38-41: LGTM!The transactional annotation is appropriate for read operations.
54-62: LGTM!Good addition of seller-specific product queries with availability filtering.
127-155: LGTM!The specification update logic correctly handles both updates and insertions.
64-76: LGTM!Good implementation with proper category validation and availability filtering.
78-93: LGTM!Proper use of cascade operations with bi-directional relationship management.
DatabaseDesign.md (2)
52-78: Schema inconsistency with actual implementation.This documentation shows
BIGINT PRIMARY KEY AUTO_INCREMENTfor IDs, but the actualDB_schema.sqlusesVARCHAR(36) PRIMARY KEY(for UUIDs). Update the documentation to match the implementation.Likely an incorrect or invalid review comment.
1-473: Excellent documentation structure and content.The documentation is comprehensive, well-organized, and provides valuable insights into the database design, including performance optimizations, data integrity rules, and usage examples. Just ensure it matches the actual implementation.
fixedDBSchema.md (2)
1-462: Clarify which schema is the source of truth.This file presents a different schema design than
DB_schema.sql:
- Uses
BIGINT AUTO_INCREMENTinstead ofVARCHAR(36)for IDs- Has more comprehensive constraints and triggers
- Includes proper indexes
Which schema should be used as the actual implementation?
419-462: LGTM! Well-designed triggers for automatic calculations.The triggers properly maintain order totals when order items change, with appropriate handling for INSERT, UPDATE, and DELETE operations.
| var auth = new UsernamePasswordAuthenticationToken(userId, null, authorities); | ||
| var ctx = new SecurityContextImpl(auth); | ||
|
|
||
| System.out.println("ITS FROM THE GATEWAY WITH AUTHORIZATION HERE IS THE PATH: "+path); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove debug logging statement.
This debug print statement should be removed for production or replaced with proper logging framework usage.
- System.out.println("ITS FROM THE GATEWAY WITH AUTHORIZATION HERE IS THE PATH: "+path);
+ // Proceeding with authenticated request📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| System.out.println("ITS FROM THE GATEWAY WITH AUTHORIZATION HERE IS THE PATH: "+path); | |
| // Proceeding with authenticated request |
🤖 Prompt for AI Agents
In
MartGateway/src/main/java/com/saudimart/Gateway/Security/filter/JwtAuthenticationFilter.java
at line 83, remove the System.out.println debug statement. If logging is needed,
replace it with a proper logging framework call at an appropriate log level
instead of using System.out.println.
| if (path.matches("^/(authen|actuator|users)(/.*)?$") || (HttpMethod.GET.equals(method) || HttpMethod.OPTIONS.equals(method)) && | ||
| path.matches("^/(categories|pricetiers|productimages|productspecifications|productvariants|products)(/.*)?$")) { | ||
| System.out.println("ITS FROM THE GATEWAY OPENEND POINT HERES THE PATH: "+path); | ||
| return chain.filter(exchange); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Remove debug logging and verify regex patterns for security.
The expanded condition correctly handles more public endpoints, but has two concerns:
- Debug logging: The
System.out.printlnstatements should be removed or replaced with proper logging in production. - Regex security: Ensure the regex patterns don't inadvertently expose sensitive endpoints.
- System.out.println("ITS FROM THE GATEWAY OPENEND POINT HERES THE PATH: "+path);
+ // Skip authentication for public endpointsVerify that the regex patterns are secure:
🏁 Script executed:
#!/bin/bash
# Check if there are any sensitive endpoints that might match the public patterns
rg -A 3 -B 3 "RequestMapping\|PostMapping\|PutMapping\|DeleteMapping" --include="*.java" | grep -E "(categories|pricetiers|productimages|productspecifications|productvariants|products)"Length of output: 629
🏁 Script executed:
#!/bin/bash
# Correctly search for controller mappings including the public patterns
rg -A3 -B3 '@(RequestMapping|GetMapping|PostMapping|PutMapping|DeleteMapping)' -g '*.java' | grep -E '(categories|pricetiers|productimages|productspecifications|productvariants|products)'Length of output: 3411
Replace debug print with proper logging; regex endpoints verified
The System.out.println in JwtAuthenticationFilter should be removed or replaced with a logger. Our search confirmed that the public-path regex only matches the intended controllers (/categories, /pricetiers, /productimages, /productspecifications, /productvariants, /products) and no other mappings use those segments.
- File: MartGateway/src/main/java/com/saudimart/Gateway/Security/filter/JwtAuthenticationFilter.java
Lines: 40–44
Replace:- System.out.println("ITS FROM THE GATEWAY OPENEND POINT HERES THE PATH: "+path); + // Skip authentication for public endpoints + logger.debug("Skipping authentication for public endpoint: {}", path);
- No other controllers or sensitive endpoints match these regex patterns; the public endpoints are correctly scoped.
🤖 Prompt for AI Agents
In
MartGateway/src/main/java/com/saudimart/Gateway/Security/filter/JwtAuthenticationFilter.java
around lines 40 to 44, replace the System.out.println debug statement with a
proper logger call. Initialize a logger instance for the class if not already
present, and use it to log the message at an appropriate level (e.g., debug or
info). Remove the System.out.println to adhere to best practices for logging.
| public CorsConfigurationSource corsConfigurationSource() { | ||
| CorsConfiguration config = new CorsConfiguration(); | ||
| config.setAllowedOriginPatterns(List.of("*")); // wildcard fix | ||
| config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); | ||
| config.setAllowedHeaders(List.of("*")); | ||
| config.addExposedHeader("Authorization"); | ||
| config.setAllowCredentials(true); | ||
|
|
||
| UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); | ||
| source.registerCorsConfiguration("/**", config); | ||
| return source; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
CORS configuration may be too permissive for production.
The CORS configuration uses wildcard patterns that could pose security risks in production:
setAllowedOriginPatterns(List.of("*"))allows any originsetAllowCredentials(true)with wildcard origins can be problematic
Consider restricting origins to specific domains in production:
- config.setAllowedOriginPatterns(List.of("*")); // wildcard fix
+ config.setAllowedOriginPatterns(List.of(
+ "https://your-frontend-domain.com",
+ "https://admin.your-domain.com"
+ ));Or use environment-specific configuration to allow wildcards only in development.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public CorsConfigurationSource corsConfigurationSource() { | |
| CorsConfiguration config = new CorsConfiguration(); | |
| config.setAllowedOriginPatterns(List.of("*")); // wildcard fix | |
| config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); | |
| config.setAllowedHeaders(List.of("*")); | |
| config.addExposedHeader("Authorization"); | |
| config.setAllowCredentials(true); | |
| UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); | |
| source.registerCorsConfiguration("/**", config); | |
| return source; | |
| } | |
| public CorsConfigurationSource corsConfigurationSource() { | |
| CorsConfiguration config = new CorsConfiguration(); | |
| - config.setAllowedOriginPatterns(List.of("*")); // wildcard fix | |
| + config.setAllowedOriginPatterns(List.of( | |
| + "https://your-frontend-domain.com", | |
| + "https://admin.your-domain.com" | |
| + )); | |
| config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); | |
| config.setAllowedHeaders(List.of("*")); | |
| config.addExposedHeader("Authorization"); | |
| config.setAllowCredentials(true); | |
| UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); | |
| source.registerCorsConfiguration("/**", config); | |
| return source; | |
| } |
🤖 Prompt for AI Agents
In MartGateway/src/main/java/com/saudimart/Gateway/Security/SecurityConfig.java
around lines 42 to 53, the CORS configuration is too permissive by allowing all
origins with setAllowedOriginPatterns(List.of("*")) and enabling credentials. To
fix this, restrict allowed origins to specific trusted domains for production
environments and avoid using wildcards with allowCredentials(true). Implement
environment-specific logic to use wildcard origins only in development and
restrict them in production.
| @Bean | ||
| public SecurityWebFilterChain securityWebFilterChain( | ||
| ServerHttpSecurity http, | ||
| JwtAuthenticationFilter jwtAuthenticationFilter) { | ||
|
|
||
| return http | ||
| .cors(c -> c.configurationSource(corsConfigurationSource())) | ||
| .csrf(ServerHttpSecurity.CsrfSpec::disable) | ||
| .securityContextRepository(NoOpServerSecurityContextRepository.getInstance()) | ||
| .addFilterAt(jwtAuthenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION) | ||
| .authorizeExchange(ex -> ex | ||
| .pathMatchers(HttpMethod.OPTIONS, "/categories/**", "/pricetiers/**", "/productimages/**", "/productspecifications/**", "/productvariants/**", "/products/**").permitAll() | ||
| .pathMatchers(HttpMethod.GET, "/categories/**", "/pricetiers/**", "/productimages/**", "/productspecifications/**", "/productvariants/**", "/products/**").permitAll() | ||
| .pathMatchers("/authen/**", "/actuator/**", "/users/**").permitAll() | ||
| .anyExchange().authenticated()) | ||
| .build(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Well-structured reactive security configuration with consistent path matching.
The security filter chain correctly implements reactive security patterns and the path matchers are consistent with the JWT filter changes. The stateless configuration with NoOpServerSecurityContextRepository is appropriate for a gateway service.
Verify consistency between filter and security config paths:
🏁 Script executed:
#!/bin/bash
# Compare path patterns between JWT filter and security config
echo "=== JWT Filter patterns ==="
rg "matches.*categories\|pricetiers\|productimages\|productspecifications\|productvariants\|products" MartGateway/src/main/java/com/saudimart/Gateway/Security/filter/JwtAuthenticationFilter.java
echo "=== Security Config patterns ==="
rg "pathMatchers.*categories\|pricetiers\|productimages\|productspecifications\|productvariants\|products" MartGateway/src/main/java/com/saudimart/Gateway/Security/SecurityConfig.javaLength of output: 651
I’ll verify the CORS setup in SecurityConfig.java to ensure origin patterns aren’t too permissive.
🏁 Script executed:
#!/bin/bash
# Show the corsConfigurationSource method to inspect allowed origins/patterns
rg -n 'corsConfigurationSource' -n -A 20 MartGateway/src/main/java/com/saudimart/Gateway/Security/SecurityConfig.javaLength of output: 1875
Restrict CORS origins when allowing credentials
While the reactive security setup and path matchers are consistent with the JWT filter, the CORS configuration is overly permissive:
- In corsConfigurationSource() (lines 43–48):
config.setAllowedOriginPatterns(List.of("*"));config.setAllowCredentials(true);
Allowing credentials from any origin ("*" with allowCredentials=true) can expose your API to CSRF and other cross-site attacks. Please restrict CORS to only the trusted origins your clients use. For example:
- config.setAllowedOriginPatterns(List.of("*"));
+ config.setAllowedOriginPatterns(
+ List.of("https://frontend.saudimart.com", "https://admin.saudimart.com")
+ );You can still call config.setAllowCredentials(true) if you need cookies or authorization headers, but ensure the origin list is locked down.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In MartGateway/src/main/java/com/saudimart/Gateway/Security/SecurityConfig.java
around lines 23 to 39, the CORS configuration in corsConfigurationSource() is
too permissive by allowing all origins with credentials enabled, which is a
security risk. To fix this, replace the wildcard origin pattern "*" with a
specific list of trusted origins that your clients use, while keeping
allowCredentials(true) if needed. This restricts CORS to only those trusted
origins and prevents potential CSRF attacks.
| @Column(name = "on_update", updatable = true) | ||
| private LocalDateTime updatedAt; | ||
|
|
||
| @PrePersist | ||
| protected void onCreate() { | ||
| applicationDate = LocalDateTime.now(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add @PreUpdate method to maintain updatedAt field.
The updatedAt field should be automatically updated when the entity is modified. Add a @PreUpdate method to handle this.
@PrePersist
protected void onCreate() {
applicationDate = LocalDateTime.now();
+ updatedAt = LocalDateTime.now();
+ }
+
+ @PreUpdate
+ protected void onUpdate() {
+ updatedAt = LocalDateTime.now();
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @Column(name = "on_update", updatable = true) | |
| private LocalDateTime updatedAt; | |
| @PrePersist | |
| protected void onCreate() { | |
| applicationDate = LocalDateTime.now(); | |
| } | |
| @Column(name = "on_update", updatable = true) | |
| private LocalDateTime updatedAt; | |
| @PrePersist | |
| protected void onCreate() { | |
| applicationDate = LocalDateTime.now(); | |
| updatedAt = LocalDateTime.now(); | |
| } | |
| @PreUpdate | |
| protected void onUpdate() { | |
| updatedAt = LocalDateTime.now(); | |
| } |
🤖 Prompt for AI Agents
In MartProduct/src/main/java/com/saudiMart/Product/Model/CreditApplication.java
around lines 68 to 74, the updatedAt field is not automatically updated on
entity modification. Add a method annotated with @PreUpdate that sets updatedAt
to the current LocalDateTime to ensure it is updated whenever the entity is
modified.
| @PostMapping | ||
| public ResponseEntity<ResponseWrapper<Products>> createProduct(@RequestBody Products product) | ||
| throws ProductException { | ||
| System.out.println("PROUDCT CATEOGORY::: "+product.getCategory().toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Replace System.out.println with proper logging and fix typo
- Use a proper logging framework instead of
System.out.println - Fix the typo: "CATEOGORY" should be "CATEGORY"
-System.out.println("PROUDCT CATEOGORY::: "+product.getCategory().toString());
+log.debug("PRODUCT CATEGORY: {}", product.getCategory());Don't forget to add the logger declaration at the class level:
private static final Logger log = LoggerFactory.getLogger(ProductsController.class);🤖 Prompt for AI Agents
In
MartProduct/src/main/java/com/saudiMart/Product/Controller/ProductsController.java
at line 50, replace the System.out.println statement with a proper logging call
using the logger instance. Fix the typo in the log message from "CATEOGORY" to
"CATEGORY". Also, ensure that a logger is declared at the class level as a
private static final Logger using LoggerFactory for ProductsController.
| public ResponseEntity<ResponseWrapper<List<ProductImage>>> getAllVarientImages() throws ProductException { | ||
| List<ProductImage> productImages = productImageService.getAllVarientImages(); | ||
| return ResponseEntity | ||
| .ok(new ResponseWrapper<>(200, "Successfully retrieved all product images.", productImages)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix typo in method name and update response message for consistency.
The method name contains a typo - "Varient" should be "Variant". Additionally, the response message should be updated to reflect the new method purpose.
Apply this diff to fix the typo and update the message:
- public ResponseEntity<ResponseWrapper<List<ProductImage>>> getAllVarientImages() throws ProductException {
- List<ProductImage> productImages = productImageService.getAllVarientImages();
+ public ResponseEntity<ResponseWrapper<List<ProductImage>>> getAllVariantImages() throws ProductException {
+ List<ProductImage> productImages = productImageService.getAllVariantImages();
return ResponseEntity
- .ok(new ResponseWrapper<>(200, "Successfully retrieved all product images.", productImages));
+ .ok(new ResponseWrapper<>(200, "Successfully retrieved all variant images.", productImages));📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public ResponseEntity<ResponseWrapper<List<ProductImage>>> getAllVarientImages() throws ProductException { | |
| List<ProductImage> productImages = productImageService.getAllVarientImages(); | |
| return ResponseEntity | |
| .ok(new ResponseWrapper<>(200, "Successfully retrieved all product images.", productImages)); | |
| } | |
| public ResponseEntity<ResponseWrapper<List<ProductImage>>> getAllVariantImages() throws ProductException { | |
| List<ProductImage> productImages = productImageService.getAllVariantImages(); | |
| return ResponseEntity | |
| .ok(new ResponseWrapper<>(200, "Successfully retrieved all variant images.", productImages)); | |
| } |
🤖 Prompt for AI Agents
In
MartProduct/src/main/java/com/saudiMart/Product/Controller/ProductImageController.java
around lines 29 to 33, rename the method from getAllVarientImages to
getAllVariantImages to fix the typo. Also, update the response message string to
reflect the corrected method name, such as changing "Successfully retrieved all
product images." to "Successfully retrieved all product variant images." for
consistency.
| @GetMapping | ||
| public ResponseEntity<ResponseWrapper<List<QuoteItem>>> getAllQuoteItems() throws ProductException { | ||
| List<QuoteItem> quoteItems = quoteItemService.getAllQuoteItems(); | ||
| return ResponseEntity.ok(new ResponseWrapper<>(200, "Successfully retrieved all quote items.", quoteItems)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Standardize exception handling across all controller methods.
The controller has inconsistent exception handling patterns. Some methods declare throws ProductException while others use try-catch blocks. This inconsistency can lead to unpredictable API behavior.
Choose one approach and apply it consistently:
Option 1: Use a global exception handler and let all methods throw exceptions:
@GetMapping("/{id}")
-public ResponseEntity<ResponseWrapper<QuoteItem>> getQuoteItemById(@PathVariable String id) {
- try {
- QuoteItem quoteItem = quoteItemService.getQuoteItemById(id);
- return ResponseEntity.ok(new ResponseWrapper<>(200, "Successfully retrieved quote item.", quoteItem));
- } catch (ProductException e) {
- return ResponseEntity.status(HttpStatus.NOT_FOUND)
- .body(new ResponseWrapper<>(HttpStatus.NOT_FOUND.value(), e.getMessage(), null));
- } catch (Exception e) {
- return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
- .body(new ResponseWrapper<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage(), null));
- }
-}
+public ResponseEntity<ResponseWrapper<QuoteItem>> getQuoteItemById(@PathVariable String id) throws ProductException {
+ QuoteItem quoteItem = quoteItemService.getQuoteItemById(id);
+ return ResponseEntity.ok(new ResponseWrapper<>(200, "Successfully retrieved quote item.", quoteItem));
+}Option 2: Add try-catch blocks to methods that currently throw exceptions.
Also applies to: 36-47, 94-100
🤖 Prompt for AI Agents
In
MartProduct/src/main/java/com/saudiMart/Product/Controller/QuoteItemController.java
around lines 29-33, 36-47, and 94-100, the exception handling is inconsistent
with some methods declaring throws ProductException and others using try-catch
blocks. Choose one consistent approach: either remove try-catch blocks and
declare throws ProductException on all methods to rely on a global exception
handler, or add try-catch blocks to all methods that throw exceptions to handle
them locally. Apply the chosen pattern uniformly across all controller methods
for predictable API behavior.
| } catch (Exception e) { | ||
| return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) | ||
| .body(new ResponseWrapper<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage(), null)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid catching generic Exception to prevent masking programming errors.
Catching generic Exception can hide programming errors and make debugging difficult. Consider catching only specific exceptions or removing these catch blocks if using a global exception handler.
- } catch (Exception e) {
- return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
- .body(new ResponseWrapper<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage(), null));
- }Also applies to: 59-62, 74-77, 88-91
🤖 Prompt for AI Agents
In
MartProduct/src/main/java/com/saudiMart/Product/Controller/QuoteItemController.java
at lines 43-46, 59-62, 74-77, and 88-91, avoid catching the generic Exception as
it can mask programming errors and hinder debugging. Instead, identify and catch
only the specific exceptions that the code is expected to handle, or remove
these catch blocks entirely if a global exception handler is in place to manage
exceptions consistently across the application.
| @Column(name = "updated_at") | ||
| private LocalDateTime updatedAt; | ||
|
|
||
| @Column(name = "is_active") | ||
| private Boolean isActive = true; | ||
| @Column(name = "created_at") | ||
| private LocalDateTime createdAt; | ||
|
|
||
| @Column(name = "created_at") | ||
| private LocalDateTime createdAt; | ||
| @PrePersist | ||
| protected void onCreate() { | ||
| createdAt = LocalDateTime.now(); | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add lifecycle callback to automatically update the updatedAt timestamp.
The updatedAt field is declared but never automatically set. Add a @PreUpdate callback to maintain this audit field.
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
}
+
+@PreUpdate
+protected void onUpdate() {
+ updatedAt = LocalDateTime.now();
+}Also add the import:
+import jakarta.persistence.PreUpdate;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @Column(name = "updated_at") | |
| private LocalDateTime updatedAt; | |
| @Column(name = "is_active") | |
| private Boolean isActive = true; | |
| @Column(name = "created_at") | |
| private LocalDateTime createdAt; | |
| @Column(name = "created_at") | |
| private LocalDateTime createdAt; | |
| @PrePersist | |
| protected void onCreate() { | |
| createdAt = LocalDateTime.now(); | |
| } | |
| // Add the new import alongside the other JPA imports | |
| import jakarta.persistence.PreUpdate; | |
| @Column(name = "updated_at") | |
| private LocalDateTime updatedAt; | |
| @Column(name = "created_at") | |
| private LocalDateTime createdAt; | |
| @PrePersist | |
| protected void onCreate() { | |
| createdAt = LocalDateTime.now(); | |
| } | |
| @PreUpdate | |
| protected void onUpdate() { | |
| updatedAt = LocalDateTime.now(); | |
| } |
🤖 Prompt for AI Agents
In MartProduct/src/main/java/com/saudiMart/Product/Model/PriceTier.java around
lines 59 to 69, the updatedAt field is declared but not automatically updated.
Add a method annotated with @PreUpdate that sets updatedAt to the current
LocalDateTime to keep this timestamp current on updates. Also, ensure the
necessary import for javax.persistence.PreUpdate is added to the imports
section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review continued from previous batch...
| @Autowired | ||
| private UserService userService; | ||
|
|
||
| private final ContractService contractService; | ||
|
|
||
| @Autowired | ||
| public ContractController(ContractService contractService) { | ||
| this.contractService = contractService; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use consistent constructor injection for all dependencies.
The controller mixes field injection (@Autowired on field) with constructor injection, violating the single responsibility principle for dependency management.
-@Autowired
-private UserService userService;
+private final UserService userService;
private final ContractService contractService;
@Autowired
-public ContractController(ContractService contractService) {
+public ContractController(ContractService contractService, UserService userService) {
this.contractService = contractService;
+ this.userService = userService;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @Autowired | |
| private UserService userService; | |
| private final ContractService contractService; | |
| @Autowired | |
| public ContractController(ContractService contractService) { | |
| this.contractService = contractService; | |
| } | |
| private final UserService userService; | |
| private final ContractService contractService; | |
| @Autowired | |
| public ContractController(ContractService contractService, UserService userService) { | |
| this.contractService = contractService; | |
| this.userService = userService; | |
| } |
🤖 Prompt for AI Agents
In
MartProduct/src/main/java/com/saudiMart/Product/Controller/ContractController.java
around lines 28 to 36, the code uses field injection for UserService and
constructor injection for ContractService, which is inconsistent. Refactor the
controller to use constructor injection for both dependencies by adding
UserService as a parameter to the constructor and removing the @Autowired
annotation from the field. This ensures consistent and clear dependency
management.
| @NotNull | ||
| @ManyToOne(fetch = FetchType.LAZY) | ||
| @JoinColumn(name = "seller_id", nullable = false) | ||
| // @JsonBackReference("user-products") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Inconsistent serialization configuration.
The @JsonBackReference annotation is commented out, which may cause circular reference issues during JSON serialization if not handled consistently across related entities.
Either remove the commented line entirely or implement a consistent serialization strategy:
-// @JsonBackReference("user-products")
+@JsonBackReference("user-products")Or use @JsonIgnore if the relationship should not be serialized at all.
🤖 Prompt for AI Agents
In MartProduct/src/main/java/com/saudiMart/Product/Model/Products.java at line
43, the @JsonBackReference annotation is commented out, which can lead to
inconsistent JSON serialization and potential circular reference issues. To fix
this, either remove the commented-out annotation entirely or apply a consistent
serialization approach by uncommenting @JsonBackReference and ensuring the
corresponding @JsonManagedReference is used on the related entity.
Alternatively, if the relationship should not be serialized, replace it with
@JsonIgnore to prevent serialization of that field.
| public ResponseEntity<ResponseWrapper<List<Warehouse>>> getWarehousesBySeller(@RequestParam String sellerId) throws ProductException { | ||
| // Fetch the user based on sellerId and then call the service | ||
| Users user = userService.getUserById(sellerId); // Assuming you have a UserService | ||
| List<Warehouse> warehouses = warehouseService.getWarehousesBySeller(user); | ||
| return ResponseEntity.ok(new ResponseWrapper<>(200, "Successfully retrieved warehouses by seller", warehouses)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Handle ProductException in seller endpoint.
The /seller endpoint throws ProductException in the method signature but doesn't handle it with try-catch blocks like other endpoints, creating inconsistent error handling.
Add exception handling for consistency:
@GetMapping("/seller")
-public ResponseEntity<ResponseWrapper<List<Warehouse>>> getWarehousesBySeller(@RequestParam String sellerId) throws ProductException {
- // Fetch the user based on sellerId and then call the service
- Users user = userService.getUserById(sellerId); // Assuming you have a UserService
- List<Warehouse> warehouses = warehouseService.getWarehousesBySeller(user);
- return ResponseEntity.ok(new ResponseWrapper<>(200, "Successfully retrieved warehouses by seller", warehouses));
+public ResponseEntity<ResponseWrapper<List<Warehouse>>> getWarehousesBySeller(@RequestParam String sellerId) {
+ try {
+ Users user = userService.getUserById(sellerId);
+ List<Warehouse> warehouses = warehouseService.getWarehousesBySeller(user);
+ return ResponseEntity.ok(new ResponseWrapper<>(200, "Successfully retrieved warehouses by seller", warehouses));
+ } catch (ProductException e) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND)
+ .body(new ResponseWrapper<>(404, e.getMessage(), null));
+ } catch (Exception e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+ .body(new ResponseWrapper<>(500, "An error occurred", null));
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public ResponseEntity<ResponseWrapper<List<Warehouse>>> getWarehousesBySeller(@RequestParam String sellerId) throws ProductException { | |
| // Fetch the user based on sellerId and then call the service | |
| Users user = userService.getUserById(sellerId); // Assuming you have a UserService | |
| List<Warehouse> warehouses = warehouseService.getWarehousesBySeller(user); | |
| return ResponseEntity.ok(new ResponseWrapper<>(200, "Successfully retrieved warehouses by seller", warehouses)); | |
| } | |
| @GetMapping("/seller") | |
| public ResponseEntity<ResponseWrapper<List<Warehouse>>> getWarehousesBySeller(@RequestParam String sellerId) { | |
| try { | |
| Users user = userService.getUserById(sellerId); | |
| List<Warehouse> warehouses = warehouseService.getWarehousesBySeller(user); | |
| return ResponseEntity.ok(new ResponseWrapper<>(200, "Successfully retrieved warehouses by seller", warehouses)); | |
| } catch (ProductException e) { | |
| return ResponseEntity.status(HttpStatus.NOT_FOUND) | |
| .body(new ResponseWrapper<>(404, e.getMessage(), null)); | |
| } catch (Exception e) { | |
| return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) | |
| .body(new ResponseWrapper<>(500, "An error occurred", null)); | |
| } | |
| } |
🤖 Prompt for AI Agents
In
MartProduct/src/main/java/com/saudiMart/Product/Controller/WarehouseController.java
around lines 104 to 109, the getWarehousesBySeller method declares throwing
ProductException but lacks try-catch handling like other endpoints. Wrap the
method logic in a try-catch block to catch ProductException, handle it
consistently by returning an appropriate error response, and remove the throws
declaration from the method signature to align with the error handling pattern
used elsewhere.
| public ResponseEntity<ResponseWrapper<Quote>> getQuoteById(@PathVariable String id) throws ProductException { | ||
| Quote quote = quoteService.getQuoteById(id); | ||
| return ResponseEntity.ok(new ResponseWrapper<>(200, "Successfully retrieved quote", quote)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Inconsistent exception handling across controllers.
This controller uses exception propagation (throws ProductException) while WarehouseController uses try-catch blocks for error handling. This creates inconsistent API error responses.
Either adopt the try-catch pattern for consistency or ensure all controllers use the same exception handling strategy. The try-catch approach provides more control over HTTP status codes and error messages.
🤖 Prompt for AI Agents
In
MartProduct/src/main/java/com/saudiMart/Product/Controller/QuoteController.java
around lines 46 to 49, the method getQuoteById currently propagates
ProductException instead of handling it. To ensure consistent API error
responses like WarehouseController, wrap the call to
quoteService.getQuoteById(id) in a try-catch block that catches
ProductException, then return an appropriate ResponseEntity with an error status
code and message. This will align the exception handling approach across
controllers and provide better control over HTTP responses.
| @Autowired | ||
| private OrderApprovalService orderApprovalService; | ||
|
|
||
| @Autowired | ||
| private OrderService orderService; // Assuming an OrderService exists to get Order objects | ||
|
|
||
| @Autowired | ||
| private UserService userService; // Assuming a UserService exists to get User objects |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use constructor injection for consistency.
This controller uses field injection while others use constructor injection. Constructor injection is preferred for better testability and immutability.
Convert to constructor injection:
-@Autowired
-private OrderApprovalService orderApprovalService;
-
-@Autowired
-private OrderService orderService; // Assuming an OrderService exists to get Order objects
-
-@Autowired
-private UserService userService; // Assuming a UserService exists to get User objects
+private final OrderApprovalService orderApprovalService;
+private final OrderService orderService;
+private final UserService userService;
+
+@Autowired
+public OrderApprovalController(OrderApprovalService orderApprovalService,
+ OrderService orderService,
+ UserService userService) {
+ this.orderApprovalService = orderApprovalService;
+ this.orderService = orderService;
+ this.userService = userService;
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @Autowired | |
| private OrderApprovalService orderApprovalService; | |
| @Autowired | |
| private OrderService orderService; // Assuming an OrderService exists to get Order objects | |
| @Autowired | |
| private UserService userService; // Assuming a UserService exists to get User objects | |
| private final OrderApprovalService orderApprovalService; | |
| private final OrderService orderService; | |
| private final UserService userService; | |
| @Autowired | |
| public OrderApprovalController(OrderApprovalService orderApprovalService, | |
| OrderService orderService, | |
| UserService userService) { | |
| this.orderApprovalService = orderApprovalService; | |
| this.orderService = orderService; | |
| this.userService = userService; | |
| } |
🤖 Prompt for AI Agents
In
MartProduct/src/main/java/com/saudiMart/Product/Controller/OrderApprovalController.java
around lines 31 to 38, replace the current field injection of
OrderApprovalService, OrderService, and UserService with constructor injection.
Remove the @Autowired annotations on the fields and create a constructor that
accepts these services as parameters, assigning them to final fields. This
change improves testability and immutability by ensuring dependencies are
provided at instantiation.
| -- SQL schema for Saudi Mart Product service based on Java models | ||
|
|
||
| -- Table: users | ||
| -- Note: This table is likely managed by a separate auth/user service. | ||
| -- It's included here as a foreign key reference. | ||
| CREATE TABLE users ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| name VARCHAR(255) NOT NULL, | ||
| email VARCHAR(255) UNIQUE NOT NULL, | ||
| phone_number VARCHAR(255) UNIQUE, | ||
| password VARCHAR(255) NOT NULL, -- bcrypt hash | ||
| role VARCHAR(50) NOT NULL, -- e.g., BUYER, SELLER, ADMIN | ||
| is_verified BOOLEAN NOT NULL, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| enabled BOOLEAN DEFAULT TRUE, | ||
| account_non_expired BOOLEAN DEFAULT TRUE, | ||
| account_non_locked BOOLEAN DEFAULT TRUE, | ||
| credentials_non_expired BOOLEAN DEFAULT TRUE | ||
| ); | ||
|
|
||
| -- Table: addresses | ||
| CREATE TABLE addresses ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| user_id VARCHAR(36) NOT NULL, | ||
| address_type VARCHAR(50) DEFAULT 'SHIPPING', -- e.g., BILLING, SHIPPING, WAREHOUSE | ||
| company_name VARCHAR(100), | ||
| street_address_1 VARCHAR(255) NOT NULL, | ||
| street_address_2 VARCHAR(255), | ||
| city VARCHAR(100) NOT NULL, | ||
| state VARCHAR(100) NOT NULL, | ||
| postal_code VARCHAR(20) NOT NULL, | ||
| country VARCHAR(100) NOT NULL, | ||
| is_default BOOLEAN DEFAULT FALSE, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| updated_at TIMESTAMP, | ||
| FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE | ||
| ); | ||
|
|
||
| -- Table: categories | ||
| CREATE TABLE categories ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| name VARCHAR(100) NOT NULL, | ||
| image_url VARCHAR(255), -- Made nullable based on common use cases | ||
| description TEXT, | ||
| is_active BOOLEAN DEFAULT TRUE, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP | ||
| ); | ||
|
|
||
| -- Table: warehouses | ||
| CREATE TABLE warehouses ( | ||
| warehouse_id VARCHAR(36) PRIMARY KEY, | ||
| seller_id VARCHAR(36) NOT NULL, | ||
| name VARCHAR(100) NOT NULL, | ||
| address_id VARCHAR(36) NOT NULL, | ||
| is_active BOOLEAN DEFAULT TRUE, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| updated_at TIMESTAMP, | ||
| FOREIGN KEY (seller_id) REFERENCES users (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (address_id) REFERENCES addresses (id) ON DELETE RESTRICT -- Prevent deleting address if warehouse uses it | ||
| ); | ||
|
|
||
| -- Table: products | ||
| CREATE TABLE products ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| seller_id VARCHAR(36) NOT NULL, | ||
| name VARCHAR(255) NOT NULL, | ||
| description TEXT, | ||
| category_id VARCHAR(36), | ||
| base_price DECIMAL(12, 2), | ||
| minimum_order_quantity INT DEFAULT 1, | ||
| weight DECIMAL(10, 2), | ||
| weight_unit VARCHAR(10) DEFAULT 'kg', | ||
| dimensions VARCHAR(50), | ||
| sku VARCHAR(50) UNIQUE, | ||
| available BOOLEAN DEFAULT TRUE, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| updated_at TIMESTAMP, | ||
| FOREIGN KEY (seller_id) REFERENCES users (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (category_id) REFERENCES categories (id) ON DELETE SET NULL | ||
| ); | ||
|
|
||
| -- Table: product_variants | ||
| CREATE TABLE product_variants ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| product_id VARCHAR(36) NOT NULL, | ||
| sku VARCHAR(50) UNIQUE NOT NULL, | ||
| variant_name VARCHAR(255), | ||
| base_price DECIMAL(12, 2) NOT NULL, | ||
| available BOOLEAN DEFAULT TRUE, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE | ||
| ); | ||
|
|
||
| -- Table: variant_price_tiers | ||
| CREATE TABLE variant_price_tiers ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| variant_id VARCHAR(36) NOT NULL, | ||
| minimum_quantity INT NOT NULL CHECK (minimum_quantity > 0), | ||
| max_quantity INT, | ||
| price_per_unit DECIMAL(12, 2) NOT NULL CHECK (price_per_unit > 0), | ||
| discount_percent DECIMAL(5, 2) NOT NULL DEFAULT 0.00 CHECK (discount_percent >= 0), | ||
| is_active BOOLEAN DEFAULT TRUE, | ||
| updated_at TIMESTAMP, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| FOREIGN KEY (variant_id) REFERENCES product_variants (id) ON DELETE CASCADE, | ||
| CONSTRAINT min_max_quantity_check CHECK (max_quantity IS NULL OR max_quantity >= minimum_quantity) | ||
| ); | ||
|
|
||
| -- Table: product_images | ||
| CREATE TABLE product_images ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| -- product_id is not directly on ProductImage in the latest model, it's via ProductVariant | ||
| variant_id VARCHAR(36), -- variant_id can be nullable if image is product-level | ||
| image_url VARCHAR(500) NOT NULL, | ||
| alt_text VARCHAR(255), | ||
| display_order INT DEFAULT 0, | ||
| is_primary BOOLEAN DEFAULT FALSE, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| -- FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE, -- Removed based on model | ||
| FOREIGN KEY (variant_id) REFERENCES product_variants (id) ON DELETE CASCADE | ||
| ); | ||
|
|
||
| -- Table: product_specifications | ||
| CREATE TABLE product_specifications ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| product_id VARCHAR(36) NOT NULL, | ||
| spec_name VARCHAR(100) NOT NULL, | ||
| spec_value TEXT, -- Made nullable as per typical specification data, value might be null | ||
| unit VARCHAR(50), | ||
| display_order INT DEFAULT 0, | ||
| variant_id VARCHAR(36), -- Added variant_id as per model | ||
| FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (variant_id) REFERENCES product_variants (id) ON DELETE CASCADE -- Link to variant | ||
| ); | ||
|
|
||
| -- Table: inventory | ||
| CREATE TABLE inventory ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| product_id VARCHAR(36) NOT NULL, | ||
| variant_id VARCHAR(36), | ||
| warehouse_id VARCHAR(36) NOT NULL, | ||
| quantity INT NOT NULL DEFAULT 0 CHECK (quantity >= 0), | ||
| reserved_quantity INT NOT NULL DEFAULT 0 CHECK (reserved_quantity >= 0), | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| updated_at TIMESTAMP, | ||
| FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (variant_id) REFERENCES product_variants (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (warehouse_id) REFERENCES warehouses (warehouse_id) ON DELETE CASCADE, | ||
| UNIQUE (product_id, variant_id, warehouse_id) -- Ensure unique entry per product/variant and warehouse | ||
| ); | ||
|
|
||
| -- Table: contracts | ||
| CREATE TABLE contracts ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| buyer_id VARCHAR(36) NOT NULL, | ||
| seller_id VARCHAR(36) NOT NULL, | ||
| contract_number VARCHAR(50) UNIQUE, | ||
| start_date DATE NOT NULL, | ||
| end_date DATE NOT NULL, | ||
| payment_terms INT DEFAULT 30, | ||
| credit_limit DECIMAL(12, 2), | ||
| status VARCHAR(50) NOT NULL DEFAULT 'DRAFT', -- e.g., DRAFT, ACTIVE, EXPIRED, TERMINATED | ||
| terms_and_conditions TEXT, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| updated_at TIMESTAMP, | ||
| FOREIGN KEY (buyer_id) REFERENCES users (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (seller_id) REFERENCES users (id) ON DELETE CASCADE | ||
| ); | ||
|
|
||
| -- Table: contract_items | ||
| CREATE TABLE contract_items ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| contract_id VARCHAR(36) NOT NULL, | ||
| product_id VARCHAR(36) NOT NULL, | ||
| variant_id VARCHAR(36), | ||
| negotiated_price DECIMAL(12, 2) NOT NULL CHECK (negotiated_price > 0), | ||
| min_commitment_quantity INT CHECK (min_commitment_quantity > 0), | ||
| max_quantity INT CHECK (max_quantity > 0), | ||
| discount_percent DECIMAL(5, 2) NOT NULL DEFAULT 0.00 CHECK (discount_percent >= 0), | ||
| is_active BOOLEAN DEFAULT TRUE, | ||
| FOREIGN KEY (contract_id) REFERENCES contracts (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (variant_id) REFERENCES product_variants (id) ON DELETE CASCADE | ||
| ); | ||
|
|
||
| -- Table: credit_applications | ||
| CREATE TABLE credit_applications ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| buyer_id VARCHAR(36) NOT NULL, | ||
| seller_id VARCHAR(36) NOT NULL, | ||
| requested_limit DECIMAL(12, 2) NOT NULL, | ||
| approved_limit DECIMAL(12, 2), | ||
| status VARCHAR(50) NOT NULL DEFAULT 'PENDING', -- e.g., PENDING, APPROVED, REJECTED, EXPIRED | ||
| application_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| review_date TIMESTAMP, | ||
| expiry_date DATE, | ||
| reviewer_id VARCHAR(36), | ||
| notes TEXT, | ||
| updated_at TIMESTAMP, | ||
| FOREIGN KEY (buyer_id) REFERENCES users (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (seller_id) REFERENCES users (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (reviewer_id) REFERENCES users (id) ON DELETE SET NULL | ||
| ); | ||
|
|
||
| -- Table: orders | ||
| CREATE TABLE orders ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| order_number VARCHAR(50) UNIQUE, | ||
| buyer_id VARCHAR(36) NOT NULL, | ||
| seller_id VARCHAR(36) NOT NULL, | ||
| contract_id VARCHAR(36), | ||
| shipping_address_id VARCHAR(36) NOT NULL, | ||
| billing_address_id VARCHAR(36) NOT NULL, | ||
| payment_method VARCHAR(50) DEFAULT 'BANK_TRANSFER', -- e.g., CASH, BANK_TRANSFER, CREDIT, CARD | ||
| reference_number VARCHAR(50), | ||
| purchase_order_number VARCHAR(50), | ||
| expected_delivery_date DATE, | ||
| actual_delivery_date DATE, | ||
| notes TEXT, | ||
| status VARCHAR(50) DEFAULT 'DRAFT', -- e.g., DRAFT, PENDING_APPROVAL, APPROVED, REJECTED, PROCESSING, SHIPPED, DELIVERED, CANCELLED | ||
| subtotal DECIMAL(12, 2) DEFAULT 0.00, | ||
| tax_amount DECIMAL(12, 2) DEFAULT 0.00, | ||
| shipping_cost DECIMAL(12, 2) DEFAULT 0.00, | ||
| discount_amount DECIMAL(12, 2) DEFAULT 0.00, | ||
| total_price DECIMAL(12, 2) DEFAULT 0.00, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| updated_at TIMESTAMP, | ||
| FOREIGN KEY (buyer_id) REFERENCES users (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (seller_id) REFERENCES users (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (contract_id) REFERENCES contracts (id) ON DELETE SET NULL, | ||
| FOREIGN KEY (shipping_address_id) REFERENCES addresses (id) ON DELETE RESTRICT, | ||
| FOREIGN KEY (billing_address_id) REFERENCES addresses (id) ON DELETE RESTRICT | ||
| ); | ||
|
|
||
| -- Table: order_items | ||
| CREATE TABLE order_items ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| order_id VARCHAR(36) NOT NULL, | ||
| product_id VARCHAR(36) NOT NULL, | ||
| variant_id VARCHAR(36), | ||
| quantity INT NOT NULL CHECK (quantity > 0), | ||
| price_per_unit DECIMAL(12, 2) NOT NULL CHECK (price_per_unit > 0), | ||
| discount_percent DECIMAL(5, 2) DEFAULT 0.00 CHECK (discount_percent >= 0), | ||
| tax_percent DECIMAL(5, 2) DEFAULT 0.00 CHECK (tax_percent >= 0), | ||
| total_price DECIMAL(12, 2) NOT NULL CHECK (total_price > 0), | ||
| ship_from_warehouse_id VARCHAR(36), | ||
| status VARCHAR(50) NOT NULL DEFAULT 'PENDING', -- e.g., PENDING, PROCESSING, SHIPPED, DELIVERED, CANCELLED | ||
| notes TEXT, | ||
| FOREIGN KEY (order_id) REFERENCES orders (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE RESTRICT, -- Prevent deleting product if it's in an order | ||
| FOREIGN KEY (variant_id) REFERENCES product_variants (id) ON DELETE RESTRICT, -- Prevent deleting variant if it's in an order | ||
| FOREIGN KEY (ship_from_warehouse_id) REFERENCES warehouses (warehouse_id) ON DELETE SET NULL | ||
| ); | ||
|
|
||
| -- Table: order_approvals | ||
| CREATE TABLE order_approvals ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| order_id VARCHAR(36) NOT NULL, | ||
| approver_id VARCHAR(36) NOT NULL, | ||
| approval_level INT DEFAULT 1, | ||
| status VARCHAR(50) DEFAULT 'PENDING', -- e.g., PENDING, APPROVED, REJECTED | ||
| comments TEXT, | ||
| approval_date TIMESTAMP, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| FOREIGN KEY (order_id) REFERENCES orders (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (approver_id) REFERENCES users (id) ON DELETE RESTRICT -- Prevent deleting user if they are an approver | ||
| ); | ||
|
|
||
| -- Table: payments | ||
| CREATE TABLE payments ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| order_id VARCHAR(36) NOT NULL, | ||
| payment_reference VARCHAR(100) UNIQUE, | ||
| amount DECIMAL(12, 2) NOT NULL CHECK (amount > 0), | ||
| payment_type VARCHAR(50) NOT NULL, -- e.g., CASH, BANK_TRANSFER, CREDIT, CARD | ||
| transaction_id VARCHAR(100), | ||
| payment_status VARCHAR(50) NOT NULL DEFAULT 'PENDING', -- e.g., PENDING, SUCCESS, FAILED, REFUNDED, CANCELLED | ||
| payment_date TIMESTAMP, | ||
| due_date DATE, | ||
| notes VARCHAR(1000), | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| updated_at TIMESTAMP, | ||
| FOREIGN KEY (order_id) REFERENCES orders (id) ON DELETE CASCADE | ||
| ); | ||
|
|
||
| -- Table: quotes | ||
| CREATE TABLE quotes ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| quote_number VARCHAR(50) UNIQUE, | ||
| buyer_id VARCHAR(36) NOT NULL, | ||
| seller_id VARCHAR(36) NOT NULL, | ||
| status VARCHAR(50) DEFAULT 'DRAFT', -- e.g., DRAFT, PENDING, APPROVED, REJECTED, ACCEPTED, EXPIRED | ||
| expiration_date DATE, | ||
| notes TEXT, | ||
| subtotal DECIMAL(12, 2) DEFAULT 0.00, | ||
| tax_amount DECIMAL(12, 2) DEFAULT 0.00, | ||
| shipping_cost DECIMAL(12, 2) DEFAULT 0.00, | ||
| discount_amount DECIMAL(12, 2) DEFAULT 0.00, | ||
| total_price DECIMAL(12, 2) DEFAULT 0.00, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| updated_at TIMESTAMP, | ||
| FOREIGN KEY (buyer_id) REFERENCES users (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (seller_id) REFERENCES users (id) ON DELETE CASCADE | ||
| ); | ||
|
|
||
| -- Table: quote_items | ||
| CREATE TABLE quote_items ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| quote_id VARCHAR(36) NOT NULL, | ||
| product_id VARCHAR(36) NOT NULL, | ||
| variant_id VARCHAR(36), | ||
| quantity INT NOT NULL CHECK (quantity > 0), | ||
| price_per_unit DECIMAL(12, 2) NOT NULL CHECK (price_per_unit > 0), | ||
| discount_percent DECIMAL(5, 2) DEFAULT 0.00 CHECK (discount_percent >= 0), | ||
| tax_percent DECIMAL(5, 2) DEFAULT 0.00 CHECK (tax_percent >= 0), | ||
| total_price DECIMAL(12, 2) NOT NULL CHECK (total_price > 0), | ||
| notes TEXT, | ||
| FOREIGN KEY (quote_id) REFERENCES quotes (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (product_id) REFERENCES products (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (variant_id) REFERENCES product_variants (id) ON DELETE CASCADE | ||
| ); No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add indexes on all foreign key columns for better query performance.
The schema defines many foreign key constraints but doesn't create indexes on these columns. This will significantly impact JOIN performance. Add indexes for all foreign key columns.
Add the following indexes at the end of your schema:
-- Indexes for foreign keys
CREATE INDEX idx_addresses_user_id ON addresses(user_id);
CREATE INDEX idx_warehouses_seller_id ON warehouses(seller_id);
CREATE INDEX idx_warehouses_address_id ON warehouses(address_id);
CREATE INDEX idx_products_seller_id ON products(seller_id);
CREATE INDEX idx_products_category_id ON products(category_id);
CREATE INDEX idx_product_variants_product_id ON product_variants(product_id);
CREATE INDEX idx_variant_price_tiers_variant_id ON variant_price_tiers(variant_id);
CREATE INDEX idx_product_images_variant_id ON product_images(variant_id);
CREATE INDEX idx_product_specifications_product_id ON product_specifications(product_id);
CREATE INDEX idx_product_specifications_variant_id ON product_specifications(variant_id);
CREATE INDEX idx_inventory_product_id ON inventory(product_id);
CREATE INDEX idx_inventory_variant_id ON inventory(variant_id);
CREATE INDEX idx_inventory_warehouse_id ON inventory(warehouse_id);
CREATE INDEX idx_contracts_buyer_id ON contracts(buyer_id);
CREATE INDEX idx_contracts_seller_id ON contracts(seller_id);
CREATE INDEX idx_contract_items_contract_id ON contract_items(contract_id);
CREATE INDEX idx_contract_items_product_id ON contract_items(product_id);
CREATE INDEX idx_contract_items_variant_id ON contract_items(variant_id);
CREATE INDEX idx_credit_applications_buyer_id ON credit_applications(buyer_id);
CREATE INDEX idx_credit_applications_seller_id ON credit_applications(seller_id);
CREATE INDEX idx_credit_applications_reviewer_id ON credit_applications(reviewer_id);
CREATE INDEX idx_orders_buyer_id ON orders(buyer_id);
CREATE INDEX idx_orders_seller_id ON orders(seller_id);
CREATE INDEX idx_orders_contract_id ON orders(contract_id);
CREATE INDEX idx_orders_shipping_address_id ON orders(shipping_address_id);
CREATE INDEX idx_orders_billing_address_id ON orders(billing_address_id);
CREATE INDEX idx_order_items_order_id ON order_items(order_id);
CREATE INDEX idx_order_items_product_id ON order_items(product_id);
CREATE INDEX idx_order_items_variant_id ON order_items(variant_id);
CREATE INDEX idx_order_items_warehouse_id ON order_items(ship_from_warehouse_id);
CREATE INDEX idx_order_approvals_order_id ON order_approvals(order_id);
CREATE INDEX idx_order_approvals_approver_id ON order_approvals(approver_id);
CREATE INDEX idx_payments_order_id ON payments(order_id);
CREATE INDEX idx_quotes_buyer_id ON quotes(buyer_id);
CREATE INDEX idx_quotes_seller_id ON quotes(seller_id);
CREATE INDEX idx_quote_items_quote_id ON quote_items(quote_id);
CREATE INDEX idx_quote_items_product_id ON quote_items(product_id);
CREATE INDEX idx_quote_items_variant_id ON quote_items(variant_id);
-- Additional performance indexes
CREATE INDEX idx_orders_status ON orders(status);
CREATE INDEX idx_products_available ON products(available);
CREATE INDEX idx_variant_price_tiers_quantity ON variant_price_tiers(variant_id, minimum_quantity, max_quantity);🤖 Prompt for AI Agents
In DB_schema.sql lines 1 to 321, the schema defines many foreign key constraints
but lacks indexes on these foreign key columns, which will degrade JOIN query
performance. To fix this, add CREATE INDEX statements for each foreign key
column as listed in the comment at the end of the schema file. Also include
additional indexes on frequently queried columns like orders.status,
products.available, and variant_price_tiers on variant_id with minimum_quantity
and max_quantity to improve query efficiency.
| CREATE TABLE contracts ( | ||
| id VARCHAR(36) PRIMARY KEY, | ||
| buyer_id VARCHAR(36) NOT NULL, | ||
| seller_id VARCHAR(36) NOT NULL, | ||
| contract_number VARCHAR(50) UNIQUE, | ||
| start_date DATE NOT NULL, | ||
| end_date DATE NOT NULL, | ||
| payment_terms INT DEFAULT 30, | ||
| credit_limit DECIMAL(12, 2), | ||
| status VARCHAR(50) NOT NULL DEFAULT 'DRAFT', -- e.g., DRAFT, ACTIVE, EXPIRED, TERMINATED | ||
| terms_and_conditions TEXT, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| updated_at TIMESTAMP, | ||
| FOREIGN KEY (buyer_id) REFERENCES users (id) ON DELETE CASCADE, | ||
| FOREIGN KEY (seller_id) REFERENCES users (id) ON DELETE CASCADE | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add constraints to enforce business rules.
Add CHECK constraints to prevent self-trading and ensure data integrity.
For the contracts table (after line 168):
CONSTRAINT chk_different_parties CHECK (buyer_id != seller_id),
CONSTRAINT chk_contract_dates CHECK (end_date > start_date)For the orders table (after line 233):
CONSTRAINT chk_different_buyer_seller CHECK (buyer_id != seller_id)Also applies to: 205-233
🤖 Prompt for AI Agents
In DB_schema.sql around lines 153 to 168, add CHECK constraints to the contracts
table to enforce business rules: include a constraint named
chk_different_parties to ensure buyer_id and seller_id are not the same, and
another named chk_contract_dates to ensure end_date is after start_date.
Additionally, in the orders table around lines 205 to 233, add a CHECK
constraint named chk_different_buyer_seller to ensure buyer_id and seller_id
differ. Add these constraints within the table definitions to maintain data
integrity.
| image_url VARCHAR(255), -- Made nullable based on common use cases | ||
| description TEXT, | ||
| is_active BOOLEAN DEFAULT TRUE, | ||
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the missing space between columns.
There's a missing space between is_active and created_at columns.
- is_active BOOLEAN DEFAULT TRUE,
- created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+ is_active BOOLEAN DEFAULT TRUE,
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP | |
| is_active BOOLEAN DEFAULT TRUE, | |
| created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP |
🤖 Prompt for AI Agents
In DB_schema.sql at line 46, there is a missing space between the `is_active`
and `created_at` columns. Add a space after the `is_active` column definition to
separate it properly from the `created_at` column definition.
| for (ProductVariant existingVariant : existingVariants) { | ||
| if (existingVariant.getId() != null && !incomingVariantsMap.containsKey(existingVariant.getId())) { | ||
| variantsToDelete.add(existingVariant); | ||
| } | ||
| } | ||
| throw new ProductException("Product with ID " + productId + " not found"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Complete the variant deletion logic.
The method collects variantsToDelete but never deletes them from the database.
Add the following after line 193:
// Delete variants that are no longer in the incoming list
if (!variantsToDelete.isEmpty()) {
productVariantRepository.deleteAll(variantsToDelete);
}
// Save the updated and new variants
productVariantRepository.saveAll(variantsToSave);🤖 Prompt for AI Agents
In MartProduct/src/main/java/com/saudiMart/Product/Service/ProductsService.java
around lines 189 to 194, the code collects variants to delete but does not
perform the deletion. After line 193, add logic to delete these variants from
the database by calling productVariantRepository.deleteAll with variantsToDelete
if the list is not empty. Then, save the updated and new variants by calling
productVariantRepository.saveAll with variantsToSave.
| existingVariant.setSku(incomingVariant.getSku()); | ||
| existingVariant.setVariantName(incomingVariant.getVariantName()); | ||
| existingVariant.setAvailable(incomingVariant.getAvailable()); | ||
| variantsToSave.add(existingVariant); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add null checks to prevent potential NullPointerException.
The variant update logic should check for null values before setting fields.
- existingVariant.setSku(incomingVariant.getSku());
- existingVariant.setVariantName(incomingVariant.getVariantName());
- existingVariant.setAvailable(incomingVariant.getAvailable());
+ if (incomingVariant.getSku() != null) {
+ existingVariant.setSku(incomingVariant.getSku());
+ }
+ if (incomingVariant.getVariantName() != null) {
+ existingVariant.setVariantName(incomingVariant.getVariantName());
+ }
+ if (incomingVariant.getAvailable() != null) {
+ existingVariant.setAvailable(incomingVariant.getAvailable());
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| existingVariant.setSku(incomingVariant.getSku()); | |
| existingVariant.setVariantName(incomingVariant.getVariantName()); | |
| existingVariant.setAvailable(incomingVariant.getAvailable()); | |
| variantsToSave.add(existingVariant); | |
| if (incomingVariant.getSku() != null) { | |
| existingVariant.setSku(incomingVariant.getSku()); | |
| } | |
| if (incomingVariant.getVariantName() != null) { | |
| existingVariant.setVariantName(incomingVariant.getVariantName()); | |
| } | |
| if (incomingVariant.getAvailable() != null) { | |
| existingVariant.setAvailable(incomingVariant.getAvailable()); | |
| } | |
| variantsToSave.add(existingVariant); |
🤖 Prompt for AI Agents
In MartProduct/src/main/java/com/saudiMart/Product/Service/ProductsService.java
around lines 178 to 181, add null checks before setting fields on
existingVariant from incomingVariant to prevent NullPointerException.
Specifically, verify that incomingVariant and its fields (sku, variantName,
available) are not null before calling the setter methods on existingVariant.
This ensures safe updates without runtime exceptions.
ADDRESS, WAREHOUSE, PRODUCT(SPEC,VAR,IMAGE), INVENTORY , USER DONE
Summary by CodeRabbit
New Features
Improvements
Documentation