一键导入
multi-warehouse
Manage inventory across multiple warehouses with smart allocation rules, transfer orders between locations, and split-fulfillment routing
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Manage inventory across multiple warehouses with smart allocation rules, transfer orders between locations, and split-fulfillment routing
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Manage supplier invoices and vendor payments with automated receipt matching, payment scheduling, early discount optimization, and reconciliation workflows
Enable wholesale and B2B sales with company accounts, custom catalogs, quote workflows, purchase orders, and net payment terms
Predict future inventory needs using historical sales data, seasonal trends, and reorder points to prevent stockouts and overstock
Launch a multi-vendor marketplace with seller onboarding, commission rules, automated payouts via Stripe Connect, and vendor dashboards
Control which products appear first in collections using automated ranking rules, manual overrides, and performance-based sorting algorithms
Sync your catalog and inventory across your own site, Amazon, eBay, and wholesale channels to sell everywhere from one system
| name | multi-warehouse |
| description | Manage inventory across multiple warehouses with smart allocation rules, transfer orders between locations, and split-fulfillment routing |
| category | catalog-inventory |
| risk | critical |
| source | curated |
| date_added | 2026-03-12 |
| tags | ["warehouse","multi-location","fulfillment","allocation","transfer","split-shipment","3pl"] |
| triggers | ["multi warehouse","multi location inventory","warehouse allocation","transfer order","split fulfillment","distributed inventory"] |
| tools | ["claude-code","cursor","gemini-cli","copilot","codex-cli","kiro","opencode"] |
| platforms | ["shopify","woocommerce","bigcommerce","custom"] |
| difficulty | advanced |
Multi-warehouse inventory lets you stock products at multiple physical locations — warehouses, stores, 3PLs — and route each order to the location best positioned to fulfill it. Shopify and BigCommerce have multi-location inventory built in. WooCommerce needs a plugin. Only build a custom allocation engine if your routing logic (zone-based, cost-optimized, split fulfillment) exceeds what platform tools support.
| Platform | Built-in Multi-Location | Recommended Extension |
|---|---|---|
| Shopify | Yes — up to 1,000 locations (Basic: 4, Shopify plan: 5, Advanced: 8) | ShipBob or Flexport for 3PL fulfillment routing; ShipHero for advanced routing rules |
| WooCommerce | No — requires a plugin | ATUM Multi-Inventory (add-on) or WooCommerce Multi-Location Inventory by Iconic |
| BigCommerce | Yes — Multi-Location Inventory app (free) | ShipStation for advanced routing; Whiplash or ShipBob for 3PL integration |
| Custom / Headless | Build allocation engine with proximity-first routing | Required when no platform tools meet routing and split-fulfillment requirements |
Shopify has native multi-location inventory.
Set up locations:
Configure fulfillment routing:
Transfer orders between locations:
3PL integration:
WooCommerce requires a plugin for multi-location inventory.
Option A: ATUM Multi-Inventory (recommended)
Option B: WooCommerce Multi-Location Inventory by Iconic
Transfer orders:
BigCommerce supports multi-location inventory via a free app.
Enable Multi-Location Inventory:
Configure fulfillment routing:
For 3PL integration:
For headless storefronts, build an allocation engine that selects the best location(s) for each order:
// lib/allocation.ts
import { haversineDistance } from './geo';
interface OrderItem { variantId: string; quantity: number; productName: string; }
interface AllocationResult {
type: 'single' | 'split';
fulfillments: { locationId: string; items: OrderItem[] }[];
}
export async function allocateOrder(orderItems: OrderItem[], shippingAddress: Address): Promise<AllocationResult> {
const locations = await db.locations.findMany({ where: { active: true } });
// Fetch inventory availability for all required variants at all locations
const inventory = await db.inventoryLevels.findMany({
where: { variantId: { in: orderItems.map(i => i.variantId) } },
});
const invMap = buildInventoryMap(inventory); // locationId -> variantId -> available
// Score locations by distance to shipping address (proximity-first routing)
const scored = locations
.map(loc => ({
...loc,
distanceKm: haversineDistance({ lat: loc.lat, lng: loc.lng }, { lat: shippingAddress.lat, lng: shippingAddress.lng }),
}))
.sort((a, b) => a.distanceKm - b.distanceKm);
// Prefer single-location fulfillment to avoid split shipments
for (const location of scored) {
const canFulfillAll = orderItems.every(item => (invMap[location.id]?.[item.variantId] ?? 0) >= item.quantity);
if (canFulfillAll) return { type: 'single', fulfillments: [{ locationId: location.id, items: orderItems }] };
}
// Fall back to split fulfillment — greedy assignment to nearest location with stock
const remaining = [...orderItems];
const fulfillments: AllocationResult['fulfillments'] = [];
for (const location of scored) {
const canFulfill = remaining.filter(item => (invMap[location.id]?.[item.variantId] ?? 0) >= item.quantity);
if (canFulfill.length > 0) {
fulfillments.push({ locationId: location.id, items: canFulfill });
canFulfill.forEach(item => remaining.splice(remaining.findIndex(r => r.variantId === item.variantId), 1));
}
if (remaining.length === 0) break;
}
if (remaining.length > 0) throw new Error('Cannot fulfill order — insufficient stock across all locations');
return { type: 'split', fulfillments };
}
// Transfer order management
export async function receiveTransferOrder(transferOrderId: string, receivedItems: { variantId: string; quantity: number }[]) {
const transfer = await db.transferOrders.findUnique({ where: { id: transferOrderId }, include: { items: true } });
await db.$transaction([
// Decrease on_hand + reserved at source
...receivedItems.map(item => db.inventoryLevels.update({
where: { variantId_locationId: { variantId: item.variantId, locationId: transfer.fromLocationId } },
data: { onHand: { decrement: item.quantity }, reserved: { decrement: item.quantity } },
})),
// Increase on_hand at destination
...receivedItems.map(item => db.inventoryLevels.upsert({
where: { variantId_locationId: { variantId: item.variantId, locationId: transfer.toLocationId } },
create: { variantId: item.variantId, locationId: transfer.toLocationId, onHand: item.quantity, reserved: 0 },
update: { onHand: { increment: item.quantity } },
})),
db.transferOrders.update({ where: { id: transferOrderId }, data: { status: 'received' } }),
]);
}
When an order is split across two locations, customers must be informed before confirming their order.
Shopify: Shopify's native checkout shows "Ships from multiple locations" in the shipping options when a split is needed. Customize the messaging in Settings → Checkout → Checkout language.
WooCommerce: Display a notice in the cart/checkout when ATUM detects a split is needed. ATUM Multi-Inventory includes configurable messaging for split shipments.
In the order confirmation email: Include all fulfillment groups with their expected shipping dates. "Your order will arrive in 2 shipments" with item breakdowns reduces support tickets.
Chronic stock imbalances (one warehouse overstocked, another out of stock) increase transfer costs and split fulfillments. Run a weekly analysis:
Signs of imbalance:
Action: Create a transfer order from the overstocked location to the understocked one before the next reorder cycle.
Shopify Stocky: Shows an "Inventory distribution" report that identifies imbalanced SKUs across locations.
| Problem | Solution |
|---|---|
| Split fulfillment creates two shipping charges | Consolidate shipping cost at the order level; absorb the second shipment cost or notify the customer during checkout — never charge twice silently |
| Transfer received quantity differs from sent | Support partial receipt — record the actual received quantity per item and handle discrepancies (damaged in transit) separately |
| Inventory double-counted across locations | Each inventory record is location-scoped; when reporting total stock, always sum across locations explicitly |
| Location goes offline mid-fulfillment | Mark location as inactive; re-run allocation for unfulfilled orders assigned to that location |
| Customer confused about multiple tracking numbers | Send a separate tracking email per fulfillment with a clear note: "This is shipment 1 of 2 for your order" |