* Vietnamese translation incomplete

Tour operator utils

Tour operator utils (English fallback)

Aug. 17, 2025

Posted by admin

Nhom

Notes

 

Tour Operators Utils - External Integration System

File Overview

Purpose: External tour provider API integration and synchronization Locationutils.py Function: Automated tour content aggregation from third-party providers Key Features: Multi-provider support, price markup management, automatic synchronization

 

 

Import Dependencies Analysis

import requests

from django.conf import settings

from django.utils import timezone

from decimal import Decimal

from datetime import datetime, timedelta

import logging

from .models import Tour, TourOperator, ExternalTourSync, TourSchedule

logger = logging.getLogger(__name__)

External Libraries:

  • requests: HTTP API communication
  • Decimal: Precise financial calculations
  • logging: Error tracking and monitoring

Django Components:

  • settings: Configuration management
  • timezone: Date/time handling
  • Custom models for tour management

Core Architecture

 

1. ExternalTourProvider (Base Class)

class ExternalTourProvider:

    """Base class for external tour providers"""

    

    def __init__(self, operator_name):

        self.operator_name = operator_name

        self.operator = None

        self.setup_operator()

Purpose: Abstract base class for all external tour providers Design Pattern: Template Method Pattern - defines common workflow

Operator Setup Method

def setup_operator(self):

    """Create or get the tour operator for this external provider"""

    operator, created = TourOperator.objects.get_or_create(

        name=self.operator_name,

        defaults={

            'operator_type': 'broker',

            'description': f'External tours from {self.operator_name}',

            'email': f'noreply@{self.operator_name.lower()}.com',

            'phone': '+1-000-000-0000',

            'address': 'External Provider',

            'is_active': True,

            'is_verified': True,

        }

    )

    self.operator = operator

Functionality:

  • Automatic Operator Creation: Creates operator record if doesn't exist
  • Standardized Setup: Consistent configuration for all external providers
  • Broker Classification: Marks as 'broker' type for business logic
  • Auto-Verification: External providers are pre-verified

Tour Creation/Update Logic

def create_or_update_tour(self, tour_data):

    """Create or update a tour from external data"""

    external_id = tour_data.get('id') or tour_data.get('external_id')

    

    # Check if tour already exists

    try:

        sync_info = ExternalTourSync.objects.get(

            external_provider=self.operator_name.lower(),

            external_tour_id=external_id

        )

        tour = sync_info.tour

        created = False

    except ExternalTourSync.DoesNotExist:

        tour = Tour(tour_operator=self.operator)

        created = True

Business Logic:

  1. Duplicate Prevention: Uses ExternalTourSync to track existing tours
  2. Update vs Create: Determines whether to update existing or create new
  3. Data Integrity: Maintains relationship between external and internal tours

Tour Data Mapping

# Update tour fields

tour.title = tour_data.get('title', '')[:200]

tour.title_vi = tour_data.get('title_vi', '')[:200]

tour.slug = self.generate_slug(tour.title, external_id)

tour.description = tour_data.get('description', '')

tour.short_description = tour_data.get('short_description', tour.description[:500])

tour.base_price = Decimal(str(tour_data.get('price', 0)))

tour.duration_days = tour_data.get('duration_days', 1)

tour.duration_hours = tour_data.get('duration_hours', 0)

tour.min_participants = tour_data.get('min_participants', 1)

tour.max_participants = tour_data.get('max_participants', 20)

tour.source = self.operator_name.lower()

tour.external_id = external_id

tour.external_url = tour_data.get('url', '')

tour.last_synced = timezone.now()

Key Features:

  • Data Truncation: Prevents database field overflow
  • Safe Defaults: Provides fallback values for missing data
  • Price Precision: Uses Decimal for accurate financial calculations
  • Source Tracking: Maintains origin information
  • Sync Timestamps: Tracks last update time

Synchronization Record Management

# Create or update sync info

if created:

    ExternalTourSync.objects.create(

        tour=tour,

        external_provider=self.operator_name.lower(),

        external_tour_id=external_id,

        last_sync_date=timezone.now(),

        external_price=tour.base_price,

        markup_percentage=Decimal('15.00')  # Default markup

    )

else:

    sync_info.last_sync_date = timezone.now()

    sync_info.external_price = tour.base_price

    sync_info.save()

Functionality:

  • Sync Tracking: Records synchronization metadata
  • Price Management: Tracks original vs marked-up prices
  • Default Markup: 15% standard markup for external tours
  • Update Timestamps: Maintains sync history

Unique Slug Generation

def generate_slug(self, title, external_id):

    """Generate a unique slug for the tour"""

    from django.utils.text import slugify

    base_slug = slugify(title)[:180]  # Leave room for suffix

    slug = f"{base_slug}-{external_id}"

    

    # Ensure uniqueness

    counter = 1

    original_slug = slug

    while Tour.objects.filter(slug=slug).exists():

        slug = f"{original_slug}-{counter}"

        counter += 1

    

    return slug

Features:

  • URL-Safe Generation: Uses Django's slugify
  • Collision Prevention: Automatic counter appending
  • Length Management: Respects database field limits
  • External ID Integration: Includes provider ID for uniqueness

 

 

2. ViatorProvider Implementation

class ViatorProvider(ExternalTourProvider):

    """Viator tour provider integration"""

    

    def __init__(self):

        super().__init__('Viator')

        self.api_key = getattr(settings, 'VIATOR_API_KEY', '')

        self.base_url = 'https://api.viator.com/partner'

Purpose: Integration with Viator's tour marketplace API Configuration: Uses Django settings for API credentials

API Communication

def fetch_tours(self, destination_code=None, limit=50):

    """Fetch tours from Viator API"""

    if not self.api_key:

        logger.warning('Viator API key not configured')

        return []

    

    headers = {

        'exp-api-key': self.api_key,

        'Accept': 'application/json',

        'Accept-Language': 'en-US'

    }

    

    # Search for products

    search_url = f"{self.base_url}/products/search"

    params = {

        'count': limit,

        'currency': 'USD'

    }

    

    if destination_code:

        params['destId'] = destination_code

  •  
  •  
  •  
  •  

Features:

  • API Key Validation: Graceful handling of missing credentials
  • Flexible Parameters: Optional destination and limit filtering
  • Proper Headers: Viator-specific authentication and content type
  • Currency Standardization: USD for consistent pricing

Data Parsing

def parse_viator_product(self, product):

    """Parse Viator product data into our tour format"""

    try:

        return {

            'id': product.get('productCode'),

            'title': product.get('title', ''),

            'description': product.get('description', ''),

            'short_description': product.get('shortDescription', ''),

            'price': product.get('pricing', {}).get('summary', {}).get('fromPrice', 0),

            'duration_days': self.parse_duration(product.get('duration')),

            'duration_hours': 0,  # Viator usually specifies in days or hours

            'min_participants': 1,

            'max_participants': 20,

            'url': f"https://www.viator.com/tours/{product.get('productCode')}",

            'schedules': self.parse_viator_schedules(product)

        }

    except Exception as e:

        logger.error(f'Error parsing Viator product {product.get("productCode")}: {e}')

        return None

Data Transformation:

  • Safe Navigation: Uses .get() to prevent KeyError
  • Nested Data Access: Handles complex JSON structures
  • Error Handling: Logs parsing errors without crashing
  • URL Construction: Builds direct links to Viator tours
  • Schedule Integration: Parses availability information

Duration Parsing

def parse_duration(self, duration_str):

    """Parse Viator duration string to days"""

    if not duration_str:

        return 1

    

    # Simple parsing - improve as needed

    duration_str = duration_str.lower()

    if 'day' in duration_str:

        try:

            return int(duration_str.split()[0])

        except (ValueError, IndexError):

            return 1

    return 1

Functionality:

  • String Processing: Handles various duration formats
  • Fallback Logic: Returns sensible defaults for unparseable data
  • Error Resilience: Prevents crashes from malformed duration strings

 

 

3. GetYourGuideProvider Implementation

class GetYourGuideProvider(ExternalTourProvider):

    """GetYourGuide tour provider integration"""

    

    def __init__(self):

        super().__init__('GetYourGuide')

        self.api_key = getattr(settings, 'GETYOURGUIDE_API_KEY', '')

        self.base_url = 'https://api.getyourguide.com'

Purpose: Integration with GetYourGuide's activity marketplace Similar Structure: Follows same pattern as Viator for consistency

Activity Data Parsing

def parse_getyourguide_activity(self, activity):

    """Parse GetYourGuide activity data into our tour format"""

    try:

        return {

            'id': activity.get('id'),

            'title': activity.get('title', ''),

            'description': activity.get('description', ''),

            'short_description': activity.get('summary', ''),

            'price': activity.get('pricing', {}).get('from_price', 0),

            'duration_days': 1,  # Most GetYourGuide activities are day tours

            'duration_hours': activity.get('duration', {}).get('hours', 4),

            'min_participants': 1,

            'max_participants': activity.get('group_size', {}).get('max', 20),

            'url': activity.get('url', ''),

            'schedules': self.parse_getyourguide_schedules(activity)

        }

    except Exception as e:

        logger.error(f'Error parsing GetYourGuide activity {activity.get("id")}: {e}')

        return None

GetYourGuide Specifics:

  • Activity Focus: Primarily day tours and activities
  • Hour-based Duration: More granular time specifications
  • Group Size Limits: Specific capacity management
  • Different Field Names: Maps GetYourGuide schema to internal format

 

 

4. Utility Functions

Synchronization Control

def sync_external_tours(provider_name, **kwargs):

    """Sync tours from external providers"""

    provider_map = {

        'viator': ViatorProvider,

        'getyourguide': GetYourGuideProvider,

    }

    

    if provider_name not in provider_map:

        raise ValueError(f'Unknown provider: {provider_name}')

    

    provider = provider_map[provider_name]()

    tours_data = provider.fetch_tours(**kwargs)

    

    created_count = 0

    updated_count = 0

    

    for tour_data in tours_data:

        try:

            tour, created = provider.create_or_update_tour(tour_data)

            if created:

                created_count += 1

            else:

                updated_count += 1

                

            logger.info(f'{"Created" if created else "Updated"} tour: {tour.title}')

            

        except Exception as e:

            logger.error(f'Error processing tour {tour_data.get("id")}: {e}')

    

    return {

        'created': created_count,

        'updated': updated_count,

        'total': len(tours_data)

    }

Features:

  • Provider Registry: Centralized provider management
  • Flexible Parameters: Passes through provider-specific options
  • Progress Tracking: Counts created vs updated tours
  • Error Isolation: Individual tour failures don't stop sync
  • Result Reporting: Returns detailed statistics

Price Management

def calculate_markup_price(external_price, markup_percentage):

    """Calculate the selling price with markup"""

    markup_amount = external_price * (markup_percentage / 100)

    return external_price + markup_amount

def update_external_tour_prices():

    """Update prices for all external tours based on current markup settings"""

    sync_records = ExternalTourSync.objects.filter(sync_status='active')

    

    for sync_record in sync_records:

        if sync_record.external_price and sync_record.markup_percentage:

            new_price = calculate_markup_price(

                sync_record.external_price,

                sync_record.markup_percentage

            )

            

            tour = sync_record.tour

            tour.base_price = new_price

            tour.save(update_fields=['base_price', 'updated_at'])

            

            logger.info(f'Updated price for tour {tour.title}: {new_price}')

Business Logic:

  • Dynamic Pricing: Recalculates prices based on current markup rates
  • Bulk Updates: Processes all external tours efficiently
  • Selective Updates: Only updates necessary fields
  • Audit Trail: Logs all price changes

Comprehensive Synchronization

def sync_all_external_tours():

    """Sync tours from all configured external providers"""

    results = {}

    

    providers = ['viator', 'getyourguide']

    

    for provider in providers:

        try:

            result = sync_external_tours(provider)

            results[provider] = result

            logger.info(f'Synced {result["created"]} new tours from {provider}')

        except Exception as e:

            logger.error(f'Error syncing from {provider}: {e}')

            results[provider] = {'error': str(e)}

    

    return results

System Integration:

  • Multi-Provider Support: Handles all configured providers
  • Error Isolation: One provider failure doesn't affect others
  • Comprehensive Reporting: Returns results for all providers
  • Logging: Detailed success and error tracking

 

 

Business Use Cases

Content Aggregation

  • Tour Inventory Expansion: Automatically adds thousands of tours
  • Geographic Coverage: Expands destination offerings
  • Real-time Updates: Keeps content fresh and accurate

Revenue Generation

  • Markup Management: Configurable profit margins
  • Dynamic Pricing: Responsive to external price changes
  • Commission Tracking: Separate pricing for cost analysis

Operational Efficiency

  • Automated Synchronization: Reduces manual content management
  • Error Handling: Robust failure recovery
  • Audit Trails: Complete change tracking

Integration Architecture

  • Extensible Design: Easy to add new providers
  • Consistent Interface: Standardized data format
  • Scalable Processing: Handles large tour catalogs

Technical Benefits

Data Consistency

  • Standardized Format: All external tours use same schema
  • Validation: Input sanitization and validation
  • Relationship Integrity: Proper foreign key management

Performance Optimization

  • Bulk Operations: Efficient database updates
  • Caching Strategy: Minimizes API calls
  • Background Processing: Non-blocking synchronization

Error Resilience

  • Graceful Degradation: Individual failures don't crash system
  • Comprehensive Logging: Detailed error tracking
  • Recovery Mechanisms: Retry logic and fallbacks

This utility system provides a sophisticated, enterprise-grade solution for aggregating and managing external tour content, enabling the platform to offer comprehensive tour inventory while maintaining pricing control and operational efficiency.

 

Vietnamese translation is not available for this article. Showing English content:

Nhom

Notes

 

Tour Operators Utils - External Integration System

File Overview

Purpose: External tour provider API integration and synchronization Locationutils.py Function: Automated tour content aggregation from third-party providers Key Features: Multi-provider support, price markup management, automatic synchronization

 

 

Import Dependencies Analysis

import requests

from django.conf import settings

from django.utils import timezone

from decimal import Decimal

from datetime import datetime, timedelta

import logging

from .models import Tour, TourOperator, ExternalTourSync, TourSchedule

logger = logging.getLogger(__name__)

External Libraries:

  • requests: HTTP API communication
  • Decimal: Precise financial calculations
  • logging: Error tracking and monitoring

Django Components:

  • settings: Configuration management
  • timezone: Date/time handling
  • Custom models for tour management

Core Architecture

 

1. ExternalTourProvider (Base Class)

class ExternalTourProvider:

    """Base class for external tour providers"""

    

    def __init__(self, operator_name):

        self.operator_name = operator_name

        self.operator = None

        self.setup_operator()

Purpose: Abstract base class for all external tour providers Design Pattern: Template Method Pattern - defines common workflow

Operator Setup Method

def setup_operator(self):

    """Create or get the tour operator for this external provider"""

    operator, created = TourOperator.objects.get_or_create(

        name=self.operator_name,

        defaults={

            'operator_type': 'broker',

            'description': f'External tours from {self.operator_name}',

            'email': f'noreply@{self.operator_name.lower()}.com',

            'phone': '+1-000-000-0000',

            'address': 'External Provider',

            'is_active': True,

            'is_verified': True,

        }

    )

    self.operator = operator

Functionality:

  • Automatic Operator Creation: Creates operator record if doesn't exist
  • Standardized Setup: Consistent configuration for all external providers
  • Broker Classification: Marks as 'broker' type for business logic
  • Auto-Verification: External providers are pre-verified

Tour Creation/Update Logic

def create_or_update_tour(self, tour_data):

    """Create or update a tour from external data"""

    external_id = tour_data.get('id') or tour_data.get('external_id')

    

    # Check if tour already exists

    try:

        sync_info = ExternalTourSync.objects.get(

            external_provider=self.operator_name.lower(),

            external_tour_id=external_id

        )

        tour = sync_info.tour

        created = False

    except ExternalTourSync.DoesNotExist:

        tour = Tour(tour_operator=self.operator)

        created = True

Business Logic:

  1. Duplicate Prevention: Uses ExternalTourSync to track existing tours
  2. Update vs Create: Determines whether to update existing or create new
  3. Data Integrity: Maintains relationship between external and internal tours

Tour Data Mapping

# Update tour fields

tour.title = tour_data.get('title', '')[:200]

tour.title_vi = tour_data.get('title_vi', '')[:200]

tour.slug = self.generate_slug(tour.title, external_id)

tour.description = tour_data.get('description', '')

tour.short_description = tour_data.get('short_description', tour.description[:500])

tour.base_price = Decimal(str(tour_data.get('price', 0)))

tour.duration_days = tour_data.get('duration_days', 1)

tour.duration_hours = tour_data.get('duration_hours', 0)

tour.min_participants = tour_data.get('min_participants', 1)

tour.max_participants = tour_data.get('max_participants', 20)

tour.source = self.operator_name.lower()

tour.external_id = external_id

tour.external_url = tour_data.get('url', '')

tour.last_synced = timezone.now()

Key Features:

  • Data Truncation: Prevents database field overflow
  • Safe Defaults: Provides fallback values for missing data
  • Price Precision: Uses Decimal for accurate financial calculations
  • Source Tracking: Maintains origin information
  • Sync Timestamps: Tracks last update time

Synchronization Record Management

# Create or update sync info

if created:

    ExternalTourSync.objects.create(

        tour=tour,

        external_provider=self.operator_name.lower(),

        external_tour_id=external_id,

        last_sync_date=timezone.now(),

        external_price=tour.base_price,

        markup_percentage=Decimal('15.00')  # Default markup

    )

else:

    sync_info.last_sync_date = timezone.now()

    sync_info.external_price = tour.base_price

    sync_info.save()

Functionality:

  • Sync Tracking: Records synchronization metadata
  • Price Management: Tracks original vs marked-up prices
  • Default Markup: 15% standard markup for external tours
  • Update Timestamps: Maintains sync history

Unique Slug Generation

def generate_slug(self, title, external_id):

    """Generate a unique slug for the tour"""

    from django.utils.text import slugify

    base_slug = slugify(title)[:180]  # Leave room for suffix

    slug = f"{base_slug}-{external_id}"

    

    # Ensure uniqueness

    counter = 1

    original_slug = slug

    while Tour.objects.filter(slug=slug).exists():

        slug = f"{original_slug}-{counter}"

        counter += 1

    

    return slug

Features:

  • URL-Safe Generation: Uses Django's slugify
  • Collision Prevention: Automatic counter appending
  • Length Management: Respects database field limits
  • External ID Integration: Includes provider ID for uniqueness

 

 

2. ViatorProvider Implementation

class ViatorProvider(ExternalTourProvider):

    """Viator tour provider integration"""

    

    def __init__(self):

        super().__init__('Viator')

        self.api_key = getattr(settings, 'VIATOR_API_KEY', '')

        self.base_url = 'https://api.viator.com/partner'

Purpose: Integration with Viator's tour marketplace API Configuration: Uses Django settings for API credentials

API Communication

def fetch_tours(self, destination_code=None, limit=50):

    """Fetch tours from Viator API"""

    if not self.api_key:

        logger.warning('Viator API key not configured')

        return []

    

    headers = {

        'exp-api-key': self.api_key,

        'Accept': 'application/json',

        'Accept-Language': 'en-US'

    }

    

    # Search for products

    search_url = f"{self.base_url}/products/search"

    params = {

        'count': limit,

        'currency': 'USD'

    }

    

    if destination_code:

        params['destId'] = destination_code

  •  
  •  
  •  
  •  

Features:

  • API Key Validation: Graceful handling of missing credentials
  • Flexible Parameters: Optional destination and limit filtering
  • Proper Headers: Viator-specific authentication and content type
  • Currency Standardization: USD for consistent pricing

Data Parsing

def parse_viator_product(self, product):

    """Parse Viator product data into our tour format"""

    try:

        return {

            'id': product.get('productCode'),

            'title': product.get('title', ''),

            'description': product.get('description', ''),

            'short_description': product.get('shortDescription', ''),

            'price': product.get('pricing', {}).get('summary', {}).get('fromPrice', 0),

            'duration_days': self.parse_duration(product.get('duration')),

            'duration_hours': 0,  # Viator usually specifies in days or hours

            'min_participants': 1,

            'max_participants': 20,

            'url': f"https://www.viator.com/tours/{product.get('productCode')}",

            'schedules': self.parse_viator_schedules(product)

        }

    except Exception as e:

        logger.error(f'Error parsing Viator product {product.get("productCode")}: {e}')

        return None

Data Transformation:

  • Safe Navigation: Uses .get() to prevent KeyError
  • Nested Data Access: Handles complex JSON structures
  • Error Handling: Logs parsing errors without crashing
  • URL Construction: Builds direct links to Viator tours
  • Schedule Integration: Parses availability information

Duration Parsing

def parse_duration(self, duration_str):

    """Parse Viator duration string to days"""

    if not duration_str:

        return 1

    

    # Simple parsing - improve as needed

    duration_str = duration_str.lower()

    if 'day' in duration_str:

        try:

            return int(duration_str.split()[0])

        except (ValueError, IndexError):

            return 1

    return 1

Functionality:

  • String Processing: Handles various duration formats
  • Fallback Logic: Returns sensible defaults for unparseable data
  • Error Resilience: Prevents crashes from malformed duration strings

 

 

3. GetYourGuideProvider Implementation

class GetYourGuideProvider(ExternalTourProvider):

    """GetYourGuide tour provider integration"""

    

    def __init__(self):

        super().__init__('GetYourGuide')

        self.api_key = getattr(settings, 'GETYOURGUIDE_API_KEY', '')

        self.base_url = 'https://api.getyourguide.com'

Purpose: Integration with GetYourGuide's activity marketplace Similar Structure: Follows same pattern as Viator for consistency

Activity Data Parsing

def parse_getyourguide_activity(self, activity):

    """Parse GetYourGuide activity data into our tour format"""

    try:

        return {

            'id': activity.get('id'),

            'title': activity.get('title', ''),

            'description': activity.get('description', ''),

            'short_description': activity.get('summary', ''),

            'price': activity.get('pricing', {}).get('from_price', 0),

            'duration_days': 1,  # Most GetYourGuide activities are day tours

            'duration_hours': activity.get('duration', {}).get('hours', 4),

            'min_participants': 1,

            'max_participants': activity.get('group_size', {}).get('max', 20),

            'url': activity.get('url', ''),

            'schedules': self.parse_getyourguide_schedules(activity)

        }

    except Exception as e:

        logger.error(f'Error parsing GetYourGuide activity {activity.get("id")}: {e}')

        return None

GetYourGuide Specifics:

  • Activity Focus: Primarily day tours and activities
  • Hour-based Duration: More granular time specifications
  • Group Size Limits: Specific capacity management
  • Different Field Names: Maps GetYourGuide schema to internal format

 

 

4. Utility Functions

Synchronization Control

def sync_external_tours(provider_name, **kwargs):

    """Sync tours from external providers"""

    provider_map = {

        'viator': ViatorProvider,

        'getyourguide': GetYourGuideProvider,

    }

    

    if provider_name not in provider_map:

        raise ValueError(f'Unknown provider: {provider_name}')

    

    provider = provider_map[provider_name]()

    tours_data = provider.fetch_tours(**kwargs)

    

    created_count = 0

    updated_count = 0

    

    for tour_data in tours_data:

        try:

            tour, created = provider.create_or_update_tour(tour_data)

            if created:

                created_count += 1

            else:

                updated_count += 1

                

            logger.info(f'{"Created" if created else "Updated"} tour: {tour.title}')

            

        except Exception as e:

            logger.error(f'Error processing tour {tour_data.get("id")}: {e}')

    

    return {

        'created': created_count,

        'updated': updated_count,

        'total': len(tours_data)

    }

Features:

  • Provider Registry: Centralized provider management
  • Flexible Parameters: Passes through provider-specific options
  • Progress Tracking: Counts created vs updated tours
  • Error Isolation: Individual tour failures don't stop sync
  • Result Reporting: Returns detailed statistics

Price Management

def calculate_markup_price(external_price, markup_percentage):

    """Calculate the selling price with markup"""

    markup_amount = external_price * (markup_percentage / 100)

    return external_price + markup_amount

def update_external_tour_prices():

    """Update prices for all external tours based on current markup settings"""

    sync_records = ExternalTourSync.objects.filter(sync_status='active')

    

    for sync_record in sync_records:

        if sync_record.external_price and sync_record.markup_percentage:

            new_price = calculate_markup_price(

                sync_record.external_price,

                sync_record.markup_percentage

            )

            

            tour = sync_record.tour

            tour.base_price = new_price

            tour.save(update_fields=['base_price', 'updated_at'])

            

            logger.info(f'Updated price for tour {tour.title}: {new_price}')

Business Logic:

  • Dynamic Pricing: Recalculates prices based on current markup rates
  • Bulk Updates: Processes all external tours efficiently
  • Selective Updates: Only updates necessary fields
  • Audit Trail: Logs all price changes

Comprehensive Synchronization

def sync_all_external_tours():

    """Sync tours from all configured external providers"""

    results = {}

    

    providers = ['viator', 'getyourguide']

    

    for provider in providers:

        try:

            result = sync_external_tours(provider)

            results[provider] = result

            logger.info(f'Synced {result["created"]} new tours from {provider}')

        except Exception as e:

            logger.error(f'Error syncing from {provider}: {e}')

            results[provider] = {'error': str(e)}

    

    return results

System Integration:

  • Multi-Provider Support: Handles all configured providers
  • Error Isolation: One provider failure doesn't affect others
  • Comprehensive Reporting: Returns results for all providers
  • Logging: Detailed success and error tracking

 

 

Business Use Cases

Content Aggregation

  • Tour Inventory Expansion: Automatically adds thousands of tours
  • Geographic Coverage: Expands destination offerings
  • Real-time Updates: Keeps content fresh and accurate

Revenue Generation

  • Markup Management: Configurable profit margins
  • Dynamic Pricing: Responsive to external price changes
  • Commission Tracking: Separate pricing for cost analysis

Operational Efficiency

  • Automated Synchronization: Reduces manual content management
  • Error Handling: Robust failure recovery
  • Audit Trails: Complete change tracking

Integration Architecture

  • Extensible Design: Easy to add new providers
  • Consistent Interface: Standardized data format
  • Scalable Processing: Handles large tour catalogs

Technical Benefits

Data Consistency

  • Standardized Format: All external tours use same schema
  • Validation: Input sanitization and validation
  • Relationship Integrity: Proper foreign key management

Performance Optimization

  • Bulk Operations: Efficient database updates
  • Caching Strategy: Minimizes API calls
  • Background Processing: Non-blocking synchronization

Error Resilience

  • Graceful Degradation: Individual failures don't crash system
  • Comprehensive Logging: Detailed error tracking
  • Recovery Mechanisms: Retry logic and fallbacks

This utility system provides a sophisticated, enterprise-grade solution for aggregating and managing external tour content, enabling the platform to offer comprehensive tour inventory while maintaining pricing control and operational efficiency.

 

Attached Files

0 files found.

You are viewing this article in public mode. Some features may be limited.