Every purchase in Urban Store follows a well-defined order lifecycle managed entirely in MongoDB. Orders are created with a 5-minute payment window; unpaid orders expire automatically and their reserved stock is restored. Paid orders move through a fulfilment pipeline, and any cancellation — whether by an admin or by expiry — triggers an automatic stock restoration to keep inventory accurate.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ALEJ4NDRO2025/urban-store/llms.txt
Use this file to discover all available pages before exploring further.
Order States
pending
Order has been created and is awaiting payment. Stock has already been decremented. The order expires 5 minutes after creation if payment is not completed.
paid
Stripe has confirmed the payment.
paid_at is set to the current timestamp. The order is ready for fulfilment.pending_shipment
Payment confirmed but the order has not yet been handed to a carrier. Set by an admin to indicate the order is being prepared for dispatch.
shipped
The order has been delivered to the carrier. Set by an admin once a tracking number is assigned.
cancelled
The order has been cancelled. Can be reached from
pending, paid, or pending_shipment. Stock is restored on cancellation (see below).Stock Management
On Order Creation
WhenPOST /api/orders/ is called, the order document is saved first, and then stock is decremented immediately afterward. For each OrderItem, the backend builds the variant key "{size}|{color}" and checks stock_by_variant:
0.
On Cancellation — Stock Restoration
When an admin cancels an order viaPATCH /api/orders/<order_id>/status/, the _restore_stock() method is called if the order was not already in pending or cancelled state (those states are treated as having no pending stock deduction to undo on the admin path; expired pending orders are handled separately by the expiry mechanism). The same variant-key logic is applied in reverse:
Passive Expiry — TTL-Based Cancellation
Urban Store uses a passive expiry model. There is no scheduled background task; instead,check_and_cancel_expired_orders() is invoked at the start of every order query (list, detail, admin list):
expires_at (expireAfterSeconds: 0), which can eventually purge the document entirely, but the passive check ensures cancelled status is reflected immediately on next access.
Order Data Model
TheOrder document is stored in the orders MongoDB collection.
Order Fields
| Field | Type | Description |
|---|---|---|
user_id | StringField | Email of the owning user (from JWT) |
order_number | StringField(unique=True) | Human-readable order ID |
items | ListField(EmbeddedDocumentField(OrderItem)) | Line items |
subtotal | FloatField | Sum of all item subtotals |
tax | FloatField(default=0) | Tax amount |
shipping | FloatField(default=0) | Shipping cost |
total | FloatField | Grand total |
status | StringField(default='pending') | Current lifecycle state |
payment_method | StringField | Payment method identifier |
shipping_address | EmbeddedDocumentField(ShippingAddress) | Delivery address |
notes | StringField(default='') | Optional customer notes |
created_at | DateTimeField | Creation timestamp (UTC) |
updated_at | DateTimeField | Last update timestamp (UTC) |
paid_at | DateTimeField | Set when status becomes paid |
payment_intent_id | StringField | Stripe PaymentIntent ID |
expires_at | DateTimeField | Expiry time for pending orders (5 min after creation) |
OrderItem Fields
| Field | Type | Description |
|---|---|---|
product_slug | StringField(required=True) | Product reference |
product_name | StringField | Display name at time of purchase |
quantity | IntField(required=True) | Units ordered |
size | StringField | Selected size |
color | StringField | Selected color |
price_paid | FloatField(required=True) | Unit price at time of purchase |
subtotal | FloatField(required=True) | price_paid × quantity |
ShippingAddress Fields
| Field | Type | Description |
|---|---|---|
email | StringField(required=True) | Contact email |
name | StringField(required=True) | Recipient full name |
phone | StringField(required=True) | Contact phone number |
address | StringField(required=True) | Street address |
city | StringField(required=True) | City |
department | StringField(required=True) | Department / state / province |
country | StringField(default='Colombia') | Country (defaults to Colombia) |
Order Number Format
Order numbers are generated byOrder.generate_order_number():
ORD-20260115143022-847
This gives a human-readable, roughly chronologically sortable identifier with very low collision probability.
Confirmation Email
A styled HTML confirmation email is sent via Django’ssend_mail immediately after a successful order creation. The email includes:
- Order number
- Itemized product list (name, size, color, quantity, subtotal)
- Subtotal, shipping, taxes, and grand total
- Full shipping address
The email is sent synchronously during the request. If the mail backend raises an exception (because
fail_silently=False), the order creation request will fail. Ensure EMAIL_BACKEND and DEFAULT_FROM_EMAIL are correctly configured in Django settings.API Endpoints
| Method | Endpoint | Access | Description |
|---|---|---|---|
POST | /api/orders/ | Authenticated user | Create a new order |
GET | /api/orders/ | Authenticated user | List own orders |
GET | /api/orders/<order_id>/ | Authenticated user or admin | Get order detail |
GET | /api/orders/all/ | Admin only | List all orders |
PATCH | /api/orders/<order_id>/status/ | Admin only | Update order status |