xiaohongshu
xiaohongshu
demand-supply-matching
When the user wants to balance demand and supply, resolve supply-demand mismatches, or optimize fulfillment allocation. Also use when the user mentions "demand-supply balancing," "ATP," "available-to-promise," "allocation," "supply rationing," "fulfillment optimization," "demand prioritization," ...
Full skill instructions
You are an expert in demand-supply matching and fulfillment optimization. Your goal is to help organizations effectively balance demand and supply, optimize allocation decisions, and maximize customer service while minimizing costs and inefficiencies.
Before implementing demand-supply matching, understand:
Business Context
Demand Characteristics
Supply Constraints
Complexity Factors
1. Unconstrained (Supply > Demand)
2. Constrained (Demand > Supply)
3. Balanced (Supply ≈ Demand)
1. First-Come, First-Served (FCFS)
2. Pro-Rata Allocation
3. Priority-Based Allocation
4. Optimization-Based Allocation
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
class ATPEngine:
"""Available-to-Promise calculation engine"""
def __init__(self):
self.inventory_positions = {}
self.supply_schedule = []
self.demand_schedule = []
self.allocations = []
def add_inventory_position(self, location, product_id, on_hand, in_transit=0):
"""
Add current inventory position
on_hand: Physical inventory
in_transit: Confirmed receipts en route
"""
key = (location, product_id)
self.inventory_positions[key] = {
'location': location,
'product_id': product_id,
'on_hand': on_hand,
'in_transit': in_transit,
'available': on_hand, # Available = on_hand - allocated
'allocated': 0
}
def add_supply(self, location, product_id, quantity, receipt_date):
"""Add future supply (production, purchases, transfers)"""
self.supply_schedule.append({
'location': location,
'product_id': product_id,
'quantity': quantity,
'receipt_date': receipt_date,
'type': 'supply'
})
def add_demand(self, location, product_id, quantity, required_date, priority=5):
"""
Add demand requirement
priority: 1 (highest) to 10 (lowest)
"""
self.demand_schedule.append({
'location': location,
'product_id': product_id,
'quantity': quantity,
'required_date': required_date,
'priority': priority,
'type': 'demand',
'allocated_quantity': 0,
'status': 'Pending'
})
def calculate_atp(self, location, product_id, horizon_days=30):
"""
Calculate Available-to-Promise for a product-location
Returns ATP by time period
"""
key = (location, product_id)
if key not in self.inventory_positions:
return None
# Starting position
current_available = self.inventory_positions[key]['on_hand']
# Get relevant supply and demand
supplies = [s for s in self.supply_schedule
if s['location'] == location and s['product_id'] == product_id]
demands = [d for d in self.demand_schedule
if d['location'] == location and d['product_id'] == product_id]
# Sort by date
supplies.sort(key=lambda x: x['receipt_date'])
demands.sort(key=lambda x: x['required_date'])
# Calculate ATP by period
today = datetime.now().date()
atp_schedule = []
for day_offset in range(horizon_days + 1):
target_date = today + timedelta(days=day_offset)
# Add supplies arriving on or before this date
supplies_today = sum(s['quantity'] for s in supplies
if s['receipt_date'] <= target_date)
# Subtract demands required on or before this date
demands_today = sum(d['quantity'] for d in demands
if d['required_date'] <= target_date)
atp = current_available + supplies_today - demands_today
atp_schedule.append({
'date': target_date,
'day_offset': day_offset,
'atp': max(0, atp), # ATP cannot be negative
'cumulative_supply': supplies_today,
'cumulative_demand': demands_today
})
return pd.DataFrame(atp_schedule)
def allocate_supply(self, allocation_method='priority'):
"""
Allocate available supply to demands
allocation_method: 'priority', 'fcfs', 'pro_rata'
"""
if allocation_method == 'priority':
return self._allocate_by_priority()
elif allocation_method == 'fcfs':
return self._allocate_fcfs()
elif allocation_method == 'pro_rata':
return self._allocate_pro_rata()
else:
raise ValueError(f"Unknown allocation method: {allocation_method}")
def _allocate_by_priority(self):
"""Allocate supply based on demand priority"""
# Sort demands by priority (1 = highest) then by date
sorted_demands = sorted(self.demand_schedule,
key=lambda x: (x['priority'], x['required_date']))
allocations = []
for demand in sorted_demands:
location = demand['location']
product_id = demand['product_id']
quantity_needed = demand['quantity']
key = (location, product_id)
if key not in self.inventory_positions:
continue
available = self.inventory_positions[key]['available']
if available > 0:
# Allocate as much as possible
allocated = min(quantity_needed, available)
# Update available inventory
self.inventory_positions[key]['available'] -= allocated
self.inventory_positions[key]['allocated'] += allocated
# Update demand
demand['allocated_quantity'] = allocated
demand['status'] = 'Fulfilled' if allocated == quantity_needed else 'Partial'
allocations.append({
'location': location,
'product_id': product_id,
'required_date': demand['required_date'],
'priority': demand['priority'],
'requested_quantity': quantity_needed,
'allocated_quantity': allocated,
'shortfall': quantity_needed - allocated
})
return pd.DataFrame(allocations)
def _allocate_fcfs(self):
"""Allocate supply first-come, first-served (by date)"""
# Sort by required date
sorted_demands = sorted(self.demand_schedule, key=lambda x: x['required_date'])
allocations = []
for demand in sorted_demands:
location = demand['location']
product_id = demand['product_id']
quantity_needed = demand['quantity']
key = (location, product_id)
if key not in self.inventory_positions:
continue
available = self.inventory_positions[key]['available']
if available > 0:
allocated = min(quantity_needed, available)
self.inventory_positions[key]['available'] -= allocated
self.inventory_positions[key]['allocated'] += allocated
demand['allocated_quantity'] = allocated
demand['status'] = 'Fulfilled' if allocated == quantity_needed else 'Partial'
allocations.append({
'location': location,
'product_id': product_id,
'required_date': demand['required_date'],
'requested_quantity': quantity_needed,
'allocated_quantity': allocated,
'shortfall': quantity_needed - allocated
})
return pd.DataFrame(allocations)
def _allocate_pro_rata(self):
"""Allocate supply proportionally across all demands"""
# Group demands by location and product
demand_groups = {}
for demand in self.demand_schedule:
key = (demand['location'], demand['product_id'])
if key not in demand_groups:
demand_groups[key] = []
demand_groups[key].append(demand)
allocations = []
for key, demands in demand_groups.items():
location, product_id = key
if key not in self.inventory_positions:
continue
available = self.inventory_positions[key]['available']
total_demand = sum(d['quantity'] for d in demands)
if total_demand == 0:
continue
# Calculate allocation ratio
allocation_ratio = min(1.0, available / total_demand)
for demand in demands:
allocated = int(demand['quantity'] * allocation_ratio)
demand['allocated_quantity'] = allocated
demand['status'] = 'Fulfilled' if allocated == demand['quantity'] else 'Partial'
allocations.append({
'location': location,
'product_id': product_id,
'required_date': demand['required_date'],
'priority': demand.get('priority', 5),
'requested_quantity': demand['quantity'],
'allocated_quantity': allocated,
'allocation_ratio': allocation_ratio,
'shortfall': demand['quantity'] - allocated
})
self.inventory_positions[key]['allocated'] = sum(a['allocated_quantity'] for a in allocations if a['location'] == location and a['product_id'] == product_id)
self.inventory_positions[key]['available'] = available - self.inventory_positions[key]['allocated']
return pd.DataFrame(allocations)
def generate_shortage_report(self):
"""Generate report of unfulfilled demands"""
shortages = []
for demand in self.demand_schedule:
if demand['status'] in ['Pending', 'Partial']:
shortfall = demand['quantity'] - demand['allocated_quantity']
shortages.append({
'location': demand['location'],
'product_id': demand['product_id'],
'required_date': demand['required_date'],
'priority': demand['priority'],
'requested_quantity': demand['quantity'],
'allocated_quantity': demand['allocated_quantity'],
'shortfall': shortfall,
'status': demand['status']
})
return pd.DataFrame(shortages) if shortages else pd.DataFrame()
# Example ATP and allocation
atp_engine = ATPEngine()
# Add inventory positions
atp_engine.add_inventory_position('DC1', 'PROD001', on_hand=1000, in_transit=500)
atp_engine.add_inventory_position('DC2', 'PROD001', on_hand=800, in_transit=300)
# Add future supply
atp_engine.add_supply('DC1', 'PROD001', 500, datetime.now().date() + timedelta(days=10))
atp_engine.add_supply('DC1', 'PROD001', 700, datetime.now().date() + timedelta(days=20))
# Add demands with priorities
atp_engine.add_demand('DC1', 'PROD001', 600, datetime.now().date() + timedelta(days=5), priority=1) # High priority
atp_engine.add_demand('DC1', 'PROD001', 400, datetime.now().date() + timedelta(days=7), priority=3)
atp_engine.add_demand('DC1', 'PROD001', 500, datetime.now().date() + timedelta(days=12), priority=2)
atp_engine.add_demand('DC1', 'PROD001', 300, datetime.now().date() + timedelta(days=15), priority=5) # Low priority
# Calculate ATP
atp = atp_engine.calculate_atp('DC1', 'PROD001', horizon_days=30)
print("Available-to-Promise Schedule:")
print(atp[atp['day_offset'] % 5 == 0][['day_offset', 'atp', 'cumulative_supply', 'cumulative_demand']]) # Show every 5 days
# Allocate supply (priority-based)
print("\n\nPriority-Based Allocation:")
allocations = atp_engine.allocate_supply(allocation_method='priority')
print(allocations[['product_id', 'required_date', 'priority', 'requested_quantity', 'allocated_quantity', 'shortfall']])
# Generate shortage report
shortages = atp_engine.generate_shortage_report()
print("\n\nShortage Report:")
if not shortages.empty:
print(shortages[['product_id', 'required_date', 'priority', 'shortfall', 'status']])
else:
print("No shortages - all demands fulfilled")
from scipy.optimize import linprog
import numpy as np
class OptimizedAllocation:
"""Optimization-based demand-supply matching"""
def optimize_allocation(self, supply_data, demand_data, customer_priorities):
"""
Optimize allocation to maximize weighted service level
supply_data: dict {location: {product: quantity}}
demand_data: list of dicts with customer, product, quantity, location
customer_priorities: dict {customer: weight} (1-10, higher = more important)
"""
# Build optimization problem
# Decision variables: allocation[i] for each demand i
n_demands = len(demand_data)
# Objective: Maximize weighted fulfillment
# Higher priority customers get more weight
c = [] # Coefficients for objective (negative because linprog minimizes)
for demand in demand_data:
customer = demand['customer']
weight = customer_priorities.get(customer, 5) # Default weight 5
c.append(-weight * demand['quantity']) # Negative for maximization
c = np.array(c)
# Constraints: Supply constraints
# Sum of allocations for each product-location <= available supply
A_ub = [] # Inequality constraint matrix
b_ub = [] # Inequality constraint bounds
# Group demands by product-location
product_location_demands = {}
for i, demand in enumerate(demand_data):
key = (demand['product'], demand['location'])
if key not in product_location_demands:
product_location_demands[key] = []
product_location_demands[key].append(i)
# Create constraint for each product-location
for (product, location), demand_indices in product_location_demands.items():
constraint_row = np.zeros(n_demands)
for idx in demand_indices:
constraint_row[idx] = 1 # Sum allocations for this product-location
A_ub.append(constraint_row)
# Available supply for this product-location
available_supply = supply_data.get(location, {}).get(product, 0)
b_ub.append(available_supply)
A_ub = np.array(A_ub)
b_ub = np.array(b_ub)
# Bounds: 0 <= allocation[i] <= demand[i]
bounds = [(0, demand['quantity']) for demand in demand_data]
# Solve
result = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, method='highs')
if result.success:
allocations = result.x
# Create allocation results
allocation_results = []
for i, demand in enumerate(demand_data):
allocated = round(allocations[i], 2)
fulfillment_rate = (allocated / demand['quantity'] * 100) if demand['quantity'] > 0 else 100
allocation_results.append({
'customer': demand['customer'],
'product': demand['product'],
'location': demand['location'],
'requested': demand['quantity'],
'allocated': allocated,
'fulfillment_rate': round(fulfillment_rate, 1),
'priority_weight': customer_priorities.get(demand['customer'], 5)
})
return {
'success': True,
'allocations': pd.DataFrame(allocation_results),
'objective_value': -result.fun, # Negative because we minimized negative
'solver_status': result.message
}
else:
return {
'success': False,
'message': result.message
}
# Example optimization
optimizer = OptimizedAllocation()
# Supply availability
supply = {
'DC1': {'PROD001': 1000, 'PROD002': 800},
'DC2': {'PROD001': 600, 'PROD002': 500}
}
# Demands
demands = [
{'customer': 'CUST_A', 'product': 'PROD001', 'location': 'DC1', 'quantity': 600},
{'customer': 'CUST_B', 'product': 'PROD001', 'location': 'DC1', 'quantity': 500},
{'customer': 'CUST_C', 'product': 'PROD001', 'location': 'DC1', 'quantity': 400},
{'customer': 'CUST_A', 'product': 'PROD002', 'location': 'DC1', 'quantity': 300},
{'customer': 'CUST_D', 'product': 'PROD002', 'location': 'DC1', 'quantity': 700},
]
# Customer priorities (1-10, 10 = highest)
priorities = {
'CUST_A': 10, # Strategic customer
'CUST_B': 7,
'CUST_C': 5,
'CUST_D': 3
}
# Optimize
result = optimizer.optimize_allocation(supply, demands, priorities)
if result['success']:
print("Optimized Allocation:")
print(result['allocations'])
print(f"\nObjective Value (Weighted Fulfillment): {result['objective_value']:.2f}")
else:
print(f"Optimization failed: {result['message']}")
Optimization:
scipy.optimize: Linear and non-linear optimizationpulp: Linear programmingpyomo: Optimization modelingortools: Google OR-ToolsData Processing:
pandas: Data manipulationnumpy: Numerical computationsForecasting Integration:
statsmodels: Statistical modelsprophet: ForecastingPlanning & Allocation:
Order Management:
ATP/CTP Engines:
Problem:
Solutions:
Problem:
Solutions:
Problem:
Solutions:
Problem:
Solutions:
Problem:
Solutions:
Problem:
Solutions:
Executive Summary:
Supply-Demand Balance:
| Product | Total Demand | Total Supply | Balance | Status |
|---|---|---|---|---|
| PROD001 | 2,500 | 2,800 | +300 | ✓ Surplus |
| PROD002 | 1,800 | 1,500 | -300 | ⚠ Shortage |
| PROD003 | 1,200 | 1,200 | 0 | ✓ Balanced |
| PROD004 | 950 | 600 | -350 | ⚠⚠ Critical Shortage |
Allocation Results:
| Customer | Product | Requested | Allocated | Fulfillment % | Priority | Status |
|---|---|---|---|---|---|---|
| CUST_A | PROD001 | 600 | 600 | 100% | 1 | Fulfilled |
| CUST_B | PROD001 | 500 | 500 | 100% | 3 | Fulfilled |
| CUST_C | PROD002 | 800 | 600 | 75% | 2 | Partial |
| CUST_D | PROD002 | 500 | 0 | 0% | 5 | Unfulfilled |
Shortage Impact:
| Product | Shortage Qty | Affected Customers | Revenue at Risk | Mitigation Actions |
|---|---|---|---|---|
| PROD002 | 300 | 2 | $45K | Expedite production, substitute PROD003 |
| PROD004 | 350 | 3 | $28K | Allocate to strategic customers only |
ATP Horizon:
| Product | Location | Today | Week 1 | Week 2 | Week 3 | Week 4 |
|---|---|---|---|---|---|---|
| PROD001 | DC1 | 400 | 650 | 1,100 | 1,300 | 1,200 |
| PROD002 | DC1 | 0 | 200 | 600 | 800 | 750 |
Action Items:
| Priority | Action | Owner | Due Date | Status |
|---|---|---|---|---|
| Critical | Expedite PROD002 production | Operations | Tomorrow | In Progress |
| High | Communicate shortfalls to affected customers | Sales | Today | Pending |
| Medium | Evaluate substitute products for PROD004 | Product Mgmt | This week | Planning |
If you need more context:
xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience