BookmarkSubscribeRSS Feed
RussellAlmeida
Calcite | Level 5
Hi All,

ODS Method: ODS PDF
Version : SAS 9.1.3
OS : AIX

I am trying to print a report which looks like a letter, i have the address of the customer, the subject and the material, based on the code i have to print the letter where the address and the subject reference is dynamic.

I would like to add a line break after the address. How can i do it.

I am attaching the code i am using.

====================

options nobyline nonumber linesize=100 pagesize=60 nocenter nodate;

ODS PATH work.templat(update) sasuser.templat(read)
sashelp.tmplmst(read);

proc template;
define style border;
parent=Styles.Printer;
replace table from table /
borderwidth=0.0
;
replace header from header /
background=grayff;
end;
run;

/* Calculate the sysdate value in the format requireda and store */
/* it in the macro variable to be used in the TITLE statement */
data _null_;
call symput('_sysdate',put(input("&sysdate.",date7.),ddmmyyp10.));
run;

ODS _ALL_ CLOSE;
*FILENAME EGPDF 'test.pdf';
*ODS PDF(ID=EGPDF)
FILE=EGPDF
NOTOC
STYLE=border ;
ods pdf file="RD033.pdf" notoc style = border;

;
ods escapechar ='~';

title1
justify = c font=Helvetica height=9pt bold '#ByVal1' ;

title2
justify = l font=arial height=8pt '#ByVal2 '
justify = r font=arial height=8pt "Utskriftsdato: &_sysdate. kl &systime. side ~{thispage} av ~{lastpage} ";
title3;
title4
justify = l font=arial height=8pt '#ByVal3' justify = c font = arial height = 8pt "Postnummer fra: &from_cd.";
title5
justify = c font=arial height=8pt "Postnummer til:&to_cd." ;

title6 '_____________________________________________________________________________________';



footnote1 ;
footnote2;
footnote3;
footnote4;
footnote5;
footnote6;
footnote7;


proc report data = VL0608_104R_ADDRESS_DISTR_LST1 nowd spacing = 50 wrap ls=100
style(summary)={htmlstyle="border-top:solid;border-bottom:solid"} split='*';
* BY Report_name Report_ID Org_unit_Nm Org_unit_id;
BY Report_Name Report_Id Title_Line2;* Postal_Code_Cd Sort_Variable Address_List;

columns
Report_Name
Report_Id
Postal_Code_Cd
Sort_Variable

Address_list
Organization_id
Organization_Nm
Rack_Id
Sort_Variable
_Postal_Code_Cd;


define Report_ID/group noprint;
define Report_name/group noprint;
define Sort_Variable/order noprint;
define Postal_Code_Cd/noprint;
define Location_set_type_cd/group noprint;


define Address_list/left flow "GATE/VEI/STED" spacing=20
style(column)=[cellwidth=380pt font=(Arial, 6pt) just = left] flow
style(header)= [font_weight=bold font=(Arial, 6pt) just = left] flow;

define Organization_Nm/left flow " "
style(column)=[cellwidth=10pt font=(Arial, 6pt) just = left] flow
style(header)= [cellwidth=10pt font_weight=bold font=(Arial, 6pt) just = left] flow;

define Organization_id/left flow 'ENHET' spacing = 10
style(column)=[cellwidth=50pt font=(Arial, 6pt) just = left] flow
style(header)= [font_weight=bold font=(Arial, 6pt) just = left] flow;

define Rack_Id/left 'REOLNR' spacing = 10
style(column)=[cellwidth=50pt font=(Arial, 6pt) just = left] flow
style(header)= [font_weight=bold font=(Arial, 6pt) just = left] flow;

define _Postal_code_cd/left 'POSTNR' spacing = 10
style(column)=[cellwidth=50pt font=(Arial, 6pt) just = left] flow
style(header)= [font_weight=bold font=(Arial, 6pt) just = left] flow;
break after Sort_Variable/skip ol suppress;

compute after Sort_Variable;
line ' ';
endcomp;
run;


ODS _all_ close;
====================
13 REPLIES 13
Cynthia_sas
SAS Super FREQ
Hi:
One technique that I have used very successfully is to design a form letter using Microsoft Word and creating the letter with the appropriate field codes for a mail merge. Word will accept a CSV file as the "data" for a mail merge. So I use SAS to make the CSV file with the name and address information.

Then, after the CSV file is created, I use Word to point to the CSV file and start the mail merge. This method has worked very well for me, because all of the formatting of the letter content is done with Word.

To answer your question, you can only insert a LINE break in PROC REPORT with a LINE statement for GROUP or ORDER items. I do not believe this will work in your case. The other approach you can use is to insert an ODS ESCAPECHAR "new line" control string at the end of the address. In SAS 9.1.3, you use the ODS ESCAPECHAR statement to declare an ESCAPECHAR for use. Then the ESCAPECHAR+n represents a line feed or carriage return character when the output is sent to ODS PDF, RTF or HTML. For more information about ODS ESCAPECHAR in SAS 9.1.3, refer to this paper:
http://www2.sas.com/proceedings/forum2007/099-2007.pdf

Another example of a form letter approach (that doesn't use Word or CSV) is shown below, using PROC REPORT and ODS PDF. In this approach, the entire text of the letter, including names and addresses is put into a LINETXT variable. Then the letter text varies, depending on each student's age. PROC REPORT has the ability to start a page for every NAME, so this technique will ensure that every student's letter starts a new page. This approach works well for paragraphs of text inside the letter.

cynthia
[pre]
data letter(keep=name lineno linetxt);
length linetxt $1000;
set sashelp.class;
where age ge 14;
lineno = 1;
linetxt = name;
output;

** this address will be the same for every person;
** because SASHELP.CLASS does not have addresses;
** but with your data, you could use the real address;
lineno=2;
linetxt= '1234 Sesame Street';
output;

lineno=3;
linetxt = 'Anytown, ST 12345~3n';
output;

lineno=4;
linetxt = catx(' ','Dear',name,'~2n');
output;

lineno=5;
hold='We notice that you are now';
linetxt=catx(' ',hold,put(age,2.0),'years old.');
if age lt 15 then do;
linetxt=catx(' ',linetxt,"You have a few years before you can apply for your learner's permit.",
"But, if you and your parents come in for our free Teen Driving seminar,",
"we will guarantee you a 20% discount on our driving lessons.~2n");
output;
end;
else if age ge 15 then do;
linetxt=catx(' ',linetxt,"Our records show that you have applied for a learner's permit.",
"If you and your parents come in for our free Teen Driving seminar,",
"we will guarantee you a 20% discount on our driving lessons.~2n");
output;
end;

lineno=6;
linetxt='To take advantage of this special offer, have your parents call 1-800-888-8888.~2n';
output;

lineno=7;
linetxt='Sincerely,~4n';
output;

lineno=8;
linetxt='Ima Salesman~nDriveMaster, Inc.';
output;
run;

ods listing close;
title; footnote;

ods pdf file='formletter_drive.pdf';
ods escapechar='~';

proc report data=letter nowd noheader
style(report)={rules=none frame=void cellspacing=0 cellpadding=3 outputwidth=80%} ;
title h=14pt 'DriveMaster, Inc.';
title2 ' ';
title3 ' ';
footnote 'The Easy Way to Teach Your Teen To Drive Safely';
column name lineno linetxt;
define name / order noprint;
define lineno / order noprint;
define linetxt/
style(column)={font_face='Helvetica'};
compute linetxt;
if lineno in (1,2,3) then do;
call define(_col_,'style','style={font_weight=bold font_size=12pt}');
end;
else do;
call define(_col_,'style','style={font_weight=medium font_size=10pt}');
end;
endcomp;
break after name / page;
run;
ods pdf close;
[/pre]
RussellAlmeida
Calcite | Level 5
Hi Cynthia,

Thankyou very much for the suggestion, now i am able to get the reports printed the way they should be.

What is the escape sequence to add leading spaces.

ODS PDF
SAS 9.1.3
AIX

Regards
Russell Message was edited by: Russell Almeida
Cynthia_sas
SAS Super FREQ
Hi:
Please look on page 3 of this paper:
http://www2.sas.com/proceedings/forum2007/099-2007.pdf

Where it explains that the escapechar + underscore is a non-breaking space. I don't know whether this is the same as what you mean by a "leading" space. I have used the non-breaking space to simulate an indent or to add a few spaces before a text string.

Remember that your ESCAPECHAR character, as defined by the
[pre]
ods escapechar='~';
[/pre]

ODS ESCAPECHAR statement usually stays the same. What differs are the functions or other characters that you use that have an impact on your reports. So if the ESCAPECHAR is ~ then the non-breaking space is ~_ (tilde+underscore) and two non-breaking spaces would be ~_~_ (tilde+underscore tilde+underscore).

cynthia
RussellAlmeida
Calcite | Level 5
Hi Cynthia,

Yes i tried this method but surprisingly it did not work with me, don't know why, will test it out again.

Also is there an option where i can indent by giving a tab or set the margin of all the contents in the letter.

Regards
Russell
Cynthia_sas
SAS Super FREQ
Hi:
Sometimes, if you are indenting through the use of non-breaking spaces, you might need to use the ASIS=ON style attribute to have leading and/or trailing blanks respected.

If you were creating RTF output, then you could use RTF control strings, such as \tab to use TAB stops, as set in the Word document. The use of \TAB is shown on page 9 of the paper previously referenced. With the RAW text insertion method. \TAB will -ONLY- work with RTF. Since the PDF file is a representation of what would normally get sent to the printer, there is nothing like a tab stop that you can set or send using ODS PDF.

The way that you set the margins for your document with ODS PDF in SAS 9.1.3 and for ODS RTF and ODS PDF in SAS 9.2 is through the use of SAS system options in an OPTIONS statement before your ODS PDF invocation:

[pre]
options topmargin="1in" rightmargin="1.25in" leftmargin="1.25in";

ODS PDF ... ;
[/pre]

In SAS 9.2, the LEFTMARGIN and INDENT style attributes are now production, so you might be able to use them to set the margin for individual cells. However, if you are still using SAS 9.1.3, this may not work for you. For specific help with ODS PDF and which style attributes to use, you might open a track with Tech Support so they can look at your data and your code and help you come up with the best approach for what you want to achieve.

cynthia
deleted_user
Not applicable
Hi

The challenge now has been change and I am asked to create following

/*Required Output
*********LEFT***************' **************RIGHT************
Customer Name(font size 11) Telephone No:12345678(font size 6)
Custoer Street(font size 11) Fax Numner; 12345678(font size 6)
City(font size 11) www.posten.no(font size 6)
*/

I have tried few things without success can you please help
Best Regards,

Rachid
sbb
Lapis Lazuli | Level 10 sbb
Lapis Lazuli | Level 10
Why did you piggy-back on another individual's post? Take ownership of your own authored material on the discussion forum, please.

Suggest you create a post with your query and paste in a link to any other relevant post threads needed.

Scott Barry
SBBWorks, Inc.
deleted_user
Not applicable
Hi,

This Is mine, 🙂

I was new to the forum and used Russell's id or Russell was writting them for me. I could have cut and passed and create a new one....but ..

Regards, Rachid
Cynthia_sas
SAS Super FREQ
Hi:
OK...so here's usual bunch of questions:
1) what is your destination of choice (is it still PDF or do you want LISTING)
2) what do you mean by "LEFT" and "RIGHT"??? That you want 2 columns, that you want the Name, Street and City to be Left-justified and the telephone, fax and web site to be right-justified???
3) the original post was about a letter??? Is that still a requirement?? Did you try any code?? What is the code you have tried??? Are you getting error messages??
4) Will you have multiple customer information per page??? (such as you might generate for labels?? or will you have 1 page for every customer???)
5) What is your procedure of choice?? Are you still using PROC REPORT??

cynthia
deleted_user
Not applicable
Hi,

Thanks for the reply:

1 -yes PFD
2 - On the right the line for address on the left the line from the header .
3 - yes still the letter. I tried some linext with bracket with ' or " without success.
4- one page(letter) per customer.
5 - yes proc Sort

regards, Rachid Message was edited by: RAMR
Cynthia_sas
SAS Super FREQ
Hi:
#1...there is no PFD destination -- assume you mean PDF???

#2...I do not understand what you mean by this??? You have 1 LINE per report ROW. There is no "right" or "left" on the report line. The report row (in the above code example) is what you find on the COLUMN statement:
[pre]
column name lineno linetxt;
[/pre]

NAME is a NOPRINT item and it is used for ordering and performing page breaking on the report. LINENO is also a NOPRINT item and it is also used for ordering each LINE of the REPORT. If you look at the program that creates the data for the PROC REPORT step, you will see that LINE 1 has the person's NAME, LINE 2 has the person's STREET ADDRESS and LINE 3 has the person's city and state.

In #2, you also says that you want the right line for the address and the left line from the header. The whole point of my example was that you could use PROC REPORT with the NOHEADER option in order to suppress the usual headers -- in order to get the LOOK of a letter -- with and address area, a salutation area (Dear ...) and then the body of the letter. I do not what "header" you want to show on the left.

#3 -- When you say you tried some "linext", I assume you mean that you tried to create a new LINETXT variable??? But I do not understand what you mean when you say you tried to create it with "or".

#5 Are you still using PROC REPORT?? I doubt that you would be able to create this report using only PROC SORT. It would be useful to either see the code that you tried or for you to show an example of what the top of the letter would look like with some fake data.

The program below is a modification to the first code example. It still has the headers in PROC REPORT turned off, but it uses a BY statement to make sure that the COMPUTE BEFORE happens for each NAME. In the COMPUTE BEFORE block a LINE statement is used to place text above the NAME and ADDRESS areas. Do note that the LINE statement results in one entire line to be displayed above the letter for each name -- there is only the line of text -- without a RIGHT or LEFT.

cynthia

[pre]
data letter(keep=name lineno linetxt);
length linetxt $1000;
set sashelp.class;
where age ge 14;
lineno = 1;
linetxt = catx(' ','Name:',name);
output;

** this address will be the same for every person;
** because SASHELP.CLASS does not have addresses;
** but with your data, you could use the real address;
lineno=2;
linetxt= 'Street: 1234 Sesame Street';
output;

lineno=3;
linetxt = 'City: Anytown, ST 12345~3n';
output;

lineno=4;
linetxt = catx(' ','Dear',name,'~2n');
output;

lineno=5;
hold='We notice that you are now';
linetxt=catx(' ',hold,put(age,2.0),'years old.');
if age lt 15 then do;
linetxt=catx(' ',linetxt,"You have a few years before you can apply for your learner's permit.",
"But, if you and your parents come in for our free Teen Driving seminar,",
"we will guarantee you a 20% discount on our driving lessons.~2n");
output;
end;
else if age ge 15 then do;
linetxt=catx(' ',linetxt,"Our records show that you have applied for a learner's permit.",
"If you and your parents come in for our free Teen Driving seminar,",
"we will guarantee you a 20% discount on our driving lessons.~2n");
output;
end;

lineno=6;
linetxt='To take advantage of this special offer, have your parents call 1-800-888-8888.~2n';
output;

lineno=7;
linetxt='Sincerely,~4n';
output;

lineno=8;
linetxt='Ima Salesman~nDriveMaster, Inc.';
output;
run;

proc sort data=letter;
by name;
run;
ods listing close;
title; footnote;

options nodate nonumber nobyline;
ods pdf file='formletter_alternate.pdf';
ods escapechar='~';

proc report data=letter(obs=4) nowd noheader
style(report)={rules=none frame=void cellspacing=0
cellpadding=3 outputwidth=80%} ;
title h=14pt 'DriveMaster, Inc.';
title2 ' ';
title3 ' ';
footnote 'The Easy Way to Teach Your Teen To Drive Safely';
by name;
column name lineno linetxt;
define name / order noprint;
define lineno / order noprint;
define linetxt/
style(column)={font_face='Helvetica'};
compute linetxt;
if lineno in (1,2,3) then do;
call define(_col_,'style','style={font_weight=bold font_size=12pt}');
end;
else do;
call define(_col_,'style','style={font_weight=medium font_size=10pt}');
end;
endcomp;
break after name / page;
compute before /
style={just=left font_weight=bold font_size=12pt};
line 'This is a left justified line that spans the letter.';
line 'This line ~_~_~_~_~_~_~_~_~_~_ has ~_~_~_~_~_~_~_~_~_~_ some ~_~_~_~_~_~_~_~_~_~_ padding with non-breaking spaces.';
line ' ';
line ' ';
endcomp;
run;
ods pdf close;
[/pre]
deleted_user
Not applicable
Hi,

Ues I meant PDF ( mistyped).

On the right corner of the letter I have inserted a logo image + (below) a text ( Company name - address- phone - fax - etc....
As you know the recipient name+ full addresses appears as usual on the left. Originally the logo would prints first on the right and then ( one line down) comes the address ( left) .
Now we found out that the customer has envellops with windows and name+adresses has to come up on the document ( about 3 lines) or else the name+address would not appear on the envellop window. therefore:

Line 1 : The customer name ( left) should appears on the same line as the Company name (Right).
Line 2 : street name+number (left) should apear on the same line as for example phone number.
Line 3: etc....

Thks,
RAMR
Cynthia_sas
SAS Super FREQ
Hi:
This kind of "form letter" type spacing will be very hard to achieve using only PROC REPORT in SAS 9.1.3. My PROC REPORT approach was only meant to simulate a "classic" letter. I would envision that the name and address of the company would appear on the letterhead area using SAS TITLE statements -- but this does not ensure that the address will fit in the window envelope area.

The type of specific spacing and layout (to fit in a window envelope) that you describe, will, eventually, be possible using the ODS LAYOUT capability within a DATA _NULL_ program, however, that capability was experimental in SAS 9.1.3 and is still experimental in SAS 9.2.

If you can format a merge document in Microsoft Word that looks as you want, through defining fixed content and merge fields, you are probably better off creating your main document in Microsoft Word and then using SAS to create a CSV file (or HTML file) of "data" which can then be merged with the main document. This method is outlined in this paper:
http://rtsug.org/pdf/ZillionLabels.pdf

Although the primary example is a label example, the same field definition process also applies to letters as the merge document.

cynthia

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 13 replies
  • 11302 views
  • 0 likes
  • 4 in conversation