How to add a Graph placeholder and Table Placeholder in PDF template using Aspose.dll - pdf

How to add a Graph placeholder and Table placeholder in PDF template using Aspose.dll
Please help me in this area.

You can add a graph to a PDF document by using the code below:
// Create Document instance
Document doc = new Document();
// Add page to pages collection of PDF file
Page page = doc.Pages.Add();
// Create Graph instance
Aspose.Pdf.Drawing.Graph graph = new Aspose.Pdf.Drawing.Graph(100, 400);
// Add graph object to paragraphs collection of page instance
page.Paragraphs.Add(graph);
// Create Rectangle instance
Aspose.Pdf.Drawing.Rectangle rect = new Aspose.Pdf.Drawing.Rectangle(100, 100, 200, 120);
// Specify fill color for Graph object
rect.GraphInfo.FillColor = Aspose.Pdf.Color.Red;
// Add rectangle object to shapes collection of Graph object
graph.Shapes.Add(rect);
dataDir = dataDir + "CreateFilledRectangle_out.pdf";
// Save PDF file
doc.Save(dataDir);
And, you can add a table in a PDF document by using the code below:
// Create Document instance
Aspose.Pdf.Document doc = new Aspose.Pdf.Document();
// Add page to pages collection of PDF file
Page page = doc.Pages.Add();
// Initializes a new instance of the Table
Aspose.Pdf.Table table = new Aspose.Pdf.Table();
// Set the table border color as LightGray
table.Border = new Aspose.Pdf.BorderInfo(Aspose.Pdf.BorderSide.All, .5f, Aspose.Pdf.Color.FromRgb(System.Drawing.Color.LightGray));
// Set the border for table cells
table.DefaultCellBorder = new Aspose.Pdf.BorderInfo(Aspose.Pdf.BorderSide.All, .5f, Aspose.Pdf.Color.FromRgb(System.Drawing.Color.LightGray));
// Create a loop to add 10 rows
for (int row_count = 1; row_count < 10; row_count++)
{
// Add row to table
Aspose.Pdf.Row row = table.Rows.Add();
// Add table cells
row.Cells.Add("Column (" + row_count + ", 1)");
row.Cells.Add("Column (" + row_count + ", 2)");
row.Cells.Add("Column (" + row_count + ", 3)");
}
// Add table object to first page of document
doc.Pages[1].Paragraphs.Add(table);
dataDir = dataDir + "document_with_table_out.pdf";
// Save updated document containing table object
doc.Save(dataDir);
You may visit following links for further information on these topics.
Working with Graphs
Working with Tables
P.S: I work with Aspose as Developer Evangelist.

Related

Why does adding w:drawing cause corrupted file

I'm trying to add a chart to a docx file using docx4j. I generated what i wanted in Word and with the help of the docx4j webapp i was able to get the corresponding java code. Unfortunately the generated docx file is said to be corrupted by Word. When trying to debug, I realised that if I commented out the line that added the drawing to the run, the file became readable. I can't figure out what's wrong. Below is my code and the link to what i tried to reproduce http://www.filedropper.com/graphique .
I'm using docx4j 8.2 and office 2016
Chart chartPart = new Chart();
Relationship chartRelationship = wordMLPackage.getMainDocumentPart().addTargetPart(chartPart);
chartPart.setJaxbElement(ChartSpace.createChartSpace());
DefaultXmlPart colorPart = new DefaultXmlPart(new PartName("/word/charts/colors1.xml"));
colorPart.setContentType(new ContentType("application/vnd.ms-office.chartcolorstyle+xml"));
colorPart.setRelationshipType("http://schemas.microsoft.com/office/2011/relationships/chartColorStyle");
chartPart.addTargetPart(colorPart);
colorPart.setDocument(new FileInputStream(new File("colors1.xml")));
DefaultXmlPart stylePart = new DefaultXmlPart(new PartName("/word/charts/style1.xml"));
stylePart.setContentType(new ContentType("application/vnd.ms-office.chartstyle+xml"));
stylePart.setRelationshipType("http://schemas.microsoft.com/office/2011/relationships/chartStyle");
chartPart.addTargetPart(stylePart);
stylePart.setDocument(new FileInputStream(new File("style1.xml")));
EmbeddedPackagePart embeddedPackagePart = new EmbeddedPackagePart(
new PartName("/word/embeddings/Microsoft_Excel_Worksheet.xlsx"));
embeddedPackagePart.setContentType(
new ContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
chartPart.addTargetPart(embeddedPackagePart);
embeddedPackagePart.setBinaryData(new java.io.FileInputStream(new File("data.xlsx")));
mainDocumentPart.getContent().add(addGraphic(factory, chartRelationship.getId()));
public static P addGraphic(ObjectFactory factory, String chartId) throws JAXBException {
P p = factory.createP();
// Create object for r
R r = factory.createR();
p.getContent().add(r);
// Create object for drawing (wrapped in JAXBElement)
Drawing drawing = factory.createDrawing();
JAXBElement<org.docx4j.wml.Drawing> drawingWrapped = factory.createRDrawing(drawing);
r.getContent().add(drawingWrapped);
org.docx4j.dml.wordprocessingDrawing.ObjectFactory dmlwordprocessingDrawingObjectFactory = new org.docx4j.dml.wordprocessingDrawing.ObjectFactory();
// Create object for inline
Inline inline = dmlwordprocessingDrawingObjectFactory.createInline();
drawing.getAnchorOrInline().add(inline);
org.docx4j.dml.ObjectFactory dmlObjectFactory = new org.docx4j.dml.ObjectFactory();
// Create object for graphic
Graphic graphic = dmlObjectFactory.createGraphic();
inline.setGraphic(graphic);
// Create object for graphicData
GraphicData graphicdata = dmlObjectFactory.createGraphicData();
graphic.setGraphicData(graphicdata);
graphicdata.setUri("http://schemas.openxmlformats.org/drawingml/2006/chart");
org.docx4j.dml.chart.ObjectFactory dmlchartObjectFactory = new org.docx4j.dml.chart.ObjectFactory();
// Create object for chart (wrapped in JAXBElement)
CTRelId relid = dmlchartObjectFactory.createCTRelId();
JAXBElement<org.docx4j.dml.chart.CTRelId> relidWrapped = dmlchartObjectFactory.createChart(relid);
graphicdata.getAny().add(relidWrapped);
relid.setId(chartId);
// Create object for cNvGraphicFramePr
CTNonVisualGraphicFrameProperties nonvisualgraphicframeproperties = dmlObjectFactory
.createCTNonVisualGraphicFrameProperties();
inline.setCNvGraphicFramePr(nonvisualgraphicframeproperties);
// Create object for extent
CTPositiveSize2D positivesize2d = dmlObjectFactory.createCTPositiveSize2D();
inline.setExtent(positivesize2d);
positivesize2d.setCx(5486400);
positivesize2d.setCy(3200400);
// Create object for effectExtent
CTEffectExtent effectextent = dmlwordprocessingDrawingObjectFactory.createCTEffectExtent();
inline.setEffectExtent(effectextent);
effectextent.setB(0);
effectextent.setL(0);
effectextent.setT(0);
effectextent.setR(0);
// Create object for docPr
CTNonVisualDrawingProps nonvisualdrawingprops = dmlObjectFactory.createCTNonVisualDrawingProps();
inline.setDocPr(nonvisualdrawingprops);
nonvisualdrawingprops.setDescr("");
nonvisualdrawingprops.setName("Graphique 1");
nonvisualdrawingprops.setId(1);
inline.setDistT(Long.valueOf(0));
inline.setDistB(Long.valueOf(0));
inline.setDistL(Long.valueOf(0));
inline.setDistR(Long.valueOf(0));
// Create object for rPr
RPr rpr = factory.createRPr();
r.setRPr(rpr);
// Create object for noProof
BooleanDefaultTrue booleandefaulttrue = factory.createBooleanDefaultTrue();
rpr.setNoProof(booleandefaulttrue);
return p;
}

pdf is created from google slide, but with the markers populated (via GAS)

The code below basically maps columns from a spreadsheet to a couple of markers I got on a google slide.
It generates copies of the google slide template, updates them with the row's data and I actually need it to be in pdf form to be emailed later.
The pdf files are created in the destination folder, with the right file names, but the markers within them are "empty". Later on, I will have to delete these google slide files, but the challenge here now is to have the pdf files correctly created.
Appreciate your time.
function mailMerge(templateID,ssID, sheetName, mapped, fileNameData, emailCol, rowLen = "auto"){
//Properties Services is Google Script Storage.
//This clears out the storage.
PropertiesService.getScriptProperties().deleteAllProperties();
const ss = SpreadsheetApp.getActiveSpreadsheet();
//const sheet = SpreadsheetApp.openById(ssID);
const sheet = ss.getSheetByName("Lista de Participantes");
//Get number of rows to process
rowLen = (rowLen = "auto") ? getRowLen() : rowLen;
const range = sheet.getRange(7,1,rowLen,sheet.getDataRange().getNumColumns());
const matrix = range.getValues();
const fileNameRows = getFileNameRows()
for(let i = 1; i < rowLen; i++){
if (matrix[i][1] == true && matrix[i][27] != "Sim") {
let row = matrix[i];
//Get the title for the file.
let fileName = buildFileName(row)
//Creates a copy of the template file and names it with the current row's details.
let newDoc = DriveApp.getFileById(templateID).makeCopy(fileName);
//Replaces all the text place markers ({{text}}) with current row information.
updateFileData(row, newDoc.getId());
//Save new File ID and email to Properties service.
PropertiesService.getScriptProperties()
.setProperty(newDoc.getId(),row[emailCol]);
// 5. Export the temporal Google Slides as a PDF file.
newDoc = DriveApp.getFileById(newDoc.getId());
DriveApp.getFolderById("folder ID").createFile(newDoc.getBlob());
}
};
Besides the code above, I go this script file within the same container/Spreadsheet, where I map the columns whose data I want to generate a google Slide for. each column of data I refer to as marker.
/*###################################################################
* Maps the relationship between the Google Sheet header and its location
* for each column along with it's corresponding Google Slide Doc template name.
*
* To update change the sheet, col and doc:
* ***
* {
* sheet: << Your sheet header
* col: << The column on the google sheet with the above header
* doc: << the corresonding name in double braces {{name}} in your Slide template
* }
* ***
*###################################################################
*/
const mappedDocToSheet = [
{
sheet:"Nome",
col:2,
doc:"primeiroNome"
},
{
sheet:"Sobrenome",
col:3,
doc:"sobrenome"
},
{
sheet:"COD. CERTIFICADO",
col:9,
doc:"codigo"
},
{
sheet:"Curso",
col:10,
doc:"curso"
},
];
I believe your goal and situation as follows.
You add the values of Google Slides and create it to PDF data
newDoc is the Google Slides
In order to achieve your goal, please use saveAndClose. For your script, please modify as follows.
Modified script:
Please add the following script to your function of mailMerge as follows.
// 5. Export the temporal Google Slides as a PDF file.
SlidesApp.openById(newDoc.getId()).saveAndClose(); // <--- Added
Reference:
saveAndClose()

PDFBox inserting data into multi-page doc

I'm trying to create a simple pdf multi-page document with fields in it. To do that I have a template pdf which in the code I clone this template as many times as needed in order to create the document itself.
The problem comes with inserting some data in it. The type of data I try to insert to the document is not supposed to change across the pages. Rather than that, it stays static in all pages, Like the "Pages" digit that represents the number of the pages that this document contains.
Now, Inside my template pdf I have some text fields like, for instance, "Shipper1" and "Pages". I want to be able to insert my data into this text fields so that all the pages in the document will have this values in their "Shipper1" and "Pages" fields.
My code currently does that only on the first page. It shows the data perfectly. On the other hand, when I go to another page, the data isn't shown there. It's just displays an empty field.
Here is the code where I initiate the pdf document:
static void initiatePdf() {
// Initiate a new PDF Box object and get the acro form from it
File file = new File(Constants.Paths.EMPTY_DOC)
PDDocument tempDoc
Evaluator evaluator = new Evaluator(metaHolder)
int numPages = evaluator.getNumOfPagesRequired(objects)
FieldRenamer renamer = new FieldRenamer()
PDResources res = new PDResources()
COSDictionary acroFormDict = new COSDictionary()
List<PDField> fields = []
Closure isFieldExist = {List<PDField> elements, String fieldName ->
elements.findAll{it.getFullyQualifiedName() == fieldName}.size() > 0
}
for(int i = 0; i < numPages; i++) {
tempDoc = new PDDocument().load(file)
PDDocumentCatalog docCatalog = tempDoc.getDocumentCatalog()
PDAcroForm acroForm = docCatalog.acroForm
PDPage page = (PDPage) docCatalog.getPages().get(0)
renamer.setCurrentForm(acroForm)
if(i == 0) {
res = acroForm.getDefaultResources()
acroFormDict.mergeInto(acroForm.getCOSObject())
renamer.renameFields(1)
} else
renamer.renameFields(i*10+1)
List<PDField> newFields = acroForm.fields.findAll { PDField newField ->
isFieldExist(fields, newField.getFullyQualifiedName()) == false
}
fields.addAll(newFields)
document.addPage(page)
}
PDAcroForm acroForm = new PDAcroForm(document, acroFormDict);
acroForm.setFields(fields)
acroForm.setDefaultResources(res);
document.documentCatalog.setAcroForm(acroForm)
}
A couple of things first:
metaHolder instance holds the information about all
the fields that reside inside the acro form. the info is: Field Name, Field Widget Width, Field Font and Font size
evaluator is just and instance of the Evaluator class. Its purpose is to analyze the dynamic data and decide how many pages will take to contain all that text data.
Here is where I try to populate the fields with text:
static void populateData() {
def properties = ["$Constants.Fields.SHIPPER" : "David"]
FieldPopulater populater = new FieldPopulater(document, metaHolder)
populater.populateStaticFields(properties)
}
FieldPopulater class:
package app.components
import app.StringUtils
import app.components.entities.DGObject
import app.components.entities.FieldMeta
import org.apache.pdfbox.pdmodel.PDDocument
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm
import org.apache.pdfbox.pdmodel.interactive.form.PDField
/**
* Created by David on 18/10/2016.
*/
class FieldPopulater {
PDAcroForm acroForm
FormMetaHolder metaHolder
FieldPopulater(PDDocument document, FormMetaHolder metaHolder) {
this.acroForm = document.getDocumentCatalog().acroForm
this.metaHolder = metaHolder
}
void populateStaticFields(properties) {
List<PDField> fields = []
properties.each {fieldName, data ->
FieldMeta fieldMeta = metaHolder.getMetaData(fieldName)
fields = acroForm.fields.findAll { PDField field ->
String currentName = field.getFullyQualifiedName()
char lastChar = currentName[-1]
if(Character.isDigit(lastChar)) {
currentName = currentName.substring(0,currentName.size()-1)
}
currentName == fieldName
}
if(fields.size() > 1) {
int counter = 1
String tempData = data
String currentFitData
while(tempData.isEmpty() != true) {
int maxWords = Utils.getMaxWords(tempData, fieldMeta)
currentFitData = StringUtils.getTextByWords(tempData, maxWords)
tempData = StringUtils.chopTextByWords(tempData, maxWords)
PDField field = fields.find{it.getFullyQualifiedName()[-1] == "$counter"}
field?.setValue(currentFitData)
counter++
}
} else {
PDField tempField = fields[0]
tempField.setValue(data)
}
}
}
}
The result is, in the first page, the field "Shipper" has a value of "David"
In the second page, the field "Shipper" is empty.
Here is an image. First page:
Second page:
What is the problem here?
UPDATE: I tried to add the widgets of every new acro form to the current page so that every field will a few kids widgets that will represent the field, but it still doesn't work.
// All the widgets that are associated with the fields
List<PDAnnotationWidget> widgets = acroForm.fields.collect {PDField field -> field.getWidgets().get(0)}
page.annotations.addAll(widgets)
UPDATE: I also tried to add the current widget of a field to the parent field's collection of widgets. Here is the code:
List<PDAnnotationWidget> widgets = []
// All the widgets that are associated with the fields
acroForm.fields.each {PDField field ->
PDAnnotationWidget widget = field.widgets.get(0)
// Adding the following widget to the page and to the field's list of annotation widgets
widgets.add(widget)
fields.find {it.getFullyQualifiedName() == field.getFullyQualifiedName()}?.widgets.add(widget)
}
page.annotations.addAll(widgets)
What you want is to have sereval visual representations of the same field. This is done by having several annotation widgets for such a field.
In PDF, when a field has only one annotation widget, they share a common dictionary. When it has several, the annotation widgets are in a child list of the field.
When you want several annotation widgets for one field, you need to create the annotation widgets with new PDAnnotationWidget() instead of calling field.getWidgets().get(0) and using that one. These widgets must be added to a list, and this list must be assigned to the field with setWidgets(). And for each widget you must call setRectangle() and setPage() and setParent().
An example for this is in the new CreateMultiWidgetsForm.java example. The setParent() method is not yet available in 2.0.3 (but will be in 2.0.4). In this answer, it is replaced with a call that does the same thing in a less elegant way.
public final class CreateMultiWidgetsForm
{
private CreateMultiWidgetsForm()
{
}
public static void main(String[] args) throws IOException
{
// Create a new document with 2 empty pages.
PDDocument document = new PDDocument();
PDPage page1 = new PDPage(PDRectangle.A4);
document.addPage(page1);
PDPage page2 = new PDPage(PDRectangle.A4);
document.addPage(page2);
// Adobe Acrobat uses Helvetica as a default font and
// stores that under the name '/Helv' in the resources dictionary
PDFont font = PDType1Font.HELVETICA;
PDResources resources = new PDResources();
resources.put(COSName.getPDFName("Helv"), font);
// Add a new AcroForm and add that to the document
PDAcroForm acroForm = new PDAcroForm(document);
document.getDocumentCatalog().setAcroForm(acroForm);
// Add and set the resources and default appearance at the form level
acroForm.setDefaultResources(resources);
// Acrobat sets the font size on the form level to be
// auto sized as default. This is done by setting the font size to '0'
String defaultAppearanceString = "/Helv 0 Tf 0 g";
acroForm.setDefaultAppearance(defaultAppearanceString);
// Add a form field to the form.
PDTextField textBox = new PDTextField(acroForm);
textBox.setPartialName("SampleField");
// Acrobat sets the font size to 12 as default
// This is done by setting the font size to '12' on the
// field level.
// The text color is set to blue in this example.
// To use black, replace "0 0 1 rg" with "0 0 0 rg" or "0 g".
defaultAppearanceString = "/Helv 12 Tf 0 0 1 rg";
textBox.setDefaultAppearance(defaultAppearanceString);
// add the field to the AcroForm
acroForm.getFields().add(textBox);
// Specify 1st annotation associated with the field
PDAnnotationWidget widget1 = new PDAnnotationWidget();
PDRectangle rect = new PDRectangle(50, 750, 250, 50);
widget1.setRectangle(rect);
widget1.setPage(page1);
widget1.getCOSObject().setItem(COSName.PARENT, textBox);
// Specify 2nd annotation associated with the field
PDAnnotationWidget widget2 = new PDAnnotationWidget();
PDRectangle rect2 = new PDRectangle(200, 650, 100, 50);
widget2.setRectangle(rect2);
widget2.setPage(page2);
widget2.getCOSObject().setItem(COSName.PARENT, textBox);
// set green border and yellow background for 1st widget
// if you prefer defaults, just delete this code block
PDAppearanceCharacteristicsDictionary fieldAppearance1
= new PDAppearanceCharacteristicsDictionary(new COSDictionary());
fieldAppearance1.setBorderColour(new PDColor(new float[]{0,1,0}, PDDeviceRGB.INSTANCE));
fieldAppearance1.setBackground(new PDColor(new float[]{1,1,0}, PDDeviceRGB.INSTANCE));
widget1.setAppearanceCharacteristics(fieldAppearance1);
// set red border and green background for 2nd widget
// if you prefer defaults, just delete this code block
PDAppearanceCharacteristicsDictionary fieldAppearance2
= new PDAppearanceCharacteristicsDictionary(new COSDictionary());
fieldAppearance2.setBorderColour(new PDColor(new float[]{1,0,0}, PDDeviceRGB.INSTANCE));
fieldAppearance2.setBackground(new PDColor(new float[]{0,1,0}, PDDeviceRGB.INSTANCE));
widget2.setAppearanceCharacteristics(fieldAppearance2);
List <PDAnnotationWidget> widgets = new ArrayList<PDAnnotationWidget>();
widgets.add(widget1);
widgets.add(widget2);
textBox.setWidgets(widgets);
// make sure the annotations are visible on screen and paper
widget1.setPrinted(true);
widget2.setPrinted(true);
// Add the annotations to the pages
page1.getAnnotations().add(widget1);
page2.getAnnotations().add(widget2);
// set the field value
textBox.setValue("Sample field");
document.save("MultiWidgetsForm.pdf");
document.close();
}
}

Undefined merge field in google apps script

I have a Google Apps Script for a Google Spreadsheet based on a Google Form that clients fill out online. The script is triggered by OnFormSubmit and generates a pdf based on a Google Doc template and sends the pdf to me by email using MailApp.sendEmail.
This script has been working fine until recently. The script runs successfully but the pdf output is incorrect. It seems like fields that are left blank are now being ignored in the script and so my pdf output shows the value for the next non-blank field. Ugh!
Anybody know what's going on here?
Below is an example of my script:
var docTemplate = "1FZL4rVe0LLpvMtIsq_3-pwv5POllIsyYThjfemkbkfg";
var docName = "Travel Details";
function onFormSubmit(e) {
var last = e.values[1];
var first = e.values[2];
var order = e.values[3];
var date = e.values[4];
var gender = e.values[5];
var email = "example#gmail.com";
var copyId = DocsList.getFileById(docTemplate)
.makeCopy(docName+' for '+last + ', ' + first)
.getId();
var copyDoc = DocumentApp.openById(copyId);
var copyBody = copyDoc.getActiveSection();
copyBody.replaceText('keyLast', last);
copyBody.replaceText('keyFirst', first);
copyBody.replaceText('keyOrder', order);
copyBody.replaceText('keyDate', date);
copyBody.replaceText('keyGender', gender);
copyDoc.saveAndClose();
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
MailApp.sendEmail(email, subject, "", {htmlBody: office_message, attachments: pdf,
noReply:true});
DocsList.getFileById(copyId).setTrashed(true);
}
Example of the problem: If client leaves date field blank on the form, the gender value in the resulting pdf is put where the date value should be and the value for gender on the pdf shows "undefined".
Any ideas out there?
You should validate the values of all your variables.
if (last === undefined) {
last = 'No Data!'; //re-assign a different value
};
So, you are changing the value of the variable last if it somehow got set to undefined. That way, hopefully the pdf would still show the field.
If there is some bug that just showed up recently, you should report it as a bug. If everything was working fine, and now it's broken, Google may have changed something.
There might be something wrong with your code. I don't know. Have you looked under the "View" menu and the "Execution Transcript" to see if there are any errors? You should also use Logger.log statements: Logger.log('The value of last is: ' + last); to print output to the log. Then you can check what is actually going on.
I am no great coder but I use this script all the time to send pdf's I have never received an undefined if a field was missing. Typically if something is missing, the keygender is replaced with a blank spot and there is no error. In a spreadsheet, typically this means the columns were changed. It used to be timestamp(0), last(1), first(2), order(3), date(4), gender(5) and now their in a different order.
Try the below code it works
//commons errors -
//Triggers are not set
//spaces after Form questions
//e.values dont work when fields are not mandatory and left blank
//e.namedValues dont work for sending emails use e.values[#]
//place holder keys in template dont match
//spelling errors
//Note expect undefined error when de-bugging as values are not defined until form completed and submitted - run first with a small test form as per below
// Get Template
//from Google Docs and name it
var docTemplate = " "; // *** replace with new templae ID if new Template created***
var docName = "Test Script"; //replace with document name
// When Form Gets submitted
function onFormSubmit(e) {
//Get information from the form and set as variables
//var variablename = "static entry or form value"
//Note: var Variablename = e.namedValues["X"]; is taking the value from the spreadsheet by column name so update if spreadsheet or form questions change
//Additions to the form will be added to the end of the spreadsheet regardless of their position in the form
var Timestamp = e.namedValues["Timestamp"];
var full_name = e.namedValues["Name"];
var position = e.namedValues["Position"]
var contact_email = e.namedValues["Contact Email"];
var phone_number = e.namedValues["Telephone Number"];
// Get document template, copy it as a new doc with Name and email, and save the id
var copyId = DocsList.getFileById(docTemplate)
.makeCopy(full_name+' '+docName+' for ' +contact_email+' '+Timestamp)//Update or remove Variablename to create full doc Name
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the documents body section
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys <<namedValues>> in template
//copyBody.replaceText('<<X>>', Variablename); Variables from above
//***Update if template is changed***
copyBody.replaceText('<<Timestamp>>', Timestamp);
copyBody.replaceText('<<Name>>', full_name);
copyBody.replaceText('<<Position>>', position);
copyBody.replaceText('<<Contact Email>>', contact_email);
copyBody.replaceText('<<Telephone Number>>', phone_number);
// Save and close the temporary document
copyDoc.saveAndClose();
// Convert temporary document to PDF by using the getAs blob conversion
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
{
// Add the data fields to the message
var s = SpreadsheetApp.getActiveSheet();
var columns = s.getRange(1,1,1,s.getLastColumn()).getValues()[0];
var message = " ";
// Only include form fields that are not blank
for ( var keys in columns ) {
var key = columns[keys];
if ( e.namedValues[key] && (e.namedValues[key] != "") ) {
message += key+ ' : '+ e.namedValues[key] + "<br>";
}
}}
// Attach PDF and send the email
//***Change the "To" email address when to form goes live***
var to = "youremail#gmail.com";
var senders_name = e.values[1]
var contact_email = e.values[3]
var subject = "Test";
var htmlbody = "text goes here"+
"<br> <br>"+message+
"<br> <br>Submitted By:"+
"<br> <br>"+full_name+
"<br>"+position+
"<br>"+contact_email+
"<br>"+phone_number+
"<br> <br>Generated by Hansmoleman for Compu-Global-Hyper-Mega-Net";
MailApp.sendEmail({
name: senders_name,
to: to,
cc: contact_email,
replyTo: contact_email,
subject: subject,
htmlBody: htmlbody,
attachments: pdf,
});
}

How to move generated PDF to a specific folder in Google Drive

Here is the jist of what I want this script to do.
User submits a form using Google Forms
Form Records to Google Sheet
Sheet replaces text and generate Google Document from Template
Template is copied
PDF is created from this template
PDF is emailed
PDF is moved to a specific folder in Google Drive.
I have all of those things to work except the last step. Can someone help us out here? We are using this for a school, and nobody in our (IT) department knows anything about scripts. Through Googling and searching I have come this far. The last step is to get the PDF to move to a specific folder.
Here is the current code:
// MacArthur High School
// Generic PLC Agenda Script
// Created 18 Jul 2014
// Author: Josh Patrick
// Decatur Public Schools #61
// Document Creation - replace docTemplate links with each template link on the PLC Drive.
var docTemplate = "1DSFCE6mFZib0ZTVOgVqPbLYaRwjS-XNsnsZn5RZewsE";
var docName = "PLC Agenda";
// Form Functions (labeled identifiers for Form)
function onFormSubmit(e) {
var TimeStamp = e.values [0]
var MeetingDate = e.values [1];
var MeetingTime = e.values [2];
var MeetingLocation = e.values [3];
var PLCFocus = e.values [4];
var PlannedActions = e.values [5];
var ResourcesNeeded = e.values [6];
var AssignedEmail = "jwpatrick#dps61.org";
// Get document template, copy it as a new temp doc, and save the Doc’s id
var copyId = DocsList.getFileById(docTemplate)
.makeCopy(docName+' for '+ MeetingDate)
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the document’s body section
var copyBody = copyDoc.getActiveSection();
// Replacing Text with Form Information
copyBody.replaceText('keyMeetingDate', MeetingDate);
copyBody.replaceText('keyMeetingTime', MeetingTime);
copyBody.replaceText('keyMeetingLocation', MeetingLocation);
copyBody.replaceText('keyPLCFocus' , PLCFocus);
copyBody.replaceText('keyPlannedActions' , PlannedActions);
copyBody.replaceText('keyResourcesNeeded' ResourcesNeeded);
// Copy Document and Save
copyDoc.saveAndClose();
// Generate PDF
var pdf = DocsList.getFileById(copyId).getAs("application/pdf");
// Email
var subject = "ELA PLC Agenda for " + MeetingDate ;
var body = "Attached is the PDF copy of the ELA PLC Agenda for " + MeetingDate;
MailApp.sendEmail(AssignedEmail, subject, body, {htmlBody: body, attachments: pdf});
// Delete Temporary Document
DocsList.getFileById(copyId).setTrashed(true);
}
**** Instead of deleting the temporary document, I want to move it to a specific file in Google Drive. I have looked up the scripts help, but I don't think I have done it correctly. I can get it to copydoc but I cannot get it to move to the right folder.
Any assistance is much appreciated.
addToFolder may fit your need.
developers.google.com/apps-script/reference/docs-list/file#addToFolder(Folder)