Skip to content

Add payment order models — requests, responses, and enums#32

Merged
rammrain merged 6 commits into
mainfrom
task-14
Apr 10, 2026
Merged

Add payment order models — requests, responses, and enums#32
rammrain merged 6 commits into
mainfrom
task-14

Conversation

@rammrain
Copy link
Copy Markdown
Member

@rammrain rammrain commented Apr 10, 2026

Summary

  • Add shared enums (Currency, Locale, PaymentMethodType, CardPaymentMethod, WalletProvider) in sdk.model
  • Add order-scoped models (PaymentStatus, Address, LineItem, Payment, PaymentMethodOptions) in order.model
  • Add CreateOrderRequest with Lombok builder and fail-fast validation in order.request
  • Add immutable response DTOs (CreateOrderResponse, OrderResponse, PaymentIntent) in order.response
  • Add jakarta.annotation-api dependency for @Nullable
  • 13 new test classes covering serialization round-trips, enum wire values, validation, and null handling

Field definitions cross-referenced from the official PHP SDK, JS SDK, and community TypeScript client.

Deferred items (new issues)

Test plan

  • All enum constants have correct wire values and round-trip through Jackson
  • Builder classes validate required fields and throw MontonioValidationException
  • Response DTOs deserialize from JSON matching the actual Montonio API shape
  • Unknown JSON fields are tolerated during deserialization
  • ./gradlew build passes (163 tests, 0 failures)

Closes #14

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added comprehensive payment order models and DTOs with immutable responses, validation and support for multiple payment methods, currencies and locales.
  • Documentation

    • Added a design plan covering model layout, enum wire values, JSON handling and validation conventions.
  • Tests

    • Added extensive unit tests for enums, models, validation and JSON serialization/deserialization.
  • Chores

    • Added a production annotation dependency.

Implements all DTOs and enums needed for the Montonio payment order API:

- Shared enums: Currency, Locale, PaymentMethodType, CardPaymentMethod, WalletProvider
- Order models: PaymentStatus, Address, LineItem, Payment, PaymentMethodOptions
- Request DTO: CreateOrderRequest with builder and fail-fast validation
- Response DTOs: CreateOrderResponse, OrderResponse, PaymentIntent (immutable)

Field definitions cross-referenced from the official PHP SDK, JS SDK,
and community TypeScript client. Uses @JsonCreator for Jackson 3
deserialization (Lombok @Jacksonized incompatible with Jackson 3).

Closes #14

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 10, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cb6a1ca5-d87e-4de0-9db4-45b514778bb1

📥 Commits

Reviewing files that changed from the base of the PR and between b70197f and f0dde52.

📒 Files selected for processing (2)
  • .github/CODEOWNERS
  • build.gradle
✅ Files skipped from review due to trivial changes (2)
  • .github/CODEOWNERS
  • build.gradle

📝 Walkthrough

Walkthrough

Adds payment order enums, immutable request/response DTOs and models with Jackson constructors and validation, a design document, a Jakarta Nullable dependency, many unit tests for serialization/validation, and a CODEOWNERS entry.

Changes

Cohort / File(s) Summary
Build Configuration
build.gradle
Added production dependency jakarta.annotation:jakarta.annotation-api:3.0.0.
Design Documentation
docs/plans/2026-04-10-payment-order-models-design.md
New design doc specifying package layout, enum wire values via @JsonValue, DTO patterns, validation rules, monetary typing, nullability conventions and test strategy.
Shared Enums (model)
src/main/java/ee/bitweb/montonio/sdk/model/CardPaymentMethod.java, src/main/java/ee/bitweb/montonio/sdk/model/Currency.java, src/main/java/ee/bitweb/montonio/sdk/model/Locale.java, src/main/java/ee/bitweb/montonio/sdk/model/PaymentMethodType.java, src/main/java/ee/bitweb/montonio/sdk/model/WalletProvider.java
Added enums exposing wire string values via @JsonValue (card method, currency, locale, payment method type, wallet provider).
Order enums
src/main/java/ee/bitweb/montonio/sdk/order/model/PaymentStatus.java
Added PaymentStatus enum with ten status constants and @JsonValue wire values.
Order models
src/main/java/ee/bitweb/montonio/sdk/order/model/Address.java, .../LineItem.java, .../Payment.java, .../PaymentMethodOptions.java
Added immutable order models with Lombok builders/getters and @JsonCreator constructors. Address has 15 nullable fields; LineItem validates name/quantity/finalPrice and fails fast; Payment validates method/currency/amount (>0); PaymentMethodOptions is a flat optional preferences holder.
Order requests
src/main/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequest.java
Added CreateOrderRequest with required fields (merchantReference, returnUrl, notificationUrl, grandTotal, currency, payment) and optional fields (locale, addresses, lineItems); constructor enforces validation and throws MontonioValidationException on violations.
Order responses
src/main/java/ee/bitweb/montonio/sdk/order/response/CreateOrderResponse.java, .../OrderResponse.java, .../PaymentIntent.java
Added immutable response DTOs: CreateOrderResponse (uuid, paymentUrl), OrderResponse (comprehensive order/payment fields, defensively copied collections), and PaymentIntent (intent data with optional metadata).
Tests — Enums
src/test/java/ee/bitweb/montonio/sdk/model/CardPaymentMethodTest.java, .../CurrencyTest.java, .../LocaleTest.java, .../PaymentMethodTypeTest.java, .../WalletProviderTest.java
Enum unit tests asserting expected constants, wire values and Jackson (de)serialization round-trips.
Tests — Models
src/test/java/ee/bitweb/montonio/sdk/order/model/AddressTest.java, .../LineItemTest.java, .../PaymentMethodOptionsTest.java, .../PaymentStatusTest.java, .../PaymentTest.java
Model tests for builder defaults, null handling, validation exceptions, serialization round-trips and option permutations.
Tests — Requests/Responses
src/test/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequestTest.java, src/test/java/ee/bitweb/montonio/sdk/order/response/CreateOrderResponseTest.java, .../OrderResponseTest.java, .../PaymentIntentTest.java
Request/response tests covering validation rules, JSON (de)serialization including unknown-field tolerance, nested structures and round-trips.
Repository config
.github/CODEOWNERS
Added CODEOWNERS entry assigning * to @BitWeb/tech.

Sequence Diagram(s)

(Skipped — changes are model, DTO and tests; no new multi-component control flow introduced.)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Initial project setup #5 — Adds jakarta.annotation-api to build.gradle, directly related to the same build configuration change in this PR.

Poem

🐰
I hopped through enums, builders and tests,
With Jackson crumbs and nullable vests,
Fields vetted, constructors neat—
DTO carrots, validation sweet,
Hooray, the payment models are complete!

🚥 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 'Add payment order models — requests, responses, and enums' is clear, concise, and accurately reflects the main change: introduction of DTOs, enums, and validation for the Montonio payment order API.
Linked Issues check ✅ Passed All enumeration requirements (#14) are implemented: PaymentStatus (10 constants), PaymentMethodType (5), Currency (EUR, PLN), Locale (8 values). All request DTOs are complete with validation: CreateOrderRequest with fail-fast validation, LineItem with field validation, Address with 15 nullable fields. All response DTOs are implemented: CreateOrderResponse, OrderResponse with 20 fields, PaymentIntent. Jackson annotations and null-safety via @Nullable are consistently applied.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #14 requirements: enums, request/response DTOs, validation logic, Jackson annotations, and comprehensive test coverage. Only scope-deferred items (#30 refunds, #31 Lombok compatibility) are intentionally excluded; no unrelated changes detected.

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

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

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

Copy link
Copy Markdown

@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: 3

🧹 Nitpick comments (4)
src/test/java/ee/bitweb/montonio/sdk/order/response/CreateOrderResponseTest.java (1)

43-55: Strengthen the unknown-fields test by asserting paymentUrl too.

This test currently verifies only uuid; adding paymentUrl makes the mapping guarantee complete.

Suggested test tightening
     `@Test`
     void deserializesWithUnknownFieldsIgnored() throws Exception {
         String json = """
                 {
                     "uuid": "550e8400-e29b-41d4-a716-446655440000",
                     "paymentUrl": "https://example.com/pay",
                     "extraField": "ignored"
                 }
                 """;

         CreateOrderResponse response = mapper.readValue(json, CreateOrderResponse.class);

         assertEquals("550e8400-e29b-41d4-a716-446655440000", response.getUuid());
+        assertEquals("https://example.com/pay", response.getPaymentUrl());
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/ee/bitweb/montonio/sdk/order/response/CreateOrderResponseTest.java`
around lines 43 - 55, In the deserializesWithUnknownFieldsIgnored test in
CreateOrderResponseTest, after mapping JSON via mapper.readValue into
CreateOrderResponse, add an assertion that response.getPaymentUrl() equals
"https://example.com/pay" (in addition to the existing uuid assertion) so the
test verifies both mapped fields and ensures unknown fields are ignored.
src/main/java/ee/bitweb/montonio/sdk/order/response/PaymentIntent.java (1)

24-25: Defensively copy paymentMethodMetadata to preserve DTO immutability.

Line 47 stores the incoming Map reference directly, so callers can mutate PaymentIntent after construction.

♻️ Proposed fix
 import lombok.Getter;
 
+import java.util.Collections;
+import java.util.LinkedHashMap;
 import java.util.Map;
@@
     public PaymentIntent(
             String uuid,
             PaymentMethodType paymentMethodType,
             String amount,
             Currency currency,
             PaymentStatus status,
             String serviceFee,
             Currency serviceFeeCurrency,
             String createdAt,
-            Map<String, String> paymentMethodMetadata
+            `@Nullable` Map<String, String> paymentMethodMetadata
     ) {
@@
-        this.paymentMethodMetadata = paymentMethodMetadata;
+        this.paymentMethodMetadata = paymentMethodMetadata == null
+                ? null
+                : Collections.unmodifiableMap(new LinkedHashMap<>(paymentMethodMetadata));
     }
 }

Also applies to: 37-48

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

In `@src/main/java/ee/bitweb/montonio/sdk/order/response/PaymentIntent.java`
around lines 24 - 25, The PaymentIntent DTO stores the incoming Map directly in
the private final field paymentMethodMetadata, allowing external mutation;
update the constructor(s) that accept a Map to defensively copy it (e.g., new
HashMap<>(incomingMap) or Collections.unmodifiableMap(new
HashMap<>(incomingMap))) and likewise return a defensive copy or unmodifiable
view from any accessor (e.g., getPaymentMethodMetadata()) so the PaymentIntent
class remains immutable; apply the same defensive-copy pattern to any other
Map/Collection fields in PaymentIntent.
src/test/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequestTest.java (1)

126-156: Add blank-value tests for URL fields

CreateOrderRequest validates both returnUrl and notificationUrl as non-null and non-blank, but this test class currently only checks null cases. Adding blank-string tests here will lock in the full fail-fast contract.

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

In
`@src/test/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequestTest.java`
around lines 126 - 156, Add two tests to CreateOrderRequestTest that mirror the
null checks but pass blank strings: implement buildWithBlankReturnUrlThrows
which calls CreateOrderRequest.builder() with returnUrl("") and other required
fields (merchantReference, notificationUrl, grandTotal, currency,
payment(validPayment())) and asserts a MontonioValidationException with
getField() == "returnUrl"; and implement buildWithBlankNotificationUrlThrows
which sets notificationUrl("") (and provides returnUrl and other required
fields) and asserts getField() == "notificationUrl". Ensure test names match and
reuse validPayment() like the existing tests.
src/main/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequest.java (1)

37-38: Defensively copy lineItems to preserve value-object semantics

lineItems is currently stored by reference, so callers can mutate request contents after build time. Consider copying it on assignment.

Suggested fix
@@
-        this.lineItems = lineItems;
+        this.lineItems = lineItems == null ? null : List.copyOf(lineItems);

Also applies to: 80-80

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

In `@src/main/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequest.java`
around lines 37 - 38, The CreateOrderRequest currently stores the incoming
List<LineItem> lineItems by reference which allows external mutation; change the
constructor/assignment (and any builder method that sets lineItems, e.g., the
builder/setter at or around the code referenced) to defensively copy the
collection (e.g., new ArrayList<>(lineItems)) and store an unmodifiable wrapper
(Collections.unmodifiableList(...)) or null if input is null; likewise ensure
any getter for lineItems returns the unmodifiable list (or a copy) so callers
cannot mutate the internal state.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/plans/2026-04-10-payment-order-models-design.md`:
- Around line 26-31: The fenced code block showing package layout (lines with
"ee.bitweb.montonio.sdk.model/", "ee.bitweb.montonio.sdk.order.model/",
"ee.bitweb.montonio.sdk.order.request/",
"ee.bitweb.montonio.sdk.order.response/") is missing a language tag and triggers
markdownlint MD040; update the opening fence to include a language identifier
(e.g., replace "```" with "```text" or another appropriate language) so the
block is properly annotated while keeping the same content and alignment.

In `@src/main/java/ee/bitweb/montonio/sdk/order/model/Payment.java`:
- Around line 41-43: The current validation in Payment (the null check for
amount) must also enforce that amount > 0; update the validation in the Payment
constructor (and any setAmount / builder method if present) to throw
MontonioValidationException("amount", "must be greater than zero") when
amount.compareTo(BigDecimal.ZERO) <= 0 (after the null check), ensuring zero and
negative values are rejected.

In `@src/main/java/ee/bitweb/montonio/sdk/order/response/OrderResponse.java`:
- Around line 29-30: OrderResponse is not deeply immutable because the List
fields paymentIntents and lineItems are stored and returned by reference; fix by
defensively copying and wrapping them as unmodifiable/immutable collections in
the constructor (e.g., List.copyOf or Collections.unmodifiableList) and return
unmodifiable lists from any getters (getPaymentIntents, getLineItems); apply the
same defensive-copy pattern to the other list fields referenced later in the
class to prevent external mutation.

---

Nitpick comments:
In `@src/main/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequest.java`:
- Around line 37-38: The CreateOrderRequest currently stores the incoming
List<LineItem> lineItems by reference which allows external mutation; change the
constructor/assignment (and any builder method that sets lineItems, e.g., the
builder/setter at or around the code referenced) to defensively copy the
collection (e.g., new ArrayList<>(lineItems)) and store an unmodifiable wrapper
(Collections.unmodifiableList(...)) or null if input is null; likewise ensure
any getter for lineItems returns the unmodifiable list (or a copy) so callers
cannot mutate the internal state.

In `@src/main/java/ee/bitweb/montonio/sdk/order/response/PaymentIntent.java`:
- Around line 24-25: The PaymentIntent DTO stores the incoming Map directly in
the private final field paymentMethodMetadata, allowing external mutation;
update the constructor(s) that accept a Map to defensively copy it (e.g., new
HashMap<>(incomingMap) or Collections.unmodifiableMap(new
HashMap<>(incomingMap))) and likewise return a defensive copy or unmodifiable
view from any accessor (e.g., getPaymentMethodMetadata()) so the PaymentIntent
class remains immutable; apply the same defensive-copy pattern to any other
Map/Collection fields in PaymentIntent.

In
`@src/test/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequestTest.java`:
- Around line 126-156: Add two tests to CreateOrderRequestTest that mirror the
null checks but pass blank strings: implement buildWithBlankReturnUrlThrows
which calls CreateOrderRequest.builder() with returnUrl("") and other required
fields (merchantReference, notificationUrl, grandTotal, currency,
payment(validPayment())) and asserts a MontonioValidationException with
getField() == "returnUrl"; and implement buildWithBlankNotificationUrlThrows
which sets notificationUrl("") (and provides returnUrl and other required
fields) and asserts getField() == "notificationUrl". Ensure test names match and
reuse validPayment() like the existing tests.

In
`@src/test/java/ee/bitweb/montonio/sdk/order/response/CreateOrderResponseTest.java`:
- Around line 43-55: In the deserializesWithUnknownFieldsIgnored test in
CreateOrderResponseTest, after mapping JSON via mapper.readValue into
CreateOrderResponse, add an assertion that response.getPaymentUrl() equals
"https://example.com/pay" (in addition to the existing uuid assertion) so the
test verifies both mapped fields and ensures unknown fields are ignored.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e3800521-9a77-4597-8252-2287cb553e6c

📥 Commits

Reviewing files that changed from the base of the PR and between 20059d3 and fc494d7.

📒 Files selected for processing (30)
  • build.gradle
  • docs/plans/2026-04-10-payment-order-models-design.md
  • src/main/java/ee/bitweb/montonio/sdk/model/CardPaymentMethod.java
  • src/main/java/ee/bitweb/montonio/sdk/model/Currency.java
  • src/main/java/ee/bitweb/montonio/sdk/model/Locale.java
  • src/main/java/ee/bitweb/montonio/sdk/model/PaymentMethodType.java
  • src/main/java/ee/bitweb/montonio/sdk/model/WalletProvider.java
  • src/main/java/ee/bitweb/montonio/sdk/order/model/Address.java
  • src/main/java/ee/bitweb/montonio/sdk/order/model/LineItem.java
  • src/main/java/ee/bitweb/montonio/sdk/order/model/Payment.java
  • src/main/java/ee/bitweb/montonio/sdk/order/model/PaymentMethodOptions.java
  • src/main/java/ee/bitweb/montonio/sdk/order/model/PaymentStatus.java
  • src/main/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequest.java
  • src/main/java/ee/bitweb/montonio/sdk/order/response/CreateOrderResponse.java
  • src/main/java/ee/bitweb/montonio/sdk/order/response/OrderResponse.java
  • src/main/java/ee/bitweb/montonio/sdk/order/response/PaymentIntent.java
  • src/test/java/ee/bitweb/montonio/sdk/model/CardPaymentMethodTest.java
  • src/test/java/ee/bitweb/montonio/sdk/model/CurrencyTest.java
  • src/test/java/ee/bitweb/montonio/sdk/model/LocaleTest.java
  • src/test/java/ee/bitweb/montonio/sdk/model/PaymentMethodTypeTest.java
  • src/test/java/ee/bitweb/montonio/sdk/model/WalletProviderTest.java
  • src/test/java/ee/bitweb/montonio/sdk/order/model/AddressTest.java
  • src/test/java/ee/bitweb/montonio/sdk/order/model/LineItemTest.java
  • src/test/java/ee/bitweb/montonio/sdk/order/model/PaymentMethodOptionsTest.java
  • src/test/java/ee/bitweb/montonio/sdk/order/model/PaymentStatusTest.java
  • src/test/java/ee/bitweb/montonio/sdk/order/model/PaymentTest.java
  • src/test/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequestTest.java
  • src/test/java/ee/bitweb/montonio/sdk/order/response/CreateOrderResponseTest.java
  • src/test/java/ee/bitweb/montonio/sdk/order/response/OrderResponseTest.java
  • src/test/java/ee/bitweb/montonio/sdk/order/response/PaymentIntentTest.java

Comment thread docs/plans/2026-04-10-payment-order-models-design.md Outdated
Comment thread src/main/java/ee/bitweb/montonio/sdk/order/model/Payment.java
- Validate Payment.amount > 0, not just non-null
- Defensive copy for list fields in OrderResponse and CreateOrderRequest
- Defensive copy for map field in PaymentIntent
- Add language tag to design doc code fence
- Add blank-URL validation tests for CreateOrderRequest
- Strengthen CreateOrderResponse unknown-fields test
- Add zero/negative amount validation tests for Payment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@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: 2

🧹 Nitpick comments (1)
docs/plans/2026-04-10-payment-order-models-design.md (1)

82-83: Tighten the deferred-refund wording for clarity.

Consider linking the specific follow-up issue directly to make this sentence clearer and easier to track.

Proposed edit
-`isRefundableType`. Refund-related fields are mostly omitted (only `isRefundableType`
-is included) pending a future refund models issue. Jackson ignores unknown fields.
+`isRefundableType`. Refund-related fields are mostly omitted (only `isRefundableType`
+is included) pending follow-up issue `#30` for refund models. Jackson ignores unknown fields.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/plans/2026-04-10-payment-order-models-design.md` around lines 82 - 83,
The sentence about deferred refund fields is vague; update the wording around
`isRefundableType` to be explicit and add a link/reference to the follow-up
refund models issue (e.g., an issue number or URL) so readers can track it;
mention that refund-related fields are intentionally omitted for now and that
Jackson will ignore unknown fields, and replace "pending a future refund models
issue" with the specific issue reference in the `isRefundableType` paragraph.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequest.java`:
- Around line 62-64: The constructor validation in CreateOrderRequest currently
only checks for null on grandTotal; update the validation in the
CreateOrderRequest constructor (the grandTotal null-check block) to also reject
non-positive values by throwing MontonioValidationException for grandTotal when
grandTotal.compareTo(BigDecimal.ZERO) <= 0 (use a message like "must be greater
than 0") so zero and negative totals fail fast.

In `@src/main/java/ee/bitweb/montonio/sdk/order/response/OrderResponse.java`:
- Around line 29-30: Mark the nullable list fields and their constructor
parameters and accessors explicitly as `@Nullable`: update the OrderResponse class
to annotate the fields paymentIntents and lineItems, the corresponding
constructor parameters (the ones assigning those fields) and their getters with
the project's nullable annotation (e.g., javax.annotation.Nullable or
org.jetbrains.annotations.Nullable) so static analysis and callers know these
lists can be null; repeat the same change for the other nullable list fields
referenced around lines 55-56.

---

Nitpick comments:
In `@docs/plans/2026-04-10-payment-order-models-design.md`:
- Around line 82-83: The sentence about deferred refund fields is vague; update
the wording around `isRefundableType` to be explicit and add a link/reference to
the follow-up refund models issue (e.g., an issue number or URL) so readers can
track it; mention that refund-related fields are intentionally omitted for now
and that Jackson will ignore unknown fields, and replace "pending a future
refund models issue" with the specific issue reference in the `isRefundableType`
paragraph.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9603b529-dd8e-4a75-b488-fe1cd8964c27

📥 Commits

Reviewing files that changed from the base of the PR and between fc494d7 and 35951fe.

📒 Files selected for processing (8)
  • docs/plans/2026-04-10-payment-order-models-design.md
  • src/main/java/ee/bitweb/montonio/sdk/order/model/Payment.java
  • src/main/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequest.java
  • src/main/java/ee/bitweb/montonio/sdk/order/response/OrderResponse.java
  • src/main/java/ee/bitweb/montonio/sdk/order/response/PaymentIntent.java
  • src/test/java/ee/bitweb/montonio/sdk/order/model/PaymentTest.java
  • src/test/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequestTest.java
  • src/test/java/ee/bitweb/montonio/sdk/order/response/CreateOrderResponseTest.java
✅ Files skipped from review due to trivial changes (2)
  • src/main/java/ee/bitweb/montonio/sdk/order/response/PaymentIntent.java
  • src/test/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequestTest.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/test/java/ee/bitweb/montonio/sdk/order/response/CreateOrderResponseTest.java
  • src/test/java/ee/bitweb/montonio/sdk/order/model/PaymentTest.java

- Validate CreateOrderRequest.grandTotal > 0, not just non-null
- Add @nullable to list fields in OrderResponse (paymentIntents, lineItems)
- Reference issue #30 in design doc for deferred refund models
- Add zero/negative grandTotal validation tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

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

🧹 Nitpick comments (1)
src/test/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequestTest.java (1)

93-272: Consider parameterising repeated required-field validation tests.

The null/blank/invalid required-field tests are currently repetitive; a parameterised approach would keep the suite easier to extend and maintain.

♻️ Refactor sketch (JUnit 5 parameterised test)
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
@@
+    private static Stream<Arguments> invalidRequiredFieldCases() {
+        return Stream.of(
+                Arguments.of("merchantReference", (Consumer<CreateOrderRequest.CreateOrderRequestBuilder>) b -> b.merchantReference(null)),
+                Arguments.of("merchantReference", (Consumer<CreateOrderRequest.CreateOrderRequestBuilder>) b -> b.merchantReference("   ")),
+                Arguments.of("returnUrl", (Consumer<CreateOrderRequest.CreateOrderRequestBuilder>) b -> b.returnUrl(null)),
+                Arguments.of("returnUrl", (Consumer<CreateOrderRequest.CreateOrderRequestBuilder>) b -> b.returnUrl("   ")),
+                Arguments.of("notificationUrl", (Consumer<CreateOrderRequest.CreateOrderRequestBuilder>) b -> b.notificationUrl(null)),
+                Arguments.of("notificationUrl", (Consumer<CreateOrderRequest.CreateOrderRequestBuilder>) b -> b.notificationUrl("   ")),
+                Arguments.of("grandTotal", (Consumer<CreateOrderRequest.CreateOrderRequestBuilder>) b -> b.grandTotal(null)),
+                Arguments.of("grandTotal", (Consumer<CreateOrderRequest.CreateOrderRequestBuilder>) b -> b.grandTotal(BigDecimal.ZERO)),
+                Arguments.of("grandTotal", (Consumer<CreateOrderRequest.CreateOrderRequestBuilder>) b -> b.grandTotal(new BigDecimal("-1"))),
+                Arguments.of("currency", (Consumer<CreateOrderRequest.CreateOrderRequestBuilder>) b -> b.currency(null)),
+                Arguments.of("payment", (Consumer<CreateOrderRequest.CreateOrderRequestBuilder>) b -> b.payment(null))
+        );
+    }
+
+    `@ParameterizedTest`
+    `@MethodSource`("invalidRequiredFieldCases")
+    void buildWithInvalidRequiredFieldsThrows(String expectedField,
+                                              Consumer<CreateOrderRequest.CreateOrderRequestBuilder> mutator) {
+        CreateOrderRequest.CreateOrderRequestBuilder builder = CreateOrderRequest.builder()
+                .merchantReference("order-123")
+                .returnUrl("https://example.com/return")
+                .notificationUrl("https://example.com/notify")
+                .grandTotal(BigDecimal.TEN)
+                .currency(Currency.EUR)
+                .payment(validPayment());
+
+        mutator.accept(builder);
+
+        MontonioValidationException exception =
+                assertThrows(MontonioValidationException.class, builder::build);
+        assertEquals(expectedField, exception.getField());
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequestTest.java`
around lines 93 - 272, The tests in CreateOrderRequestTest repeat the same
required-field validation pattern; refactor by replacing the multiple
buildWithXThrows methods with parameterised tests that drive field name, builder
mutations, and expected invalid values: create a `@ParameterizedTest` (e.g.,
testInvalidRequiredFields) with a static Stream<Arguments> provider that yields
tuples of (String expectedField, UnaryOperator<CreateOrderRequest.Builder>
invalidator) and in the test call
invalidator.apply(CreateOrderRequest.builder()...commonValidValues...) .build()
inside assertThrows(MontonioValidationException.class) and
assertEquals(expectedField, exception.getField()); keep the existing helper
validPayment() and reference CreateOrderRequest.builder(),
MontonioValidationException, and getField() to locate code. Ensure providers
cover null/blank/zero/negative cases originally tested.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@src/test/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequestTest.java`:
- Around line 93-272: The tests in CreateOrderRequestTest repeat the same
required-field validation pattern; refactor by replacing the multiple
buildWithXThrows methods with parameterised tests that drive field name, builder
mutations, and expected invalid values: create a `@ParameterizedTest` (e.g.,
testInvalidRequiredFields) with a static Stream<Arguments> provider that yields
tuples of (String expectedField, UnaryOperator<CreateOrderRequest.Builder>
invalidator) and in the test call
invalidator.apply(CreateOrderRequest.builder()...commonValidValues...) .build()
inside assertThrows(MontonioValidationException.class) and
assertEquals(expectedField, exception.getField()); keep the existing helper
validPayment() and reference CreateOrderRequest.builder(),
MontonioValidationException, and getField() to locate code. Ensure providers
cover null/blank/zero/negative cases originally tested.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 89b5eb77-89f3-4cfa-972c-d1453f7e11f8

📥 Commits

Reviewing files that changed from the base of the PR and between 35951fe and b70197f.

📒 Files selected for processing (4)
  • docs/plans/2026-04-10-payment-order-models-design.md
  • src/main/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequest.java
  • src/main/java/ee/bitweb/montonio/sdk/order/response/OrderResponse.java
  • src/test/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequestTest.java
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/ee/bitweb/montonio/sdk/order/response/OrderResponse.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/ee/bitweb/montonio/sdk/order/request/CreateOrderRequest.java

@rammrain
Copy link
Copy Markdown
Member Author

Re: the nitpick about parameterizing the CreateOrderRequestTest validation tests —

I'd prefer to keep the individual test methods for now. They follow the same pattern used in MontonioSdkConfigurationTest (the existing test in this project), where each validation case is its own named method. The advantages:

  • Each test has a descriptive name that shows exactly what fails in test reports
  • Easy to navigate and debug individually
  • Consistent with the existing test style in this codebase

The parameterized approach trades readability for conciseness, which isn't a great tradeoff when we only have ~12 cases and the pattern is established.

All actionable comments from the review have been addressed. The four inline threads are now resolved.

rammrain and others added 3 commits April 10, 2026 08:59
Both branches added dependencies; kept both:
- jakarta.annotation-api (this branch)
- java-jwt (from main)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Assigns @BitWeb/montonio-sdk-maintainers as owners for all key areas:
core SDK source/tests, Gradle build files, GitHub config, and AI tooling.

Partial progress on #6

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@rammrain rammrain merged commit 1d42f8e into main Apr 10, 2026
6 checks passed
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.

Payment order models — requests, responses, and enums

1 participant