How to script Excel files with Groovy - excel

I want to create excel files in Groovy, then have them plotted. This code was taken from an example using Microsoft's Shell Scripting language:
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = True
Set objWorkbook = objExcel.Workbooks.Add()
Set objWorksheet = objWorkbook.Worksheets(1)
objWorksheet.Cells(1,1) = "Operating System"
objWorksheet.Cells(2,1) = "Windows Server 2003"
objWorksheet.Cells(3,1) = "Windows XP"
objWorksheet.Cells(5,1) = "Windows NT 4.0"
objWorksheet.Cells(6,1) = "Other"
objWorksheet.Cells(1,2) = "Number of Computers"
objWorksheet.Cells(2,2) = 145
objWorksheet.Cells(3,2) = 987
objWorksheet.Cells(4,2) = 611
objWorksheet.Cells(5,2) = 41
objWorksheet.Cells(6,2) = 56
Set objRange = objWorksheet.UsedRange
objRange.Select
Set colCharts = objExcel.Charts
colCharts.Add()
Set objChart = colCharts(1)
objChart.Activate
objChart.HasLegend = FALSE
objChart.ChartTitle.Text = "Operating System Use"
How would I modify this to work in Groovy?

You need groovy to work with COM. Towards the bottom of this page is an example of automating Excel.
EDITS
Here's your example translated into Groovy (I ran this under Groovy 1.8.2):
import org.codehaus.groovy.scriptom.*
import org.codehaus.groovy.scriptom.tlb.office.excel.XlChartType
import org.codehaus.groovy.scriptom.tlb.office.excel.XlRowCol
import org.codehaus.groovy.scriptom.tlb.office.excel.XlChartLocation
// create a xls instance
def xls = new ActiveXObject("Excel.Application")
xls.Visible = true
Thread.sleep(1000)
// get the workbooks object
def workbooks = xls.Workbooks
// add a new workbook
def workbook = workbooks.Add()
// select the active sheet
def sheet = workbook.ActiveSheet
cell = sheet.Range("A1")
cell.Value = "Operating System"
cell = sheet.Range("A2")
cell.Value = "Windows Server 2003"
cell = sheet.Range("A3")
cell.Value = "Windows XP"
cell = sheet.Range("A4")
cell.Value = "Windows NT 4.0"
cell = sheet.Range("A5")
cell.Value = "Other"
cell = sheet.Range("B1")
cell.Value = "Number of Computers"
cell = sheet.Range("B2")
cell.Value = 145
cell = sheet.Range("B3")
cell.Value = 987
cell = sheet.Range("B4")
cell.Value = 611
cell = sheet.Range("B5")
cell.Value = 41
def chart = workbook.Charts.Add(Scriptom.MISSING, sheet) // create chart object
chart.ChartType = XlChartType.xl3DArea // set type to pie
chart.SetSourceData(sheet.Range("A1:B5"), XlRowCol.xlColumns) // set source data
chart.Location(XlChartLocation.xlLocationAsNewSheet) // add chart as new sheet

Mark's answer above was a great example. It's event easier to follow if you make a couple simple changes:
import org.codehaus.groovy.scriptom.*
import org.codehaus.groovy.scriptom.tlb.office.excel.*
def xls = new ActiveXObject("Excel.Application")
xls.Visible = true
Thread.sleep(1000)
// add a new workbook
def workbook = xls.Workbooks.Add()
// select the active sheet
def sheet = workbook.ActiveSheet
sheet.Range("A1").Value = "Operating System"
sheet.Range("A2").Value = "Windows Server 2003"
sheet.Range("A3").Value = "Windows XP"
sheet.Range("A4").Value = "Windows NT 4.0"
sheet.Range("A5").Value = "Other"
sheet.Range("B1").Value = "Number of Computers"
sheet.Range("B2").Value = 145
sheet.Range("B3").Value = 987
sheet.Range("B4").Value = 611
sheet.Range("B5").Value = 41
def chart = workbook.Charts.Add(Scriptom.MISSING, sheet) // create chart object
chart.ChartType = XlChartType.xl3DArea // set type to pie
chart.SetSourceData(sheet.Range("A1:B5"), XlRowCol.xlColumns) // set source data
chart.Location(XlChartLocation.xlLocationAsNewSheet) // add chart as new sheet

Another option may be Apache POI, depending on what all you need to actually implement.
Either option will be complicated for a beginner; the easy path would be to use the shell.

I would also go for Apache POI. A working example can be found at the busy developer guide. There is also GSheets, a thin groovy wrapper for Apache POI, see the blog post and the unit test for an example usage.

Probably simplest (in terms of external code) is text format, cells are delimited by '\t' and lines "\r\n".
Be careful on cell having sense String but with num characters (or Date-alike), best to prepend with single apostrophe
Such format can be pasted by clipboard or open from file menu.

Related

How to export text from annotation fields in Nuance Power PDF to Excel using VBA?

I am trying to export some text from annotation fields in Nuance Power PDF to Excel using VBA. I added the Nuance Power PDF reference to Excel VBA (PDF Plus).
I used it and it works well but the text returned from fields is empty.
Set PDFApp = CreateObject("NuancePDF.App")
Set dvDoc = CreateObject("NuancePDF.DVDoc")
dvDoc.Open("\\adpdc-2\Users$\a.goudinoux\Documents\Macro Formulaire\fiche.pdf")
Set ddDoc = dvDoc.GetDDDoc()
Set ddPage = ddDoc.AcquirePage(0)
nbannots = ddPage.GetNumAnnots() - 1
For i = 0 To nbannots
Texte = ""
Set ddAnnot = ddPage.GetAnnot(i)
Set ddText = ddDoc.CreateTextSelect(0, ddAnnot.GetRect())
ThisWorkbook.Sheets(1).Cells(1, i) = ddAnnot.GetTitle()
For k = 0 To ddText.GetNumText()
Texte = Texte & ddText.GetText(k)
Next
ThisWorkbook.Sheets(1).Cells(2, i) = Texte
Next
Part of the PDF document :
Results :
As you can see the first line is working but not the second one.
I thought the problem was with ddText but ddText.GetNumText() gives the right number of text elements in the text selection (ex : 2, 5, 4, etc...) when I run my program in Debug Mode.
I think the problem is from the function GetText(k).
I made it work once but I can't find my code back..
Do you see any mistake ?
Either your annotations are more complex than indicated or you're overthinking it.
Just read the annotation with GetContents and call it a day.
Set PDFApp = CreateObject("NuancePDF.App")
Set dvDoc = CreateObject("NuancePDF.DVDoc")
dvDoc.Open("\\adpdc-2\Users$\a.goudinoux\Documents\Macro Formulaire\fiche.pdf")
Set ddDoc = dvDoc.GetDDDoc()
Set ddPage = ddDoc.AcquirePage(0)
nbannots = ddPage.GetNumAnnots() - 1
For i = 0 To nbannots
Set ddAnnot = ddPage.GetAnnot(i)
ThisWorkbook.Sheets(1).Cells(1, i) = ddAnnot.GetTitle
ThisWorkbook.Sheets(1).Cells(2, i) = ddAnnot.GetContents
Next i

Selecting multiple fields in win32c.xlPageField

Objective: I'm using a python script to generate an excel report (contains lots of pivot tables).
Problem: Unable to figure out how to add multiple items to pivot table filter
I've figured out a cumbersome solution where I can create individual data sets that are pre-filtered so I don't need to filter them in the pivot table. However, this isn't really efficient or effective if somebody wants to swap the filter on the final excel report.
I'll use code I found online as an example:
import win32com.client
Excel = win32com.client.gencache.EnsureDispatch('Excel.Application')
win32c = win32com.client.constants
wb = Excel.Workbooks.Add()
Sheet1 = wb.Worksheets("Sheet1")
TestData = [['Country','Name','Gender','Sign','Amount'],
['CH','Max' ,'M','Plus',123.4567],
['FR','Max' ,'M','Minus',-23.4567],
['CH','Max' ,'M','Plus',12.2314],
['SP','Max' ,'M','Minus',-2.2314],
['CH','Sam' ,'M','Plus',453.7685],
['CH','Sam' ,'M','Minus',-53.7685],
['CH','Sara','F','Plus',777.666],
['CH','Sara','F','Minus',-77.666],
['DE','Hans','M','Plus',345.088],
['DE','Hans','M','Minus',-45.088],
['DE','Paul','M','Plus',222.455],
['DE','Paul','M','Minus',-22.455]]
for i, TestDataRow in enumerate(TestData):
for j, TestDataItem in enumerate(TestDataRow):
Sheet1.Cells(i+2,j+4).Value = TestDataItem
cl1 = Sheet1.Cells(2,4)
cl2 = Sheet1.Cells(2+len(TestData)-1,4+len(TestData[0])-1)
PivotSourceRange = Sheet1.Range(cl1,cl2)
PivotSourceRange.Select()
wb.Worksheets.Add()
Sheet2 = wb.Worksheets("Sheet2")
cl3=Sheet2.Cells(4,1)
PivotTargetRange= Sheet2.Range(cl3,cl3)
PivotTableName = 'ReportPivotTable'
PivotCache = wb.PivotCaches().Create(SourceType=win32c.xlDatabase, SourceData=PivotSourceRange, Version=win32c.xlPivotTableVersion14)
PivotTable = PivotCache.CreatePivotTable(TableDestination=PivotTargetRange, TableName=PivotTableName, DefaultVersion=win32c.xlPivotTableVersion14)
PivotTable.PivotFields('Name').Orientation = win32c.xlRowField
PivotTable.PivotFields('Country').Orientation = win32c.xlPageField
PivotTable.PivotFields('Country').CurrentPage = 'SP'
PivotTable.PivotFields('Gender').Orientation = win32c.xlColumnField
PivotTable.PivotFields('Sign').Orientation = win32c.xlColumnField
DataField = PivotTable.AddDataField(PivotTable.PivotFields('Amount'))
Excel.Visible = 1
wb.SaveAs('ranges_and_offsets.xlsx')
Excel.Application.Quit()
This generates a pivot table in excel and sets the Country Filter to SP. I know adding the following line will enable the multi selection option.
PivotTable.PivotFields('Country').EnableMultiplePageItems = True
At this point, I'm stuck. I would like to find a way to set Country to both SP and DE. I feel like the correct way to do this is to switch .CurrentPage to .CurrentPageList
However, I can't seem to get .CurrentPageList to work
Any help would be highly appreciated!
this maybe too late for this post, but the way I solved this was creating two loops
PivotTable.PivotFields(target_column).Position = some_position
PivotTable.PivotFields(target_column).EnableMultiplePageItems = True
for item in show_values:
PivotTable.PivotFields(target_column).PivotItems(item).Visible = True
for item in excl_values:
PivotTable.PivotFields(target_column).PivotItems(item).Visible = False
I hope it helps!

How to add Calculated Member to Pivot Table via Python win32

I'm trying to add a calculated column into this pivot table that is being generated via a python script with import win32com.client.
Code is posted below that is generating the pivot table. I'm not sure how to add a column. In VBA it would be wb.PivotTable.CalculatedField.Add but that didn't work (at least the syntax I tried).
I'm trying to calculate [OoCUnits] / [GrossUnits]
#Make Pivot version with four weeks data
Excel = win32com.client.gencache.EnsureDispatch('Excel.Application')
win32c = win32com.client.constants
wb = Excel.Workbooks.Open(filename)
ws3 = wb.Worksheets('Dataset')
cl1 = ws3.Cells(1,1)
cl2 = ws3.Cells(max_row,max_col)
PivotSourceRange = ws3.Range(cl1,cl2)
ws3.Activate()
PivotSourceRange.Select()
wb.Sheets.Add (After=wb.Sheets(3))
ws4 = wb.Worksheets(4)
ws4.Name = 'Pivot'
cl3 = ws4.Cells(4,1)
PivotTargetRange = ws4.Range(cl3,cl3)
PivotTableName = 'OoCPivot'
#Make Pivot Table
PivotCache = wb.PivotCaches().Create(SourceType=win32c.xlDatabase, SourceData=PivotSourceRange, Version=win32c.xlPivotTableVersion14)
PivotTable = PivotCache.CreatePivotTable(TableDestination=PivotTargetRange, TableName=PivotTableName, DefaultVersion=win32c.xlPivotTableVersion14)
PivotTable.PivotFields('Product Name').Orientation = win32c.xlRowField
PivotTable.PivotFields('Product Name').Position = 1
PivotTable.PivotFields('Customer Number').Orientation = win32c.xlPageField
PivotTable.PivotFields('Customer Number').Position = 1
PivotTable.PivotFields('Customer Name').Orientation = win32c.xlPageField
PivotTable.PivotFields('Customer Name').Position = 2
PivotTable.PivotFields('Week Ending Date').Orientation = win32c.xlColumnField
PivotTable.PivotFields('Week Ending Date').Position = 1
DataField = PivotTable.AddDataField(PivotTable.PivotFields('GrossUnits'))
DataField.NumberFormat = '#0.00'
DataField = PivotTable.AddDataField(PivotTable.PivotFields('OoCUnits'))
DataField.NumberFormat = '#0.00'
I'm inserting the values with the DataField. The script is not presenting any issues as is.
EDIT: The exact code I implemented to solve. The last two lines are just formatting. I'm including in case it helps someone else.
CalcField = PivotTable.CalculatedFields().Add('OoC Unit %','= OoCUnits / GrossUnits')
DataField = PivotTable.AddDataField(PivotTable.PivotFields('OoC Unit %'))
DataField.NumberFormat = '#%'
PivotTable.DisplayErrorString = True
Actually, the method is PivotTable.CalculatedFields().Add() according to docs. Consider placing below at bottom:
CalcField = PivotTable.CalculatedFields().Add("OC_GrossPct", "= OoCUnits / GrossUnits")
PivotTable.PivotFields("OC_GrossPct").Orientation = win32c.xlDataField

Connect Excel with SAP using RFC

I need to know how to connect Excel with SAP using RFC. I have not managed to import any SAP data to Excel using the codes found so far.
I would like to be able to import data from any known transaction (e.g. a bill of materials from transaction CO03). From this I would try to understand how to extract other type of tables.
My goal is to be able to import any SAP data on a Excel spreadsheet using RFC. That would be a good start.
Do I need a special SAP account? How to verify my account is enabled to perform this type of tasks?
It is not possible to call any standard transaction remotely as most of them are legacy-like and doesn't return anything directly.
There are couple of ways to fetch data from any transaction but they are out of the scope of this question. The most practical way of retrieveing data from SAP to Excel is to find proper BAPI or remote-enabled FM, (including writing own wrapper FM) and this is the way I gonna describe here.
You don't need special account, you just need to have proper authorizations for RFC-calls, which mainly comprise of S_RFC authorization object
If you use BAPI, you can omit this point. If you created own wrapper, then you have to assure it is remote-enabled.
And then you can call your FM in VBA code and return results to Excel book. Here is the sample code:
' Logging in
Dim retcd As Boolean
Dim SilentLogon As Boolean
Set LogonControl = CreateObject("SAP.LogonControl.1")
Set objBAPIControl = CreateObject("SAP.Functions")
Set R3Connection = LogonControl.NewConnection
R3Connection.Client = "700"
R3Connection.ApplicationServer = "server_address"
R3Connection.Language = "EN"
R3Connection.User = "sap_user"
R3Connection.Password = "sap_pass"
R3Connection.System = "system_id"
R3Connection.SystemNumber = "sys_num"
R3Connection.UseSAPLogonIni = False
retcd = R3Connection.Logon(0, SilentLogon)
If retcd <> True Then MsgBox "Logon failed": Exit Sub
' Declaring FM interface
objBAPIControl.Connection = R3Connection
Set objgetaddress = objBAPIControl.Add("ZNM_GET_EMPLOYEE_DETAILS")
Set objkunnr = objgetaddress.Tables("ET_KUNNR")
Set objaddress = objgetaddress.Tables("ET_CUST_LIST")
' Filling select-options values table from sheet
Dim sht As Worksheet
Set sht = ThisWorkbook.ActiveSheet
If sht.Cells(6, 2).Value <> " " Then
objkunnr.Rows.Add
objkunnr.Value(1, "SIGN") = sht.Cells(6, 2).Value
objkunnr.Value(1, "OPTION") = sht.Cells(6, 3).Value
objkunnr.Value(1, "LOW") = sht.Cells(6, 4).Value
objkunnr.Value(1, "HIGH") = sht.Cells(6, 5).Value
R3Connection.Logoff
P.S. For all this to work in your VBA project you should add references to SAP ActiveX controls, which are located in %ProgramFiles%\SAP\FronEnd\SAPgui directory:
wdtaocxU.ocx
wdtfuncU.ocx
wdtlogU.ocx
wdobapiU.ocx
So references list of your VBA project should look like this
Additionally to Excel solution you may try this open source MS Access application I created long time ago and used many times:
https://blogs.sap.com/2013/08/16/read-data-from-sap-tables-into-ms-access-2003-database/

Epplus use Excel Styles like Hyperlink

I am trying to style some cells, I'd like to use the standard "Hyperlink" Style, but I am unable to find it.
here is my best guess code, but the Workbook does not contain a style other than "standard"
var hLinkStyle = (from s in dataSheet.Workbook.Styles.NamedStyles where s.Name == "Hyperlink" select s).FirstOrDefault();
hyperlinkCell.StyleName = hLinkStyle.Name;
Try to create a named style and set it to the cell as follows:
// string link = "your link".
// worksheet is your worksheet reference.
var namedStyle = worksheet.Workbook.Styles.CreateNamedStyle("HyperLink");
namedStyle.Style.Font.UnderLine = true;
namedStyle.Style.Font.Color.SetColor(Color.Blue);
cell.Hyperlink = new ExcelHyperLink(link);
cell.StyleName = namedStyle.Name;
cell.Value = link;
Please refer to EPP example for detail.

Resources