Customers.psm1

<#
.SYNOPSIS
    This function returns a list of the relevant TechData customer properties.
.EXAMPLE
    Get-TechDataCustomerPropertyNames
#>

function Get-TechDataCustomerPropertyNames {
    # Create list of property names
    $propertyNames = @(
        "companyName",
        "firstName",
        "lastName",
        "title",
        "email",
        "phone1",
        "phone2",
        "addressLine1",
        "addressLine2",
        "city",
        "state",
        "zip",
        "country"
    )

    # Return list of property names
    return $propertyNames
}

<#
.SYNOPSIS
    This function retrieves all TechData customers which match the provided criteria.
.DESCRIPTION
    This function retrieves all TechData customers which match the provided criteria.
    The customers returned from this function do not contain all their details.
    For retrieving customers with their full details, use the Get-TechDataCustomerDetails function.
.PARAMETER apiHeaders
    The TechData API headers generated by Get-TechDataRestApiHeaders.
.PARAMETER customerId
    The ID of the customer.
.PARAMETER companyName
    The name of the company of the customer.
.PARAMETER firstName
    The first name of the customer.
.PARAMETER lastName
    The last name of the customer.
.PARAMETER title
    The title of the customer (eg. Mr, Mrs).
.PARAMETER email
    The email address of the customer.
.PARAMETER phone1
    The primary phone number of the customer.
.PARAMETER phone2
    The secondary phone number of the customer.
.PARAMETER addressLine1
    The first line of the postal address of the customer.
.PARAMETER addressLine2
    The second line of the postal address of the customer.
.PARAMETER city
    The name of the city of the customer.
.PARAMETER state
    The name of the state of the customer.
.PARAMETER zip
    The zip or postal code of the customer.
.PARAMETER country
    The name of the country of the customer.
.PARAMETER environment
    The environment to which the call will be made, either production or test.
#>

function Get-TechDataCustomer {
    param (
        # The TechData API headers generated by Get-TechDataRestApiHeaders.
        [Parameter(Mandatory=$false, ValueFromPipeline=$true)]
        [ValidateNotNull()]
        $apiHeaders = $Global:TechDataApiHeaders,

        # The ID of the customer.
        [Parameter(Mandatory=$false)]
        [String]$customerID,

        # The name of the company of the customer.
        [Parameter(Mandatory=$false)]
        [String]$companyName,

        # The first name of the customer.
        [Parameter(Mandatory=$false)]
        [String]$firstName,

        # The last name of the customer.
        [Parameter(Mandatory=$false)]
        [String]$lastName,

        # The title of the customer (eg. Mr, Mrs).
        [Parameter(Mandatory=$false)]
        [String]$title,

        # The email address of the customer.
        [Parameter(Mandatory=$false)]
        [String]$email,

        # The primary phone number of the customer.
        [Parameter(Mandatory=$false)]
        [String]$phone1,

        # The secondary phone number of the customer.
        [Parameter(Mandatory=$false)]
        [String]$phone2,

        # The first line of the postal address of the customer.
        [Parameter(Mandatory=$false)]
        [String]$addressLine1,

        # The second line of the postal address of the customer.
        [Parameter(Mandatory=$false)]
        [String]$addressLine2,

        # The name of the city of the customer.
        [Parameter(Mandatory=$false)]
        [String]$city,

        # The name of the state of the customer.
        [Parameter(Mandatory=$false)]
        [String]$state,

        # The zip or postal code of the customer.
        [Parameter(Mandatory=$false)]
        [String]$zip,

        # The name of the country of the customer.
        [Parameter(Mandatory=$false)]
        [String]$country,

        # The environment to which the call will be made, either production or test.
        [Parameter(Mandatory=$false)]
        [ValidateSet("production", "test")]
        [String]$environment = "test"
    )

    try {
        # Set the protocol to TLS 1.2
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12

        # Retrieve the URL
        $urlTemplate = Get-TechDataApiEndpointUrl -GetCustomer -Environment $environment

        # Create array to store filtered customers
        $customers = @()

        # Call the API for the first time only on page 1 as we don't know how many pages of records there are
        $url = $urlTemplate -f 1

        # Try to call the API
        $response = Invoke-RestMethodWithRetry -Uri $url -Headers $apiHeaders -Method "GET" -IntervalMilliseconds 500 -MaximumNumberOfCalls 20

        # Add to list of customers
        $customers += $response.BodyText.endCustomersDetails

        # Call the API for the rest of the pages, starting from page 2
        $totalPages = $response.BodyText.totalPages
        for ($pageNumber = 2; $pageNumber -le $totalPages; $pageNumber += 1) {
            # Set the page number for the API call
            $url = $urlTemplate -f $pageNumber

            # Try to call the API
            $response = Invoke-RestMethodWithRetry -Uri $url -Headers $apiHeaders -Method "GET" -IntervalMilliseconds 500 -MaximumNumberOfCalls 20
            if (!$response) {
                return $null
            }

            # Add to list of customers
            $customers += $response.BodyText.endCustomersDetails
        }

        # Create a comparison customer object for easier filtering
        $comparisonCustomer = [PSCustomObject]@{}
        $customerPropertyNames = Get-TechDataCustomerPropertyNames
        foreach ($property in $customerPropertyNames) {
            $comparisonCustomer | Add-Member -NotePropertyName $property -NotePropertyValue $null -Force
        }

        # Add in parameters which were provided
        foreach ($property in $PSBoundParameters.GetEnumerator()) {
            if ($property.Key -notIn @("apiHeaders", "environment")) {
                $comparisonCustomer.($property.Key) = $property.Value
            }
        }

        # Filter the list of customers using comparison customer object
        if ($null -ne $customers) {
            $customers = $customers | ForEach-Object -Process {
                # Create temporary customer as copy of comparison customer
                $tempComparisonCustomer = $comparisonCustomer.PSObject.Copy()

                # Fill in unspecified properties to ensure that they don't affect the match
                foreach ($property in $customerPropertyNames) {
                    if ([String]::IsNullOrWhiteSpace($tempComparisonCustomer.$property)) {
                        $tempComparisonCustomer.$property = $_.$property
                    }
                }

                # Perform the comparison
                $compareObjectResult = "$(Compare-Object -ReferenceObject $_ -DifferenceObject $tempComparisonCustomer -Property $customerPropertyNames | Out-String)"
                if ([String]::IsNullOrWhiteSpace($compareObjectResult)) {
                    return $_
                }
            }
        }

        # Return the filtered list of customers
        return $customers
    }
    catch {
        Write-Error "Exception occurred on line $($_.InvocationInfo.ScriptLineNumber): `r`n$($_.Exception.Message)"
        return $null
    }
}

<#
.SYNOPSIS
    This function retrieves the details of a single TechData customer.
.DESCRIPTION
    This function retrieves the details of a single TechData customer.
    The customer object retrieved is more detailed than that retrieved using Get-TechDataCustomer.
.PARAMETER apiHeaders
    The TechData API headers generated by Get-TechDataRestApiHeaders.
.PARAMETER customerId
    The ID of the company of the customer.
.PARAMETER environment
    The environment to which the call will be made, either production or test.
#>

function Get-TechDataCustomerDetails {
    param (
        # The TechData API headers generated by Get-TechDataRestApiHeaders.
        [Parameter(Mandatory=$false, ValueFromPipeline=$true)]
        [ValidateNotNull()]
        $apiHeaders = $Global:TechDataApiHeaders,

        # The ID of the company of the customer.
        [Parameter(Mandatory=$true)]
        [String]$customerID,

        # The environment to which the call will be made, either production or test.
        [Parameter(Mandatory=$false)]
        [ValidateSet("production", "test")]
        [String]$environment = "test"
    )

    try {
        # Set the protocol to TLS 1.2
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12

        # Retrieve the URL
        $url = (Get-TechDataApiEndpointUrl -GetCustomerDetails -Environment $environment) -f $customerId

        # Try to call the API
        $response = Invoke-RestMethodWithRetry -Uri $url -Headers $apiHeaders -Method "GET" -IntervalMilliseconds 500 -MaximumNumberOfCalls 20
        if (!$response) {
            return $null
        }

        # Return the customer details
        return $response.BodyText.endCustomerDetails
    }
    catch {
        Write-Error "Exception occurred on line $($_.InvocationInfo.ScriptLineNumber): `r`n$($_.Exception.Message)"
        return $null
    }
}

<#
.SYNOPSIS
    This function creates a new TechData customer.
.DESCRIPTION
    This function creates a new TechData customer.
    It returns the created customer object, if successful.
.PARAMETER apiHeaders
    The TechData API headers generated by Get-TechDataRestApiHeaders.
.PARAMETER companyName
    The name of the company of the customer.
.PARAMETER firstName
    The first name of the customer.
.PARAMETER lastName
    The last name of the customer.
.PARAMETER title
    The title of the customer (eg. Mr, Mrs).
.PARAMETER email
    The email address of the customer.
.PARAMETER phone1
    The primary phone number of the customer.
.PARAMETER phone2
    The secondary phone number of the customer.
.PARAMETER addressLine1
    The first line of the postal address of the customer.
.PARAMETER addressLine2
    The second line of the postal address of the customer.
.PARAMETER city
    The name of the city of the customer.
.PARAMETER state
    The name of the state of the customer.
.PARAMETER zip
    The zip or postal code of the customer.
.PARAMETER country
    The name of the country of the customer.
.PARAMETER environment
    The environment to which the call will be made, either production or test.
#>

function New-TechDataCustomer {
    param (
        # The TechData API headers generated by Get-TechDataRestApiHeaders.
        [Parameter(Mandatory=$false, ValueFromPipeline=$true)]
        [ValidateNotNull()]
        $apiHeaders = $Global:TechDataApiHeaders,

        # The name of the company of the customer.
        [Parameter(Mandatory=$true)]
        [String]$companyName,

        # The first name of the customer.
        [Parameter(Mandatory=$true)]
        [String]$firstName,

        # The last name of the customer.
        [Parameter(Mandatory=$true)]
        [String]$lastName,

        # The title of the customer (eg. Mr, Mrs).
        [Parameter(Mandatory=$false)]
        [String]$title,

        # The email address of the customer.
        [Parameter(Mandatory=$true)]
        [String]$email,

        # The primary phone number of the customer.
        [Parameter(Mandatory=$true)]
        [String]$phone1,

        # The secondary phone number of the customer.
        [Parameter(Mandatory=$false)]
        [String]$phone2,

        # The first line of the postal address of the customer.
        [Parameter(Mandatory=$true)]
        [String]$addressLine1,

        # The second line of the postal address of the customer.
        [Parameter(Mandatory=$false)]
        [String]$addressLine2,

        # The name of the city of the customer.
        [Parameter(Mandatory=$true)]
        [String]$city,

        # The name of the state of the customer.
        [Parameter(Mandatory=$false)]
        [String]$state,

        # The zip or postal code of the customer.
        [Parameter(Mandatory=$true)]
        [String]$zip,

        # The name of the country of the customer.
        [Parameter(Mandatory=$true)]
        [String]$country,

        # The environment to which the call will be made, either production or test.
        [Parameter(Mandatory=$false)]
        [ValidateSet("production", "test")]
        [String]$environment = "test"
    )

    try {
        # Set the protocol to TLS 1.2
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12

        # Retrieve the URL
        $url = Get-TechDataApiEndpointUrl -NewCustomer -Environment $environment

        # Create the body of the API call
        $body = @{}

        # Add the parameters for creating the customer to the body
        $customerPropertyNames = Get-TechDataCustomerPropertyNames
        foreach ($property in $customerPropertyNames) {
            # Parameter is provided
            if ($property -in $PSBoundParameters.Keys) {
                $body.Add($property, $PSBoundParameters.$property)
            }

            # Parameter is not provided
            else {
                $body.Add($property, "")
            }
        }

        # Convert body to JSON
        $body = $body | ConvertTo-Json

        # Try to call the API
        $response = Invoke-RestMethodWithRetry -Uri $url -Headers $apiHeaders -Body $body -Method "POST" -IntervalMilliseconds 500 -MaximumNumberOfCalls 20 -ReturnUnsuccessfulResponseObject
        if (!$response) {
            return $null
        }

        # Check if call was a success
        if ($response.Result -eq "Failed") {
            # Collate error messages
            $errorMessages = ""
            foreach ($property in $response.ErrorMessage.PSObject.Properties) {
                $errorMessages += "`r`n$($property.Name): $($property.Value)"
            }
            $errorMessages = $response.ErrorMessage | Out-String

            Write-Error "API call failed with error code $($response.ErrorCode) and error messages: $($errorMessages)."
            return $null
        }

        # Return the customer with full details
        $getTechDataCustomerDetailsParams = @{
            ApiHeaders = $apiHeaders
            CustomerID = $response.BodyText.endCustomerDetails.endCustomerId
            Environment = $environment
        }
        return Get-TechDataCustomerDetails @getTechDataCustomerDetailsParams
    }
    catch {
        Write-Error "Exception occurred on line $($_.InvocationInfo.ScriptLineNumber): `r`n$($_.Exception.Message)"
        return $null
    }
}