Zones Services - Zone Assignment Business Logic
Location: api/nextango/apps/zones/services.py
Last Updated: 2025-12-21
Overview
The zones services module implements the business logic for zone-driven product assignments and inventory infrastructure management. The ZoneAssignmentService class provides methods for creating inventory tracking infrastructure based on par level assignments, validating SKU assignments, and managing the relationship between zones and inventory.
Core Concept: Zones define "what should be where" through par levels (ParLevelItem), and the service layer ensures inventory tracking (InventoryLevel) exists for these assignments.
Key Service: ZoneAssignmentService
Key Methods:
create_inventory_infrastructure_for_zone()- Create InventoryLevel records for zonesync_par_levels_to_inventory()- Sync all par levels to inventory infrastructureget_zone_assignments_for_product()- Find where a product should be locatedget_products_for_zone()- Get all products assigned to a zonevalidate_sku_assignments()- Validate par level SKUs match ProductVariantscleanup_orphaned_inventory_levels()- Remove inventory without par levels
Zone-Driven Inventory Architecture
Conceptual Model
Zones → Par Levels → Inventory Levels
Zone (physical location within store)
↓
ZoneInventory (if zone has inventory configuration)
↓
ParLevelItem (assigns product variant to zone with ideal quantity)
↓
InventoryLevel (tracks actual inventory at store for that variant)
Data Flow
1. Zone Assignment (Sanity CMS):
- Admin creates Zone with ZoneInventory configuration
- Admin adds ParLevelItem: "Coffee Bar zone should have 10x Dark Roast 12oz"
2. Infrastructure Creation (ZoneAssignmentService):
- Service creates InventoryLevel for Dark Roast 12oz at that store
- Inventory tracking now exists for that variant at that location
3. Inventory Management (Operations):
- Staff can now track quantity_on_hand for Dark Roast 12oz
- Par level (10) provides the "ideal" quantity
- Inventory level tracks the "actual" quantity
Key Relationships
ParLevelItem:
- product: FK to Product
- variant_sku: String (matches ProductVariant.sku)
- quantity: Integer (par level - ideal quantity)
- zone_inventory: FK to ZoneInventory
InventoryLevel:
- product: FK to Product
- variant_sku: String (matches ProductVariant.sku)
- quantity_on_hand: Integer (actual quantity)
- store: FK to Store
The service ensures: Every ParLevelItem has a corresponding InventoryLevel
ZoneAssignmentService
Main service class for zone assignment and inventory infrastructure management.
Initialization
class ZoneAssignmentService:
"""
Service for managing zone-driven product assignments and inventory infrastructure.
Implements the core logic for "what should be where" through par levels.
"""
def __init__(self):
self.Product = apps.get_model('products', 'Product')
self.ProductVariant = apps.get_model('products', 'ProductVariant')
self.InventoryLevel = apps.get_model('products', 'InventoryLevel')
self.Store = apps.get_model('stores', 'Store')
Uses lazy model loading (apps.get_model) to avoid circular imports between zones, products, and stores apps.
create_inventory_infrastructure_for_zone()
Create InventoryLevel records for all par level items in a specific zone.
Purpose
Ensures that inventory tracking infrastructure exists for every product variant assigned to a zone through par levels. This is the core method that connects zone assignments (what should be where) with inventory tracking (what is actually there).
Signature
def create_inventory_infrastructure_for_zone(self, zone: Zone) -> Dict[str, int]:
"""
Create InventoryLevel records for all par level items in a zone.
Returns:
Dict with counts of created, existing, and failed records
"""
Parameters
zone(Zone): Zone instance to create infrastructure for
Returns
{
'created': 5, # New InventoryLevel records created
'existing': 3, # InventoryLevel records already existed
'failed': 0, # Failed to create
'errors': [] # List of error messages
}
Implementation Logic
# 1. Check if zone has inventory configuration
if zone.zone_type != 'inventory':
logger.info(f"Zone {zone.zone_name} is not an inventory zone, skipping")
return stats
# 2. Get zone inventory and par levels
zone_inventory = zone.zone_inventory
par_levels = zone_inventory.par_levels.all()
# 3. For each par level item
for par_level in par_levels:
try:
# 4. Ensure InventoryLevel exists (calls ParLevelItem.ensure_inventory_level_exists())
inventory_level = par_level.ensure_inventory_level_exists()
# 5. Track statistics
if inventory_level:
if hasattr(inventory_level, '_created') or inventory_level.quantity_on_hand == 0:
stats['created'] += 1
else:
stats['existing'] += 1
except Exception as e:
stats['failed'] += 1
stats['errors'].append(str(e))
Use Cases
1. After Zone Creation:
# New zone created in Sanity, synced to Django
zone = Zone.objects.get(sanity_id='zone_123')
service = ZoneAssignmentService()
stats = service.create_inventory_infrastructure_for_zone(zone)
logger.info(f"Created infrastructure: {stats}")
# Output: Created infrastructure: {'created': 10, 'existing': 0, 'failed': 0, 'errors': []}
2. After Par Level Updates:
# Admin added 5 new par level items to existing zone
zone = Zone.objects.get(pk=zone_id)
service = ZoneAssignmentService()
stats = service.create_inventory_infrastructure_for_zone(zone)
# Output might be: {'created': 5, 'existing': 15, 'failed': 0, 'errors': []}
3. Manual Infrastructure Rebuild:
# Rebuild infrastructure for all zones at a store
store = Store.objects.get(pk=store_id)
zones = Zone.objects.filter(store_location=store, zone_type='inventory')
service = ZoneAssignmentService()
for zone in zones:
stats = service.create_inventory_infrastructure_for_zone(zone)
logger.info(f"Zone {zone.zone_name}: {stats}")
sync_par_levels_to_inventory()
Sync all par level assignments to inventory infrastructure across one or all stores.
Purpose
Bulk operation to ensure InventoryLevel records exist for all ParLevelItems. Useful for:
- Initial system setup
- After bulk par level imports
- Periodic reconciliation jobs
Signature
def sync_par_levels_to_inventory(self, store: Optional['Store'] = None) -> Dict[str, int]:
"""
Sync all par level assignments to inventory infrastructure.
Args:
store: Optional store to limit sync to specific store
Returns:
Dict with sync statistics
"""
Parameters
store(Store, optional): If provided, only sync par levels for this store's zones
Returns
{
'zones_processed': 25,
'par_levels_processed': 342,
'inventory_levels_created': 98,
'inventory_levels_existing': 244,
'errors': []
}
Implementation Logic
# 1. Get zones to process
zones_queryset = Zone.objects.filter(zone_type='inventory')
if store:
zones_queryset = zones_queryset.filter(store_location=store)
# 2. Optimize queries
zones = zones_queryset.select_related('zone_inventory').prefetch_related(
'zone_inventory__par_levels__product'
)
# 3. Process each zone
for zone in zones:
zone_stats = self.create_inventory_infrastructure_for_zone(zone)
# 4. Aggregate statistics
stats['zones_processed'] += 1
stats['inventory_levels_created'] += zone_stats['created']
stats['inventory_levels_existing'] += zone_stats['existing']
stats['errors'].extend(zone_stats['errors'])
Use Cases
1. Initial System Setup:
# Set up inventory infrastructure for entire system
service = ZoneAssignmentService()
stats = service.sync_par_levels_to_inventory()
logger.info(f"System sync complete: {stats}")
# Output: System sync complete: {'zones_processed': 50, 'par_levels_processed': 1250, ...}
2. Store-Specific Sync:
# Sync just one store after bulk par level import
store = Store.objects.get(name='Downtown Location')
service = ZoneAssignmentService()
stats = service.sync_par_levels_to_inventory(store=store)
logger.info(f"Store sync complete: {stats}")
3. Management Command:
# management/commands/sync_zone_inventory.py
from nextango.apps.zones.services import ZoneAssignmentService
class Command(BaseCommand):
def handle(self, *args, **options):
service = ZoneAssignmentService()
stats = service.sync_par_levels_to_inventory()
self.stdout.write(f"Zones processed: {stats['zones_processed']}")
self.stdout.write(f"Inventory levels created: {stats['inventory_levels_created']}")
get_zone_assignments_for_product()
Get all zone assignments for a specific product variant across all stores.
Purpose
Answers the question: "Where should this product variant be located?"
Returns list of zones that have par level assignments for the specified product variant.
Signature
def get_zone_assignments_for_product(
self,
product: 'Product',
variant_sku: str
) -> List[Dict[str, Any]]:
"""
Get all zone assignments for a specific product variant.
Returns:
List of zone assignment dictionaries
"""
Parameters
product(Product): Product instancevariant_sku(str): SKU of the specific product variant
Returns
[
{
'zone_id': 'uuid-123',
'zone_name': 'Coffee Bar',
'store_id': 'uuid-456',
'store_name': 'Downtown Location',
'par_quantity': 10,
'zone_type': 'inventory'
},
{
'zone_id': 'uuid-789',
'zone_name': 'Coffee Display',
'store_id': 'uuid-012',
'store_name': 'Uptown Location',
'par_quantity': 15,
'zone_type': 'inventory'
}
]
Implementation Logic
# 1. Find all par level assignments for product variant
par_levels = ParLevelItem.objects.filter(
product=product,
variant_sku=variant_sku
).select_related(
'zone_inventory__zone__store_location'
)
# 2. Build assignment list
for par_level in par_levels:
zone = par_level.zone_inventory.zone
assignments.append({
'zone_id': zone.pk,
'zone_name': zone.zone_name,
'store_id': zone.store_location.pk,
'store_name': zone.store_location.name,
'par_quantity': par_level.quantity,
'zone_type': zone.zone_type
})
Use Cases
1. Product Distribution View:
# Show where a product should be located
product = Product.objects.get(name='Dark Roast Coffee')
variant_sku = 'DARK-12OZ'
service = ZoneAssignmentService()
assignments = service.get_zone_assignments_for_product(product, variant_sku)
for assignment in assignments:
print(f"{assignment['store_name']} - {assignment['zone_name']}: {assignment['par_quantity']} units")
# Output:
# Downtown Location - Coffee Bar: 10 units
# Uptown Location - Coffee Display: 15 units
2. Inventory Reconciliation:
# Compare par levels across all stores for a variant
assignments = service.get_zone_assignments_for_product(product, variant_sku)
for assignment in assignments:
# Get actual inventory level
inventory_level = InventoryLevel.objects.get(
product=product,
variant_sku=variant_sku,
store_id=assignment['store_id']
)
discrepancy = inventory_level.quantity_on_hand - assignment['par_quantity']
print(f"{assignment['store_name']}: {discrepancy} units {'over' if discrepancy > 0 else 'under'} par")
3. API Endpoint:
# /api/products/{product_id}/assignments/
@action(detail=True, methods=['get'])
def assignments(self, request, pk=None):
product = self.get_object()
variant_sku = request.query_params.get('variant_sku')
service = ZoneAssignmentService()
assignments = service.get_zone_assignments_for_product(product, variant_sku)
return Response(assignments)
get_products_for_zone()
Get all products assigned to a specific zone through par levels.
Purpose
Answers the question: "What products should be in this zone?"
Returns list of products with their par level assignments for the specified zone.
Signature
def get_products_for_zone(self, zone: Zone) -> List[Dict[str, Any]]:
"""
Get all products assigned to a specific zone through par levels.
Returns:
List of product assignment dictionaries
"""
Parameters
zone(Zone): Zone instance
Returns
[
{
'product_id': 'uuid-123',
'product_name': 'Dark Roast Coffee',
'variant_sku': 'DARK-12OZ',
'variant_name': '12 oz Bag',
'par_quantity': 10,
'par_level_id': 'uuid-456'
},
{
'product_id': 'uuid-789',
'product_name': 'Light Roast Coffee',
'variant_sku': 'LIGHT-12OZ',
'variant_name': '12 oz Bag',
'par_quantity': 8,
'par_level_id': 'uuid-012'
}
]
Implementation Logic
# 1. Check if zone has inventory configuration
if zone.zone_type != 'inventory' or not hasattr(zone, 'zone_inventory'):
return []
# 2. Get par levels with related products
par_levels = zone.zone_inventory.par_levels.select_related('product')
# 3. Build product list
for par_level in par_levels:
variant = par_level.get_product_variant() # Calls ProductVariant lookup
products.append({
'product_id': par_level.product.pk,
'product_name': par_level.product.name,
'variant_sku': par_level.variant_sku,
'variant_name': variant.name if variant else 'Unknown Variant',
'par_quantity': par_level.quantity,
'par_level_id': par_level.pk
})
Use Cases
1. Zone Inventory Checklist:
# Generate checklist for zone stockingzone = Zone.objects.get(zone_name='Coffee Bar')
service = ZoneAssignmentService()
products = service.get_products_for_zone(zone)
print(f"Stocking checklist for {zone.zone_name}:")
for product in products:
print(f"- {product['product_name']} ({product['variant_name']}): {product['par_quantity']} units")
# Output:
# Stocking checklist for Coffee Bar:
# - Dark Roast Coffee (12 oz Bag): 10 units
# - Light Roast Coffee (12 oz Bag): 8 units
2. Zone Compliance Report:
# Check if zone has correct products stocked
zone = Zone.objects.get(pk=zone_id)
products = service.get_products_for_zone(zone)
for product in products:
inventory_level = InventoryLevel.objects.get(
product_id=product['product_id'],
variant_sku=product['variant_sku'],
store=zone.store_location
)
actual = inventory_level.quantity_on_hand
par = product['par_quantity']
if actual < par:
print(f"{product['product_name']} below par: {actual}/{par}")
else:
print(f"{product['product_name']} at par: {actual}/{par}")
3. API Endpoint:
# /api/zones/{zone_id}/products/
@action(detail=True, methods=['get'])
def products(self, request, pk=None):
zone = self.get_object()
service = ZoneAssignmentService()
products = service.get_products_for_zone(zone)
return Response(products)
validate_sku_assignments()
Validate that all par level SKUs in a zone inventory match actual ProductVariant records.
Purpose
Data integrity check to ensure par level assignments reference valid product variants. Catches:
- Typos in SKUs
- Deleted product variants
- Mismatched product/variant relationships
Signature
def validate_sku_assignments(self, zone_inventory: ZoneInventory) -> Dict[str, Any]:
"""
Validate that all par level SKUs match actual ProductVariant records.
Returns:
Dict with validation results
"""
Parameters
zone_inventory(ZoneInventory): Zone inventory instance to validate
Returns
{
'valid_count': 18,
'invalid_count': 2,
'total_count': 20,
'invalid_items': [
{
'par_level_id': 'uuid-123',
'product_name': 'Dark Roast Coffee',
'variant_sku': 'DARK-16OZ-TYPO',
'error': "No ProductVariant with SKU 'DARK-16OZ-TYPO' found for product 'Dark Roast Coffee'"
},
{
'par_level_id': 'uuid-456',
'product_name': 'Light Roast Coffee',
'variant_sku': 'DELETED-SKU',
'error': "No ProductVariant with SKU 'DELETED-SKU' found for product 'Light Roast Coffee'"
}
]
}
Implementation Logic
# 1. Get all par levels for zone inventory
par_levels = zone_inventory.par_levels.select_related('product')
# 2. Validate each par level
for par_level in par_levels:
variant = par_level.get_product_variant() # Calls ProductVariant lookup
if variant:
results['valid_count'] += 1
else:
results['invalid_count'] += 1
results['invalid_items'].append({
'par_level_id': par_level.pk,
'product_name': par_level.product.name,
'variant_sku': par_level.variant_sku,
'error': f"No ProductVariant with SKU '{par_level.variant_sku}' found"
})
Use Cases
1. Data Import Validation:
# After bulk import from Sanity, validate all SKUs
zones = Zone.objects.filter(zone_type='inventory')
service = ZoneAssignmentService()
total_invalid = 0
for zone in zones:
if hasattr(zone, 'zone_inventory'):
results = service.validate_sku_assignments(zone.zone_inventory)
if results['invalid_count'] > 0:
print(f"{zone.zone_name}: {results['invalid_count']} invalid SKUs")
for item in results['invalid_items']:
print(f" - {item['product_name']}: {item['variant_sku']}")
total_invalid += results['invalid_count']
if total_invalid == 0:
print("All SKU assignments are valid")
2. Management Command:
# management/commands/validate_zone_skus.py
class Command(BaseCommand):
def handle(self, *args, **options):
service = ZoneAssignmentService()
zone_inventories = ZoneInventory.objects.all()
for zone_inv in zone_inventories:
results = service.validate_sku_assignments(zone_inv)
if results['invalid_count'] > 0:
self.stdout.write(self.style.WARNING(
f"{zone_inv.zone.zone_name}: {results['invalid_count']} invalid"
))
for item in results['invalid_items']:
self.stdout.write(f" {item['error']}")
3. Pre-Sync Check:
# Before syncing par levels to inventory, validate SKUs
def safe_sync_par_levels_to_inventory(store):
service = ZoneAssignmentService()
# Step 1: Validate all SKUs
zones = Zone.objects.filter(store_location=store, zone_type='inventory')
has_errors = False
for zone in zones:
if hasattr(zone, 'zone_inventory'):
results = service.validate_sku_assignments(zone.zone_inventory)
if results['invalid_count'] > 0:
logger.error(f"Zone {zone.zone_name} has invalid SKUs")
has_errors = True
if has_errors:
raise ValueError("Cannot sync - fix invalid SKUs first")
# Step 2: Sync infrastructure
stats = service.sync_par_levels_to_inventory(store=store)
return stats
cleanup_orphaned_inventory_levels()
Remove InventoryLevel records that no longer have corresponding par level assignments.
Purpose
Cleanup operation to remove inventory tracking for products that are no longer assigned to any zone at a store. Maintains data integrity by removing orphaned records.
Signature
def cleanup_orphaned_inventory_levels(self, store: Optional['Store'] = None) -> Dict[str, int]:
"""
Remove InventoryLevel records that no longer have corresponding par level assignments.
Args:
store: Optional store to limit cleanup to specific store
Returns:
Dict with cleanup statistics
"""
Parameters
store(Store, optional): If provided, only cleanup inventory levels for this store
Returns
{
'checked': 150,
'removed': 8,
'errors': []
}
Implementation Logic
# 1. Get inventory levels to check
inventory_levels_queryset = self.InventoryLevel.objects.all()
if store:
inventory_levels_queryset = inventory_levels_queryset.filter(store=store)
# 2. Check each inventory level
for inventory_level in inventory_levels:
# 3. Check if there's a corresponding par level assignment
par_level_exists = ParLevelItem.objects.filter(
product=inventory_level.product,
variant_sku=inventory_level.variant_sku,
zone_inventory__zone__store_location=inventory_level.store
).exists()
# 4. If no par level exists, remove inventory level
if not par_level_exists:
logger.info(f"Removing orphaned InventoryLevel: {inventory_level}")
inventory_level.delete()
stats['removed'] += 1
Use Cases
1. After Zone Reconfiguration:
# Admin removed products from zone in Sanity, cleanup orphaned inventory
store = Store.objects.get(name='Downtown Location')
service = ZoneAssignmentService()
stats = service.cleanup_orphaned_inventory_levels(store=store)
logger.info(f"Cleanup complete: {stats['removed']} orphaned inventory levels removed")
2. Periodic Maintenance:
# Scheduled job to cleanup orphaned inventory levels
from nextango.apps.zones.services import ZoneAssignmentService
def scheduled_inventory_cleanup():
service = ZoneAssignmentService()
# Cleanup all stores
stats = service.cleanup_orphaned_inventory_levels()
logger.info(f"System-wide cleanup: {stats}")
return stats
3. Management Command:
# management/commands/cleanup_orphaned_inventory.py
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('--store-id', type=str, help='Store ID to cleanup')
def handle(self, *args, **options):
service = ZoneAssignmentService()
if options['store_id']:
store = Store.objects.get(pk=options['store_id'])
stats = service.cleanup_orphaned_inventory_levels(store=store)
self.stdout.write(f"Store cleanup: {stats}")
else:
stats = service.cleanup_orphaned_inventory_levels()
self.stdout.write(f"System cleanup: {stats}")
4. Pre-Deployment Cleanup:
# Before major zone reconfiguration, cleanup orphaned records
def prepare_for_zone_migration(store):
service = ZoneAssignmentService()
# Step 1: Cleanup orphaned inventory levels
cleanup_stats = service.cleanup_orphaned_inventory_levels(store=store)
logger.info(f"Pre-migration cleanup: {cleanup_stats}")
# Step 2: Validate remaining SKUs
zones = Zone.objects.filter(store_location=store, zone_type='inventory')
for zone in zones:
if hasattr(zone, 'zone_inventory'):
validation = service.validate_sku_assignments(zone.zone_inventory)
if validation['invalid_count'] > 0:
raise ValueError(f"Invalid SKUs found in {zone.zone_name}")
# Step 3: Sync new infrastructure
sync_stats = service.sync_par_levels_to_inventory(store=store)
logger.info(f"Post-migration sync: {sync_stats}")
Error Handling
All service methods use try-except blocks to catch and log errors without crashing:
try:
# Service logic
inventory_level = par_level.ensure_inventory_level_exists()
stats['created'] += 1
except Exception as e:
# Log error
error_msg = f"Failed to create inventory level for par level {par_level.pk}: {e}"
stats['errors'].append(error_msg)
stats['failed'] += 1
logger.error(error_msg)
Benefits:
- Partial failures don't stop entire operation
- All errors logged for debugging
- Statistics include error counts and messages
- Allows retry of individual failures
Related Documentation
Zones Domain
- README - Zones domain overview
- models.md - Zone, ParLevelItem, ZoneInventory models
- serializers.md - Zone data validation
- views.md - Zone API endpoints
- signals.md - Zone sync patterns
Related Domains
- products/models.md - Product, ProductVariant, InventoryLevel models
- stores/models.md - Store model
Summary: ZoneAssignmentService implements zone-driven inventory infrastructure management, ensuring that inventory tracking exists for all product variants assigned to zones through par levels.