Create hash of rolled-up values

I have coded myself into a corner.  I have a script where I read in a bunch of .csv files into a hash that has a number of invoice lines from different invoices, containing 3 keys: UNIT (the item number), QTY (the number of items purchased) and PRICE (the unit cost of the item).  I need to output a summary of the order, with a record for each unique UNIT and the total of the QTYs, like a pivot table.  My newness to Powershell has me frustrated trying to implement the business logic.  All I need to do is look for the presence of the UNIT and add it if not found, or replace the QTY with the sum of the current and new QTY.

But I can't get it to work.  Can anyone post for example code?

February 2nd, 2015 12:30pm

Can you post the code you have?
Free Windows Admin Tool Kit Click here and download it now
February 2nd, 2015 1:14pm

Sorry, here is the script.  Lines 87 - 100 is the conditional and actions that I cannot get to work.  

Thanks

If (-NOT (Test-Path \\NCPSERVER\TCR_Share\ProjectsFolder\ProjectSandBox\etl\ToBeProcessed\* -Include qb_i*.csv)){
    Exit
    Write-Host -Message "CRAP"
    }
Write-Host -BackgroundColor Blue -ForegroundColor Yellow -Message "Generating Invoice Batch"

# --- Create UNIQUE identifier for batch run
$BatchRunID              = Get-Date -Format yyyyMMdd-HHmmss

# --- Define OUTPUT files
$ABCRollUpTestFile       = "\\NCPSERVER\TCR_Share\ProjectsFolder\ProjectSandBox\etl\ToBeImported\"+$BatchRunID+"-ABCInvoiceRollUpTest.csv"

# --- Create NULL HASHES for work tables
$ABCInvoiceRollUpRow     = @{}

# --- Not really sure WHAT these do :-)
[System.Collections.ArrayList] $ABCInvoiceRollUpTable = New-Object System.Collections.ArrayList($null)

$Header = 'Rec_Type','PO','Customer','Invoice','Ship','Date','B1','Name','Addr1','Addr2','City','State','Zip','Country','Line','Qty','Unit','Site','Carton'


Foreach ($InvoiceBatchFiles in Get-ChildItem -Path \\NCPSERVER\TCR_Share\ProjectsFolder\ProjectSandBox\etl\ToBePr~1 -Filter qb_i*.csv) {
        $InvoiceArray += Import-Csv \\NCPSERVER\TCR_Share\ProjectsFolder\ProjectSandBox\etl\ToBePr~1\$InvoiceBatchFiles -Header $Header
        #Rename-Item \\NCPSERVER\TCR_Share\ProjectsFolder\ProjectSandBox\etl\ToBePr~1\$InvoiceBatchFiles \\NCPSERVER\TCR_Share\ProjectsFolder\ProjectSandBox\etl\ToBePr~1\$BatchRunID-$InvoiceBatchFiles
}

# --- Create ABC Rollup Invoice HEADER and write to output fileut don't write it yet
$ABCInvoiceRollUpRow.Rec_Type = "NCP INVOICE"
$ABCInvoiceRollUpRow.PO       = ""
$ABCInvoiceRollUpRow.Customer = "ABC.COM"
$ABCInvoiceRollUpRow.Invoice  = $BatchRunID
$ABCInvoiceRollUpRow.Ship     = ""
$ABCInvoiceRollUpRow.Date     = Get-Date -Format d
$ABCInvoiceRollUpRow.B1       = ""
$ABCInvoiceRollUpRow.Name     = ""
$ABCInvoiceRollUpRow.Addr1    = ""
$ABCInvoiceRollUpRow.Addr2    = ""
$ABCInvoiceRollUpRow.City     = ""
$ABCInvoiceRollUpRow.State    = ""
$ABCInvoiceRollUpRow.Zip      = ""
$ABCInvoiceRollUpRow.Country  = ""
$ABCInvoiceRollUpRow.Line     = ""
$ABCInvoiceRollUpRow.Qty      = ""
$ABCInvoiceRollUpRow.Unit     = ""
$ABCInvoiceRollUpRow.Site     = ""
$ABCInvoiceRollUpRow.Carton   = ""
$ABCInvoiceRollUpTable.Add((New-Object PSObject -Property $ABCInvoiceRollUpRow))


Foreach ($InvoiceBatch in $InvoiceArray) {

# --- Check to see if Customer is ABC
	If	($InvoiceBatch.Customer -eq "ABC.COM") {

	    # --- See if the ABC record is a Header or a Line
        If (-NOT [string]::IsNullOrEmpty($InvoiceBatch.Unit)){
			# --- It's a ABC LINE
	        If ($InvoiceBatch.Line -ne "Freight"){
                $ABCInvoiceRollUpRow.Rec_Type = "NCP INVOICE"
		        $ABCInvoiceRollUpRow.PO       = $InvoiceBatch.PO
		        $ABCInvoiceRollUpRow.Customer = "ABC.COM"
		        $ABCInvoiceRollUpRow.Invoice  = $BatchRunID
		        $ABCInvoiceRollUpRow.Ship     = ""
    		    $ABCInvoiceRollUpRow.Date     = Get-Date -Format d
	    	    $ABCInvoiceRollUpRow.B1       = ""
		        $ABCInvoiceRollUpRow.Name     = ""
                $ABCInvoiceRollUpRow.Addr1    = ""
		        $ABCInvoiceRollUpRow.Addr2    = ""
    		    $ABCInvoiceRollUpRow.City     = ""
		        $ABCInvoiceRollUpRow.State    = ""
		        $ABCInvoiceRollUpRow.Zip      = ""
		        $ABCInvoiceRollUpRow.Country  = ""
                
# --- Need a lookup into the $ABCInvoiceRollUP table to see if LINE already exists
                Write-Host "About to test"
                Write-Host $InvoiceBatch.Line
                If($ABCInvoiceRollUpTable.Contains($InvoiceBatch.Line)){
                    Write-Host "Yep!"
                    $ABCInvoiceRollUpRow.Qty      = $ABCInvoiceRollUpRow.Qty + $InvoiceBatch.Qty
                    }
                Else {
                    Write-Host "Nope!"
                    $ABCInvoiceRollUpRow.Line     = $InvoiceBatch.Line
		            $ABCInvoiceRollUpRow.Qty      = $InvoiceBatch.Qty
		            $ABCInvoiceRollUpRow.Unit     = $InvoiceBatch.Unit
                }
            $ABCInvoiceRollUpTable.Add((New-Object PSObject -Property $ABCInvoiceRollUpRow))
            }# If ($InvoiceBatch.Line -ne "Freight")
        
        } #If (-NOT [string]::IsNullOrEmpty($InvoiceBatch.Unit))

	   }       
}
# ---------------------------------------- OUTPUTS ---------------------------
# --- ABCInvoiceRollUpTest file output
$ABCInvoiceRollUpTable |
    Select Rec_Type,PO,Customer,Invoice,Ship,Date,B1,Name,Addr1,Addr2,City,State,Zip,Country,Line,Qty,Unit,Site,Carton |
    Export-Csv -Path $ABCRollUpTestFile -NoTypeInformation
    (Get-Content $ABCRollUpTestFile | Select-Object -Skip 1) | Set-Content $ABCRollUpTestFile

February 2nd, 2015 2:25pm

Here you have an example. Hope it helps:

$hash1 = @{
    "UNIT" = 111
    "QTY" = 2
    "PRICE" = 10
}
$hash2 = @{
    "UNIT" = 222
    "QTY" = 4
    "PRICE" = 10
}
$hash3 = @{
    "UNIT" = 333
    "QTY" = 5
    "PRICE" = 10
}


Function Merge-InvoiceLines {
Param([hashtable[]]$ArrayOfInvoiceLines)
    # First convert the hashtables (invoicelines) to an array of objects.
    $ArrayOfInvoiceLineObjects = @()
    foreach ($InvoiceLine in $ArrayOfInvoiceLines) {
        $ArrayOfInvoiceLineObjects += New-Object TypeName PSObject -Prop $InvoiceLine
    }
    
    # Then (hope it fits the requirements) you could sort the invoicelines by NIT.
    # This way, you can check for duplicate UNIT-numbers: previous invoiceline versus current invoiceline.
    $MergedInvoiceLines = @()
    $ArrayOfInvoiceLineObjects | Sort-Object -Property "UNIT" | ForEach-Object {       
        if ($MergedInvoiceLines[-1].UNIT -eq $_.UNIT) {
            $MergedInvoiceLines[-1].QTY += $_.QTY
        } else {
            $MergedInvoiceLines += ,$_
        }
    }
    return $MergedInvoiceLines    
}

# A test:
Merge-InvoiceLines -ArrayOfInvoiceLines $hash1,$hash1,$hash1,$hash2,$hash1,$hash2,$hash3,$hash3,$hash2


Free Windows Admin Tool Kit Click here and download it now
February 4th, 2015 1:59pm

Here you have an example. Hope it helps:

$hash1 = @{
    "UNIT" = 111
    "QTY" = 2
    "PRICE" = 10
}
$hash2 = @{
    "UNIT" = 222
    "QTY" = 4
    "PRICE" = 10
}
$hash3 = @{
    "UNIT" = 333
    "QTY" = 5
    "PRICE" = 10
}


Function Merge-InvoiceLines {
Param([hashtable[]]$ArrayOfInvoiceLines)
    # First convert the hashtables (invoicelines) to an array of objects.
    $ArrayOfInvoiceLineObjects = @()
    foreach ($InvoiceLine in $ArrayOfInvoiceLines) {
        $ArrayOfInvoiceLineObjects += New-Object TypeName PSObject -Prop $InvoiceLine
    }
    
    # Then (hope it fits the requirements) you could sort the invoicelines by NIT.
    # This way, you can check for duplicate UNIT-numbers: previous invoiceline versus current invoiceline.
    $MergedInvoiceLines = @()
    $ArrayOfInvoiceLineObjects | Sort-Object -Property "UNIT" | ForEach-Object {       
        if ($MergedInvoiceLines[-1].UNIT -eq $_.UNIT) {
            $MergedInvoiceLines[-1].QTY += $_.QTY
        } else {
            $MergedInvoiceLines += ,$_
        }
    }
    return $MergedInvoiceLines    
}

# A test:
Merge-InvoiceLines -ArrayOfInvoiceLines $hash1,$hash1,$hash1,$hash2,$hash1,$hash2,$hash3,$hash3,$hash2


  • Proposed as answer by Wieger1983 4 hours 57 minutes ago
February 4th, 2015 9:57pm

Wow.  It looked a little clunky to me at first.  I expected some sort of lookup command that would have a return code that I could use in decision-making.  But with only few small modifications to the code I got the suggested method working perfectly.  

Thanks

Free Windows Admin Tool Kit Click here and download it now
February 9th, 2015 1:08pm

Glad it worked for you with some modifications :-)
February 9th, 2015 1:12pm

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics