CargoWise for Ocean Freight: Container Management & Documentation (2025 Guide)

Jan 19, 2025
cargowiseocean-freightcontainer-managementbill-of-lading
0

Ocean freight is the backbone of global trade, handling over 90% of international cargo by volume. CargoWise provides comprehensive tools for managing ocean freight operations, from container tracking and bill of lading management to carrier integrations and demurrage handling. Understanding these workflows is essential for efficient ocean freight operations.

This comprehensive guide covers everything you need to know about CargoWise ocean freight workflows, from container management and documentation to carrier integrations and demurrage management. Whether you're managing FCL, LCL, or specialized ocean cargo, this guide will help you optimize your ocean freight processes.

Understanding Ocean Freight in CargoWise

Ocean Freight Workflow Overview

Core Ocean Freight Processes:

  • Booking Management: Vessel reservations and space allocation
  • Container Management: Container tracking and status updates
  • Bill of Lading: B/L creation and management
  • Documentation: Customs and regulatory compliance
  • Tracking: Real-time shipment monitoring and updates
  • Demurrage Management: Container detention and demurrage tracking

Key Ocean Freight Stakeholders:

  • Shipping Lines: Vessel operators and capacity providers
  • Terminal Operators: Port operations and container handling
  • Customs Brokers: Regulatory compliance and clearance
  • Consignees: End customers and delivery recipients
  • Shippers: Cargo owners and origin customers

Ocean Freight Data Model

CargoWise Ocean Freight Entities:

OceanShipment (1) -----> (N) Container
    |                      |
    |                      |
    v                      v
BillOfLading (1) -----> (N) ContainerItem
    |                      |
    |                      |
    v                      v
VesselBooking (1) -----> (N) VesselSchedule
    |                      |
    |                      |
    v                      v
DemurrageRecord (1) -----> (N) DemurrageCharge

Container Management

Container Tracking and Status

C# Container Management Service:

public class CargoWiseContainerManagementService
{
    private readonly ILogger<CargoWiseContainerManagementService> _logger;
    private readonly IContainerRepository _containerRepository;
    private readonly ICarrierService _carrierService;
    private readonly ITrackingService _trackingService;
    
    public CargoWiseContainerManagementService(
        ILogger<CargoWiseContainerManagementService> logger,
        IContainerRepository containerRepository,
        ICarrierService carrierService,
        ITrackingService trackingService)
    {
        _logger = logger;
        _containerRepository = containerRepository;
        _carrierService = carrierService;
        _trackingService = trackingService;
    }
    
    public async Task<ContainerResult> CreateContainer(CreateContainerRequest request)
    {
        var result = new ContainerResult
        {
            StartTime = DateTime.UtcNow,
            Status = ContainerStatus.InProgress
        };
        
        try
        {
            _logger.LogInformation("Creating container: {ContainerNumber}", request.ContainerNumber);
            
            // Validate container data
            var validationResult = await ValidateContainerData(request);
            if (!validationResult.IsValid)
            {
                result.Status = ContainerStatus.ValidationFailed;
                result.ErrorMessage = validationResult.ErrorMessage;
                return result;
            }
            
            // Create container record
            var container = new Container
            {
                Id = Guid.NewGuid().ToString(),
                ContainerNumber = request.ContainerNumber,
                ContainerType = request.ContainerType,
                Size = request.Size,
                Status = ContainerStatus.Created,
                Vessel = request.Vessel,
                Voyage = request.Voyage,
                PortOfLoading = request.PortOfLoading,
                PortOfDischarge = request.PortOfDischarge,
                ETD = request.ETD,
                ETA = request.ETA,
                Shipper = request.Shipper,
                Consignee = request.Consignee,
                GoodsDescription = request.GoodsDescription,
                Weight = request.Weight,
                Volume = request.Volume,
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow
            };
            
            // Save container
            await _containerRepository.CreateAsync(container);
            
            result.Status = ContainerStatus.Created;
            result.Container = container;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            _logger.LogInformation("Container created successfully: {ContainerNumber}", request.ContainerNumber);
            
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error creating container: {ContainerNumber}", request.ContainerNumber);
            
            result.Status = ContainerStatus.Failed;
            result.ErrorMessage = ex.Message;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            return result;
        }
    }
    
    public async Task<ContainerTrackingResult> TrackContainer(string containerNumber)
    {
        var result = new ContainerTrackingResult
        {
            ContainerNumber = containerNumber,
            StartTime = DateTime.UtcNow,
            Status = ContainerTrackingStatus.InProgress
        };
        
        try
        {
            _logger.LogInformation("Tracking container: {ContainerNumber}", containerNumber);
            
            // Get container record
            var container = await _containerRepository.GetByContainerNumberAsync(containerNumber);
            if (container == null)
            {
                result.Status = ContainerTrackingStatus.ContainerNotFound;
                result.ErrorMessage = "Container not found";
                return result;
            }
            
            // Get tracking data from carrier
            var trackingData = await _trackingService.GetContainerTrackingDataAsync(containerNumber);
            
            if (trackingData.IsSuccess)
            {
                // Update container status
                container.Status = trackingData.Status;
                container.LastTrackingUpdate = DateTime.UtcNow;
                container.CurrentLocation = trackingData.CurrentLocation;
                container.Events = trackingData.Events;
                
                await _containerRepository.UpdateAsync(container);
                
                result.Status = ContainerTrackingStatus.Completed;
                result.Container = container;
                result.TrackingData = trackingData;
            }
            else
            {
                result.Status = ContainerTrackingStatus.TrackingFailed;
                result.ErrorMessage = trackingData.ErrorMessage;
            }
            
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            _logger.LogInformation("Container tracking completed: {ContainerNumber}, Status: {Status}", 
                containerNumber, result.Status);
            
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error tracking container: {ContainerNumber}", containerNumber);
            
            result.Status = ContainerTrackingStatus.Failed;
            result.ErrorMessage = ex.Message;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            return result;
        }
    }
    
    private async Task<ContainerValidationResult> ValidateContainerData(CreateContainerRequest request)
    {
        var result = new ContainerValidationResult { IsValid = true };
        
        // Validate required fields
        if (string.IsNullOrEmpty(request.ContainerNumber))
        {
            result.IsValid = false;
            result.ErrorMessage = "Container number is required";
            return result;
        }
        
        if (string.IsNullOrEmpty(request.Vessel))
        {
            result.IsValid = false;
            result.ErrorMessage = "Vessel is required";
            return result;
        }
        
        if (string.IsNullOrEmpty(request.Voyage))
        {
            result.IsValid = false;
            result.ErrorMessage = "Voyage is required";
            return result;
        }
        
        if (string.IsNullOrEmpty(request.PortOfLoading))
        {
            result.IsValid = false;
            result.ErrorMessage = "Port of loading is required";
            return result;
        }
        
        if (string.IsNullOrEmpty(request.PortOfDischarge))
        {
            result.IsValid = false;
            result.ErrorMessage = "Port of discharge is required";
            return result;
        }
        
        // Validate container number format
        if (!IsValidContainerNumber(request.ContainerNumber))
        {
            result.IsValid = false;
            result.ErrorMessage = "Invalid container number format";
            return result;
        }
        
        // Validate dates
        if (request.ETD >= request.ETA)
        {
            result.IsValid = false;
            result.ErrorMessage = "ETD must be before ETA";
            return result;
        }
        
        return result;
    }
    
    private bool IsValidContainerNumber(string containerNumber)
    {
        // ISO 6346 container number validation
        if (string.IsNullOrEmpty(containerNumber) || containerNumber.Length != 11)
        {
            return false;
        }
        
        // Check format: 4 letters + 7 digits
        var ownerCode = containerNumber.Substring(0, 4);
        var serialNumber = containerNumber.Substring(4, 6);
        var checkDigit = containerNumber.Substring(10, 1);
        
        if (!ownerCode.All(char.IsLetter) || !serialNumber.All(char.IsDigit) || !checkDigit.All(char.IsDigit))
        {
            return false;
        }
        
        // Validate check digit
        var calculatedCheckDigit = CalculateContainerCheckDigit(ownerCode + serialNumber);
        return calculatedCheckDigit == int.Parse(checkDigit);
    }
    
    private int CalculateContainerCheckDigit(string ownerCodeAndSerial)
    {
        var weights = new int[] { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 };
        var sum = 0;
        
        for (int i = 0; i < ownerCodeAndSerial.Length; i++)
        {
            var value = char.IsLetter(ownerCodeAndSerial[i]) ? 
                GetLetterValue(ownerCodeAndSerial[i]) : 
                int.Parse(ownerCodeAndSerial[i].ToString());
            
            sum += value * weights[i];
        }
        
        return sum % 11 % 10;
    }
    
    private int GetLetterValue(char letter)
    {
        var letterValues = new Dictionary<char, int>
        {
            {'A', 10}, {'B', 12}, {'C', 13}, {'D', 14}, {'E', 15}, {'F', 16}, {'G', 17}, {'H', 18},
            {'I', 19}, {'J', 20}, {'K', 21}, {'L', 23}, {'M', 24}, {'N', 25}, {'O', 26}, {'P', 27},
            {'Q', 28}, {'R', 29}, {'S', 30}, {'T', 31}, {'U', 32}, {'V', 34}, {'W', 35}, {'X', 36},
            {'Y', 37}, {'Z', 38}
        };
        
        return letterValues.ContainsKey(char.ToUpper(letter)) ? letterValues[char.ToUpper(letter)] : 0;
    }
}

Container Status Management

C# Container Status Tracker:

public class CargoWiseContainerStatusTracker
{
    private readonly ILogger<CargoWiseContainerStatusTracker> _logger;
    private readonly IContainerRepository _containerRepository;
    private readonly ICarrierService _carrierService;
    private readonly INotificationService _notificationService;
    
    public CargoWiseContainerStatusTracker(
        ILogger<CargoWiseContainerStatusTracker> logger,
        IContainerRepository containerRepository,
        ICarrierService carrierService,
        INotificationService notificationService)
    {
        _logger = logger;
        _containerRepository = containerRepository;
        _carrierService = carrierService;
        _notificationService = notificationService;
    }
    
    public async Task<ContainerStatusUpdateResult> UpdateContainerStatus(string containerNumber, ContainerStatus newStatus, string statusReason = null)
    {
        var result = new ContainerStatusUpdateResult
        {
            ContainerNumber = containerNumber,
            StartTime = DateTime.UtcNow,
            Status = ContainerStatusUpdateStatus.InProgress
        };
        
        try
        {
            _logger.LogInformation("Updating container status: {ContainerNumber} to {NewStatus}", containerNumber, newStatus);
            
            // Get container record
            var container = await _containerRepository.GetByContainerNumberAsync(containerNumber);
            if (container == null)
            {
                result.Status = ContainerStatusUpdateStatus.ContainerNotFound;
                result.ErrorMessage = "Container not found";
                return result;
            }
            
            // Validate status transition
            var transitionValidation = await ValidateStatusTransition(container.Status, newStatus);
            if (!transitionValidation.IsValid)
            {
                result.Status = ContainerStatusUpdateStatus.InvalidTransition;
                result.ErrorMessage = transitionValidation.ErrorMessage;
                return result;
            }
            
            // Update container status
            var previousStatus = container.Status;
            container.Status = newStatus;
            container.StatusReason = statusReason;
            container.StatusUpdatedAt = DateTime.UtcNow;
            container.UpdatedAt = DateTime.UtcNow;
            
            await _containerRepository.UpdateAsync(container);
            
            // Log status change
            await LogStatusChange(container, previousStatus, newStatus, statusReason);
            
            // Send notifications
            await SendStatusNotifications(container, previousStatus, newStatus);
            
            result.Status = ContainerStatusUpdateStatus.Completed;
            result.PreviousStatus = previousStatus;
            result.NewStatus = newStatus;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            _logger.LogInformation("Container status updated successfully: {ContainerNumber} from {PreviousStatus} to {NewStatus}", 
                containerNumber, previousStatus, newStatus);
            
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error updating container status: {ContainerNumber}", containerNumber);
            
            result.Status = ContainerStatusUpdateStatus.Failed;
            result.ErrorMessage = ex.Message;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            return result;
        }
    }
    
    private async Task<StatusTransitionValidationResult> ValidateStatusTransition(ContainerStatus currentStatus, ContainerStatus newStatus)
    {
        var result = new StatusTransitionValidationResult { IsValid = true };
        
        // Define valid status transitions
        var validTransitions = new Dictionary<ContainerStatus, List<ContainerStatus>>
        {
            { ContainerStatus.Created, new List<ContainerStatus> { ContainerStatus.Booked, ContainerStatus.Cancelled } },
            { ContainerStatus.Booked, new List<ContainerStatus> { ContainerStatus.Empty, ContainerStatus.Cancelled } },
            { ContainerStatus.Empty, new List<ContainerStatus> { ContainerStatus.Loaded, ContainerStatus.Cancelled } },
            { ContainerStatus.Loaded, new List<ContainerStatus> { ContainerStatus.InTransit, ContainerStatus.Cancelled } },
            { ContainerStatus.InTransit, new List<ContainerStatus> { ContainerStatus.Discharged, ContainerStatus.Exception } },
            { ContainerStatus.Discharged, new List<ContainerStatus> { ContainerStatus.Delivered, ContainerStatus.Detained } },
            { ContainerStatus.Delivered, new List<ContainerStatus>() }, // Final status
            { ContainerStatus.Detained, new List<ContainerStatus> { ContainerStatus.Delivered, ContainerStatus.Demurrage } },
            { ContainerStatus.Demurrage, new List<ContainerStatus> { ContainerStatus.Delivered } },
            { ContainerStatus.Cancelled, new List<ContainerStatus>() }, // Final status
            { ContainerStatus.Exception, new List<ContainerStatus> { ContainerStatus.InTransit, ContainerStatus.Cancelled } }
        };
        
        if (validTransitions.ContainsKey(currentStatus))
        {
            if (!validTransitions[currentStatus].Contains(newStatus))
            {
                result.IsValid = false;
                result.ErrorMessage = $"Invalid status transition from {currentStatus} to {newStatus}";
            }
        }
        else
        {
            result.IsValid = false;
            result.ErrorMessage = $"Unknown current status: {currentStatus}";
        }
        
        return result;
    }
}

Bill of Lading Management

B/L Creation and Processing

C# Bill of Lading Service:

public class CargoWiseBillOfLadingService
{
    private readonly ILogger<CargoWiseBillOfLadingService> _logger;
    private readonly IBillOfLadingRepository _bolRepository;
    private readonly IContainerRepository _containerRepository;
    private readonly IDocumentService _documentService;
    
    public CargoWiseBillOfLadingService(
        ILogger<CargoWiseBillOfLadingService> logger,
        IBillOfLadingRepository bolRepository,
        IContainerRepository containerRepository,
        IDocumentService documentService)
    {
        _logger = logger;
        _bolRepository = bolRepository;
        _containerRepository = containerRepository;
        _documentService = documentService;
    }
    
    public async Task<BillOfLadingResult> CreateBillOfLading(CreateBillOfLadingRequest request)
    {
        var result = new BillOfLadingResult
        {
            StartTime = DateTime.UtcNow,
            Status = BillOfLadingStatus.InProgress
        };
        
        try
        {
            _logger.LogInformation("Creating bill of lading: {BOLNumber}", request.BOLNumber);
            
            // Validate B/L data
            var validationResult = await ValidateBillOfLadingData(request);
            if (!validationResult.IsValid)
            {
                result.Status = BillOfLadingStatus.ValidationFailed;
                result.ErrorMessage = validationResult.ErrorMessage;
                return result;
            }
            
            // Create B/L record
            var billOfLading = new BillOfLading
            {
                Id = Guid.NewGuid().ToString(),
                BOLNumber = request.BOLNumber,
                ContainerId = request.ContainerId,
                Vessel = request.Vessel,
                Voyage = request.Voyage,
                PortOfLoading = request.PortOfLoading,
                PortOfDischarge = request.PortOfDischarge,
                ETD = request.ETD,
                ETA = request.ETA,
                Shipper = request.Shipper,
                Consignee = request.Consignee,
                NotifyParty = request.NotifyParty,
                GoodsDescription = request.GoodsDescription,
                Weight = request.Weight,
                Volume = request.Volume,
                Pieces = request.Pieces,
                Value = request.Value,
                Currency = request.Currency,
                FreightTerms = request.FreightTerms,
                SpecialInstructions = request.SpecialInstructions,
                Status = BillOfLadingStatus.Created,
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow
            };
            
            // Save B/L
            await _bolRepository.CreateAsync(billOfLading);
            
            // Generate B/L document
            var documentResult = await _documentService.GenerateBillOfLadingDocument(billOfLading);
            if (documentResult.IsSuccess)
            {
                billOfLading.DocumentId = documentResult.DocumentId;
                await _bolRepository.UpdateAsync(billOfLading);
            }
            
            result.Status = BillOfLadingStatus.Created;
            result.BillOfLading = billOfLading;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            _logger.LogInformation("Bill of lading created successfully: {BOLNumber}", request.BOLNumber);
            
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error creating bill of lading: {BOLNumber}", request.BOLNumber);
            
            result.Status = BillOfLadingStatus.Failed;
            result.ErrorMessage = ex.Message;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            return result;
        }
    }
    
    public async Task<BillOfLadingResult> SurrenderBillOfLading(string bolNumber, string surrenderedBy)
    {
        var result = new BillOfLadingResult
        {
            StartTime = DateTime.UtcNow,
            Status = BillOfLadingStatus.InProgress
        };
        
        try
        {
            _logger.LogInformation("Surrendering bill of lading: {BOLNumber}", bolNumber);
            
            // Get B/L record
            var billOfLading = await _bolRepository.GetByBOLNumberAsync(bolNumber);
            if (billOfLading == null)
            {
                result.Status = BillOfLadingStatus.NotFound;
                result.ErrorMessage = "Bill of lading not found";
                return result;
            }
            
            // Check if B/L can be surrendered
            if (billOfLading.Status != BillOfLadingStatus.Created && billOfLading.Status != BillOfLadingStatus.Released)
            {
                result.Status = BillOfLadingStatus.InvalidStatus;
                result.ErrorMessage = $"B/L cannot be surrendered in status: {billOfLading.Status}";
                return result;
            }
            
            // Update B/L status
            billOfLading.Status = BillOfLadingStatus.Surrendered;
            billOfLading.SurrenderedBy = surrenderedBy;
            billOfLading.SurrenderedAt = DateTime.UtcNow;
            billOfLading.UpdatedAt = DateTime.UtcNow;
            
            await _bolRepository.UpdateAsync(billOfLading);
            
            result.Status = BillOfLadingStatus.Surrendered;
            result.BillOfLading = billOfLading;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            _logger.LogInformation("Bill of lading surrendered successfully: {BOLNumber}", bolNumber);
            
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error surrendering bill of lading: {BOLNumber}", bolNumber);
            
            result.Status = BillOfLadingStatus.Failed;
            result.ErrorMessage = ex.Message;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            return result;
        }
    }
    
    private async Task<BillOfLadingValidationResult> ValidateBillOfLadingData(CreateBillOfLadingRequest request)
    {
        var result = new BillOfLadingValidationResult { IsValid = true };
        
        // Validate required fields
        if (string.IsNullOrEmpty(request.BOLNumber))
        {
            result.IsValid = false;
            result.ErrorMessage = "B/L number is required";
            return result;
        }
        
        if (string.IsNullOrEmpty(request.Vessel))
        {
            result.IsValid = false;
            result.ErrorMessage = "Vessel is required";
            return result;
        }
        
        if (string.IsNullOrEmpty(request.Voyage))
        {
            result.IsValid = false;
            result.ErrorMessage = "Voyage is required";
            return result;
        }
        
        if (string.IsNullOrEmpty(request.PortOfLoading))
        {
            result.IsValid = false;
            result.ErrorMessage = "Port of loading is required";
            return result;
        }
        
        if (string.IsNullOrEmpty(request.PortOfDischarge))
        {
            result.IsValid = false;
            result.ErrorMessage = "Port of discharge is required";
            return result;
        }
        
        if (string.IsNullOrEmpty(request.Shipper))
        {
            result.IsValid = false;
            result.ErrorMessage = "Shipper is required";
            return result;
        }
        
        if (string.IsNullOrEmpty(request.Consignee))
        {
            result.IsValid = false;
            result.ErrorMessage = "Consignee is required";
            return result;
        }
        
        // Validate dates
        if (request.ETD >= request.ETA)
        {
            result.IsValid = false;
            result.ErrorMessage = "ETD must be before ETA";
            return result;
        }
        
        // Validate container exists
        if (!string.IsNullOrEmpty(request.ContainerId))
        {
            var container = await _containerRepository.GetByIdAsync(request.ContainerId);
            if (container == null)
            {
                result.IsValid = false;
                result.ErrorMessage = "Container not found";
                return result;
            }
        }
        
        return result;
    }
}

Demurrage Management

Demurrage Tracking and Calculation

C# Demurrage Management Service:

public class CargoWiseDemurrageManagementService
{
    private readonly ILogger<CargoWiseDemurrageManagementService> _logger;
    private readonly IDemurrageRepository _demurrageRepository;
    private readonly IContainerRepository _containerRepository;
    private readonly ICalculationService _calculationService;
    
    public CargoWiseDemurrageManagementService(
        ILogger<CargoWiseDemurrageManagementService> logger,
        IDemurrageRepository demurrageRepository,
        IContainerRepository containerRepository,
        ICalculationService calculationService)
    {
        _logger = logger;
        _demurrageRepository = demurrageRepository;
        _containerRepository = containerRepository;
        _calculationService = calculationService;
    }
    
    public async Task<DemurrageResult> CalculateDemurrage(string containerNumber, DateTime dischargeDate)
    {
        var result = new DemurrageResult
        {
            ContainerNumber = containerNumber,
            StartTime = DateTime.UtcNow,
            Status = DemurrageStatus.InProgress
        };
        
        try
        {
            _logger.LogInformation("Calculating demurrage for container: {ContainerNumber}", containerNumber);
            
            // Get container record
            var container = await _containerRepository.GetByContainerNumberAsync(containerNumber);
            if (container == null)
            {
                result.Status = DemurrageStatus.ContainerNotFound;
                result.ErrorMessage = "Container not found";
                return result;
            }
            
            // Get demurrage rates
            var demurrageRates = await _demurrageRepository.GetDemurrageRatesAsync(container.Carrier, container.PortOfDischarge);
            
            // Calculate demurrage
            var demurrageCalculation = await _calculationService.CalculateDemurrage(container, dischargeDate, demurrageRates);
            
            // Create demurrage record
            var demurrageRecord = new DemurrageRecord
            {
                Id = Guid.NewGuid().ToString(),
                ContainerId = container.Id,
                ContainerNumber = containerNumber,
                DischargeDate = dischargeDate,
                FreeTimeDays = demurrageCalculation.FreeTimeDays,
                DemurrageDays = demurrageCalculation.DemurrageDays,
                DemurrageRate = demurrageCalculation.DemurrageRate,
                DemurrageAmount = demurrageCalculation.DemurrageAmount,
                Currency = demurrageCalculation.Currency,
                Status = DemurrageStatus.Calculated,
                CreatedAt = DateTime.UtcNow,
                UpdatedAt = DateTime.UtcNow
            };
            
            // Save demurrage record
            await _demurrageRepository.CreateAsync(demurrageRecord);
            
            result.Status = DemurrageStatus.Calculated;
            result.DemurrageRecord = demurrageRecord;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            _logger.LogInformation("Demurrage calculated successfully: {ContainerNumber}, Amount: {Amount} {Currency}", 
                containerNumber, demurrageCalculation.DemurrageAmount, demurrageCalculation.Currency);
            
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error calculating demurrage for container: {ContainerNumber}", containerNumber);
            
            result.Status = DemurrageStatus.Failed;
            result.ErrorMessage = ex.Message;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            return result;
        }
    }
    
    public async Task<DemurrageResult> ProcessDemurragePayment(string demurrageId, decimal paymentAmount, string paymentMethod)
    {
        var result = new DemurrageResult
        {
            StartTime = DateTime.UtcNow,
            Status = DemurrageStatus.InProgress
        };
        
        try
        {
            _logger.LogInformation("Processing demurrage payment: {DemurrageId}", demurrageId);
            
            // Get demurrage record
            var demurrageRecord = await _demurrageRepository.GetByIdAsync(demurrageId);
            if (demurrageRecord == null)
            {
                result.Status = DemurrageStatus.NotFound;
                result.ErrorMessage = "Demurrage record not found";
                return result;
            }
            
            // Validate payment amount
            if (paymentAmount < demurrageRecord.DemurrageAmount)
            {
                result.Status = DemurrageStatus.InsufficientPayment;
                result.ErrorMessage = "Payment amount is less than demurrage amount";
                return result;
            }
            
            // Update demurrage record
            demurrageRecord.PaymentAmount = paymentAmount;
            demurrageRecord.PaymentMethod = paymentMethod;
            demurrageRecord.PaymentDate = DateTime.UtcNow;
            demurrageRecord.Status = DemurrageStatus.Paid;
            demurrageRecord.UpdatedAt = DateTime.UtcNow;
            
            await _demurrageRepository.UpdateAsync(demurrageRecord);
            
            result.Status = DemurrageStatus.Paid;
            result.DemurrageRecord = demurrageRecord;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            _logger.LogInformation("Demurrage payment processed successfully: {DemurrageId}", demurrageId);
            
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error processing demurrage payment: {DemurrageId}", demurrageId);
            
            result.Status = DemurrageStatus.Failed;
            result.ErrorMessage = ex.Message;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            return result;
        }
    }
}

Carrier Integration

Shipping Line API Integration

C# Shipping Line Integration Service:

public class CargoWiseShippingLineIntegrationService
{
    private readonly ILogger<CargoWiseShippingLineIntegrationService> _logger;
    private readonly IShippingLineApiClient _shippingLineApiClient;
    private readonly ICarrierRepository _carrierRepository;
    private readonly IEncryptionService _encryptionService;
    
    public CargoWiseShippingLineIntegrationService(
        ILogger<CargoWiseShippingLineIntegrationService> logger,
        IShippingLineApiClient shippingLineApiClient,
        ICarrierRepository carrierRepository,
        IEncryptionService encryptionService)
    {
        _logger = logger;
        _shippingLineApiClient = shippingLineApiClient;
        _carrierRepository = carrierRepository;
        _encryptionService = encryptionService;
    }
    
    public async Task<ShippingLineIntegrationResult> BookVesselSpace(BookVesselSpaceRequest request)
    {
        var result = new ShippingLineIntegrationResult
        {
            StartTime = DateTime.UtcNow,
            Status = ShippingLineIntegrationStatus.InProgress
        };
        
        try
        {
            _logger.LogInformation("Booking vessel space with carrier: {Carrier}", request.Carrier);
            
            // Get carrier configuration
            var carrier = await _carrierRepository.GetByCodeAsync(request.Carrier);
            if (carrier == null)
            {
                result.Status = ShippingLineIntegrationStatus.CarrierNotFound;
                result.ErrorMessage = "Carrier not found";
                return result;
            }
            
            // Prepare booking request
            var bookingRequest = new VesselBookingRequest
            {
                Carrier = request.Carrier,
                Vessel = request.Vessel,
                Voyage = request.Voyage,
                PortOfLoading = request.PortOfLoading,
                PortOfDischarge = request.PortOfDischarge,
                ETD = request.ETD,
                ETA = request.ETA,
                ContainerType = request.ContainerType,
                ContainerSize = request.ContainerSize,
                Weight = request.Weight,
                Volume = request.Volume,
                Shipper = request.Shipper,
                Consignee = request.Consignee
            };
            
            // Call shipping line API
            var bookingResponse = await _shippingLineApiClient.BookVesselSpaceAsync(bookingRequest);
            
            if (bookingResponse.IsSuccess)
            {
                result.Status = ShippingLineIntegrationStatus.Completed;
                result.BookingReference = bookingResponse.BookingReference;
                result.Vessel = bookingResponse.Vessel;
                result.Voyage = bookingResponse.Voyage;
                result.ConfirmedETD = bookingResponse.ConfirmedETD;
                result.ConfirmedETA = bookingResponse.ConfirmedETA;
            }
            else
            {
                result.Status = ShippingLineIntegrationStatus.Failed;
                result.ErrorMessage = bookingResponse.ErrorMessage;
            }
            
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            _logger.LogInformation("Vessel space booking completed: {Carrier}, Status: {Status}", 
                request.Carrier, result.Status);
            
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error booking vessel space with carrier: {Carrier}", request.Carrier);
            
            result.Status = ShippingLineIntegrationStatus.Failed;
            result.ErrorMessage = ex.Message;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            return result;
        }
    }
    
    public async Task<ShippingLineIntegrationResult> GetVesselSchedule(string carrier, string portOfLoading, string portOfDischarge, DateTime fromDate, DateTime toDate)
    {
        var result = new ShippingLineIntegrationResult
        {
            StartTime = DateTime.UtcNow,
            Status = ShippingLineIntegrationStatus.InProgress
        };
        
        try
        {
            _logger.LogInformation("Getting vessel schedule: {Carrier} {PortOfLoading} to {PortOfDischarge}", 
                carrier, portOfLoading, portOfDischarge);
            
            // Call shipping line API
            var scheduleResponse = await _shippingLineApiClient.GetVesselScheduleAsync(carrier, portOfLoading, portOfDischarge, fromDate, toDate);
            
            if (scheduleResponse.IsSuccess)
            {
                result.Status = ShippingLineIntegrationStatus.Completed;
                result.VesselSchedules = scheduleResponse.VesselSchedules;
            }
            else
            {
                result.Status = ShippingLineIntegrationStatus.Failed;
                result.ErrorMessage = scheduleResponse.ErrorMessage;
            }
            
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            _logger.LogInformation("Vessel schedule retrieved: {Carrier}, Schedules: {Count}", 
                carrier, scheduleResponse.VesselSchedules?.Count ?? 0);
            
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting vessel schedule: {Carrier}", carrier);
            
            result.Status = ShippingLineIntegrationStatus.Failed;
            result.ErrorMessage = ex.Message;
            result.EndTime = DateTime.UtcNow;
            result.Duration = result.EndTime - result.StartTime;
            
            return result;
        }
    }
}

Conclusion

CargoWise ocean freight workflows provide comprehensive tools for managing complex ocean cargo operations efficiently. By implementing the workflows and automation strategies outlined in this guide, you can streamline your ocean freight processes, improve operational efficiency, and enhance customer service.

Key Takeaways:

  1. Streamline Container Management: Implement automated container tracking and status updates
  2. Optimize B/L Processing: Use automated B/L creation and management workflows
  3. Integrate with Shipping Lines: Connect with carrier APIs for real-time data exchange
  4. Manage Demurrage Effectively: Implement automated demurrage calculation and tracking
  5. Monitor Performance: Track KPIs and optimize workflows continuously

Next Steps:

  1. Assess Current Processes and identify optimization opportunities
  2. Implement Container Automation for streamlined tracking and management
  3. Set up Shipping Line Integrations for real-time data exchange
  4. Create B/L Workflows for efficient document processing
  5. Monitor and Optimize performance based on operational metrics

For more CargoWise ocean freight guidance and implementation support, explore our CargoWise Integration Services or contact our team for personalized consulting.

FAQ

Q: How do I track containers in CargoWise? A: Use the CargoWise Container Management Service to track containers with real-time status updates, location tracking, and event logging. Implement automated tracking through carrier integrations.

Q: What is the difference between FCL and LCL in CargoWise? A: FCL (Full Container Load) uses the container management service for individual containers, while LCL (Less than Container Load) uses the consolidation service for groupage operations. Both are supported in CargoWise.

Q: How can I integrate CargoWise with shipping line APIs? A: Use the CargoWise Shipping Line Integration Service to connect with carrier APIs for vessel bookings, schedule updates, and real-time data exchange. Implement proper authentication and error handling.

Q: What automation features are available for ocean freight in CargoWise? A: CargoWise provides automation for container tracking, B/L processing, demurrage calculation, status updates, and workflow management. Use the automation service to streamline routine operations.

Q: How do I manage demurrage in CargoWise? A: Implement the CargoWise Demurrage Management Service to automatically calculate demurrage charges, track free time, and process payments. Use carrier-specific demurrage rates and rules.

Related posts