Solved From Access VBA an Output to Excel that filters the Output

BenMason

Member
Local time
Today, 04:27
Joined
May 14, 2021
Messages
33
I inherited code from another developer. The code works fine to export to Excel as shown in CurrentOutput.jpg example. But, now they want to break up the output to filter by fixture category. When the fixture category changes, then write out a new header row'(see example attached on NewOutput.jpg)

I have attached the code and a copy of the Excel output showing how it outputs today, and the way they want it changed.
The vendor is in column F and the fixture category is in column U
I need to code Access VBA to filter so that on change of fixture category, a new PO line is created and the line numbers in column M starts over with 1. So the same vendor can have two or more POs. In the example the yellow highlighted is vendor with cash wrap as the fixture category. It breaks/filters on change of fixture category to Fitting Room. It's the same vendor but the line numbering starts over at 1.

When end of file for that vendor and there is another vendor as in row 11, a new vendor is written and the line numbering starts over.

I see that the array is writing the line numbers, but not sure how to make it start over when it finds a different category. I thought about putting the fixture category in a string and then if the next one doesn't match, that would be the trigger. There must be a better cleaner way to do this.

I need help with the Access VBA to code the onChange of fixture category.

Thank you for your help.
Ben
 

Attachments

  • ButtonExportVBA.txt
    ButtonExportVBA.txt
    8.3 KB · Views: 19
  • CurrentOutput.jpg
    CurrentOutput.jpg
    127.3 KB · Views: 25
  • NewOutput.jpg
    NewOutput.jpg
    172.1 KB · Views: 24
"category in a string and then if the next one doesn't match, that would be the trigger" - I have used this.

Yeah, VBA could do it. But also might be able to do this by exporting a report.

Could you provide database?
 
you may try to test this code:
Code:
Private Sub Button_Export_Click()
    Dim cPie            As New cls_PIE
    
    'sub vars
    Dim i                   As Integer
    Dim sSQL                As String
    Dim stnum               As String
    Dim Proj_Fldr_dir       As String
    Dim obj_XL              As Object
    Dim obj_XL_wb           As Workbook
    
    'arrays and recordsets
    Dim rs_temp_PIE_vendor  As DAO.Recordset    'dim list of distinct vendors and phase
    Dim rs_Count_Fixt_Price As DAO.Recordset    'variable fixture list per vendor per phase
    Dim rs_array_temp()     As Variant          'array form of rs
    Dim rs_array()          As String           'formatted version of rs_array_temp
    
    DoCmd.SetWarnings False
    Me.Requery  'intentional redundancy
        
    If DCount("Form_select_boo", "temp_PIE_BPO_vendor_phase", "Form_select_boo=true") = 0 Then  'too many nested ifs
        MsgBox "No vendors selected."
        GoTo hell
    End If

    '============================
    'start declare base variables
    '============================
        sSQL = "SELECT DISTINCT t_VendorInformation.VendorID, t_VendorInformation.Vendor_Name, t_Phase.PhaseNo, temp_PIE_BPO_vendor_phase.Form_select_boo, t_Components.PhaseId, t_Phase.ChangeOrderNo, t_Emails.EmailID, t_VendorInformation.vendor_id, t_Phase.StoreAffectedID, t_StoresAffected.StoreNo, t_StoresAffected.ProjectKey, t_Project.Project_Type_Id" & _
            " FROM (t_StoresAffected INNER JOIN (((t_Phase INNER JOIN (temp_PIE_BPO_vendor_phase INNER JOIN t_Components ON (temp_PIE_BPO_vendor_phase.PhaseID = t_Components.PhaseId) AND (temp_PIE_BPO_vendor_phase.VendorID = t_Components.VendorId)) ON (t_Phase.PhaseId = t_Components.PhaseId) AND (t_Phase.PhaseId = t_Components.PhaseId)) INNER JOIN t_VendorInformation ON t_Components.VendorId = t_VendorInformation.VendorID) INNER JOIN t_Emails ON (temp_PIE_BPO_vendor_phase.PhaseID = t_Emails.PhaseId) AND (temp_PIE_BPO_vendor_phase.VendorID = t_Emails.VendorId)) ON t_StoresAffected.StoreAffectedID = t_Phase.StoreAffectedID) INNER JOIN t_Project ON t_StoresAffected.ProjectKey = t_Project.ProjectKey" & _
            " WHERE (((temp_PIE_BPO_vendor_phase.Form_select_boo) = True) And ((t_Emails.Active) = True))" & _
            " ORDER BY t_Phase.PhaseNo;"
    
        Set rs_temp_PIE_vendor = CurrentDb.OpenRecordset(sSQL, dbOpenDynaset, dbSeeChanges)
            'rs_temp_PIE_vendor(0) = vendorID
            'rs_temp_PIE_vendor(1) = vendorname
            'rs_temp_PIE_vendor(2) = phaseno
            'rs_temp_PIE_vendor(3) = form select boo (unused)
            'rs_temp_PIE_vendor(4) = PhaseID
            'rs_temp_PIE_vendor(5) = ChangeOrderNo
            'rs_temp_PIE_vendor(6) = EmailID
            'rs_temp_PIE_vendor(7) = vendor_id
            'rs_temp_PIE_vendor(8) = StoreAffectedID
            'rs_temp_PIE_vendor(9) = StoreNo
            'rs_temp_PIE_vendor(10) = ProjectKey
            'rs_temp_PIE_vendor(11) = Project_Type_Id
            
        stnum = Format(Nz(rs_temp_PIE_vendor(9), 0), "0000")
        Proj_Fldr_dir = cdefault.BuildPath(rs_temp_PIE_vendor(10), rs_temp_PIE_vendor(9))
        Set obj_XL = cExcel.Make_Excel_ob   'declare to kill later
        Set obj_XL_wb = cExcel.make_Excel_wb(obj_XL)    'must make workbook object outside of loop so that each vendor uses same object
    '============================
    'end declare base variables
    '============================

    cPie.MakeDirectories rs_temp_PIE_vendor(10), stnum
    
    If Not rs_temp_PIE_vendor.BOF And Not rs_temp_PIE_vendor.EOF Then   'loop through list of vendors, loop through phases, clear and format data
        rs_temp_PIE_vendor.MoveFirst
        While (Not rs_temp_PIE_vendor.EOF)
            If rs_temp_PIE_vendor(0) = 30 And (rs_temp_PIE_vendor(11) = 5 Or rs_temp_PIE_vendor(11) = 10) Then
                'skip IRSG for NSO
            ElseIf rs_temp_PIE_vendor(0) = 20 Then  '"YUNKER INDUSTRIES, INC."
                cExcel.Export_signage stnum, rs_temp_PIE_vendor(8), Proj_Fldr_dir, obj_XL 'Signage take off
            Else    'fill out csv for PS
                'add packing slip per phase. Only for vendor, Madix Inc. and phase below 100
                If rs_temp_PIE_vendor(0) = 11 And rs_temp_PIE_vendor(2) < 100 Then cPie.Madix_phased_packing_slips rs_temp_PIE_vendor(4), rs_temp_PIE_vendor(10)

                sSQL = "SELECT DISTINCT Sum(t_Components.Count) AS SumOfCount, t_Fixtures.Fixture_Code,t_Components.Actual_Price" & _
                    " FROM t_VendorPricing INNER JOIN ((t_Fixtures INNER JOIN t_Components ON t_Fixtures.FixtureId = t_Components.FixtureId) INNER JOIN t_VendorInformation ON t_Components.VendorId = t_VendorInformation.VendorID) ON (t_VendorPricing.Vendorid = t_Components.VendorId) AND (t_VendorPricing.FixtureId = t_Fixtures.FixtureId)" & _
                    " GROUP BY t_Fixtures.Fixture_Code, t_Components.Actual_Price, t_VendorPricing.Fixture_Buyable, t_VendorInformation.VendorID, t_Components.PhaseId" & _
                    " HAVING (((t_VendorPricing.Fixture_Buyable)=True) AND ((t_VendorInformation.VendorID)=" & rs_temp_PIE_vendor(0) & ") AND ((t_Components.PhaseId)=" & rs_temp_PIE_vendor(4) & "))" & _
                    " ORDER BY t_Fixtures.Fixture_Code;"    'fixture code, sum of count, unit price per phase+vendor
                Set rs_Count_Fixt_Price = CurrentDb.OpenRecordset(sSQL, dbOpenDynaset, dbSeeChanges)    'dim fixture list per vendor per phase
                
    
                If rs_Count_Fixt_Price.RecordCount <> 0 Then 'do stuff only if there are things to buy for vendor on certain phase
                    rs_array_temp = rs_Count_Fixt_Price.GetRows(9999) 'pass recordset data to array. 9999 is assumed overkill limit on rec count
                    
                    ReDim rs_array(0 To 3, 0 To UBound(rs_array_temp, 2))   'prime array to receive rs data
    
                    For i = LBound(rs_array_temp, 2) To UBound(rs_array_temp, 2)    'pss temp array to usable array
                        rs_array(0, i) = i + 1                  '*Line Number
                        rs_array(1, i) = rs_array_temp(0, i)    '*Purchase Order Quantity
                        rs_array(2, i) = Trim(rs_array_temp(1, i))    'Item ID
                        rs_array(3, i) = rs_array_temp(2, i)    '*Purchase Order Price
                    Next i
                    
                    '*********************************************************************************************
                    cExcel.Fill_PS_CSV obj_XL_wb, rs_array, stnum, rs_temp_PIE_vendor, rs_temp_PIE_vendor(10)  'actual line of code that passes array info to excel
                    '*********************************************************************************************
                Else    'uh oh no buyable fixtures
                    If MsgBox("No buyable fixtures detected in vendor selection:" & Chr(10) & Chr(10) & _
                    "Vendor: " & rs_temp_PIE_vendor(1) & Chr(10) & Chr(10) & _
                    "Phase: " & rs_temp_PIE_vendor(2) & Chr(10) & Chr(10) & _
                    "Continue with other vendors and phases?", vbYesNo) = vbYes Then
                        GoTo Keepgoing
                    Else
                        GoTo cleanup
                    End If
                End If
Keepgoing:
            End If
            rs_temp_PIE_vendor.MoveNext
        Wend
    End If

    With obj_XL_wb  'saving workbook here and not in cExcel.Fill_PS_CSV obj_XL_wb since its nested in a loop
        If .Sheets(1).Range("A1") <> "" Then    'dump workbook if nothing got filled
            ' arnelgp
            Call RenumberPO(.Sheets(1))
            
            .Application.DisplayAlerts = False
            .SaveAs Filename:=Proj_Fldr_dir & "Uploads\" & stnum & "_Bulk_PO_Upload" & Format(Now(), "_yyyymmdd_hhmmss_AM/PM") & ".csv", FileFormat:=6
            .Application.DisplayAlerts = True
        End If
    End With
    

    If MsgBox("Peoplesoft Upload sheet creation successful." & Chr(10) & Chr(10) & "Open folder location?", vbYesNo) = vbYes Then
        Shell "C:\WINDOWS\explorer.exe """ & Proj_Fldr_dir & "Uploads\" & "", vbNormalFocus
    End If

cleanup:

    obj_XL_wb.Close savechanges:=False
    obj_XL.Quit 'kill app
    Set rs_temp_PIE_vendor = Nothing
    Set rs_Count_Fixt_Price = Nothing

    DoCmd.Close acForm, Me.Name
hell:
    echoT
    DoCmd.SetWarnings True
End Sub

'arnelgp
'renumber the worksheet
Private Sub RenumberPO(ByRef ws As Object)
    Dim rw As Long
    Dim last_row As Long
    Dim previous_category As String
    Dim current_category As String
    Dim line As Integer
    Dim arr As Variant
    Dim j As Integer
    With ws
        last_row = .Range("U2").End(xlDown).Row
        For rw = 3 To last_row
            current_category = .Range("U" & rw)
            If current_category <> previous_category Then
                previous_category = current_category
                line = 1
                If Len(.Range("A" & rw) & "") <> 0 Then
                    arr = Range("A" & rw & ":L" & rw)
                    .Range("M" & rw) = line
                    'Debug.Print UBound(arr, 1), UBound(arr, 2)
                Else
                    For j = 1 To UBound(arr, 2)
                        .Cells(rw, j) = arr(1, j)
                    Next
                    .Range("M" & rw) = line
                End If
            
            Else
                line = line + 1
                .Range("M" & rw) = line
            End If
        Next
    End With
End Sub
 
Last edited:
you may try to test this code:
Code:
Private Sub Button_Export_Click()
    Dim cPie            As New cls_PIE
   
    'sub vars
    Dim i                   As Integer
    Dim sSQL                As String
    Dim stnum               As String
    Dim Proj_Fldr_dir       As String
    Dim obj_XL              As Object
    Dim obj_XL_wb           As Workbook
   
    'arrays and recordsets
    Dim rs_temp_PIE_vendor  As DAO.Recordset    'dim list of distinct vendors and phase
    Dim rs_Count_Fixt_Price As DAO.Recordset    'variable fixture list per vendor per phase
    Dim rs_array_temp()     As Variant          'array form of rs
    Dim rs_array()          As String           'formatted version of rs_array_temp
   
    DoCmd.SetWarnings False
    Me.Requery  'intentional redundancy
       
    If DCount("Form_select_boo", "temp_PIE_BPO_vendor_phase", "Form_select_boo=true") = 0 Then  'too many nested ifs
        MsgBox "No vendors selected."
        GoTo hell
    End If

    '============================
    'start declare base variables
    '============================
        sSQL = "SELECT DISTINCT t_VendorInformation.VendorID, t_VendorInformation.Vendor_Name, t_Phase.PhaseNo, temp_PIE_BPO_vendor_phase.Form_select_boo, t_Components.PhaseId, t_Phase.ChangeOrderNo, t_Emails.EmailID, t_VendorInformation.vendor_id, t_Phase.StoreAffectedID, t_StoresAffected.StoreNo, t_StoresAffected.ProjectKey, t_Project.Project_Type_Id" & _
            " FROM (t_StoresAffected INNER JOIN (((t_Phase INNER JOIN (temp_PIE_BPO_vendor_phase INNER JOIN t_Components ON (temp_PIE_BPO_vendor_phase.PhaseID = t_Components.PhaseId) AND (temp_PIE_BPO_vendor_phase.VendorID = t_Components.VendorId)) ON (t_Phase.PhaseId = t_Components.PhaseId) AND (t_Phase.PhaseId = t_Components.PhaseId)) INNER JOIN t_VendorInformation ON t_Components.VendorId = t_VendorInformation.VendorID) INNER JOIN t_Emails ON (temp_PIE_BPO_vendor_phase.PhaseID = t_Emails.PhaseId) AND (temp_PIE_BPO_vendor_phase.VendorID = t_Emails.VendorId)) ON t_StoresAffected.StoreAffectedID = t_Phase.StoreAffectedID) INNER JOIN t_Project ON t_StoresAffected.ProjectKey = t_Project.ProjectKey" & _
            " WHERE (((temp_PIE_BPO_vendor_phase.Form_select_boo) = True) And ((t_Emails.Active) = True))" & _
            " ORDER BY t_Phase.PhaseNo;"
   
        Set rs_temp_PIE_vendor = CurrentDb.OpenRecordset(sSQL, dbOpenDynaset, dbSeeChanges)
            'rs_temp_PIE_vendor(0) = vendorID
            'rs_temp_PIE_vendor(1) = vendorname
            'rs_temp_PIE_vendor(2) = phaseno
            'rs_temp_PIE_vendor(3) = form select boo (unused)
            'rs_temp_PIE_vendor(4) = PhaseID
            'rs_temp_PIE_vendor(5) = ChangeOrderNo
            'rs_temp_PIE_vendor(6) = EmailID
            'rs_temp_PIE_vendor(7) = vendor_id
            'rs_temp_PIE_vendor(8) = StoreAffectedID
            'rs_temp_PIE_vendor(9) = StoreNo
            'rs_temp_PIE_vendor(10) = ProjectKey
            'rs_temp_PIE_vendor(11) = Project_Type_Id
           
        stnum = Format(Nz(rs_temp_PIE_vendor(9), 0), "0000")
        Proj_Fldr_dir = cdefault.BuildPath(rs_temp_PIE_vendor(10), rs_temp_PIE_vendor(9))
        Set obj_XL = cExcel.Make_Excel_ob   'declare to kill later
        Set obj_XL_wb = cExcel.make_Excel_wb(obj_XL)    'must make workbook object outside of loop so that each vendor uses same object
    '============================
    'end declare base variables
    '============================

    cPie.MakeDirectories rs_temp_PIE_vendor(10), stnum
   
    If Not rs_temp_PIE_vendor.BOF And Not rs_temp_PIE_vendor.EOF Then   'loop through list of vendors, loop through phases, clear and format data
        rs_temp_PIE_vendor.MoveFirst
        While (Not rs_temp_PIE_vendor.EOF)
            If rs_temp_PIE_vendor(0) = 30 And (rs_temp_PIE_vendor(11) = 5 Or rs_temp_PIE_vendor(11) = 10) Then
                'skip IRSG for NSO
            ElseIf rs_temp_PIE_vendor(0) = 20 Then  '"YUNKER INDUSTRIES, INC."
                cExcel.Export_signage stnum, rs_temp_PIE_vendor(8), Proj_Fldr_dir, obj_XL 'Signage take off
            Else    'fill out csv for PS
                'add packing slip per phase. Only for vendor, Madix Inc. and phase below 100
                If rs_temp_PIE_vendor(0) = 11 And rs_temp_PIE_vendor(2) < 100 Then cPie.Madix_phased_packing_slips rs_temp_PIE_vendor(4), rs_temp_PIE_vendor(10)

                sSQL = "SELECT DISTINCT Sum(t_Components.Count) AS SumOfCount, t_Fixtures.Fixture_Code,t_Components.Actual_Price" & _
                    " FROM t_VendorPricing INNER JOIN ((t_Fixtures INNER JOIN t_Components ON t_Fixtures.FixtureId = t_Components.FixtureId) INNER JOIN t_VendorInformation ON t_Components.VendorId = t_VendorInformation.VendorID) ON (t_VendorPricing.Vendorid = t_Components.VendorId) AND (t_VendorPricing.FixtureId = t_Fixtures.FixtureId)" & _
                    " GROUP BY t_Fixtures.Fixture_Code, t_Components.Actual_Price, t_VendorPricing.Fixture_Buyable, t_VendorInformation.VendorID, t_Components.PhaseId" & _
                    " HAVING (((t_VendorPricing.Fixture_Buyable)=True) AND ((t_VendorInformation.VendorID)=" & rs_temp_PIE_vendor(0) & ") AND ((t_Components.PhaseId)=" & rs_temp_PIE_vendor(4) & "))" & _
                    " ORDER BY t_Fixtures.Fixture_Code;"    'fixture code, sum of count, unit price per phase+vendor
                Set rs_Count_Fixt_Price = CurrentDb.OpenRecordset(sSQL, dbOpenDynaset, dbSeeChanges)    'dim fixture list per vendor per phase
               
   
                If rs_Count_Fixt_Price.RecordCount <> 0 Then 'do stuff only if there are things to buy for vendor on certain phase
                    rs_array_temp = rs_Count_Fixt_Price.GetRows(9999) 'pass recordset data to array. 9999 is assumed overkill limit on rec count
                   
                    ReDim rs_array(0 To 3, 0 To UBound(rs_array_temp, 2))   'prime array to receive rs data
   
                    For i = LBound(rs_array_temp, 2) To UBound(rs_array_temp, 2)    'pss temp array to usable array
                        rs_array(0, i) = i + 1                  '*Line Number
                        rs_array(1, i) = rs_array_temp(0, i)    '*Purchase Order Quantity
                        rs_array(2, i) = Trim(rs_array_temp(1, i))    'Item ID
                        rs_array(3, i) = rs_array_temp(2, i)    '*Purchase Order Price
                    Next i
                   
                    '*********************************************************************************************
                    cExcel.Fill_PS_CSV obj_XL_wb, rs_array, stnum, rs_temp_PIE_vendor, rs_temp_PIE_vendor(10)  'actual line of code that passes array info to excel
                    '*********************************************************************************************
                Else    'uh oh no buyable fixtures
                    If MsgBox("No buyable fixtures detected in vendor selection:" & Chr(10) & Chr(10) & _
                    "Vendor: " & rs_temp_PIE_vendor(1) & Chr(10) & Chr(10) & _
                    "Phase: " & rs_temp_PIE_vendor(2) & Chr(10) & Chr(10) & _
                    "Continue with other vendors and phases?", vbYesNo) = vbYes Then
                        GoTo Keepgoing
                    Else
                        GoTo cleanup
                    End If
                End If
Keepgoing:
            End If
            rs_temp_PIE_vendor.MoveNext
        Wend
    End If

    With obj_XL_wb  'saving workbook here and not in cExcel.Fill_PS_CSV obj_XL_wb since its nested in a loop
        If .Sheets(1).Range("A1") <> "" Then    'dump workbook if nothing got filled
            ' arnelgp
            Call RenumberPO(.Sheets(1))
           
            .Application.DisplayAlerts = False
            .SaveAs Filename:=Proj_Fldr_dir & "Uploads\" & stnum & "_Bulk_PO_Upload" & Format(Now(), "_yyyymmdd_hhmmss_AM/PM") & ".csv", FileFormat:=6
            .Application.DisplayAlerts = True
        End If
    End With
   

    If MsgBox("Peoplesoft Upload sheet creation successful." & Chr(10) & Chr(10) & "Open folder location?", vbYesNo) = vbYes Then
        Shell "C:\WINDOWS\explorer.exe """ & Proj_Fldr_dir & "Uploads\" & "", vbNormalFocus
    End If

cleanup:

    obj_XL_wb.Close savechanges:=False
    obj_XL.Quit 'kill app
    Set rs_temp_PIE_vendor = Nothing
    Set rs_Count_Fixt_Price = Nothing

    DoCmd.Close acForm, Me.Name
hell:
    echoT
    DoCmd.SetWarnings True
End Sub

'arnelgp
'renumber the worksheet
Private Sub RenumberPO(ByRef ws As Object)
    Dim rw As Long
    Dim last_row As Long
    Dim previous_category As String
    Dim current_category As String
    Dim line As Integer
    Dim arr As Variant
    Dim j As Integer
    With ws
        last_row = .Range("U2").End(xlDown).Row
        For rw = 3 To last_row
            current_category = .Range("U" & rw)
            If current_category <> previous_category Then
                previous_category = current_category
                line = 1
                If Len(.Range("A" & rw) & "") <> 0 Then
                    arr = Range("A" & rw & ":L" & rw)
                    .Range("M" & rw) = line
                    'Debug.Print UBound(arr, 1), UBound(arr, 2)
                Else
                    For j = 1 To UBound(arr, 2)
                        .Cells(rw, j) = arr(1, j)
                    Next
                    .Range("M" & rw) = line
                End If
           
            Else
                line = line + 1
                .Range("M" & rw) = line
            End If
        Next
    End With
End Sub
I tried the code but it did work. Made it worst actually and deleted the vendor list from the main form. Still trying to find a solution.
 
"category in a string and then if the next one doesn't match, that would be the trigger" - I have used this.

Yeah, VBA could do it. But also might be able to do this by exporting a report.

Could you provide database?
Database is huge and connected to SQL. I like your idea of a report. I will try it although they prefer to see output in Excel format.
 
Made it worst actually and deleted the vendor list from the main form.
you upload a sample db to test.
what i did test is the sample excel file (image) you upload.
and this is what i have:
 
By "Excel format" you mean not repeating data, as shown in your example?
Can get this appearance by using report Sorting & Grouping and/or textbox HideDuplicates property.
I just did a simple test of this. It does have issues. I didn't appreciate that all output except column headers was in a faded light grey. And a textbox that calculated time with =Time() came over as a decimal. However, a textbox with =Date() displayed correctly.
 
I cannot see why you cannot do what you were doing previously, then run Private Sub RenumberPO(ByRef ws As Object) to amend the workbook.?

I did something for someone, but in Excel a good few years back, but would not be able to find it and have to recode.
I would take arnelgp's code and tweak it if it does not work out of the box.
 
If this is in SQL server you could write a stored procedure to return those records exactly as you want them formatted and simply export it, after putting in the headers.

SQL Servers windowing functions would make this very simple, and allow you to hide the repeating data.
 
you upload a sample db to test.
what i did test is the sample excel file (image) you upload.
and this is what i have:
I see what happened. On output to Excel, it lost the group by fixture category in column " U". Is there a way in your renumber routine to group by column "U" first before doing your renumbering?
The renumbering is working, but we need to group them so the onChange works better.

My apologies for not understanding earlier.

Thanks,
Ben
 
I see what happened. On output to Excel, it lost the group by fixture category in column " U". Is there a way in your renumber routine to group by column "U" first before doing your renumbering?
The renumbering is working, but we need to group them so the onChange works better.

My apologies for not understanding earlier.

Thanks,
Ben
Clarifying: For each vendor, group by fixture category in column "U" - Thanks.
 

Users who are viewing this thread

Back
Top Bottom