0

have posted about this before, and have received some very good awnsers recently though I still have not completely solved the issue. I now have some somewhat workable code, that I though someone on this site may be able to fix, or show me how to fix lol.

Okay basically a rundown as to what I am aiming to accomplish, because I have been told many times that what i am doing is useless or that I have not provided enough information, I will try my best here. I have a program that creates invoices on PDF files and prints them out. The python script is fed from a CSV file of all necessary customer/service info etc.

Now, The issue in my code so far, is the number of services I have, and the fact that in Python Reportlabs, You must choose the location of where to draw the string on the page. A command example for this would be:

cursor.drawstring(xLocation,yLocation,String)

The common practice would be draw string 1 through string six, one by one underneath the one above it. In the next three examples you see, the first is how the function would output if all services are being charged. The second(Middle) is the output if some services are not being charged to the customer. the final(RightMost) example is the code How I would like it outputted.

Service 1         Service 1        Service 1
Service 2                          Service 3
Service 3         Service 3        Service 4
Service 4         Service 4        Service 6
Service 5                          
Service 6         Service 6

Unfortunaly, based on boolean logic, and the fact that there are 6 possible services, and each can be charged or not charged, empty or full if you prefer, Then there are 64 possible ways of writing this same function to achieve perfect output.

If we make a boolean for each service, 0 being empty and 1 being full, then we would have to test every possibilty from 000000-111111. That is 64. Which is completely reasonable to code out.

However, I need much more than six services, and the number of functions needed grows exponentially. Instead of writing each function, I have been working on a program that will take a file of 0 and 1 sets, ie:

0000000000
0000000001
0000000010
etc..

and test each bit in each line. this function will then write out a function for each line in the file, based on the bits in the line. Right now, it produces incorrect output. I will show you my script first:

def testFIle():
# This Function will be used to enumerate through the same file you 
used to create the switch dictionary,
# but will define a function for each line.

# filepath = '/home/smiley/Desktop/sampletenbools'
filepath = '/home/smiley/Desktop/10boolsALL'
with open(filepath) as fp:
    num = 1
    for cnt, line in enumerate(fp):
        var = line
        b1 = str(var)[0]
        b2 = str(var)[1]
        b3 = str(var)[2]
        b4 = str(var)[3]
        b5 = str(var)[4]
        b6 = str(var)[5]
        b7 = str(var)[6]
        b8 = str(var)[7]
        b9 = str(var)[8]
        b10 = str(var)[9]

        # YdrawLocationSVC1=490
        # YdrawLocationSVC2=475
        # YdrawLocationSVC3=460
        # YdrawLocationSVC4=445
        # YdrawLocationSVC5=430
        # YdrawLocationSVC6=415
        # YdrawLocationSVC7=400
        # YdrawLocationSVC8=375
        # YdrawLocationSVC9=360
        # YdrawLocationSVC10=345

        if b1 == "0":
            YdrawLocationSVC1=1111
            YdrawLocationSVC2=1
        if b1 == "1":
            YdrawLocationSVC1 = 1

        if b2 == "0":
            YdrawLocationSVC2=1111
            YdrawLocationSVC3=2
        if b2 == "1":
            YdrawLocationSVC2 = 2

        if b3 == "0":
            YdrawLocationSVC3=1111
            YdrawLocationSVC4=3
        if b3 == "1":
            YdrawLocationSVC3 = 3

        if b4 == "0":
            YdrawLocationSVC4=1111
            YdrawLocationSVC5=4
        if b4 == "1":
            YdrawLocationSVC4 = 4

        if b5 == "0":
            YdrawLocationSVC5=1111
            YdrawLocationSVC6=5
        if b5 == "1":
            YdrawLocationSVC5 = 5

        if b6 == "0":
            YdrawLocationSVC6=1111
            YdrawLocationSVC7=6
        if b6 == "1":
            YdrawLocationSVC6 = 6

        if b7 == "0":
            YdrawLocationSVC7=1111
            YdrawLocationSVC8=7
        if b7 == "1":
            YdrawLocationSVC7 = 7

        if b8 == "0":
            YdrawLocationSVC8=1111
            YdrawLocationSVC9=8
        if b8 == "1":
            YdrawLocationSVC8 = 9

        if b9 == "0":
            YdrawLocationSVC9=1111
            YdrawLocationSVC10=9
        if b9 == "1":
            YdrawLocationSVC9 = 9

        if b10 == "0":
            YdrawLocationSVC10=1111
        if b10 == "1":
            YdrawLocationSVC10 = 10


        print "# Bitrep ="+str(var).strip("\n")
        print "def Print"+str(num)+"():"
        print"\tc.setFont('Deja', 12, leading=None)"
        print "\t# SERVICE NAME"+\
        "\n\tc.drawString(100, "+str(YdrawLocationSVC1)+", stringn1)"+\
        "\n\tc.drawString(100, "+str(YdrawLocationSVC2)+", stringn2)"+\
        "\n\tc.drawString(100, "+str(YdrawLocationSVC3)+", stringn3)"+\
        "\n\tc.drawString(100, "+str(YdrawLocationSVC4)+", stringn4)"+\
        "\n\tc.drawString(100, "+str(YdrawLocationSVC5)+", stringn5)"+\
        "\n\tc.drawString(100, "+str(YdrawLocationSVC6)+", stringn6)"+\
        "\n\tc.drawString(100, "+str(YdrawLocationSVC7)+", stringn7)"+\
        "\n\tc.drawString(100, "+str(YdrawLocationSVC8)+", stringn8)"+\
        "\n\tc.drawString(100, "+str(YdrawLocationSVC9)+", stringn9)"+\
        "\n\tc.drawString(100, "+str(YdrawLocationSVC10)+", stringn10)"




        # print("{} : {}".format(str(line).strip("\n"), "Print" + str(num)))
        num += 1
        # print "\n"


testFIle()

Currntly this code produces proper Output like this here so long as only one service is missing:

# Bitrep =1111111101
def Print1022():
c.setFont('Deja', 12, leading=None)
# SERVICE NAME
c.drawString(100, 1, stringn1)
c.drawString(100, 2, stringn2)
c.drawString(100, 3, stringn3)
c.drawString(100, 4, stringn4)
c.drawString(100, 5, stringn5)
c.drawString(100, 6, stringn6)
c.drawString(100, 7, stringn7)
c.drawString(100, 9, stringn8)
c.drawString(100, 1111, stringn9)
c.drawString(100, 10, stringn10)
# Bitrep =1111111110
def Print1023():
c.setFont('Deja', 12, leading=None)
# SERVICE NAME
c.drawString(100, 1, stringn1)
c.drawString(100, 2, stringn2)
c.drawString(100, 3, stringn3)
c.drawString(100, 4, stringn4)
c.drawString(100, 5, stringn5)
c.drawString(100, 6, stringn6)
c.drawString(100, 7, stringn7)
c.drawString(100, 9, stringn8)
c.drawString(100, 9, stringn9)
c.drawString(100, 1111, stringn10)
# Bitrep =1111111111
def Print1024():
c.setFont('Deja', 12, leading=None)
# SERVICE NAME
c.drawString(100, 1, stringn1)
c.drawString(100, 2, stringn2)
c.drawString(100, 3, stringn3)
c.drawString(100, 4, stringn4)
c.drawString(100, 5, stringn5)
c.drawString(100, 6, stringn6)
c.drawString(100, 7, stringn7)
c.drawString(100, 9, stringn8)
c.drawString(100, 9, stringn9)
c.drawString(100, 10, stringn10)

However the logic in my code breaks with more than one missing service, like this here:

# Bitrep =1111100101
def Print998():
c.setFont('Deja', 12, leading=None)
# SERVICE NAME
c.drawString(100, 1, stringn1)
c.drawString(100, 2, stringn2)
c.drawString(100, 3, stringn3)
c.drawString(100, 4, stringn4)
c.drawString(100, 5, stringn5)
c.drawString(100, 1111, stringn6)
c.drawString(100, 1111, stringn7)
c.drawString(100, 9, stringn8)
c.drawString(100, 1111, stringn9)
c.drawString(100, 10, stringn10)
# Bitrep =1111100110
def Print999():
c.setFont('Deja', 12, leading=None)
# SERVICE NAME
c.drawString(100, 1, stringn1)
c.drawString(100, 2, stringn2)
c.drawString(100, 3, stringn3)
c.drawString(100, 4, stringn4)
c.drawString(100, 5, stringn5)
c.drawString(100, 1111, stringn6)
c.drawString(100, 1111, stringn7)
c.drawString(100, 9, stringn8)
c.drawString(100, 9, stringn9)
c.drawString(100, 1111, stringn10)

If anyone can Fix this so that the output comes out looking like this next bit for all lines in the file, I will upvote the **** out of you lol:

def Print999():
c.setFont('Deja', 12, leading=None)
# SERVICE NAME
c.drawString(100, 1, stringn1)
c.drawString(100, 2, stringn2)
c.drawString(100, 3, stringn3)
c.drawString(100, 4, stringn4)
c.drawString(100, 5, stringn5)
c.drawString(100, 1111, stringn6)
c.drawString(100, 1111, stringn7)
c.drawString(100, 6, stringn8)
c.drawString(100, 7, stringn9)
c.drawString(100, 1111, stringn10)

def Print764():
c.setFont('Deja', 12, leading=None)
# SERVICE NAME
c.drawString(100, 1, stringn1)
c.drawString(100, 2, stringn2)
c.drawString(100, 1111, stringn3)
c.drawString(100, 3, stringn4)
c.drawString(100, 4, stringn5)
c.drawString(100, 1111, stringn6)
c.drawString(100, 1111, stringn7)
c.drawString(100, 5, stringn8)
c.drawString(100, 6, stringn9)
c.drawString(100, 1111, stringn10)

As always, if you made it to the end of my post I am more than impressed lol. Thank you to anyone who puts even the slightest effort into this, and to all the people who have helped me get this far already.

Jake
  • 1
  • Just had a thought, perhaps there is a way i can assign a name and a value like in a dictionary to each boolean. Say 0:s1,0:s2,1:s3,0:s4,0:s5,0:s6,1:s7,0:s8,1:s9,0:s10, where 0 or 1 is the boolean state, the ':' is the seperator, and s1-s10 are service names associated with corresponding bit. – Jake Nov 29 '17 at 07:07
  • If we did something like this above ^, Then we could remove all empty services, and know which strings are empty, and how to refer to them. Does anyone think they could make something like that work? – Jake Nov 29 '17 at 07:08

1 Answers1

0

Not wanting to deflate your efforts, but people have been telling you you're doing it wrong for a reason :)

Reportlab lets you use programming tools to create dynamic PDF documents, meaning that the layout changes when the content changes. Attempting to hard-code the position of every line when you're expecting a variety of different content will become unwieldy/impossible very quickly and break easily.

Make it easy on yourself and use a loop instead. As a simplest case, here is some code for a basic page list...

from reportlab.lib.units import cm 

# get the data selection first
my_services_list = [1,3,6]  # or my_dict, e.g. services {'1': 'message1', etc}

# set the cursor starting position
pos_X, pos_Y = 5, 15

for service in my_services_list:
    c.drawString(pos_X*cm, pos_Y*cm, service)
    # move the cursor down a line - remember that zero is the page bottom
    pos_Y -= 1

And that's it, no blank lines. .drawString will work fine for simpler pages. If you need a more comprehensive approach, read the documentation on Frames and Flowables. You can flow your text into text boxes if you need to, just as you would with desktop publishing software.

birophilo
  • 912
  • 10
  • 20