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:

  1. create_inventory_infrastructure_for_zone() - Create InventoryLevel records for zone
  2. sync_par_levels_to_inventory() - Sync all par levels to inventory infrastructure
  3. get_zone_assignments_for_product() - Find where a product should be located
  4. get_products_for_zone() - Get all products assigned to a zone
  5. validate_sku_assignments() - Validate par level SKUs match ProductVariants
  6. cleanup_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 instance
  • variant_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

Zones Domain

Related Domains


Summary: ZoneAssignmentService implements zone-driven inventory infrastructure management, ensuring that inventory tracking exists for all product variants assigned to zones through par levels.

Was this page helpful?