Varibill.SourceData.psm1
enum SourceDataType { Unrated Rated } class SourceDataBase { hidden [string] $apiUrl hidden [SourceDataType] $sourceDataType hidden [guid] $sourceCollectorKey hidden [xml] $sourceXml hidden [xml] $resultXml hidden [string] $path SourceDataBase() { } SourceDataBase([string]$apiUrl, [string]$sourceCollectorName, [guid]$sourceCollectorKey) { $this.apiUrl = $apiUrl $this.sourceCollectorKey = $sourceCollectorKey $fileOrPath = Join-Path -Path $global:HOME -ChildPath 'varibill' $fileOrPath = Join-Path -Path $fileOrPath -ChildPath 'collectors' $fileOrPath = Join-Path -Path $fileOrPath -ChildPath $sourceCollectorKey $this.path = $fileOrPath Write-Verbose "The root path for the collector is $fileOrPath" Write-Verbose "The collector API URL is $apiUrl" Write-Verbose "The collector name is $sourceCollectorName and the key is $sourceCollectorKey" } SaveSourceData() { $now = Get-Date -Format "yyyyMMdd_HHmmss_fff" $now += '.xml' $dataPath = $this.path switch ($this.sourceDataType) { Unrated { $dataPath = Join-Path -Path $dataPath -ChildPath 'unrated' } Rated { $dataPath = Join-Path -Path $dataPath -ChildPath 'unrated' } } New-Item -ItemType Directory -Force -Path $dataPath $file = Join-Path -Path $dataPath -ChildPath $now $this.sourceXml.Save($file) Write-Host "Data file saved to $file" } SaveSourceData([string] $file) { $this.sourceXml.Save($file) } [xml] GetSourceData() { return $this.sourceXml } SaveResultXml() { if ($this.resultXml -ne $null) { $now = Get-Date -Format "yyyyMMdd_HHmmss_fff" $now += '.xml' $logPath = Join-Path -Path $this.path -ChildPath 'log' New-Item -ItemType Directory -Force -Path $logPath $file = Join-Path -Path $logPath -ChildPath $now $this.resultXml.Save($file) Write-Host "Log file saved to $file" } } SaveResultXml([string] $fileOrPath) { if ($this.resultXml -ne $null) { $this.resultXml.Save($fileOrPath) } } [xml] GetResultXml() { return $this.resultXml } } class SourceData : SourceDataBase { hidden $recordsNode SourceData([string]$apiUrl, [string]$sourceCollectorName, [guid]$sourceCollectorKey) : base([string]$apiUrl, [string]$sourceCollectorName, [guid]$sourceCollectorKey) { $sourceDataType = "Unrated"; $this.sourceXml = New-Object System.Xml.XmlDocument; $prolog = $this.sourceXml.CreateXmlDeclaration("1.0", "ISO-8859-15", $null); $namespaceSoapenv = "http://schemas.xmlsoap.org/soap/envelope/"; $namespaceTem = "http://tempuri.org/"; $namespaceVar = "http://schemas.datacontract.org/2004/07/Varibill.WebService"; $this.sourceXml.AppendChild($prolog) | Out-Null; #Build the Envelope node $envelopeNode = $this.sourceXml.CreateNode([System.Xml.XmlNodeType]::Element, "soapenv:Envelope", $namespaceSoapenv); $envelopeNode.SetAttribute("xmlns:var", $namespaceVar) $envelopeNode.SetAttribute("xmlns:tem", $namespaceTem) $this.sourceXml.AppendChild($envelopeNode) | Out-Null; #Build the Body node $bodyNode = $this.sourceXml.CreateNode([System.Xml.XmlNodeType]::Element, "soapenv:Body", $namespaceSoapenv); $envelopeNode.AppendChild($bodyNode) | Out-Null; #Build the ImportSourceData node $importSourceDataNode = $this.sourceXml.CreateNode([System.Xml.XmlNodeType]::Element, "tem:ImportSourceData", $namespaceTem); $bodyNode.AppendChild($importSourceDataNode) | Out-Null; # Build the Source node $sourceNode = $this.sourceXml.CreateNode([System.Xml.XmlNodeType]::Element, "tem:source", $namespaceTem); $element = $this.sourceXml.CreateElement("var:Key", $namespaceVar) $element.InnerText = $sourceCollectorKey; $sourceNode.AppendChild($element) | Out-Null; $element = $this.sourceXml.CreateElement("var:Name", $namespaceVar) $element.InnerText = $sourceCollectorName; $sourceNode.AppendChild($element) | Out-Null; $importSourceDataNode.AppendChild($sourceNode) | Out-Null; # End the Source Node #Build the Records node $this.recordsNode = $this.sourceXml.CreateNode([System.Xml.XmlNodeType]::Element, "tem:records", $namespaceTem); $importSourceDataNode.AppendChild($this.recordsNode) | Out-Null; } AddSourceDataRecord([string] $clientIdentifier, [datetime] $lastSeenDateTime, [string] $productCode, [decimal] $quantity, [string] $recordGUID, [string] $recordIdentifier) { # Build the Record node $namespaceVar = "http://schemas.datacontract.org/2004/07/Varibill.WebService"; $recordNode = $this.sourceXml.CreateElement("var:Record", $namespaceVar); $element = $this.sourceXml.CreateElement("var:ClientIdentifier", $namespaceVar) $element.InnerText = $clientIdentifier $recordNode.AppendChild($element) | Out-Null; $element = $this.sourceXml.CreateElement("var:LastSeenDateTime", $namespaceVar) $element.InnerText = $lastSeenDateTime.ToString("o") $recordNode.AppendChild($element) | Out-Null; $element = $this.sourceXml.CreateElement("var:ProductCode", $namespaceVar) $element.InnerText = $productCode $recordNode.AppendChild($element) | Out-Null; $element = $this.sourceXml.CreateElement("var:Quantity", $namespaceVar) $element.InnerText = $quantity $recordNode.AppendChild($element) | Out-Null; $element = $this.sourceXml.CreateElement("var:RecordGUID", $namespaceVar) $element.InnerText = $recordGUID $recordNode.AppendChild($element) | Out-Null; $element = $this.sourceXml.CreateElement("var:RecordIdentifier", $namespaceVar) $element.InnerText = $recordIdentifier $recordNode.AppendChild($element) | Out-Null; $this.recordsNode.AppendChild($recordNode) | Out-Null; # End Record Node } [bool] PostSourceData() { $headers = @{"SOAPAction" = "http://tempuri.org/ISourceData/ImportSourceData"} $postXml = $this.sourceXml if($postXml.FirstChild.NodeType -eq 'XmlDeclaration') { $postXml.FirstChild.Encoding = $null } if ($global:PSVersionTable.PSVersion.Major -ge 7) { $this.resultXml = Invoke-WebRequest $this.apiUrl -Method post -ContentType 'text/xml' -Body $postXml.OuterXML -Headers $headers -RetryIntervalSec 5 -MaximumRetryCount 5 } else { $this.resultXml = Invoke-WebRequest $this.apiUrl -Method post -ContentType 'text/xml' -Body $postXml.OuterXML -Headers $headers } $this.resultXml.GetElementsByTagName("a:ExitCode").innerXML return ($this.resultXml.GetElementsByTagName("a:ExitCode").innerXML -eq 0) } } class RatedSourceData : SourceDataBase { hidden $ratedRecordsNode RatedSourceData([string]$apiUrl, [string]$sourceCollectorName, [guid]$sourceCollectorKey) : base([string]$apiUrl, [string]$sourceCollectorName, [guid]$sourceCollectorKey) { $sourceDataType = "Rated"; $this.sourceXml = New-Object System.Xml.XmlDocument; $prolog = $this.sourceXml.CreateXmlDeclaration("1.0", "ISO-8859-15", $null); $namespaceSoapenv = "http://schemas.xmlsoap.org/soap/envelope/"; $namespaceTem = "http://tempuri.org/"; $namespaceVar = "http://schemas.datacontract.org/2004/07/Varibill.WebService"; $this.sourceXml.AppendChild($prolog) | Out-Null; #Build the Envelope node $envelopeNode = $this.sourceXml.CreateNode([System.Xml.XmlNodeType]::Element, "soapenv:Envelope", $namespaceSoapenv); $envelopeNode.SetAttribute("xmlns:var", $namespaceVar) $envelopeNode.SetAttribute("xmlns:tem", $namespaceTem) $this.sourceXml.AppendChild($envelopeNode) | Out-Null; #Build the Body node $bodyNode = $this.sourceXml.CreateNode([System.Xml.XmlNodeType]::Element, "soapenv:Body", $namespaceSoapenv); $envelopeNode.AppendChild($bodyNode) | Out-Null; #Build the ImportSourceData node $importSourceDataNode = $this.sourceXml.CreateNode([System.Xml.XmlNodeType]::Element, "tem:ImportRatedSourceData", $namespaceTem); $bodyNode.AppendChild($importSourceDataNode) | Out-Null; # Build the Source node $sourceNode = $this.sourceXml.CreateNode([System.Xml.XmlNodeType]::Element, "tem:source", $namespaceTem); $element = $this.sourceXml.CreateElement("var:Key", $namespaceVar) $element.InnerText = $sourceCollectorKey; $sourceNode.AppendChild($element) | Out-Null; $element = $this.sourceXml.CreateElement("var:Name", $namespaceVar) $element.InnerText = $sourceCollectorName; $sourceNode.AppendChild($element) | Out-Null; $importSourceDataNode.AppendChild($sourceNode) | Out-Null; # End the Source Node #Build the Records node $this.ratedRecordsNode = $this.sourceXml.CreateNode([System.Xml.XmlNodeType]::Element, "tem:ratedRecords", $namespaceTem); $importSourceDataNode.AppendChild($this.ratedRecordsNode) | Out-Null; } AddSourceDataRecord([string] $clientIdentifier, [string] $productCode, [string] $recordGUID, [string] $recordIdentifier, [datetime] $lastSeenDateTime, [decimal] $quantity, [decimal] $total) { # Build the Record node $namespaceVar = "http://schemas.datacontract.org/2004/07/Varibill.WebService"; $ratedRecordNode = $this.sourceXml.CreateElement("var:RatedRecord", $namespaceVar); $element = $this.sourceXml.CreateElement("var:ClientIdentifier", $namespaceVar) $element.InnerText = $clientIdentifier $ratedRecordNode.AppendChild($element) | Out-Null; $element = $this.sourceXml.CreateElement("var:LastSeenDateTime", $namespaceVar) $element.InnerText = $lastSeenDateTime.ToString("o") $ratedRecordNode.AppendChild($element) | Out-Null; $element = $this.sourceXml.CreateElement("var:ProductCode", $namespaceVar) $element.InnerText = $productCode $ratedRecordNode.AppendChild($element) | Out-Null; $element = $this.sourceXml.CreateElement("var:Quantity", $namespaceVar) $element.InnerText = $quantity $ratedRecordNode.AppendChild($element) | Out-Null; $element = $this.sourceXml.CreateElement("var:RecordGUID", $namespaceVar) $element.InnerText = $recordGUID $ratedRecordNode.AppendChild($element) | Out-Null; $element = $this.sourceXml.CreateElement("var:RecordIdentifier", $namespaceVar) $element.InnerText = $recordIdentifier $ratedRecordNode.AppendChild($element) | Out-Null; $element = $this.sourceXml.CreateElement("var:Total", $namespaceVar) $element.InnerText = $total $ratedRecordNode.AppendChild($element) | Out-Null; $this.ratedRecordsNode.AppendChild($ratedRecordNode) | Out-Null; # End Record Node } [bool] PostSourceData() { $headers = @{"SOAPAction" = "http://tempuri.org/IRatedSourceData/ImportRatedSourceData"} $postXml = $this.sourceXml if($postXml.FirstChild.NodeType -eq 'XmlDeclaration') { $postXml.FirstChild.Encoding = $null } if ($global:PSVersionTable.PSVersion.Major -ge 7) { $this.resultXml = Invoke-WebRequest $this.apiUrl -Method post -ContentType 'text/xml' -Body $postXml.OuterXML -Headers $headers -RetryIntervalSec 5 -MaximumRetryCount 5 } else { $this.resultXml = Invoke-WebRequest $this.apiUrl -Method post -ContentType 'text/xml' -Body $postXml.OuterXML -Headers $headers } $this.resultXml.GetElementsByTagName("a:ExitCode").innerXML return ($this.resultXml.GetElementsByTagName("a:ExitCode").innerXML -eq 0) } } <# .SYNOPSIS The Varibill.SourceCollector module provides the framework so that base data can be easily post to the Varibill web service for consumption. .DESCRIPTION Varibill collects data from various source systems for billing purposes. Some of this data is collected via Powershell, and needs to be posted to the Varibill web service for billing purposes. This module absctracts the creation and posting of the XML data so that the users can focus on the business requirements. More information can be found at https://docs.varibill.com .PARAMETER ApiUrl The URL to the tenant specific API. The URL would follow the pattern of https://api-<COUNTRY>-<LOCATION>_<ID>.varibill.com/SourceData.svc .PARAMETER SourceCollectorName The name of the Source Collector as configured in Varibill. .PARAMETER sourceCollectorKey The key of the Source Collector as configured in Varibill. .EXAMPLE $sourceData = New-SourceData -ApiUrl 'https://api-<COUNTRY>-<LOCATION>_<ID>.varibill.com/SourceData.svc' -SourceCollectorName 'Source Collector Name' -sourceCollectorKey '00000000-0000-0000-0000-000000000000' $sourceData.AddSourceDataRecord('Client Identifier', '2020-01-01 00:00:00', 'Product Code', 1.234, 'Unique Identifier', 'Record Identifier') $sourceData.PostSourceData() $ratedSourceData = New-RatedSourceData -ApiUrl 'https://api-<COUNTRY>-<LOCATION>_<ID>.varibill.com/SourceData.svc' -SourceCollectorName 'Source Collector Name' -sourceCollectorKey '00000000-0000-0000-0000-000000000000' $ratedSourceData.AddSourceDataRecord('Client Identifier', 'Product Code', 'Unique Identifier', 'Record Identifier', '2020-01-01 00:00:00', 1.234, 9.876) $ratedSourceData.PostSourceData() .NOTES General notes #> Function New-SourceData { [CmdletBinding(SupportsShouldProcess)] Param( [string] $ApiUrl, [string] $SourceCollectorName, [guid] $SourceCollectorKey ) if ($PSCmdlet.ShouldProcess($SourceCollectorName)) { [SourceData]::New($ApiUrl, $SourceCollectorName, $SourceCollectorKey) } } Function New-RatedSourceData { [CmdletBinding(SupportsShouldProcess)] Param( [string] $ApiUrl, [string] $SourceCollectorName, [guid] $SourceCollectorKey ) if ($PSCmdlet.ShouldProcess($SourceCollectorName)) { [RatedSourceData]::New($ApiUrl, $SourceCollectorName, $SourceCollectorKey) } } Export-ModuleMember -Function New-SourceData Export-ModuleMember -Function New-RatedSourceData |