Skip to content

Update bundles and bundled products

This is an example for how a script can be written to handle bundling of products and / or articles in Easit GO.

Scenario

We have all our product and services in the Item / Article module in Easit GO and our employees can order them through our selfservice portal in Easit GO. Now we would like to bundle some of these product and services and offer them as a "Product package" (a new item type) in the selfservice portal. As we create these packages we want Easit GO to calculate the prize for us and keep it up to date as the prize for an individual item / article change and / or if the package changes (items may be added or removed from the package).

Configuration in Easit GO

We start by creating an Export configuration by going to the Control panel, search for Export and click the first result. Click on Add, change the Module to Item, give it a give it a suitable name and tag. At the bottom we need to add the collection that holds the bundled items / articles and give it the property name bundledProducts.

We then create the views we need the script to get bundles and items from in order to calculate the prize when something change. Go to the control panel in Easit GO and click on View under Admin Center and select the Items module. If you have a folder called API, click on that, otherwise create a new folder called API. Here we create 2 new view, one for items / articles, and one for bundles.

Items / Articles view (Name: CalculatePrizeProducts)

This view should at least include the following fields:

  • Id
  • Field with prize

Bundles view (Name: CalculatePrizeBundles)

This view should at least include the following fields:

  • Id
  • Field with bundled items / articles

Now we need to add these views to the API so that the script can call them and retrieve the objects from them. Go to control panel, click on Settings and under Integration / Web service click on Views. Change the module to Item and click Add. Give the view the name CalculatePrizeProducts and a tag, select CalculatePrizeProducts in the drop down box View and click on Save and close. Click on Add again, give the view the name CalculatePrizeBundles and a tag, select CalculatePrizeBundles in the drop down box View and click on Save and close.

Then we create an item rule by opening the Control panel, click Automation rules in the Design studio section. Select the Item module and click on Item rules. Click on Add to create a new item rule, give it a suitable name and tag. The rule should be applied after an item has been saved, select the item type that you use for bundles AND the item types that can be bundled. We add the collection field that holds the bundled items / articles under Any of the following fields have changed. In the section Do this we select Export item and then configuration the function to call our instance of EPR the export configuration we created at the very beginning.

Script settings

These are the settings we used in the example and is found in globalSettings.json. Update the settings as need to fit your scenario and configuration.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
    {
        "global":{
            "goWsUrl": "https://urltoeasit/webservice",
            "goWsApikey":"key"
        },
        "CalculateBundlePrize":{
            "LogOutputLevel": "VERBOSE",
            "LogRotationInterval": 30,
            "goWsUrl": "__globalValue__",
            "goWsApikey":"__globalValue__",
            "bundleView":"CalculatePrizeBundles",
            "bundledItemsCollectionName":"bundledProducts",
            "bundledItemsViewCollectionName":"fieldWithBundledItemsArticles",
            "itemView":"CalculatePrizeProducts",
            "itemPriceAttributes":["fieldNameWithPrize"],
            "updateBundleImporthandler":"UpdateBundlePrize",
            "ReturnMessageFailed":"fail",
            "ReturnMessageSuccess":"success"
        }
    }

Code

The code below should be ready to copy and paste, but it is not tested or verified and therefore may contain bugs or issues.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
    [CmdletBinding()]
    param(
        [Parameter(Mandatory,Position=0)]
        [string]$Base64StringFromStdIn
    )
    begin {
        Import-Module -Name 'Easit.ProcessRunner.GlobalFunctions'
        Write-CustomLog -Message "Starting script"
        Write-CustomLog -Message "Rotating logs" -Rotate
        function Set-BundlePrize {
            [CmdletBinding()]
            param (
                [Parameter(Mandatory)]
                [PSCustomObject]$Bundle,
                [Parameter(Mandatory)]
                [Array]$Items,
                [Parameter(Mandatory)]
                [Array]$Prizes
            )
            begin {
                Write-CustomLog -Message "$($MyInvocation.MyCommand) begin" -Level VERBOSE
            }
            process {
                foreach ($prize in $Prizes) {
                    Write-CustomLog -Message "Calculating new total prize for itemPriceAttribute ($prize)" -Level VERBOSE
                    try {
                        $Bundle | Add-Member -MemberType NoteProperty -Name "${prize}_total" -Value 0 -Force -TypeName Double
                    } catch {
                        Write-CustomLog -Message "$($_.Exception)" -Level ERROR
                        return
                    }
                    Write-CustomLog -Message "Looping over all items in bundle" -Level VERBOSE
                    foreach ($item in $Items) {
                        $item."$prize" = $item."$prize" -replace ',','.'
                        $item."$prize" = $item."$prize" -replace ' ',''
                        if (($item."$prize") -and ($item."$prize" -gt 0)) {
                            try {
                                $Bundle."${prize}_total" = [Double]$Bundle."${prize}_total" + [Double]$item."$prize"
                            } catch {
                                Write-CustomLog -Message "$($_.Exception)" -Level ERROR
                                return
                            }
                        } else {
                            $Bundle | Add-Member -MemberType NoteProperty -Name "BundlePrizeCalculationFailed" -Value $true -Force
                            $item | Add-Member -MemberType NoteProperty -Name "BundlePrizeCalculationFailed" -Value $true -Force -PassThru
                            Write-CustomLog -Message "Item ($($item.uid)) prize = $($item."$prize"). Bundle = $($Bundle.Id)" -Level WARN
                        }
                    }
                    Write-CustomLog -Message "New total prize for itemPriceAttribute ($prize) = $($Bundle."${prize}_total")" -Level VERBOSE
                }
                return $Bundle
            }
            end {
                Write-CustomLog -Message "$($MyInvocation.MyCommand) end" -Level VERBOSE
            }
        }
    }
    process {
        try {
            $easitObject = Convert-EasitGOExportString -InputString $Base64StringFromStdIn
        } catch {
            $customExitCode = 1
            Write-CustomLog -Message "$($_.Exception)" -Level ERROR
            return
        }
        $wsParams = @{
            url = $settings.goWsUrl
            apikey = $settings.goWsApikey
        }
        $bundles = [System.Collections.ArrayList]::new()
        $bundlesToUpdate = [System.Collections.ArrayList]::new()
        $bundledItems = [System.Collections.ArrayList]::new()
        $bundledItemsRaw = [System.Collections.ArrayList]::new()
        try {
            [System.Collections.ArrayList]$bundledItemsRaw += $easitObject.property | Where-Object -Property Name -EQ -Value $settings.bundledItemsCollectionName
        } catch {
            Write-CustomLog -Message "$($_.Exception)" -Level ERROR
            return
        }
        if ($bundledItemsRaw.Count -gt 0) {
            Write-CustomLog -Message "Received a bundle, will attempt to calculate new prize and update bundle"
            Write-CustomLog -Message "Collected $($bundledItemsRaw.Count) object(s) from exported object" -Level VERBOSE
            foreach ($bundledItemRaw in $bundledItemsRaw) {
                try {
                    [System.Collections.ArrayList]$bundledItems += Get-EasitGOItem @wsParams -view $settings.itemView -IdFilter "$($bundledItemRaw.content)" -ReturnAsSeparateObjects
                } catch {
                    Write-CustomLog -Message "$($_.Exception)" -Level ERROR
                    return
                }
            }
            Write-CustomLog -Message "Collected $($bundledItems.Count) object(s) from GO"
            try {
                Write-CustomLog -Message "Calculating prize for bundle $($easitObject.uid) ($($easitObject.Id))"
                [System.Collections.ArrayList]$bundlesToUpdate += Set-BundlePrize -Bundle $easitObject -Items $bundledItems -Prizes $settings.itemPriceAttributes
            } catch {
                Write-CustomLog -Message "$($_.Exception)" -Level ERROR
                return
            }
        } else {
            Write-CustomLog -Message "Received an item, all bundles that includes this item needs to be updated"
            $cachedItems = [System.Collections.ArrayList]::new()
            $allBundledItems = [System.Collections.ArrayList]::new()
            try {
                Write-CustomLog -Message "ColumnFilter = $($settings.bundledItemsViewCollectionName),$($easitObject.id),IN," -Level VERBOSE
                $filter = New-ColumnFilter -ColumnName $settings.bundledItemsViewCollectionName -RawValue $easitObject.id -Comparator 'IN'
                [System.Collections.ArrayList]$bundles += Get-EasitGOItem @wsParams -view $settings.bundleView -ColumnFilter $filter
            } catch {
                Write-CustomLog -Message "$($_.Exception)" -Level ERROR
                return
            }
            Write-CustomLog -Message "Collected $($bundles.Count) bundles from GO"
            foreach ($bundle in $bundles) {
                foreach ($bundledItem in $bundle."$($settings.bundledItemsViewCollectionName)") {
                    Write-CustomLog -Message "Looking up GO object for item $($bundledItem.rawValue)" -Leve VERBOSE
                    if ($cachedItems -contains $bundledItem.rawValue) {
                        Write-CustomLog -Message "Found GO object for bundled item ($($bundledItem.rawValue)) in cache" -Leve VERBOSE
                    } else {
                        Write-CustomLog -Message "GO object for bundled item ($($bundledItem.rawValue)) not found in cache" -Leve VERBOSE
                        try {
                            Write-CustomLog -Message "Retrieving GO object for bundled item ($($bundledItem.rawValue))" -Leve VERBOSE
                            [System.Collections.ArrayList]$allBundledItems += Get-EasitGOItem @wsParams -view $settings.itemView -IdFilter "$($bundledItem.rawValue)"
                        } catch {
                            Write-CustomLog -Message "$($_.Exception)" -Level ERROR
                            return
                        }
                        try {
                            Write-CustomLog -Message "Adding GO object for bundled item ($($bundledItem.rawValue)) to cache" -Level VERBOSE
                            [void]$cachedItems.Add("$($bundledItem.rawValue)")
                        } catch {
                            Write-CustomLog -Message "$($_.Exception)" -Level ERROR
                            return
                        }
                    }
                    try {
                        [System.Collections.ArrayList]$bundledItems += $allBundledItems | Where-Object -Property databaseId -EQ $bundledItem.rawValue
                    } catch {
                        Write-CustomLog -Message "$($_.Exception)" -Level ERROR
                        return
                    }
                }
                try {
                    Write-CustomLog -Message "Calculating prize for bundle $($bundle.Id)"
                    [System.Collections.ArrayList]$bundlesToUpdate += Set-BundlePrize -Bundle $bundle -Items $bundledItems -Prizes $settings.itemPriceAttributes
                    Write-CustomLog -Message "Calculating for $($bundle.Id) completed"
                } catch {
                    Write-CustomLog -Message "$($_.Exception)" -Level ERROR
                    return
                }
            }
        }
        Write-CustomLog -Message "$($bundlesToUpdate.Count) object(s) to update in GO" -Level VERBOSE
        try {
            Send-ToEasitGO @wsParams -ImportHandlerIdentifier $settings.updateBundleImporthandler -Item $bundlesToUpdate
        } catch {
            Write-CustomLog -Message "Failed to update one or more bundles" -Level WARN
            Write-CustomLog -Message "$($_.Exception)" -Level ERROR
            continue
        }
    }
    end {
        $goWebserviceParams = @{
            url = $settings.goWsUrl
            apikey = $settings.goWsApikey
        }
        $resultPropertiesParams = @{
            ID = $easitObject.uid
            exitCode = $customExitCode
        }
        if ($customExitCode -ne 0) {
            $resultPropertiesParams.Add('ReturnMessage',"$($settings.ReturnMessageFailed)")

        }
        if ($customExitCode -eq 0) {
            $resultPropertiesParams.Add('ReturnMessage',"$($settings.ReturnMessageSuccess)")
        }
        try {
            Send-ToEasitGO @goWebserviceParams -ImportHandlerIdentifier $settings.updateBundleImporthandler -CustomItem $resultPropertiesParams
        } catch {
            Write-CustomLog -InputObject $_ -Level ERROR
        }
    }

We have added the function Set-BundlePrize to make it easier to follow what the script does.