Skip to content

Fixes #1 - Merchant validation and Error handling#2

Open
Rd4dev wants to merge 5 commits into
mainfrom
merchant-validation-error-handling
Open

Fixes #1 - Merchant validation and Error handling#2
Rd4dev wants to merge 5 commits into
mainfrom
merchant-validation-error-handling

Conversation

@Rd4dev

@Rd4dev Rd4dev commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Fixes #1

Included in this PR

  1. Fix merchant deletion handling by validating existence of merchant before deletion, if not return appropriate error response.
  2. Added regex validations for phone numbers and dates
  3. Added error handling with meaningful client-facing error messages

[Experimentation]

  • Also, this PR is mainly to work along with CodeRabbit review system and see how it functions and how can we make it function more code-base style oriented.

Summary by CodeRabbit

  • Bug Fixes

    • Deletion flow now verifies merchant exists before removal and returns clearer errors when not found; delete endpoint behavior unchanged (204 on success).
  • Improvements

    • Stricter validation: registered date must be YYYY-MM-DD and phone numbers must be 10–15 digits (optional +); validation applied to creation flow.
    • More descriptive error responses for invalid merchant ID and date formats.
  • Tests

    • Added unit tests for successful deletion and deletion when merchant is missing.

Rd4dev added 2 commits June 5, 2026 19:14
When the merchant id is not present and given the id is a proper UUID, the default string to UUID is handled by the Spring itself
The phone number validation is just a regex for making sure it has 10 to 15 digits with no space after country code or inbetween. The error handlings are included for string to UUID inclusion errors where it doesn't accept non uuids on the merchant id and it is not evident on the response, same for the date format, though a regex is added it still doesn't verify the date within range. Few other fixes could be since registration date should be less than the current date, we should probably restrict any dates from today being provided. But for now let's leave to CodeRabbit and see what all suggestions it comes up with
@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b8e5a24b-adf1-4da8-a49e-4f37a5f33c96

📥 Commits

Reviewing files that changed from the base of the PR and between d2903c0 and cea8641.

📒 Files selected for processing (1)
  • merchant-service/src/main/java/com/mert/merchantservice/service/MerchantService.java
💤 Files with no reviewable changes (1)
  • merchant-service/src/main/java/com/mert/merchantservice/service/MerchantService.java

📝 Walkthrough

Walkthrough

Adds regex validation for registeredDate and phoneNumber, new exception handlers for UUID and date parse errors, fixes the controller delete call, updates MerchantService to verify existence before delete, and adds unit tests for delete behavior.

Changes

Merchant Validation and Error Handling

Layer / File(s) Summary
Input validation constraints
merchant-service/src/main/java/com/mert/merchantservice/dto/MerchantRequestDTO.java
Adds Pattern import; registeredDate is scoped to CreateMerchantValidationGroup @NotBlank and @Pattern enforcing yyyy-MM-dd; phoneNumber gains @Pattern enforcing 10–15 digits with optional leading +.
Exception handlers for parsing/type errors
merchant-service/src/main/java/com/mert/merchantservice/exception/GlobalExceptionHandler.java
Adds handlers for MethodArgumentTypeMismatchException (returns 400 with an invalid merchant ID format message) and DateTimeParseException (returns 400 with a registeredDate format error message).
Safe delete flow, controller fix, and tests
merchant-service/src/main/java/com/mert/merchantservice/service/MerchantService.java, merchant-service/src/main/java/com/mert/merchantservice/controller/MerchantController.java, merchant-service/src/test/java/com/mert/merchantservice/service/MerchantServiceTest.java
Replaces deleMerchant with deleteMerchant(UUID), performs findById and throws MerchantNotFoundException if absent, deletes retrieved entity via merchantRepository.delete(merchant), fixes controller call, and adds unit tests for successful delete and not-found scenarios.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through code to mend a bug and test,
Dates now match yyyy-MM-dd at best,
Phones count digits, plus optional plus,
Deletions check first before making a fuss,
Tests guard the path so nothing goes bust.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objectives: merchant validation enhancements and error handling improvements, which are the primary focus of the changeset.
Linked Issues check ✅ Passed The PR implements all key requirements from Issue #1: validates merchant existence before deletion with appropriate error responses, adds regex validations for phone numbers and dates, and includes client-facing error handling with meaningful messages.
Out of Scope Changes check ✅ Passed All changes are directly aligned with Issue #1 objectives: merchant deletion validation, input validation enhancements (phone numbers and dates), error handling, and fixing the typo in the method name (which was left intentionally per issue notes).

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch merchant-validation-error-handling

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

Rd4dev added 2 commits June 9, 2026 20:21
These are sample tests again to see what else coderabbit suggests and this for now includes tests only related to parts of changes made in this PR

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
merchant-service/src/test/java/com/mert/merchantservice/service/MerchantServiceTest.java (1)

26-48: ⚡ Quick win

Consider adding a null ID test case.

The test suite covers valid and not-found scenarios but doesn't test null ID input. Given that the service has a null-check guard (line 77 in MerchantService.java), adding this test would improve coverage and immediately catch the critical inverted-logic bug present in the current implementation.

🧪 Suggested test case
`@Test`
void testMerchantService_nullIdProvided_shouldThrowIllegalArgumentException() {
    assertThrows(
            IllegalArgumentException.class,
            () -> merchantService.deleteMerchant(null)
    );
    verify(merchantRepository, never()).findById(any());
    verify(merchantRepository, never()).delete(any());
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@merchant-service/src/test/java/com/mert/merchantservice/service/MerchantServiceTest.java`
around lines 26 - 48, Add a unit test for the null-ID branch of
MerchantService.deleteMerchant: in MerchantServiceTest add a test (e.g.,
testMerchantService_nullIdProvided_shouldThrowIllegalArgumentException) that
calls merchantService.deleteMerchant(null) and asserts IllegalArgumentException
is thrown, and verifies merchantRepository.findById(...) and
merchantRepository.delete(...) are never invoked; this will exercise the
null-check guard in MerchantService.deleteMerchant and catch the inverted-logic
bug.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@merchant-service/src/main/java/com/mert/merchantservice/service/MerchantService.java`:
- Line 77: The null-check is inverted in MerchantService: the code currently
throws when a valid id is provided (if(id != null) throw new
RuntimeException()). Update the guard to check for a missing id (if(id == null))
and throw a clearer exception (e.g., IllegalArgumentException with a descriptive
message) so delete operations proceed for non-null ids; locate and fix the
null-check on the id variable in the MerchantService delete method.

In
`@merchant-service/src/test/java/com/mert/merchantservice/service/MerchantServiceTest.java`:
- Around line 20-24: The test fails to initialize because MerchantService's
constructor requires three dependencies but only MerchantRepository is mocked;
add `@Mock` declarations for BillingServiceGrpcClient and KafkaProducer in
MerchantServiceTest so `@InjectMocks` can create MerchantService successfully,
then wire any expected behavior on those mocks for the tests that use methods on
BillingServiceGrpcClient or KafkaProducer.

---

Nitpick comments:
In
`@merchant-service/src/test/java/com/mert/merchantservice/service/MerchantServiceTest.java`:
- Around line 26-48: Add a unit test for the null-ID branch of
MerchantService.deleteMerchant: in MerchantServiceTest add a test (e.g.,
testMerchantService_nullIdProvided_shouldThrowIllegalArgumentException) that
calls merchantService.deleteMerchant(null) and asserts IllegalArgumentException
is thrown, and verifies merchantRepository.findById(...) and
merchantRepository.delete(...) are never invoked; this will exercise the
null-check guard in MerchantService.deleteMerchant and catch the inverted-logic
bug.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 29a0d7d3-f4c2-4a76-91a4-e67c1a072d00

📥 Commits

Reviewing files that changed from the base of the PR and between 40e9491 and d2903c0.

📒 Files selected for processing (3)
  • merchant-service/src/main/java/com/mert/merchantservice/controller/MerchantController.java
  • merchant-service/src/main/java/com/mert/merchantservice/service/MerchantService.java
  • merchant-service/src/test/java/com/mert/merchantservice/service/MerchantServiceTest.java

public void deleMerchant(UUID id) {
merchantRepository.deleteById(id);
public void deleteMerchant(UUID id) {
if(id != null) throw new RuntimeException();

@coderabbitai coderabbitai Bot Jun 9, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: Inverted null-check logic breaks all valid deletions.

The guard if(id != null) throws an exception when a valid ID is provided, causing all legitimate delete operations to fail. The condition should be if(id == null) to properly reject null input.

🐛 Proposed fix
-        if(id != null) throw new RuntimeException();
+        if(id == null) throw new IllegalArgumentException("Merchant ID cannot be 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
if(id != null) throw new RuntimeException();
if(id == null) throw new IllegalArgumentException("Merchant ID cannot be null");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@merchant-service/src/main/java/com/mert/merchantservice/service/MerchantService.java`
at line 77, The null-check is inverted in MerchantService: the code currently
throws when a valid id is provided (if(id != null) throw new
RuntimeException()). Update the guard to check for a missing id (if(id == null))
and throw a clearer exception (e.g., IllegalArgumentException with a descriptive
message) so delete operations proceed for non-null ids; locate and fix the
null-check on the id variable in the MerchantService delete method.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Good catch!

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@Rd4dev, glad it was helpful! The inverted != vs == is easy to miss but causes every valid delete request to fail immediately. Once flipped to if(id == null) with a descriptive IllegalArgumentException, the guard will correctly protect only against null inputs and let legitimate deletions through.

(ノ◕ヮ◕)ノ*:・゚✧ 🐇

Comment on lines +20 to +24
@Mock
private MerchantRepository merchantRepository;

@InjectMocks
private MerchantService merchantService;

@coderabbitai coderabbitai Bot Jun 9, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Incomplete mock setup will cause test initialization failure.

MerchantService's constructor requires three dependencies: MerchantRepository, BillingServiceGrpcClient, and KafkaProducer (see lines 23-31 in MerchantService.java). Only MerchantRepository is mocked here. Without mocking the other two required dependencies, @InjectMocks cannot instantiate the service, and these tests will fail during setup.

🔧 Proposed fix
 `@ExtendWith`(MockitoExtension.class)
 public class MerchantServiceTest {
     `@Mock`
     private MerchantRepository merchantRepository;
+    
+    `@Mock`
+    private BillingServiceGrpcClient billingServiceGrpcClient;
+    
+    `@Mock`
+    private KafkaProducer kafkaProducer;
 
     `@InjectMocks`
     private MerchantService merchantService;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@merchant-service/src/test/java/com/mert/merchantservice/service/MerchantServiceTest.java`
around lines 20 - 24, The test fails to initialize because MerchantService's
constructor requires three dependencies but only MerchantRepository is mocked;
add `@Mock` declarations for BillingServiceGrpcClient and KafkaProducer in
MerchantServiceTest so `@InjectMocks` can create MerchantService successfully,
then wire any expected behavior on those mocks for the tests that use methods on
BillingServiceGrpcClient or KafkaProducer.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

@coderabbitai -- Good one. Follow-up: If that is the case, I don't see any issue until now as both test cases seem to pass, why? Are you proposing this to be an issue now or with the test cases that need to be added in the future?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the MerchantService constructor and fields
cat merchant-service/src/main/java/com/mert/merchantservice/service/MerchantService.java

Length of output: 3887



@Rd4dev — Great follow-up question. Here's exactly what's happening:

Why the current tests pass despite the missing mocks:

Mockito's @InjectMocks attempts constructor injection first. When it finds the 3-argument constructor but only has one matching mock (MerchantRepository), it passes null for the two unmatched parameters (BillingServiceGrpcClient and KafkaProducer). The service instance is created successfully — it just has null for those two fields. Since deleteMerchant() never calls either of those two fields, the tests don't encounter a NullPointerException and the mocks aren't needed right now.

So my original comment is more of a forward-looking concern: the moment you add tests for createMerchant() or any other method that calls billingServiceGrpcClient or kafkaProducer, those tests will fail with NullPointerException at runtime unless you add the missing @Mock declarations.


However, there's a more critical bug in deleteMerchant itself:

public void deleteMerchant(UUID id) {
    if(id != null) throw new RuntimeException(); // ← inverted condition!
    ...
}

The condition is invertedid != null means any valid (non-null) UUID will immediately throw RuntimeException. It should be id == null. This means both your current tests, which pass non-null UUIDs, should actually be failing — unless you haven't run the test suite yet. Can you confirm whether you've run the tests locally?


Summary:

Concern Scope
Missing @Mock for BillingServiceGrpcClient / KafkaProducer Future tests for createMerchant, updateMerchant
if(id != null) → should be if(id == null) Current tests, production behavior

The id != null inversion is the more urgent fix.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Got it, I just wanted to keep things contained to what the PR needs, will add them as the needs arise, thanks.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@Rd4dev — That's a perfectly reasonable approach — no need to add mocks you won't exercise yet.

Just a reminder that the id != null inversion in deleteMerchant is a separate, current concern (not a future one). That condition causes valid UUIDs to immediately throw RuntimeException in production. It's worth fixing in this PR before merging:

// Current (inverted)
if (id != null) throw new RuntimeException();

// Should be
if (id == null) throw new RuntimeException("Merchant ID must not be null");

Would you like me to open a follow-up issue for tracking the missing mocks, or are you comfortable handling that informally when the time comes?

The coderabbit rightly identified this but suggested a fix for this rather its just a sanity check so removing it and leaving the test case as well without any additional deps included that are not part of the PR
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.

Improve Merchant Validation and Error Handling

1 participant