RentOne Commerce Service — Business Flow Documentation
Service:
commerce-service
Port: 6008
Stack: Spring Boot 3.5.6 · Java 21 · MongoDB · Eureka · OpenFeign
Architecture: Multi-tenant, JWT-authenticated REST microservice
Service Overview
The Commerce Service is the transactional core of the RentOne platform. It owns the full rental lifecycle: browsing intent (wishlist) → selection (cart) → pricing → checkout → payment → fulfilment (delivery) → ongoing subscription billing → invoicing and history. All data is tenant-isolated; the JWT filter resolves the correct MongoDB connection per tenant on every request.
Infrastructure Topology
Client → API Gateway → commerce-service (:6008)
│
┌────────────────┼─────────────────────┐
▼ ▼ ▼
rentone-product-catalog payment-gateway notifications
▼ ▼
inventory-system operation-service
▼
rentone-users
MongoDB Collections
| Collection | Description |
|---|---|
user_carts |
Active shopping carts per user/tenant |
users_wishlist |
Saved wishlist items per user |
user_addresses |
User delivery addresses (geo-indexed) |
order_draft |
Pre-payment checkout snapshots |
orders |
Confirmed rental orders + subscription state |
delivery_assignments |
Delivery partner assignments |
invoices |
Invoice records with URLs |
order_history |
Immutable audit trail of order state changes |
db_sequences |
MongoDB-based auto-increment counters |
1. Customer Cart Flow
Flow Description
A customer adds rental items (variants or pre-configured packages) to their cart. The cart is created on first add. Each save recalculates a live pricing summary. The cart persists until an order is placed and payment succeeds, at which point it is deleted.
REST Endpoints
| Method | Path | Description |
|---|---|---|
POST |
/cart/v1/add |
Add item to cart |
PUT |
/cart/remove-item |
Remove a single cart item |
PUT |
/cart/update/quantity-and-tenure |
Update quantity or rental tenure |
GET |
/cart/get/by-user-id |
Retrieve full cart |
POST |
/cart/pricing/preview |
Preview pricing without persisting |
GET |
/cart/check-exist-in-cart |
Single item existence check |
GET |
/cart/check-exist-in-cart/bulk |
Bulk existence check |
Business Rules
- One cart per
(userId, tenantId)combination. A second add merges quantities if the same(itemType, variantId/packageId, selectedTenure)already exists. - PACKAGE items require both
packageIdandselectedTenure. The price is fetched live fromrentone-product-catalogand must match an active package'sTenurePricingmap. - VARIANT items require
variantIdand must carry apricePerMonth. - Removing the last item from a cart deletes the cart document entirely.
- Setting quantity ≤ 0 on update is treated as a remove.
- Pricing is recalculated and persisted on every mutating operation.
Validation Rules
itemTypeis mandatory on add.packageIdrequired whenitemType = PACKAGE.selectedTenurerequired whenitemType = PACKAGE; must exist in the package'stenurePricingmap.variantIdrequired whenitemType = VARIANT.- Package must be
active = true. quantitydefaults to 1 if null.
Flowchart
flowchart TD
A[Customer] --> B[Add Item to Cart]
B --> C[Validate Request]
C --> D{Cart Exists?}
D -- No --> E[Create New Cart]
D -- Yes --> F[Load Existing Cart]
E --> G{Package Item?}
F --> G
G -- Yes --> H[Fetch Package & Validate Tenure]
G -- No --> I[Use Variant Details]
H --> J{Duplicate Item?}
I --> J
J -- Yes --> K[Merge Quantity]
J -- No --> L[Add New Item]
K --> M[Recalculate Pricing]
L --> M
M --> N[Save Cart]
N --> O[Return Success]
Data Flow Diagram
CartItemRequest ──► CartService ──► [ProductCatalog if PACKAGE]
│
├──► merge/add CartItem to cart.items[]
│
└──► PricingEngine.calculatePricing()
│
└──► save Cart to user_carts
External Service Dependencies
rentone-product-catalog—GET /product/packages/get/by-id(PACKAGE adds and quantity/tenure updates)
Error Scenarios
| Scenario | Response |
|---|---|
itemType missing |
false, "ItemType required" |
| Package not found in catalog | false, "Package not found" |
| Package inactive | false, "Package not active" |
| Invalid tenure for package | false, "Invalid tenure for package" |
variantId missing for VARIANT |
false, "VariantId required" |
| Cart not found on remove/update | false, "Cart not found" |
| Cart item not found | false, "Cart item not found" |
2. Customer Wishlist Flow
Flow Description
Customers save items for later consideration. A wishlist is created on first add. Items can be moved directly to the cart in bulk. Empty wishlists are automatically deleted.
REST Endpoints
| Method | Path | Description |
|---|---|---|
POST |
/wishlist/add |
Add item to wishlist |
DELETE |
/wishlist/remove/item |
Remove item from wishlist |
GET |
/wishlist/get |
Retrieve full wishlist |
POST |
/wishlist/move-to-cart |
Move selected items to cart |
GET |
/wishlist/check-exist-in-wishlist |
Single item check |
GET |
/wishlist/check-exist-in-wishlist/bulk |
Bulk existence check |
Business Rules
- One wishlist per
userId. Wishlists are not tenant-scoped. - Duplicate detection: for PACKAGE items, match on
packageId; for VARIANT items, match onvariantId. - Adding a VARIANT triggers
recordWishlist()onrentone-product-catalogfor popularity tracking. move-to-cartprocesses each selectedwishlistItemId, callsCartService.addToCart()for each, then removes successfully moved items from the wishlist.- If the wishlist becomes empty after remove or move, it is deleted.
Validation Rules
- Duplicate items are rejected:
false, "Item already exists in wishlist". - Move-to-cart with no
wishListItemIdsis rejected:false, "No wishlist items selected". wishlistItemIdthat does not exist is silently skipped during bulk move.
Flowchart
flowchart TD
A[Customer] --> B{Action}
B -- Add Item --> C[Load or Create Wishlist]
C --> D{Already in Wishlist?}
D -- Yes --> E[Reject Duplicate]
D -- No --> F[Save Item to Wishlist]
F --> G{Variant Item?}
G -- Yes --> H[Record Wishlist Stat in Catalog]
G -- No --> I[Done]
H --> I
B -- Move to Cart --> J[Load Wishlist]
J --> K[Add Each Selected Item to Cart]
K --> L[Remove Moved Items from Wishlist]
L --> M{Wishlist Empty?}
M -- Yes --> N[Delete Wishlist]
M -- No --> O[Save Wishlist]
MongoDB Collections Used
users_wishlist
External Service Dependencies
rentone-product-catalog—POST /variant-stats/record-wishlist(VARIANT adds only)
Error Scenarios
| Scenario | Response |
|---|---|
| Item already in wishlist | false, "Item already exists in wishlist" |
| Wishlist not found on remove | false, "Wishlist is empty" |
| Item not found on remove | false, "Item not found in wishlist" |
| Empty wishlist on move | false, "Wishlist is empty" |
| No item ids on move | false, "No wishlist items selected" |
3. Address Management Flow
Flow Description
Customers manage delivery addresses. Each address stores geospatial coordinates (GeoJsonPoint) and a Google Places reference. The first address saved is automatically marked as default. Marking a new address as default unsets the previous default.
REST Endpoints
| Method | Path | Description |
|---|---|---|
POST |
/addresses/save |
Create address |
PUT |
/addresses/update |
Update existing address |
DELETE |
/addresses/delete |
Delete address by id |
GET |
/addresses/get-all |
Paginated list by userId |
GET |
/addresses/get/by-user-and-address-id |
Single address lookup |
GET |
/addresses/get/default |
Get default address |
Business Rules
- Address ID is a Long generated via
SequenceGeneratorService(MongoDB counter:address_sequence). - If a user has no existing addresses, the new address is forced to
defaultAddress = true. - Switching default: the existing default is set to
falsebefore the new one is set totrue. saveInternalis used by bulk upload flows; same validation, no HTTP request object required.- GeoJsonPoint uses
[longitude, latitude]ordering (GeoJSON standard).
Validation Rules
Required fields on save: userId, name, phone, line1, city, state, pincode.
Missing any required field → false, "Required Fields Missing".
Flowchart
flowchart TD
A[Customer] --> B[Submit Address]
B --> C[Validate Required Fields]
C --> D{First Address?}
D -- Yes --> E[Force Set as Default]
D -- No --> F{Mark as Default?}
F -- Yes --> G[Unset Previous Default]
F -- No --> H[Keep Existing Default]
G --> I[Generate Address ID]
E --> I
H --> I
I --> J[Save Address]
J --> K[Return Saved Address]
MongoDB Collections Used
user_addresses(geo-spatial index onlocation)db_sequences(counter:address_sequence)
External Service Dependencies
operation-service—GET /maps/place-details(used for Google Maps place resolution, called optionally viaOperationServiceProxy)
Error Scenarios
| Scenario | Response |
|---|---|
| Required field missing | false, "Required Fields Missing" |
| Address not found on update | false, "Address Not Found" |
| Address not found on delete | false, "Address Not Found" |
| No addresses found | false, "Address Not Found" |
| Default address not found | false, "Default Address Not Found" |
4. Order Draft Flow
Flow Description
An Order Draft is a pre-payment snapshot of the intended order. It is created during checkout, holds all order items (including expanded package variants), the chosen delivery address (embedded), and a computed pricing summary. It is the bridge between the cart and the payment gateway. The draft is deleted once payment succeeds and the real order is persisted.
Business Rules
- Draft ID is a UUID string.
- The cart must not be empty.
- A valid delivery address must be selected.
payableNowmust be > 0; otherwise checkout is rejected.- PACKAGE cart items: package details are fetched from
rentone-product-catalogand eachPackageItemis snapshotted intoPackageVariantSnapshot. - Non-package items get a tenure adjustment applied to
finalPricePerMonth: - 3 months: +20%
- 6 months: +10%
- 12 months: 0% (baseline)
- 18 months: -10%
- 24 months: -20%
- PACKAGE prices are not tenure-adjusted at draft time (already adjusted at catalog level).
- Draft initial status:
PENDING_PAYMENT.
Flowchart
flowchart TD
A[Customer Initiates Checkout] --> B[Load Customer Cart]
B --> C{Cart Empty?}
C -- Yes --> D[Reject: Cart Empty]
C -- No --> E[Load Delivery Address]
E --> F{Address Valid?}
F -- No --> G[Reject: No Address]
F -- Yes --> H[Map Cart Items to Order Items]
H --> I[Apply Tenure Price Adjustment]
I --> J{Package Item?}
J -- Yes --> K[Fetch & Snapshot Package Variants]
J -- No --> L[Use Variant Details]
K --> M[Calculate Pricing Summary]
L --> M
M --> N{Payable Amount Valid?}
N -- No --> O[Reject: Invalid Pricing]
N -- Yes --> P[Save Order Draft]
P --> Q[Return Draft to Checkout]
MongoDB Collections Used
order_draft
External Service Dependencies
rentone-product-catalog—GET /product/packages/get/by-id(for each PACKAGE cart item)
Error Scenarios
| Scenario | Response |
|---|---|
| Cart empty or not found | false, "Cart is empty or not found" |
| Address not selected | false, "Please select a delivery address" |
| Package not found in catalog | RuntimeException: "Package not found while creating draft" |
| Pricing is zero or invalid | false, "Invalid pricing. Please try again." |
| Draft not found on fetch | false, "Draft not found" |
5. Order Creation Flow
Flow Description
Order creation is driven by payment verification. After the customer completes payment via the gateway, the gateway webhook calls /orders/payment/status. The service verifies the amount, creates the Orders document, expands cart items by quantity (each physical unit becomes a distinct OrderItem), records order stats to the product catalog, initialises order history, deletes the cart and draft, and fires notifications.
REST Endpoints
| Method | Path | Description |
|---|---|---|
POST |
/orders/checkout |
Initiate checkout (create draft + payment intent) |
POST |
/orders/payment/status |
Payment gateway callback |
POST |
/orders/cancel |
Cancel a confirmable order |
POST |
/orders/payment/manual |
Record manual/offline payment |
GET |
/orders/get/by-user-id |
Customer order history |
GET |
/orders/get/all |
Admin paginated order list |
GET |
/orders/get/by-id |
Single order detail (with delivery/history) |
GET |
/orders/get/active-rentals |
Active subscriptions for a user |
GET |
/orders/get/overdue-orders |
All overdue orders (scheduled task use) |
Business Rules
- Order ID format: generated by
OrderIdGeneratorUtil(custom format, not UUID). - Idempotency:
existByCartId(cartId)check prevents duplicate orders from duplicate callbacks. - Amount verification:
payableNowfrom draft must exactly matchresponse.amount; mismatch throws exception. - Payment failure: draft status set to
PAYMENT_FAILED, no order created. - On success: items are expanded by quantity — each unit gets a new UUID
cartItemId. PACKAGE items are further expanded perPackageItem × quantity. productCatalogProxy.recordOrder()is called for every expanded variant to update inventory stats.- Initial subscription:
billingCycle = MONTHLY,nextPaymentDate = +1 month,subscriptionStatusis set to ACTIVE on delivery. - Cancellable statuses:
PAID,CONFIRMED,SCHEDULED. Cancellation triggerspaymentGatewayProxy.refundPayment(). - Cart and draft documents are deleted after successful order creation.
Validation Rules
payableNowamount must match payment callback amount exactly.- Order must exist for cancellation; must be in a cancellable status.
- Cancellation requires at least one
PaymentStatus.SUCCESSpayment record.
Flowchart
flowchart TD
A[Customer Checks Out] --> B[Create Order Draft]
B --> C[Initiate Payment via Gateway]
C --> D[Return Payment Intent to Customer]
D --> E[Customer Completes Payment]
E --> F[Gateway Sends Payment Result]
F --> G{Duplicate Order?}
G -- Yes --> H[Return Already Processed]
G -- No --> I{Payment Successful?}
I -- No --> J[Mark Draft as Failed]
I -- Yes --> K[Verify Amount Match]
K --> L[Create Order Record]
L --> M[Expand Items by Quantity]
M --> N[Record Stats in Product Catalog]
N --> O[Create Order History]
O --> P[Delete Cart & Draft]
P --> Q[Notify Customer]
MongoDB Collections Used
order_draft(read + delete)user_carts(delete)orders(create)order_history(create)
External Service Dependencies
payment-gateway—POST /rentone/payment-gateway/payment/initiatepayment-gateway—POST /rentone/payment-gateway/refund-payment(on cancel)rentone-product-catalog—POST /variant-stats/record-ordernotifications—POST /app-notifications/create
Error Scenarios
| Scenario | Response |
|---|---|
| Cart empty | RuntimeException from draft creation |
| Amount mismatch | RuntimeException: "Payable amount mismatch" |
| Duplicate callback | true, "Order already processed" |
| Draft not found on callback | RuntimeException: "Draft not found" |
| Order not found on cancel | false, "Order not found" |
| Non-cancellable status | false, "Order cannot be cancelled when status is X" |
| No successful payment for refund | false, "Payment record not found for order" |
| Refund initiation failed | false, "Refund initiation failed" |
6. Pricing Calculation Flow
Flow Description
Pricing is computed by DefaultPricingEngine on every cart mutation, at draft creation, and on demand via the preview endpoint. It produces a CartPricing object covering checkout amounts, recurring monthly amounts, GST, deposit, and delivery charge.
Business Rules
Tenure-based price adjustments (VARIANT items only):
| Tenure (months) | Adjustment |
|---|---|
| 3 | +20% |
| 6 | +10% |
| 12 | 0% (baseline) |
| 18 | -10% |
| 24 | -20% |
GST: 18% GST is baked into the monthly rent. Extracted as: GST = amount - (amount / 1.18).
Delivery charge: Free if monthlyRent ≥ ₹500; otherwise ₹500 flat.
Deposit: Sum of depositAmount × quantity across all items.
payableNow = monthlyRent (first month paid at checkout; deposit is tracked separately via DepositInfo).
Estimated delivery: current date + 3 days.
Overdue penalty:
- 1–5 days overdue: flat ₹100
- Beyond 5 days: ₹100 × (floor(daysOverdue / 30) + 1) (i.e. ₹100 per month, minimum ₹100)
Recalculation on item return/maintenance: updateOrderItemsBillingStatus marks individual OrderItem.active = false, recalculates monthly pricing based only on active items, and updates SubscriptionStatus accordingly.
Flowchart
flowchart TD
A[Cart Items] --> B[Calculate Monthly Rent per Item]
B --> C{Item Type?}
C -- Variant --> D[Apply Tenure Adjustment]
C -- Package --> E[Use Price As-Is]
D --> F[Sum Total Monthly Rent]
E --> F
F --> G[Extract 18% GST from Total]
F --> H{Total Under ₹500?}
H -- Yes --> I[Add ₹500 Delivery Charge]
H -- No --> J[Free Delivery]
F --> K[Sum Deposit Amount]
G --> L[Build Pricing Summary]
I --> L
J --> L
K --> L
L --> M[Return CartPricing]
Data Flow Diagram
List<CartItem>
│
▼
[Per item: pricePerMonth × quantity] ──── VARIANT: apply tenure adjustment
──── PACKAGE: no adjustment
│
▼
totalMonthlyRent
├──► gstAmount = total − (total / 1.18)
├──► payableNow = totalMonthlyRent
└──► deliveryCharge = (total < 500) ? 500 : 0
totalDeposit = Σ(depositAmount × quantity)
Error Scenarios
| Scenario | Behaviour |
|---|---|
pricePerMonth is null |
Item skipped in calculation |
quantity is null or ≤ 0 |
Item skipped |
VARIANT with null selectedTenure |
Item skipped (no tenure = no adjustment, item excluded) |
| Empty cart | All fields return "0" |
7. Rental Subscription Flow
Flow Description
After an order is delivered, its subscriptionStatus is set to ACTIVE. Each month the customer pays their monthlyPayable. Overdue detection runs via a scheduled task that queries findActiveOrdersBeforeDate(today). Overdue orders accumulate a penalty added to the next payment. Manual payments (cash/offline) are recorded via an admin endpoint.
REST Endpoints
| Method | Path | Description |
|---|---|---|
POST |
/orders/payment/monthly |
Initiate monthly rent payment |
POST |
/orders/payment/status |
Gateway callback (shared, moduleName = RENTAL_MONTHLY) |
POST |
/orders/payment/manual |
Record manual payment |
GET |
/orders/get/overdue-orders |
List overdue subscriptions (public, no auth) |
GET |
/orders/get/active-rentals |
Customer's active rentals |
Subscription Status Values
| Status | Meaning |
|---|---|
ACTIVE |
Paid and current |
OVERDUE |
Payment due date passed |
PAUSED |
All items returned/inactive |
CANCELLED |
Order cancelled |
COMPLETED |
Tenure expired |
Business Rules
nextPaymentDateadvances by exactly 1 calendar month on each successful payment.- Penalty is applied only when
System.currentTimeMillis() > nextPaymentDate.getTime(). failedPaymentCountincrements on failed gateway attempts; resets to 0 on success.overdueNotifiedflag prevents duplicate overdue notifications; reset tofalseon payment.- Manual payments use transaction ID prefix
API_MONTHLY_+ timestamp; these are excluded from the monthly payment dashboard "paid" totals. - CSV-imported payments use prefix
CSV_; also excluded from dashboard. updateOrderItemsBillingStatusis called by the Operations service when items are returned or placed under maintenance to recalculate billing from active items only.
Flowchart
flowchart TD
A[Customer Pays Monthly Rent] --> B[Load Active Order]
B --> C{Payment Overdue?}
C -- Yes --> D[Calculate Penalty]
C -- No --> E[No Penalty]
D --> F[Total = Monthly Rent + Penalty]
E --> F
F --> G[Initiate Payment via Gateway]
G --> H[Customer Completes Payment]
H --> I{Payment Successful?}
I -- No --> J[Record Failed Attempt]
I -- Yes --> K[Append Payment Record]
K --> L[Advance Next Payment Date +1 Month]
L --> M[Reset Overdue Flags]
M --> N[Mark Subscription Active]
MongoDB Collections Used
orders
External Service Dependencies
payment-gateway—POST /rentone/payment-gateway/payment/initiatepayment-gateway— callback to/orders/payment/status
Error Scenarios
| Scenario | Response |
|---|---|
| Order not found | RuntimeException: "Order not found for monthly payment" |
| Amount mismatch | RuntimeException: "Monthly rent mismatch" |
| Payment gateway failure | false, "Monthly payment failed" |
8. Delivery Assignment Flow
Flow Description
Once an order reaches CONFIRMED status, an admin or the system assigns it to a delivery partner. The assignment progresses through ASSIGNED → OUT_FOR_DELIVERY → DELIVERED. Each stage transition updates both the delivery_assignments collection and the parent orders.status via OrderStatusSyncService, and fires push notifications to the partner and customer.
Business Rules
- Only
CONFIRMEDorders can be assigned. - Duplicate assignment is prevented by checking if a
DeliveryAssignmentalready exists for theorderId. - Reassignment is only allowed when current status is
ASSIGNED; cannot reassign to the same partner. - Status progression is strictly linear:
ASSIGNED → OUT_FOR_DELIVERY → DELIVERED. - A
DELIVEREDorCANCELLEDassignment cannot be advanced. assignTypeisMANUAL(admin-assigned) orAUTOMATIC(system-assigned).- Address is snapshotted from the order's
EmbeddedAddressat time of assignment. OrderStatusSyncServicemaps assignment statuses to order statuses:ASSIGNED→OrderStatus.SCHEDULEDOUT_FOR_DELIVERY→OrderStatus.OUT_FOR_DELIVERYDELIVERED→OrderStatus.DELIVERED+subscriptionStatus = ACTIVE
Flowchart
flowchart TD
A[Admin Assigns Order to Partner] --> B{Order Status Confirmed?}
B -- No --> C[Reject: Must be Confirmed]
B -- Yes --> D{Already Assigned?}
D -- Yes --> E[Reject: Duplicate Assignment]
D -- No --> F[Create Delivery Assignment]
F --> G[Notify Delivery Partner]
G --> H[Partner Updates Status]
H --> I{Current Status?}
I -- Assigned --> J[Mark Out for Delivery]
I -- Out for Delivery --> K[Mark Delivered]
J --> L[Sync Order Status]
K --> M[Activate Subscription]
L --> N[Update Order History]
M --> N
N --> O[Notify Customer]
MongoDB Collections Used
delivery_assignmentsordersorder_history
External Service Dependencies
notifications—POST /app-notifications/create(ORDER_ASSIGNED, OUT_FOR_DELIVERY, ORDER_DELIVERED)
Error Scenarios
| Scenario | Response |
|---|---|
| Order not CONFIRMED | false, "Order must be CONFIRMED before assignment" |
| Duplicate assignment | false, "Order Already Assigned" |
| Assignment not found on reassign | false, "Delivery Assignment Not Found" |
| Reassign to same partner | false, "cannot be re-assigned to the same partner" |
| Non-ASSIGNED status on reassign | false, "Cannot reassign order in X state" |
| Assignment not found on update | false, "Delivery Assignment Not found" |
| Already delivered | false, "Order is already delivered" |
| Assignment cancelled | false, "Cannot update status of a cancelled assignment" |
| Invalid status transition | false, "Cannot move to OUT_FOR_DELIVERY from X" |
9. Invoice Generation Flow
Flow Description
Invoices are generated externally (PDF likely by a batch/admin process) and their URLs are stored in the invoices collection. The Commerce Service provides CRUD endpoints and a bulk URL lookup used to enrich order list responses with invoice links.
REST Endpoints (via InvoiceController)
| Method | Path | Description |
|---|---|---|
POST |
/invoices/save |
Persist invoice URL for an order |
GET |
/invoices/get/by-order-id |
Retrieve invoice URL by orderId |
GET |
/invoices/get/all |
Paginated admin invoice list |
Invoice ID Format
INV + yyyyMMdd + auto-increment sequence number
Example: INV202406240042
Business Rules
- Invoice ID is generated by
SequenceGeneratorServiceusing counterinvoice_sequence. - One invoice per order. The invoice URL is a hosted file link (S3/CDN).
- Order lists (
getAllOrders,getActiveRentals) automatically hydrateinvoiceUrlon each order via a bulkgetInvoiceUrlsByOrderIds()call. - Date filtering uses
dd-MM-yyyy HH:mmformat (Asia/Kolkata timezone).
Flowchart
flowchart TD
A[Admin Saves Invoice URL] --> B[Generate Invoice ID]
B --> C[Format: INV + Date + Sequence]
C --> D[Save Invoice Record]
D --> E[Return Invoice Response]
F[Order List Request] --> G[Collect Order IDs]
G --> H[Bulk Lookup Invoice URLs]
H --> I[Attach URL to Each Order]
I --> J[Return Enriched Order List]
K[Customer Requests Invoice] --> L{Invoice Exists?}
L -- Yes --> M[Return Invoice URL]
L -- No --> N[Return Not Found]
MongoDB Collections Used
invoicesdb_sequences(counter:invoice_sequence)
External Service Dependencies
None — invoice PDF generation is external to this service.
Error Scenarios
| Scenario | Response |
|---|---|
| Invoice not found by orderId | false, "Invoice Not Found" |
| No invoices in search result | false, "Invoices Not Found" |
10. Order History Flow
Flow Description
OrderHistory is an immutable audit log created at order placement and extended at every status change. It records who made the change, when, why, and what delivery partner (if any) was involved. It is the source of truth for order tracking.
Business Rules
- History document ID:
"HIS-" + orderId. - Each
OrderStageMgmtentry tracks:status,isCurrentStatus,changedAt,updatedBy,reason,assignType,deliveryPartnerId. - On each stage add, the previous current stage's
isCurrentStatusis set tofalse. - Created at order placement with status
PAID,updatedBy = SYSTEM_USER. - Subsequently added by
OrderStatusSyncServiceon each delivery assignment transition.
REST Endpoints
| Method | Path | Description |
|---|---|---|
GET |
/order-history/get/by-order-id |
Full history for an order |
GET |
/orders/track/{orderId} |
Customer-facing order tracking |
Flowchart
flowchart TD
A[Order Placed] --> B[Create History Record]
B --> C[Record Initial Stage: PAID]
C --> D[Save Order History]
E[Status Change Event] --> F[Load Order History]
F --> G[Mark Previous Stage Inactive]
G --> H[Append New Stage]
H --> I[Record Who Changed & Why]
I --> J[Save Updated History]
K[Customer Tracks Order] --> L[Load Order History]
L --> M[Return All Stages in Sequence]
MongoDB Collections Used
order_history
External Service Dependencies
None.
Error Scenarios
| Scenario | Response |
|---|---|
| History not found on fetch | false, "Order History not found" |
| History not found on addStage | false, "Order History not found" |
| Track — history not found | false, "Order History not fount" |
Cross-Cutting Concerns
Authentication & Multi-Tenancy
All requests require an X-Tenant-ID header. The JwtAuthenticationFilter resolves the tenant's MongoDB connection string (from a tenant registry service, cached in-memory per JVM), sets it on a thread-local MongoConnectionStorage, and clears it after the request. Protected routes additionally require a Bearer token in the Authorization header.
Public (unauthenticated) endpoints:
- GET /orders/get/overdue-orders
- POST /cart/pricing/preview
- GET /cart/check-exist-in-cart
- GET /wishlist/check-exist-in-wishlist
Error Reporting
MainExceptionHandler is a global @ControllerAdvice that:
1. Prints the stack trace.
2. Finds the first stack frame within the RentOne package to extract filename and line number.
3. Constructs an ErrorContext and calls notificationsProxy.reportError() to the Notifications service.
4. Returns 500 INTERNAL_SERVER_ERROR with { success: false, message: "Something went wrong" }.
Sequence ID Generation
SequenceGeneratorService uses MongoDB's findAndModify with upsert: true to atomically increment a counter in the db_sequences collection. Used for: address_sequence, invoice_sequence, delivery_assignment_sequence.
Full Entity Reference
Orders (collection: orders)
id String Custom order ID (OrderIdGeneratorUtil)
tenantId String
userId String
cartId String Reference to source cart
items OrderItem[] Expanded by quantity
address EmbeddedAddress Snapshot at order time
shippingMethod String
pricingSummary CartPricing Snapshot at checkout
depositInfo DepositInfo Cash/offline deposit tracking
billingCycle MONTHLY
subscriptionStatus ACTIVE | PAUSED | CANCELLED | COMPLETED | OVERDUE
nextPaymentDate Date Advances +1 month per payment
failedPaymentCount int
overdueNotified boolean
reminderNotified boolean
lastPaymentAttempt Date
paymentInfo PaymentInfo[] Appended on each payment
status OrderStatus (see enum below)
remark String
createdAt / updatedAt Date
invoiceUrl @Transient (hydrated at read time)
OrderItem (embedded in Orders and OrderDraft)
cartItemId String (UUID per unit after expansion)
itemType PACKAGE | VARIANT
packageId Long
packageItems PackageVariantSnapshot[]
variantId Long
productId Long
variantSku String
variantName String
pricePerMonth String Catalog base price
finalPricePerMonth String After tenure adjustment
adjustmentAmount String Adjustment delta
depositAmount String
quantity Integer Always 1 after expansion
selectedTenure Long Months
itemValidTill Date
active boolean false = excluded from billing
image String
CartPricing (embedded pricing object)
deposit String
deliveryCharge String
payableNow String = monthlyRent (charged at checkout)
monthlyRent String
gstAmount String 18% extracted from monthlyRent
monthlyPayable String = monthlyRent
discount String Tenure adjustment total
couponApplied String (reserved, not implemented)
estimatedDeliveryDate Date +3 days from calculation
penalty @Transient computed at read time
Order Status State Machine
DRAFT → PENDING_PAYMENT → PAYMENT_FAILED
→ PAID → CONFIRMED → SCHEDULED → OUT_FOR_DELIVERY → DELIVERED
→ CANCELLED → REFUNDED
Delivery Assignment Status Machine
ASSIGNED → OUT_FOR_DELIVERY → DELIVERED
→ CANCELLED
External Microservice Dependency Map
| Proxy | Service Name (Eureka) | Key Calls from Commerce |
|---|---|---|
ProductCatalogProxy |
rentone-product-catalog |
Get package by ID, record-order, record-wishlist, get variant/product/category maps |
PaymentGatewayProxy |
payment-gateway |
Initiate payment, refund payment |
NotificationsProxy |
notifications |
Report error, create push notifications |
OperationServiceProxy |
operation-service |
Get delivery partner by ID, get place details, get return/maintenance active order IDs |
InventoryProxy |
inventory-system |
Bulk upload inventory items (bulk order import) |
UsersProxy |
rentone-users |
Create internal users, get total user count, submit KYC |
Document generated from source analysis of commerce-service v0.0.1-SNAPSHOT · Spring Boot 3.5.6 · Java 21