Skip to content

Conversation

@sayeedajmal
Copy link
Owner

@sayeedajmal sayeedajmal commented Jun 29, 2025

ADDRESS, WAREHOUSE, PRODUCT(SPEC,VAR,IMAGE), INVENTORY , USER DONE

Summary by CodeRabbit

  • New Features

    • Added comprehensive REST APIs for managing all core entities including addresses, categories, contracts, contract items, credit applications, inventory, orders, order approvals, order items, payments, price tiers, product images, product specifications, product variants, products, quotes, quote items, users, and warehouses.
    • Introduced advanced filtering, querying, and CRUD operations across business entities.
    • Implemented enhanced global error handling and refined public endpoint access.
    • Included detailed documentation and configuration enhancements for easier deployment and integration.
  • Improvements

    • Transitioned all entity identifiers to UUID strings for consistency and scalability.
    • Improved validation, error handling, and support for partial updates in services and controllers.
    • Optimized database schema with additional indexes and enforced data integrity constraints.
    • Refined security configurations to permit unauthenticated GET and OPTIONS requests on product and category endpoints.
  • Documentation

    • Completely restructured and expanded project documentation, including database schema design, API usage, and setup instructions.

@coderabbitai
Copy link

coderabbitai bot commented Jun 29, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This 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

File(s) / Group Change Summary
DB_schema.sql, fixedDBSchema.md Introduced or updated full SQL schemas for SaudiMart, defining all core tables, relationships, constraints, triggers, and indexes for a B2B marketplace.
DatabaseDesign.md, DatabasePath.md, README.md Documentation overhauled and expanded: schema design, operational flows, setup, best practices, and project overview added.
MartProduct/Model/* Added/modified JPA entity classes for all business domains (addresses, categories, contracts, contract items, credit applications, inventory, orders, order approvals, order items, payments, price tiers, product images, product specifications, product variants, products, quotes, quote items, users, warehouses), with UUID IDs, constraints, enums, relationships, and lifecycle callbacks.
MartProduct/Repository/* Added/modified Spring Data JPA repositories for all entities, with query methods for filtering by related entities and updated ID types to String.
MartProduct/Service/* Added/extended service classes for all domains, providing CRUD operations, business logic, validation, and error handling for each entity.
MartProduct/Controller/* Added/extended REST controllers for all entities, exposing CRUD and filtered query endpoints, with consistent response wrapping and error handling.
MartProduct/Security/* Security config updated: CORS bean removed, GET/OPTIONS to /products and /categories made public, filter logic updated for public endpoints, and debug logs added.
MartProduct/resources/application.yaml Added default values for DB, Redis, JWT, and Eureka config variables.
MartGateway/Security/* Gateway security config updated: public GET/OPTIONS on product-related endpoints, filter logic expanded for open endpoints, debug logs added.
MartGateway/config/* Added custom global error handler for WebFlux gateway.
MartGateway/resources/application.yml Expanded product-service routes to include all new resource paths.
MartAuth/Security/* CORS config removed, JWT filter logic updated for new open endpoints, debug logs added.

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
Loading
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
Loading

Poem

Oh what a leap for SaudiMart’s den,
With tables and code for women and men!
Products, orders, contracts—so neat,
Warehouses, payments, all can compete.
Docs and endpoints, bunnies rejoice—
A marketplace built with a hoppy voice!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@sayeedajmal sayeedajmal merged commit b7936b7 into main Jun 29, 2025
1 check failed
Copy link

@coderabbitai coderabbitai bot left a 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 update

The 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.println for 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 findByEmail method based on the method name, making the explicit @Query annotation 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 processing

Also 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.

-```
+```text

Apply 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) vs sellerUser (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 @Query annotations 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:

  1. Add transaction management:
+import org.springframework.transaction.annotation.Transactional;

 @Service
+@Transactional
 public class OrderItemService {
  1. 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);
 }
  1. 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 BigDecimal for monetary fields with precision/scale
  • Appropriate validation constraints
  • Lazy loading for performance optimization
  • Correct nullable configurations

Consider these enhancements:

  1. 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;
  1. 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);
+    }
+}
  1. 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 EAGER fetch 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 using LAZY fetching.

-    @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 EAGER which 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 Timestamp while other entities in the codebase use LocalDateTime. 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 using FetchType.LAZY as 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 Timestamp while other entities in the codebase use LocalDateTime (e.g., Products.java lines 66-67, Warehouse.java lines 49-50). Consider using LocalDateTime for 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 imageUrl field 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 logic

The 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 management

Instead of manually setting updatedAt, consider using JPA's @PreUpdate lifecycle callback in your entity class for automatic timestamp management.

In your CreditApplication entity, 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 logic

While 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 @ControllerAdvice with @ExceptionHandler methods 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 userService field 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 throw ProductException, 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 /all is 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 ProductVariant entity has proper cascade settings on the images relationship, 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 warehouses table uses warehouse_id as the primary key name, while all other tables use id. Consider renaming to id for consistency.

-    warehouse_id VARCHAR(36) PRIMARY KEY,
+    id VARCHAR(36) PRIMARY KEY,

Note: This change would require updating all foreign key references from warehouse_id to id.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1ed30d7 and 375dead.

📒 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 /authen or /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 Implemented

The GatewayErrorWebExceptionHandler class exists under com.saudimart.Gateway.config, implements ErrorWebExceptionHandler, 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 in GatewayConfig is correctly defined.

Optional suggestion:

  • For more robust JSON handling, consider using Jackson’s ObjectMapper instead of the custom toJson method.
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 Long to String ID type is consistent with the UUID migration strategy mentioned in the PR objectives.


23-23: LGTM! Useful cascade deletion method added.

The deleteByProduct method 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 Long to String ID type is consistent with the UUID migration strategy.


16-17: LGTM! Parameter type correctly updated.

The findBySellerId method parameter type change from Long to String properly 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 Long to String ID type is consistent with the UUID migration strategy.


20-20: LGTM! Useful cascade deletion method added.

The deleteByProduct method 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 JpaRepository with 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.ContractStatus enum in the findByStatus method 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 /products or /categories, and /productspecifications remains 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 findByOrderAndProduct for 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 Refactoring

Automated searches did not reveal any remaining Long references in the ProductImage context. To ensure the change is complete, please manually verify:

  • All findById calls (in services/controllers) now use String IDs.
  • Any JSON (de)serialization or DTO mappings expect String for the id field.
  • 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
  • @JsonBackReference annotation prevents infinite recursion in bidirectional relationships during JSON serialization

The 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 (email and role) will improve query performance, especially for authentication and authorization operations.


29-29: Proper JSON serialization configuration.

The @JsonIgnoreProperties annotation 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 findByIdAndSeller and findByIdAndBuyer demonstrates 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 OrderApproval entity 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 @PrePersist
MartProduct/src/main/java/com/saudiMart/Product/Model/Warehouse.java (1)

20-63: LGTM! Well-structured warehouse entity with proper validation.

The Warehouse entity demonstrates good design practices:

  • Appropriate UUID primary key strategy
  • Proper validation constraints with @NotNull and @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:

  • BigDecimal for precise monetary calculations
  • Comprehensive validation constraints with meaningful messages
  • Appropriate precision and scale for database columns
  • Sensible default values for discountPercent and isActive
MartProduct/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 String ID type matching UUID strategy
  • Logical shift from Products to ProductVariant for 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 @JsonBackReference

The 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 updateContractItem method 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 Long to String ID 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 WarehouseService and 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 (@JsonManagedReference and @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 ContractService follows the consistent CRUD pattern used throughout the application with proper error handling via ProductException. The selective field updates in the updateContract method 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 Long to String ID 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 @JsonIgnoreProperties annotation 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 ResponseWrapper usage, appropriate HTTP status codes, and comprehensive exception handling that distinguishes between domain-specific ProductException and 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 ProductVariant instead of Products, 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 pattern

The 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 logic

The method properly validates the quantity parameter and correctly filters tiers based on quantity ranges, including proper handling of null maxQuantity values.


97-100: Excellent business rule enforcement

Great 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 logic

Great 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 endpoints

The 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 Long to String are 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 AddressService but field injection for UserService. 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.UUID strategy 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 @GenericGenerator for 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, and available columns are well-chosen for common query patterns in a B2B e-commerce platform.


59-65: Back-References Verified – No Further Action Needed
The cascade = CascadeType.ALL and orphanRemoval = true settings on Products (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 UserService and 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 OrderService to 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 LocalDateTime parameters 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 Long to String for 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_id is not directly on ProductImage in the latest model, but the image_url is required while variant_id is nullable. This creates ambiguity about whether images belong to products or variants.

Consider either:

  1. Making variant_id NOT NULL if images should only belong to variants
  2. Adding product_id column if images can belong to either products or variants
  3. 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_INCREMENT for IDs, but the actual DB_schema.sql uses VARCHAR(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_INCREMENT instead of VARCHAR(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);
Copy link

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.

Suggested change
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.

Comment on lines +40 to 44
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);
}
Copy link

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:

  1. Debug logging: The System.out.println statements should be removed or replaced with proper logging in production.
  2. 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 endpoints

Verify 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.

Comment on lines +42 to +53
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;
}
Copy link

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:

  1. setAllowedOriginPatterns(List.of("*")) allows any origin
  2. setAllowCredentials(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.

Suggested change
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.

Comment on lines +23 to +39
@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();
}
Copy link

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.java

Length 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.java

Length 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.

Comment on lines +68 to +74
@Column(name = "on_update", updatable = true)
private LocalDateTime updatedAt;

@PrePersist
protected void onCreate() {
applicationDate = LocalDateTime.now();
}
Copy link

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.

Suggested change
@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());
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Replace System.out.println with proper logging and fix typo

  1. Use a proper logging framework instead of System.out.println
  2. 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.

Comment on lines +29 to 33
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));
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +29 to +33
@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));
}
Copy link

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.

Comment on lines +43 to +46
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ResponseWrapper<>(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage(), null));
}
Copy link

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.

Comment on lines +59 to 69
@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();
}

Copy link

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.

Suggested change
@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.

Copy link

@coderabbitai coderabbitai bot left a 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...

Comment on lines +28 to +36
@Autowired
private UserService userService;

private final ContractService contractService;

@Autowired
public ContractController(ContractService contractService) {
this.contractService = contractService;
}
Copy link

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.

Suggested change
@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")
Copy link

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.

Comment on lines +104 to +109
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));
}
Copy link

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.

Suggested change
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.

Comment on lines +46 to +49
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));
}
Copy link

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.

Comment on lines +31 to +38
@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
Copy link

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.

Suggested change
@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.

Comment on lines +1 to +321
-- 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
Copy link

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.

Comment on lines +153 to +168
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
);
Copy link

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
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +189 to 194
for (ProductVariant existingVariant : existingVariants) {
if (existingVariant.getId() != null && !incomingVariantsMap.containsKey(existingVariant.getId())) {
variantsToDelete.add(existingVariant);
}
}
throw new ProductException("Product with ID " + productId + " not found");
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

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.

Comment on lines +178 to +181
existingVariant.setSku(incomingVariant.getSku());
existingVariant.setVariantName(incomingVariant.getVariantName());
existingVariant.setAvailable(incomingVariant.getAvailable());
variantsToSave.add(existingVariant);
Copy link

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.

Suggested change
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.

@sayeedajmal sayeedajmal deleted the SchemaProduct branch July 4, 2025 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants