- 0 minutes to read

O2C Demo Data Generator - Complete Script

This page contains the complete refactored PowerShell 7+ script for generating Order-to-Cash demo data. This version consolidates message generation, BPM logic, and helper functions for improved maintainability.

Key improvements:

  • Cross-platform compatible (PowerShell 7+ with ternary operators)
  • Consolidated message payload generation
  • Streamlined BPM relationship logic
  • Helper functions for code reuse
  • Better performance and readability

Script Requirements

  • PowerShell Version: 7.0 or later
  • Cross-Platform: Works on Windows, Linux, and macOS
  • Dependencies: None (uses built-in cmdlets)

Complete Script

# Generate-O2C-Demo-Data.ps1 (REFACTORED - PowerShell 7+ Required)
#
# PowerShell script to generate 100 Order-to-Cash (O2C) demo orders and log them to Nodinite Log API
# Refactored version with consolidated message generation, BPM logic, and helper functions
# REQUIRES: PowerShell 7.0+ for ternary operators and null-coalescing (cross-platform compatible)
#
# Usage:
#   pwsh .\Generate-O2C-Demo-Data.ps1 -LogApiUrl "https://your-nodinite-instance/api/v2/LogEvents" `
#                                      -ApiKey "your-api-key" `
#                                      -OutputFile "/tmp/O2C-Orders.json"

param(
    [Parameter(Mandatory = $false)]
    [string]$LogApiUrl = "https://localhost:5001/api/v2/LogEvents",
    
    [Parameter(Mandatory = $false)]
    [string]$ApiKey = "YOUR_API_KEY_HERE",
    
    [Parameter(Mandatory = $false)]
    [string]$OutputFile = "C:\Temp\O2C-Demo-Data.json",
    
    [Parameter(Mandatory = $false)]
    [int]$OrderCount = 100,
    
    [Parameter(Mandatory = $false)]
    [switch]$ExportToFile,
    
    [Parameter(Mandatory = $false)]
    [switch]$DryRun
)

$LOG_AGENT_VALUE_ID = 5
$ENDPOINT_TYPE_ID = 60
$PROGRESSION_PROBABILITY = 0.90

$today = (Get-Date).Date
$baseDate = [DateTime]::SpecifyKind((Get-Date -Year $today.Year -Month $today.Month -Day $today.Day -Hour 6 -Minute 0 -Second 0 -Millisecond 0), [DateTimeKind]::Utc)
$executionDate = (Get-Date).ToString("yyyyMMdd")
$customerPrefix = "PIC"

# Compact step definitions - only unique properties per step
$stepTemplates = @{
    0 = @{ System = "Portal"; Domain = "Sales"; DomainIndex = 0; MessageType = "O2C.Order.Received/1.0"; ProcessName = "O2C-Order-Reception"; ProcessingMachineName = "portal-server-01" }
    1 = @{ System = "ERP"; Domain = "Planning"; DomainIndex = 1; MessageType = "O2C.Order.Entry/1.0"; ProcessName = "O2C-Order-Entry"; ProcessingMachineName = "erp-server-01" }
    2 = @{ System = "Portal"; Domain = "Sales"; DomainIndex = 0; MessageType = "O2C.Order.Confirmation/1.0"; ProcessName = "O2C-Confirmation"; ProcessingMachineName = "portal-server-01" }
    3 = @{ System = "ERP"; Domain = "Planning"; DomainIndex = 1; MessageType = "O2C.Order.Scheduled/1.0"; ProcessName = "O2C-Planning"; ProcessingMachineName = "erp-server-01" }
    4 = @{ System = "WMS"; Domain = "Logistics"; DomainIndex = 2; MessageType = "O2C.Order.Ready/1.0"; ProcessName = "O2C-Packing"; ProcessingMachineName = "wms-server-01" }
    5 = @{ System = "WMS"; Domain = "Logistics"; DomainIndex = 2; MessageType = "O2C.Order.Delivered/1.0"; ProcessName = "O2C-Delivery"; ProcessingMachineName = "wms-server-01" }
    6 = @{ System = "ERP-Finance"; Domain = "Finance"; DomainIndex = 3; MessageType = "O2C.Order.Invoice/1.0"; ProcessName = "O2C-Invoicing"; ProcessingMachineName = "erp-server-01" }
}

$eventDefs = @(
    @{ StepNumber = 0; Direction = 0; Format = "JSON"; Service = "INT1337-RCV-Order-Incoming"; Endpoint = "Portal-OrderReceived-Drop"; Uri = "C:\Integration\Portal\Orders\In"; Module = "Portal.OrderService.Receiver"; IsBiz = $true }
    @{ StepNumber = 0; Direction = 1; Format = "JSON"; Service = "INT1337-SND-Order-Incoming"; Endpoint = "Portal-Order-Send"; Uri = "C:\Integration\Portal\Orders\Out"; Module = "Portal.OrderService.Forwarder"; IsBiz = $false }
    @{ StepNumber = 1; Direction = 0; Format = "XML"; Service = "INT1337-RCV-Order-Entry"; Endpoint = "ERP-OrderEntry-Receive"; Uri = "C:\Integration\ERP\Orders\In"; Module = "ERP.Order.EntryService.Receiver"; IsBiz = $false }
    @{ StepNumber = 1; Direction = 1; Format = "XML"; Service = "INT1337-ENT-Order-Entry"; Endpoint = "ERP-OrderEntry-Send"; Uri = "C:\Integration\ERP\Orders\Out"; Module = "ERP.Order.EntryService"; IsBiz = $true }
    @{ StepNumber = 2; Direction = 0; Format = "CSV"; Service = "INT1337-RCV-Confirm-Incoming"; Endpoint = "Portal-Confirmation-Receive"; Uri = "C:\Integration\Portal\Confirmations\In"; Module = "Portal.ConfirmationService.Receiver"; IsBiz = $false }
    @{ StepNumber = 2; Direction = 1; Format = "CSV"; Service = "INT1337-SND-Confirm-Outgoing"; Endpoint = "Portal-Confirmation-Send"; Uri = "C:\Integration\Portal\Confirmations\Out"; Module = "Portal.ConfirmationService.Sender"; IsBiz = $true }
    @{ StepNumber = 3; Direction = 0; Format = "JSON"; Service = "INT1337-RCV-Planned-Incoming"; Endpoint = "ERP-Planning-Receive"; Uri = "C:\Integration\ERP\Planning\In"; Module = "ERP.PlanningService.Receiver"; IsBiz = $false }
    @{ StepNumber = 3; Direction = 1; Format = "JSON"; Service = "INT1337-PLN-Order-Scheduled"; Endpoint = "ERP-Planning-Send"; Uri = "C:\Integration\ERP\Planning\Out"; Module = "ERP.PlanningService.Scheduler"; IsBiz = $true }
    @{ StepNumber = 4; Direction = 0; Format = "XML"; Service = "INT1337-RCV-Packing-Incoming"; Endpoint = "WMS-Packing-Receive"; Uri = "C:\Integration\WMS\Packing\In"; Module = "WMS.PackingService.Receiver"; IsBiz = $false }
    @{ StepNumber = 4; Direction = 1; Format = "XML"; Service = "INT1337-PKG-Order-Packed"; Endpoint = "WMS-Packing-Send"; Uri = "C:\Integration\WMS\Packing\Out"; Module = "WMS.PackingService.Completer"; IsBiz = $true }
    @{ StepNumber = 5; Direction = 0; Format = "PSV"; Service = "INT1337-RCV-Order-Delivered-Incoming"; Endpoint = "WMS-Delivery-Receive"; Uri = "C:\Integration\WMS\Delivery\In"; Module = "WMS.DeliveryService.Receiver"; IsBiz = $false }
    @{ StepNumber = 5; Direction = 1; Format = "PSV"; Service = "INT1337-RCV-Order-Delivered"; Endpoint = "WMS-Delivery-Send"; Uri = "C:\Integration\WMS\Delivery\Out"; Module = "WMS.DeliveryService.Sender"; IsBiz = $true }
    @{ StepNumber = 6; Direction = 0; Format = "JSON"; Service = "INT1337-RCV-Invoice-Incoming"; Endpoint = "ERP-Finance-Invoice-Receive"; Uri = "C:\Integration\ERP\Finance\Invoices\In"; Module = "ERP.FinanceService.Receiver"; IsBiz = $false }
    @{ StepNumber = 6; Direction = 1; Format = "JSON"; Service = "INT1337-INV-Order-Invoiced"; Endpoint = "ERP-Finance-Invoice-Send"; Uri = "C:\Integration\ERP\Finance\Invoices\Out"; Module = "ERP.FinanceService.Invoicer"; IsBiz = $true }
)

$milestones = @{
    0 = @{ Rcv = "Order Received from Customer"; Snd = "Order Forwarded to ERP" }
    1 = @{ Rcv = "Order Entry Received"; Snd = "Order Entry in ERP Finished" }
    2 = @{ Rcv = "Confirmation Received"; Snd = "Order Confirmation Delivered to Customer" }
    3 = @{ Rcv = "Planning Request Received"; Snd = "Production Scheduled in ERP" }
    4 = @{ Rcv = "Packing Request Received"; Snd = "Order Completed for Transport" }
    5 = @{ Rcv = "Order Delivered Received"; Snd = "Order Delivered" }
    6 = @{ Rcv = "Invoice Request Received"; Snd = "Order Invoiced" }
}

$downstreamFlows = @{
    0 = @(1); 1 = @(2, 3); 2 = @(3); 3 = @(4); 4 = @(5); 5 = @(6); 6 = @()
}

function ConvertTo-Base64 {
    param([string]$Text)
    return [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($Text))
}

function Get-FileExtension {
    param([string]$Format)
    return $Format -eq "JSON" ? ".json" : $Format -eq "XML" ? ".xml" : $Format -eq "CSV" ? ".csv" : $Format -eq "PSV" ? ".psv" : ".dat"
}

function Get-ShortMilestone {
    param([string]$Milestone)
    $m = $Milestone -replace " from Customer| to Customer| in ERP Finished| in ERP", ""
    $words = $m -split ' '
    if ($words.Count -ge 3) {
        $m = $m -eq "Order Confirmation Delivered" ? "Confirmation Sent" : $m -eq "Order Completed for Transport" ? "Ready for Transport" : $words.Count -gt 3 ? "$($words[0]) $($words[-2]) $($words[-1])" : $m
    }
    return $m
}

function New-MessagePayload {
    param([int]$StepNum, [string]$OrderId, [string]$CorrelationId)
    
    $ordNum = $OrderId.Substring(4)
    
    $payloads = @{
        0 = @{
            batchId = "batch-2025-10-14-001"
            generatedAt = $baseDate.ToString("O")
            orderId = $OrderId
            customer = @{ customerId = "CUST-001"; name = "Acme Corporation"; email = "orders@acme.example.com" }
            orderDate = $baseDate.ToString("O")
            orderRows = @(@{ rowId = 1; sku = "SKU-DEMO-001"; description = "Demo Widget"; quantity = 1; unitPrice = 99.95; lineTotal = 99.95 })
            orderTotal = 99.95
            currency = "USD"
        } | ConvertTo-Json -Depth 10
        
        1 = @"
<?xml version="1.0" encoding="utf-8"?>
<OrderEntry xmlns="http://schemas.acme.example/O2C/1.0">
  <OrderHeader><OrderId>$OrderId</OrderId><OrderDate>2025-10-14T09:15:00Z</OrderDate><EntryDate>2025-10-14T09:18:30Z</EntryDate><OrderStatus>ENTERED</OrderStatus></OrderHeader>
  <Customer><CustomerId>CUST-001</CustomerId><CustomerName>Acme Corporation</CustomerName><CustomerEmail>orders@acme.example.com</CustomerEmail></Customer>
  <OrderLines><OrderLine><LineId>1</LineId><SKU>SKU-DEMO-001</SKU><Description>Demo Widget</Description><Quantity>1</Quantity><UnitPrice>99.95</UnitPrice><LineTotal>99.95</LineTotal><InventoryReserved>true</InventoryReserved></OrderLine></OrderLines>
  <OrderTotal>99.95</OrderTotal><Currency>USD</Currency><ERPReferenceNumber>ERP-2025-$ordNum</ERPReferenceNumber>
</OrderEntry>
"@
        
        2 = @"
OrderConfirmationHeader
ConfirmationId,ConfirmationDate,CorrelationId,OrderId,OrderDate,CustomerID,CustomerName,CustomerEmail,ConfirmationStatus
CONF-2025-$ordNum,2025-10-14T09:22:15Z,$CorrelationId,ORD-$ordNum,2025-10-14T09:15:00Z,CUST-001,Acme Corporation,orders@acme.example.com,CONFIRMED

OrderConfirmationDetails
LineNumber,SKU,Description,QuantityOrdered,UnitPrice,LineTotal
1,SKU-DEMO-001,Demo Widget,1,99.95,99.95

OrderConfirmationFooter
OrderTotal,Currency,EstimatedShipDate,TrackingEnabled
99.95,USD,2025-10-21,true
"@
        
        3 = @{
            scheduleId = "SCH-2025-$ordNum"; orderId = $OrderId; customerId = "CUST-001"; customerName = "Acme Corporation"
            orderDate = "2025-10-14T09:15:00Z"; scheduleDate = "2025-10-14T09:37:45Z"
            productionLines = @(@{ lineId = "LINE-01"; lineName = "Assembly Line A"; scheduledStart = "2025-10-16T06:00:00Z"; scheduledEnd = "2025-10-16T14:30:00Z"; expectedDuration = 510; shift = "DAY"; capacity = 50 })
            materials = @(@{ materialId = "MAT-SKU-DEMO-001"; sku = "SKU-DEMO-001"; description = "Demo Widget"; quantityRequired = 1; quantityAllocated = 1; availableAtScheduleTime = $true })
            orderQuantity = 1; orderAmount = 99.95; currency = "USD"; priorityLevel = "NORMAL"; schedulingStatus = "CONFIRMED"; estimatedCompletionDate = "2025-10-16T14:30:00Z"
        } | ConvertTo-Json -Depth 10
        
        4 = @"
<?xml version="1.0" encoding="utf-8"?>
<OrderPacking xmlns="http://schemas.acme.example/O2C/1.0">
  <PackingHeader><PackingId>PKG-2025-$ordNum</PackingId><OrderId>$OrderId</OrderId><PackingDate>2025-10-16T16:45:30Z</PackingDate><PackingStatus>COMPLETED</PackingStatus><Warehouse>WH-01</Warehouse><Zone>ZONE-A</Zone></PackingHeader>
  <Customer><CustomerId>CUST-001</CustomerId><CustomerName>Acme Corporation</CustomerName><ShippingAddress>100 Commerce Drive, Suite 100, Springfield, IL 62701</ShippingAddress></Customer>
  <PackedItems><PackedItem><LineId>1</LineId><SKU>SKU-DEMO-001</SKU><Description>Demo Widget</Description><OrderedQuantity>1</OrderedQuantity><PackedQuantity>1</PackedQuantity><SerialNumber>SN-DW-2025$ordNum</SerialNumber><Condition>NEW</Condition></PackedItem></PackedItems>
  <ShipmentInfo><TrackingNumber>TRK-20251016-$ordNum</TrackingNumber><Carrier>Standard Courier</Carrier><ShippingMethod>GROUND</ShippingMethod><EstimatedDeliveryDate>2025-10-21</EstimatedDeliveryDate><ShipmentWeight>5.0</ShipmentWeight><WeightUnit>LBS</WeightUnit></ShipmentInfo>
  <OrderTotal>99.95</OrderTotal><Currency>USD</Currency>
</OrderPacking>
"@
        
        5 = @"
DeliveryConfirmationHeader
DeliveryId|DeliveryDate|CorrelationId|OrderId|CustomerID|CustomerName|ShippingAddress|DeliveryStatus
DLVY-2025-$ordNum|2025-10-20T14:32:15Z|$CorrelationId|$OrderId|CUST-001|Acme Corporation|100 Commerce Drive, Suite 100, Springfield, IL 62701|DELIVERED

DeliveryDetails
LineNumber|SKU|Description|QuantityOrdered|QuantityDelivered|Condition
1|SKU-DEMO-001|Demo Widget|1|1|GOOD

DeliveryProof
TrackingNumber|Carrier|DeliverySignature|DeliveryTime|RecipientName|ProofOfDeliveryLocation|PhotoUrl
TRK-20251016-$ordNum|Standard Courier|ACM-AUTO-SIGN|2025-10-20T14:32:15Z|Auto-confirmed|Front Porch|https://pod.courier.example/2025/10/dlvy-$ordNum.jpg

DeliveryFooter
OrderTotal|Currency|ReturnWindow|ReturnInstructions
99.95|USD|30|Visit returns.acme.com
"@
        
        6 = @{
            invoiceId = "INV-2025-$ordNum"; orderId = $OrderId; customerId = "CUST-001"; customerName = "Acme Corporation"; customerEmail = "orders@acme.example.com"
            invoiceDate = "2025-10-21T09:15:00Z"; dueDate = "2025-11-20"; paymentTerms = "NET30"; invoiceStatus = "ISSUED"
            invoiceItems = @(@{ lineNumber = 1; description = "Demo Widget"; sku = "SKU-DEMO-001"; quantity = 1; unitPrice = 99.95; lineTotal = 99.95; taxCode = "STANDARD"; taxRate = 0.0; taxAmount = 0.0 })
            subtotal = 99.95; taxTotal = 0.0; shippingCharge = 0.0; invoiceTotal = 99.95; currency = "USD"; paymentMethod = "INVOICE"
            purchaseOrder = "PO-2025-$ordNum"; trackingNumber = "TRK-20251016-$ordNum"; gl_account = "4100-Sales-Revenue"; revenue_recognition_date = "2025-10-20"
        } | ConvertTo-Json -Depth 10
    }
    
    return ConvertTo-Base64 $payloads[$StepNum]
}

function New-NodiniteLogEvent {
    param([hashtable]$EventDef, [string]$OrderId, [string]$CorrelationId, [DateTime]$LogDateTime, [int]$SequenceNo, [int]$ProcessingTimeMs, [int]$LogStatus, [string]$Body, [hashtable]$PrevSendService, [hashtable]$SameStepRecvService)
    
    $stepNum = $EventDef.StepNumber
    $stepTemplate = $stepTemplates[$stepNum]
    $isDir0 = $EventDef.Direction -eq 0
    $milestone = $milestones[$stepNum][$isDir0 ? "Rcv" : "Snd"]
    
    # Build Repository Binding
    $repBinding = @{
        Name = "Standard Transport Contract"
        Service = @{
            Name = $EventDef.Service
            Direction = $isDir0 ? "Receive" : "Send"
            System = @{ Name = $stepTemplate.System }
            Integration = @{ Name = "INT1337 - Order-to-Cash" }
        }
    }
    
    if ($isDir0 -and $null -ne $PrevSendService) {
        $repBinding.Service.ExternalServiceRelations = @(@{ 
            Name = $PrevSendService.Service
            Direction = $PrevSendService.Direction -eq 0 ? "Receive" : "Send"
            System = @{ Name = $PrevSendService.System }
        })
    }
    
    if (-not $isDir0 -and $null -ne $SameStepRecvService) {
        $repBinding.Service.InternalServiceRelations = @(@{ 
            Name = $SameStepRecvService.Service
            Direction = $SameStepRecvService.Direction -eq 0 ? "Receive" : "Send"
            System = @{ Name = $SameStepRecvService.System }
        })
    }
    
    if ($EventDef.IsBiz) {
        $bpmRels = @()
        foreach ($downStep in $downstreamFlows[$stepNum]) {
            $dnEvent = $eventDefs | Where-Object { $_.StepNumber -eq $downStep -and $_.IsBiz }
            if ($dnEvent) {
                $dnTemplate = $stepTemplates[$downStep]
                $dnMilestone = $milestones[$downStep]["Snd"]
                $shortMile = Get-ShortMilestone $dnMilestone
                $label = $downStep -eq 3 ? "Order Planned" : $shortMile
                
                $bpmRels += @{
                    Name = $dnEvent.Service
                    ArtifactRenaming = $shortMile
                    Direction = $dnEvent.Direction -eq 0 ? "Receive" : "Send"
                    Domain = @{ Name = $dnTemplate.Domain; Index = $dnTemplate.DomainIndex }
                    System = @{ Name = $dnTemplate.System }
                    Step = $downStep
                    Label = $label
                    ConnectorStyle = 0
                    SourceAttachmentPoint = 3
                    TargetAttachmentPoint = 1
                }
            }
        }
        
        $shortMile = Get-ShortMilestone $milestone
        $repBinding.Service.BPMs = @(@{
            Name = "INT1337 - Order-to-Cash Flow"
            ArtifactRenaming = $shortMile
            Domain = @{ Name = $stepTemplate.Domain; Index = $stepTemplate.DomainIndex }
            Step = $stepNum
            ServiceRelations = $bpmRels
        })
    }
    
    $bindingJson = ($repBinding | ConvertTo-Json -Depth 10) -replace '\r?\n\s*', ''
    
    $context = New-Object PSObject
    $context | Add-Member -MemberType NoteProperty -Name "FileName" -Value "$OrderId-$($milestone.ToLower() -replace ' ', '-')$(Get-FileExtension $EventDef.Format)"
    $context | Add-Member -MemberType NoteProperty -Name "OrderNumber" -Value $OrderId
    $context | Add-Member -MemberType NoteProperty -Name "CustomerId" -Value "CUST-001"
    $context | Add-Member -MemberType NoteProperty -Name "CustomerName" -Value "Acme Corporation"
    $context | Add-Member -MemberType NoteProperty -Name "OrderAmount" -Value "99.95"
    $context | Add-Member -MemberType NoteProperty -Name "ExtendedProperties/1.0#RepositoryBinding" -Value $bindingJson
    
    return @{
        LogAgentValueId = $LOG_AGENT_VALUE_ID
        EndPointName = $EventDef.Endpoint
        EndPointUri = $EventDef.Uri
        EndPointDirection = $EventDef.Direction
        EndPointTypeId = $ENDPOINT_TYPE_ID
        OriginalMessageTypeName = $EventDef.IsBiz ? $stepTemplate.MessageType : "O2C.Forwarding/1.0"
        LogDateTime = $LogDateTime.ToString("O")
        EventDirection = $isDir0 ? 17 : 18
        ProcessingUser = "$($stepTemplate.System)\OrderService"
        SequenceNo = $SequenceNo
        EventNumber = $SequenceNo
        LogText = $milestone
        ApplicationInterchangeId = $CorrelationId
        LocalInterchangeId = $null
        LogStatus = $LogStatus
        ProcessName = $stepTemplate.ProcessName
        ProcessingMachineName = $stepTemplate.ProcessingMachineName
        ProcessingModuleName = $EventDef.Module
        ProcessingModuleType = "WindowsService"
        ServiceInstanceActivityId = $null
        ProcessingTime = $ProcessingTimeMs
        Body = $Body
        Context = $context
    }
}

Write-Host "Order-to-Cash (O2C) Demo Data Generator [REFACTORED]" -ForegroundColor Cyan
Write-Host "====================================================" -ForegroundColor Cyan
Write-Host "Generating $OrderCount orders with probabilistic step completion..." -ForegroundColor Yellow
Write-Host ""

$allLogEvents = @()
$globalDateTime = $baseDate
$globalSequenceNo = 0

for ($orderNum = 1; $orderNum -le $OrderCount; $orderNum++) {
    $orderId = "ORD-" + (10000 + $orderNum).ToString()
    $currentTime = Get-Date -Format "HHmm"
    $correlationId = "$customerPrefix-$executionDate-$currentTime-" + $orderNum.ToString("D4")
    
    # Determine which steps this order will complete (first order always completes all 7 steps)
    $completedSteps = $orderNum -eq 1 ? 7 : {
        $steps = 1
        for ($s = 1; $s -le 6; $s++) {
            if ((Get-Random -Minimum 0 -Maximum 100) / 100 -le $PROGRESSION_PROBABILITY) { $steps = $s + 1 }
            else { break }
        }
        [int]$steps
    }.Invoke()[0]
    
    $previousSendService = $null
    $currentDateTime = $globalDateTime
    
    for ($stepNum = 0; $stepNum -lt $completedSteps; $stepNum++) {
        $rcvEvent = $eventDefs | Where-Object { $_.StepNumber -eq $stepNum -and $_.Direction -eq 0 }
        $sndEvent = $eventDefs | Where-Object { $_.StepNumber -eq $stepNum -and $_.Direction -eq 1 }
        $body = New-MessagePayload $stepNum $orderId $correlationId
        $isLastStep = $stepNum -eq ($completedSteps - 1)
        $isIncomplete = $completedSteps -lt 7
        
        $currentDateTime = $currentDateTime.AddSeconds((Get-Random -Minimum 30 -Maximum 300))
        $globalSequenceNo++
        
        $allLogEvents += New-NodiniteLogEvent $rcvEvent $orderId $correlationId $currentDateTime $globalSequenceNo (Get-Random -Minimum 5 -Maximum 50) 0 $body $previousSendService $null
        
        $currentDateTime = $currentDateTime.AddSeconds((Get-Random -Minimum 1 -Maximum 5))
        $sendStatus = $isLastStep -and $isIncomplete ? -1337 : 0
        $globalSequenceNo++
        
        $rcvEventInfo = @{ Service = $rcvEvent.Service; Direction = $rcvEvent.Direction; System = $stepTemplates[$stepNum].System }
        $allLogEvents += New-NodiniteLogEvent $sndEvent $orderId $correlationId $currentDateTime $globalSequenceNo (Get-Random -Minimum 40 -Maximum 300) $sendStatus $body $null $rcvEventInfo
        
        $previousSendService = @{ Service = $sndEvent.Service; Direction = $sndEvent.Direction; System = $stepTemplates[$stepNum].System }
    }
    
    $globalDateTime = $currentDateTime.AddSeconds((Get-Random -Minimum 120 -Maximum 600))
    
    if ($orderNum % 10 -eq 0) {
        Write-Host "Generated $orderNum/$OrderCount orders..." -ForegroundColor Green
    }
}

Write-Host ""
Write-Host "Generated $(($allLogEvents | Measure-Object).Count) total log events" -ForegroundColor Cyan

if ($DryRun) {
    Write-Host ""
    Write-Host "DRY RUN MODE - First 2 orders only:" -ForegroundColor Yellow
    $allLogEvents | Select-Object -First 14 | ConvertTo-Json -Depth 20 | Write-Host
}
elseif ($ExportToFile) {
    Write-Host ""
    Write-Host "Exporting to file: $OutputFile" -ForegroundColor Cyan
    $allLogEvents | ConvertTo-Json -Depth 20 | Out-File -FilePath $OutputFile -Encoding UTF8
    Write-Host "Export completed successfully" -ForegroundColor Green
}
else {
    Write-Host ""
    Write-Host "Would call Log API at: $LogApiUrl" -ForegroundColor Cyan
    Write-Host "With $($allLogEvents.Count) events" -ForegroundColor Cyan
}

Write-Host ""
Write-Host "Summary:" -ForegroundColor Cyan
Write-Host "  Orders: $OrderCount" -ForegroundColor White
Write-Host "  Log Events: $($allLogEvents.Count)" -ForegroundColor White
Write-Host "  Average Events per Order: $([Math]::Round($allLogEvents.Count / $OrderCount, 2))" -ForegroundColor White
Write-Host ""

Usage Examples

See the O2C Demo Data Generator Usage Guide for complete usage examples, parameters, and use cases.

Quick Start:

# Preview first order only
.\Generate-O2C-Demo-Data-REFACTORED.ps1 -DryRun

# Export 100 orders to file
.\Generate-O2C-Demo-Data-REFACTORED.ps1 -ExportToFile -OutputFile "C:\Temp\O2C-Demo.json"

Script Features

Consolidated Functions:

  • ConvertTo-Base64 - Base64 encoding for message bodies
  • Get-FileExtension - Format-specific file extensions
  • Get-ShortMilestone - Shortened milestone names for BPM visualization
  • New-MessagePayload - Centralized message payload generation (all 7 steps)
  • New-NodiniteLogEvent - Complete log event construction with BPM metadata

Improved Organization:

  • Step templates defined in single hashtable
  • Event definitions array with all metadata
  • Milestone definitions consolidated
  • Downstream flow relationships mapped

Cross-Platform Support:

  • PowerShell 7+ ternary operators (condition ? true : false)
  • Cross-platform path handling
  • UTC datetime management
  • Consistent encoding (UTF8)

Next Steps

O2C Demo Usage Guide - Complete usage examples and parameters
Run the script with -DryRun to preview generated data
Download and save as Generate-O2C-Demo-Data-REFACTORED.ps1

O2C Demo Overview - Complete Order-to-Cash scenario documentation
Usage Guide and Examples - Detailed usage instructions
Log API Reference - Integration with Nodinite Log API
Order Received Stylesheet - Message visualization examples