Order Management
The Order Management submodule handles order tracking, product-specific fulfillment timelines, onboarding status management, and invoice retrieval for the DashClicks Store platform.
API Endpoints Overview
| Method | Endpoint | Description |
|---|---|---|
GET | /v1/store/orders | Get orders with advanced filtering |
GET | /v1/store/orders/my-orders | Get my orders with onboarding status |
GET | /v1/store/orders/my-forms | Get onboarding forms for sub-account |
GET | /v1/store/orders/:id | Get specific order details |
GET | /v1/store/orders/:id/timeline | Get order fulfillment timeline |
GET | /v1/store/orders/:id/status | Get current order status |
GET | /v1/store/orders/:id/invoices | Get all invoices for order's subscription |
MongoDB Collections Used
Primary Collections
_store.orders- Order records with product and fulfillment data_store.subscriptions- Linked subscriptions for orders_store.products- Product information_store.prices- Pricing details_accounts- Account relationshipscrm.contacts- Business contact informationprojects-typeforms- Onboarding form requestsprojects-typeform.responses- Form submission data
Related Collections
_store.invoices- Invoice recordsqueues- Fulfillment job statusprojects.tasks- Service delivery tasksprojects.pulse- Project status updates
Core Order Workflows
Order Creation Flow
graph TD
A[Checkout Complete] --> B[Create Order Record]
B --> C[Link Subscription]
C --> D[Store Product Metadata]
D --> E[Initialize Status: pending]
E --> F{Requires Onboarding?}
F -->|Yes| G[Create Typeform Request]
F -->|No| H[Queue Fulfillment Job]
G --> I[Send Onboarding Invite]
I --> H
H --> J[Update Status: processing]
J --> K[Track Fulfillment Progress]
Onboarding Status Flow
graph TD
A[Order Created] --> B{Onboarding Required?}
B -->|No| C[Status: approved]
B -->|Yes| D[Create Typeform]
D --> E[Status: pending]
E --> F[Send Invite Email]
F --> G{Form Submitted?}
G -->|No| H[Status: sent]
G -->|Yes| I[Status: received]
I --> J{Needs Review?}
J -->|Yes| K[Status: verification]
J -->|No| L[Status: approved]
K --> M{Issues Found?}
M -->|Yes| N[Status: issues]
M -->|No| L
N --> O[Request Revision]
O --> I
Service Methods & Functionality
Order Retrieval
getMyOrders(req, res, next) - Retrieve orders with advanced filtering
-
Purpose: Get orders with comprehensive filtering, pagination, and onboarding status
-
Query Parameters:
start_date(String): Start date for date range filterend_date(String): End date for date range filteronboarding_status(String): Filter by onboarding stagepending: Form not sent or not submittedverification: Form submitted, awaiting reviewissues: Issues found in submissionapproved: Approved and ready for fulfillment
product(String): Filter by product typeorder_status(String): Filter by order statussearch(String): Text search across order fieldssort_by(String): Sort field (default:created_at)order(String): Sort direction (asc|desc)page(Number): Page number for paginationlimit(Number): Items per page
-
Business Logic:
-
Complex Aggregation Pipeline:
[
// Filter by account
{ $match: { account_id: ObjectId(account_id) } },
// Lookup subscription
{
$lookup: {
from: '_store.subscriptions',
localField: 'subscription',
foreignField: '_id',
as: 'subscription_data',
},
},
// Lookup product
{
$lookup: {
from: '_store.products',
localField: 'product',
foreignField: '_id',
as: 'product_data',
},
},
// Lookup typeform requests
{
$lookup: {
from: 'projects-typeforms',
localField: '_id',
foreignField: 'order',
as: 'typeform_requests',
},
},
// Lookup typeform responses
{
$lookup: {
from: 'projects-typeform.responses',
localField: 'typeform_requests._id',
foreignField: 'request',
as: 'typeform_responses',
},
},
]; -
Onboarding Status Calculation:
- pending: No typeform request OR request sent but no response
- verification: Response received (
response.status: 'pending') - issues: Response has issues flagged
- approved: Response approved OR no onboarding required
-
Website Reactivation Eligibility:
- Checks if canceled website can be reactivated
- Verifies domain still available
- Adds
can_reactivate: trueflag
-
Missing Metadata Update:
- If order missing product/price metadata
- Fetches from subscription and updates order
- Ensures data consistency
-
Result Grouping:
{
orders: [...], // Paginated order array
total: 150, // Total orders matching filters
page: 1, // Current page
limit: 20, // Items per page
status_counts: { // Filter statistics
pending: 25,
verification: 10,
issues: 5,
approved: 110
}
}
-
-
Returns: Paginated orders with status counts
getOrders(req, res, next) - Get all orders (admin view)
- Purpose: Retrieve all orders across accounts with filtering
- Query Parameters: Same as
getMyOrdersplus:account_id(ObjectId): Filter by specific account
- Business Logic: Similar to
getMyOrderswithout account restriction - Returns: Paginated orders
getOrder(req, res, next) - Get specific order
- Purpose: Retrieve single order with full details
- Parameters: Order ID
- Business Logic:
- Populates subscription, product, price
- Includes typeform requests and responses
- Calculates current onboarding status
- Generates onboarding link if applicable
- Returns: Order object with populated fields
Timeline Management
getOrderTimeline(req, res, next) - Generate fulfillment timeline
-
Purpose: Create product-specific fulfillment timeline with status indicators
-
Parameters: Order ID
-
Business Logic:
-
Product Type Detection:
- Retrieves order with product information
- Determines product category (Content, Facebook Ads, Google Ads, etc.)
-
Timeline Templates by Product:
Content Products:
[
{
stage: 'submit',
label: 'Onboarding Form Submitted',
status: 'completed',
date: '2025-01-01T00:00:00Z',
},
{
stage: 'review',
label: 'Form Under Review',
status: 'completed',
date: '2025-01-02T00:00:00Z',
},
{
stage: 'setup',
label: 'Account Setup',
status: 'in_progress',
date: null,
},
{
stage: 'topic_generation',
label: 'Topic Ideas Generated',
status: 'pending',
date: null,
},
{
stage: 'topic_approval',
label: 'Topic Approval',
status: 'pending',
date: null,
},
{
stage: 'monthly_delivery',
label: 'Monthly Content Delivery',
status: 'pending',
date: null,
recurring: true,
},
];Facebook Ads / Google Ads:
[
{
stage: 'submit',
label: 'Onboarding Form Submitted',
status: 'completed',
},
{
stage: 'review',
label: 'Form Review',
status: 'completed',
},
{
stage: 'setup',
label: 'Ad Account Setup',
status: 'in_progress',
},
{
stage: 'buildout',
label: 'Campaign Buildout',
status: 'pending',
},
{
stage: 'qa',
label: 'Quality Assurance',
status: 'pending',
},
{
stage: 'approval',
label: 'Client Approval',
status: 'pending',
},
{
stage: 'launch',
label: 'Campaign Launch',
status: 'pending',
},
{
stage: 'monthly_optimization',
label: 'Monthly Optimization',
status: 'pending',
recurring: true,
},
]; -
Status Determination:
- completed: Stage finished (has completion date)
- in_progress: Current stage being worked on
- pending: Future stage not yet started
- issues: Stage has problems requiring attention
-
Date Population:
- Pulls completion dates from queue records
- Links to project task completion dates
- Shows null for future stages
-
Progress Calculation:
{
total_stages: 7,
completed_stages: 3,
progress_percentage: 42.86
}
-
-
Returns: Timeline array with progress metrics
getOrderStatus(req, res, next) - Get current order status
-
Purpose: Retrieve simplified current status
-
Parameters: Order ID
-
Business Logic:
- Checks latest queue job status
- Determines current fulfillment stage
- Returns user-friendly status message
-
Returns: Status object:
{
current_stage: 'setup',
status: 'in_progress',
message: 'Your account is being configured',
estimated_completion: '2025-01-15'
}
Invoice Management
getOrderInvoices(req, res, next) - Retrieve subscription invoices
-
Purpose: Get all invoices for order's subscription
-
Parameters: Order ID
-
Business Logic:
- Finds order and linked subscription
- Retrieves all invoices for subscription from Stripe
- Sorts by creation date (newest first)
- Includes invoice status and payment details
-
Returns: Invoice array:
[
{
id: 'in_xxx',
subscription: 'sub_xxx',
amount_due: 29900,
amount_paid: 29900,
status: 'paid',
created: 1704067200,
paid_at: 1704067200,
invoice_pdf: 'https://...',
},
];
Onboarding Forms
getMyForms(req, res, next) - Retrieve onboarding forms
-
Purpose: Get onboarding forms for sub-account
-
Parameters: Sub-account ID (query param)
-
Business Logic:
-
Access Validation:
- Verifies sub-account belongs to parent account
- Checks user has permission to view
-
Business Lookup:
- Finds business contact linked to sub-account
-
Form Aggregation:
[
// Match typeform requests for business
{ $match: { business: ObjectId(business_id) } },
// Lookup latest response
{
$lookup: {
from: 'projects-typeform.responses',
localField: '_id',
foreignField: 'request',
as: 'responses',
},
},
// Lookup subscription
{
$lookup: {
from: '_store.subscriptions',
localField: 'subscription',
foreignField: '_id',
as: 'subscription_data',
},
},
// Lookup business contact
{
$lookup: {
from: 'crm.contacts',
localField: 'business',
foreignField: '_id',
as: 'business_data',
},
},
]; -
Form Name Generation:
- Extracts product name from subscription
- Formats: "[Product Name] - Onboarding Form"
-
Response Processing:
- Gets latest response if multiple exist
- Includes submission status and date
- Adds revision history if applicable
-
-
Returns: Forms array:
[
{
_id: 'typeform_request_id',
form_name: 'Content Services - Onboarding Form',
form_url: 'https://dashclicks.typeform.com/to/xxx',
status: 'pending',
submitted_at: '2025-01-05T10:30:00Z',
response: {
answers: [...],
status: 'pending',
issues: []
},
business: {
name: 'Acme Corp',
email: 'contact@acme.com'
}
}
]
Technical Implementation Details
Onboarding Status Logic
Status Determination Algorithm:
function determineOnboardingStatus(order) {
const { typeform_requests, typeform_responses } = order;
// No onboarding required
if (!typeform_requests || typeform_requests.length === 0) {
return 'approved';
}
const latestRequest = typeform_requests[typeform_requests.length - 1];
const latestResponse = typeform_responses.find(
r => r.request.toString() === latestRequest._id.toString(),
);
// Form sent but not submitted
if (!latestResponse) {
return latestRequest.sent_at ? 'sent' : 'pending';
}
// Form submitted
if (latestResponse.status === 'pending') {
return 'verification';
}
// Issues found
if (latestResponse.status === 'issues') {
return 'issues';
}
// Approved
return 'approved';
}
Timeline Status Tracking
Queue-Based Progress Tracking:
Orders track fulfillment progress through queue jobs:
const queueJob = await Queue.findOne({
'metadata.order_id': orderId,
type: 'fulfillment',
});
const stageMapping = {
pending: 'submit',
processing: 'setup',
review: 'review',
completed: 'launch',
};
const currentStage = stageMapping[queueJob.status];
Product-Specific Timelines
Timeline Configuration by Product Type:
const timelineTemplates = {
content: [
{ stage: 'submit', duration_days: 0 },
{ stage: 'review', duration_days: 1 },
{ stage: 'setup', duration_days: 2 },
{ stage: 'topic_generation', duration_days: 3 },
{ stage: 'topic_approval', duration_days: 1 },
{ stage: 'monthly_delivery', duration_days: 0, recurring: true },
],
facebook_ads: [
{ stage: 'submit', duration_days: 0 },
{ stage: 'review', duration_days: 1 },
{ stage: 'setup', duration_days: 2 },
{ stage: 'buildout', duration_days: 5 },
{ stage: 'qa', duration_days: 2 },
{ stage: 'approval', duration_days: 3 },
{ stage: 'launch', duration_days: 1 },
{ stage: 'monthly_optimization', duration_days: 0, recurring: true },
],
google_ads: [
// Similar to facebook_ads
],
website: [
{ stage: 'submit', duration_days: 0 },
{ stage: 'review', duration_days: 1 },
{ stage: 'design', duration_days: 7 },
{ stage: 'development', duration_days: 7 },
{ stage: 'review_approval', duration_days: 3 },
{ stage: 'launch', duration_days: 1 },
],
};
Estimated Completion Dates
Calculation Based on Timeline:
function calculateEstimatedCompletion(order, timeline) {
const currentStageIndex = timeline.findIndex(t => t.status === 'in_progress');
if (currentStageIndex === -1) return null;
const remainingStages = timeline.slice(currentStageIndex);
const totalDays = remainingStages.reduce((sum, stage) => sum + stage.duration_days, 0);
const estimatedDate = new Date();
estimatedDate.setDate(estimatedDate.getDate() + totalDays);
return estimatedDate;
}
Website Reactivation Check
Eligibility Verification:
async function checkWebsiteReactivation(order) {
if (order.product.type !== 'website') return false;
const subscription = await Subscription.findById(order.subscription);
if (subscription.status !== 'canceled') return false;
// Check if domain still available
const domain = order.metadata.domain;
const domainAvailable = await checkDomainAvailability(domain);
if (!domainAvailable) return false;
// Check if within reactivation window (90 days)
const canceledDate = new Date(subscription.canceled_at);
const daysSinceCancellation = Math.floor((new Date() - canceledDate) / (1000 * 60 * 60 * 24));
return daysSinceCancellation <= 90;
}
Error Handling
Common Error Codes
- 400 Bad Request: Invalid filter parameters, malformed date range
- 403 Forbidden: Attempting to access another account's orders
- 404 Not Found: Order ID not found, subscription not found
- 422 Unprocessable: Invalid onboarding status filter value
- 500 Server Error: Database query failures, aggregation errors
Validation Patterns
// Order query validation (Joi)
{
start_date: Joi.date().iso(),
end_date: Joi.date().iso().min(Joi.ref('start_date')),
onboarding_status: Joi.string().valid(
'pending', 'verification', 'issues', 'approved'
),
product: Joi.string(),
order_status: Joi.string(),
search: Joi.string().max(100),
sort_by: Joi.string().valid('created_at', 'updated_at', 'status'),
order: Joi.string().valid('asc', 'desc'),
page: Joi.number().integer().min(1).default(1),
limit: Joi.number().integer().min(1).max(100).default(20)
}
Integration Points
External Services
- Typeform API: Form creation and response retrieval
- Email Service: Onboarding invitation emails
- Queue Manager: Fulfillment job status tracking
- Project Management: Task and pulse integration
Internal Services
- Subscription Service: Subscription data and status
- Product Service: Product metadata and configuration
- Account Service: Account relationships and permissions
- Notification Service: Status update notifications
PubSub Events
// Published on status changes
pubsub.publish('store:order:status_changed', {
order_id,
old_status: 'pending',
new_status: 'verification',
timestamp: new Date(),
});
// Published on timeline progression
pubsub.publish('store:order:stage_completed', {
order_id,
stage: 'setup',
next_stage: 'buildout',
timestamp: new Date(),
});
Performance Considerations
Optimization Strategies
-
Aggregation Pipeline Efficiency:
- Indexes on
account_id,subscription,created_at - Early filtering with
$matchstages - Limit result set before expensive
$lookupoperations
- Indexes on
-
Caching:
- Timeline templates cached in memory
- Product metadata cached for timeline generation
- Status counts cached for 5 minutes
-
Pagination:
- Skip-limit pagination for small datasets
- Cursor-based pagination for large datasets
- Total count cached when filters unchanged
Database Indexes
// Orders collection indexes
{
account_id: 1,
created_at: -1
}
{
subscription: 1
}
{
'product.type': 1,
status: 1
}
{
business: 1,
created_at: -1
}
Related Documentation
- Subscription Management - Subscription lifecycle
- Cart Management (link removed - file does not exist) - Cart and checkout
- Product Management - Product catalog
- Store Module Overview - Architecture and configuration