- Timestamp:
- 20 Sep 2012, 08:49:37 (12 years ago)
- Location:
- main/waeup.kofa/branches/uli-zc-async
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
main/waeup.kofa/branches/uli-zc-async
- Property svn:mergeinfo changed
-
main/waeup.kofa/branches/uli-zc-async/src/waeup/kofa/students/utils.py
r8708 r9209 19 19 """ 20 20 import grok 21 from random import SystemRandom as r22 21 from time import time 23 from datetime import datetime24 from zope.i18n import translate25 from zope.component import getUtility, createObject26 from reportlab.pdfgen import canvas27 22 from reportlab.lib import colors 28 23 from reportlab.lib.units import cm 29 from reportlab.lib.enums import TA_RIGHT30 24 from reportlab.lib.pagesizes import A4 31 from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle 32 from reportlab.platypus import (Frame, Paragraph, Image, PageBreak, Table, 33 Spacer) 34 from reportlab.platypus.tables import TableStyle 35 from reportlab.platypus.flowables import PageBreak 36 from zope.component import getUtility 25 from reportlab.lib.styles import getSampleStyleSheet 26 from reportlab.platypus import Paragraph, Image, Table, Spacer 27 from zope.component import getUtility, createObject 37 28 from zope.formlib.form import setUpEditWidgets 38 29 from zope.i18n import translate 39 30 from waeup.kofa.interfaces import ( 40 31 IExtFileStore, IKofaUtils, RETURNING, PAID, CLEARED) 41 32 from waeup.kofa.interfaces import MessageFactory as _ 42 33 from waeup.kofa.students.interfaces import IStudentsUtils 43 from waeup.kofa.utils.helpers import now44 34 45 35 SLIP_STYLE = [ … … 127 117 #data.append([Spacer(1, 12)]) 128 118 portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE 119 120 f_label = formatted_label(size=12) % _('Name') 121 f_label = Paragraph(f_label, style["Normal"]) 122 f_text = formatted_text(studentview.context.display_fullname, size=12) 123 f_text = Paragraph(f_text, style["Normal"]) 124 data_right.append([f_label,f_text]) 125 129 126 for widget in studentview.widgets: 130 if widget.name == 'form.adm_code':127 if 'name' in widget.name: 131 128 continue 132 129 f_label = formatted_label(size=12) % translate( … … 137 134 f_text = Paragraph(f_text, style["Normal"]) 138 135 data_right.append([f_label,f_text]) 136 137 if hasattr(studentview.context, 'certcode'): 138 f_label = formatted_label(size=12) % _('Study Course') 139 f_label = Paragraph(f_label, style["Normal"]) 140 f_text = formatted_text( 141 studentview.context['studycourse'].certificate.longtitle(), size=12) 142 f_text = Paragraph(f_text, style["Normal"]) 143 data_right.append([f_label,f_text]) 144 145 f_label = formatted_label(size=12) % _('Department') 146 f_label = Paragraph(f_label, style["Normal"]) 147 f_text = formatted_text( 148 studentview.context[ 149 'studycourse'].certificate.__parent__.__parent__.longtitle(), 150 size=12) 151 f_text = Paragraph(f_text, style["Normal"]) 152 data_right.append([f_label,f_text]) 153 154 f_label = formatted_label(size=12) % _('Faculty') 155 f_label = Paragraph(f_label, style["Normal"]) 156 f_text = formatted_text( 157 studentview.context[ 158 'studycourse'].certificate.__parent__.__parent__.__parent__.longtitle(), 159 size=12) 160 f_text = Paragraph(f_text, style["Normal"]) 161 data_right.append([f_label,f_text]) 162 139 163 table_left = Table(data_left,style=SLIP_STYLE) 140 164 table_right = Table(data_right,style=SLIP_STYLE, colWidths=[5*cm, 6*cm]) … … 165 189 return table 166 190 191 def get_signature_table(signatures, lang='en'): 192 """Return a reportlab table containing signature fields (with date). 193 """ 194 style = getSampleStyleSheet() 195 space_width = 0.4 # width in cm of space between signatures 196 table_width = 16.0 # supposed width of signature table in cms 197 # width of signature cells in cm... 198 sig_col_width = table_width - ((len(signatures) - 1) * space_width) 199 sig_col_width = sig_col_width / len(signatures) 200 data = [] 201 col_widths = [] # widths of columns 202 203 sig_style = [ 204 ('VALIGN',(0,-1),(-1,-1),'TOP'), 205 ('FONT', (0,0), (-1,-1), 'Helvetica-BoldOblique', 12), 206 ('BOTTOMPADDING', (0,0), (-1,0), 36), 207 ('TOPPADDING', (0,-1), (-1,-1), 0), 208 ] 209 for num, elem in enumerate(signatures): 210 # draw a line above each signature cell (not: empty cells in between) 211 sig_style.append( 212 ('LINEABOVE', (num*2,-1), (num*2, -1), 1, colors.black)) 213 214 row = [] 215 for signature in signatures: 216 row.append(trans(_('Date:'), lang)) 217 row.append('') 218 if len(signatures) > 1: 219 col_widths.extend([sig_col_width*cm, space_width*cm]) 220 else: 221 col_widths.extend([sig_col_width/2*cm, sig_col_width/2*cm]) 222 row.append('') # empty spaceholder on right 223 data.append(row[:-1]) 224 data.extend(([''],)*3) # insert 3 empty rows... 225 row = [] 226 for signature in signatures: 227 row.append(Paragraph(trans(signature, lang), style["Normal"])) 228 row.append('') 229 data.append(row[:-1]) 230 table = Table(data, style=sig_style, repeatRows=len(data), 231 colWidths=col_widths) 232 return table 233 167 234 def docs_as_flowables(view, lang='en'): 168 235 """Create reportlab flowables out of scanned docs. … … 190 257 if img_path is None: 191 258 pass 192 elif not img_path .endswith('.jpg'):259 elif not img_path[-4:] in ('.jpg', '.JPG'): 193 260 # reportlab requires jpg images, I think. 194 f_text = Paragraph('%s ( Not displayable)' % (261 f_text = Paragraph('%s (not displayable)' % ( 195 262 viewlet.title,), ENTRY1_STYLE) 196 263 else: … … 202 269 return data 203 270 204 def insert_footer(pdf,width,style,text=None, number_of_pages=1):205 """Render the whole footer frame.206 """207 story = []208 frame_footer = Frame(1*cm,0,width-(2*cm),1*cm)209 tz = getUtility(IKofaUtils).tzinfo210 timestamp = now(tz).strftime("%d/%m/%Y %H:%M:%S %Z")211 left_text = '<font size=10>%s</font>' % timestamp212 story.append(Paragraph(left_text, style["Normal"]))213 frame_footer.addFromList(story,pdf)214 story = []215 frame_footer = Frame(1*cm,0,width-(2*cm),1*cm)216 portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE217 right_text = translate(_('<font size=10>${a} Page ${b} of ${c}</font>',218 mapping = {'a':text, 'b':pdf.getPageNumber(), 'c':number_of_pages}),219 'waeup.kofa', target_language=portal_language)220 story.append(Paragraph(right_text, style["Right"]))221 frame_footer.addFromList(story,pdf)222 223 271 class StudentsUtils(grok.GlobalUtility): 224 272 """A collection of methods subject to customization. … … 227 275 228 276 def getReturningData(self, student): 229 """ This method defineswhat happens after school fee payment277 """ Define what happens after school fee payment 230 278 depending on the student's senate verdict. 231 279 … … 238 286 239 287 def setReturningData(self, student): 240 """ This method defines what happens after school fee payment 241 depending on the student's senate verdict. It folllows 242 the same algorithm as getReturningData but it also sets the new 243 values 244 245 In the base configuration current level is always increased 246 by 100 no matter which verdict has been assigned. 288 """ Define what happens after school fee payment 289 depending on the student's senate verdict. 290 291 This method folllows the same algorithm as getReturningData but 292 it also sets the new values. 247 293 """ 248 294 new_session, new_level = self.getReturningData(student) … … 250 296 student['studycourse'].current_session = new_session 251 297 verdict = student['studycourse'].current_verdict 252 student['studycourse'].current_verdict = ' NY'298 student['studycourse'].current_verdict = '0' 253 299 student['studycourse'].previous_verdict = verdict 254 300 return 255 301 256 def setPaymentDetails(self, category, student): 302 def setPaymentDetails(self, category, student, 303 previous_session, previous_level): 257 304 """Create Payment object and set the payment data of a student for 258 305 the payment category specified. 259 306 260 307 """ 261 details = {}262 308 p_item = u'' 263 309 amount = 0.0 264 error = u'' 265 p_session = student['studycourse'].current_session 266 p_level = student['studycourse'].current_level 310 if previous_session: 311 p_session = previous_session 312 p_level = previous_level 313 p_current = False 314 else: 315 p_session = student['studycourse'].current_session 316 p_level = student['studycourse'].current_level 317 p_current = True 267 318 session = str(p_session) 268 319 try: … … 276 327 except (AttributeError, TypeError): 277 328 return _('Study course data are incomplete.'), None 278 if student.state == CLEARED: 279 amount = getattr(certificate, 'school_fee_1', 0.0) 280 elif student.state == RETURNING: 281 # In case of returning school fee payment the payment session 282 # and level contain the values of the session the student 283 # has paid for. 284 p_session, p_level = self.getReturningData(student) 285 amount = getattr(certificate, 'school_fee_2', 0.0) 286 elif student.is_postgrad and student.state == PAID: 287 # Returning postgraduate students also pay for the next session 288 # but their level always remains the same. 289 p_session += 1 290 amount = getattr(certificate, 'school_fee_2', 0.0) 329 if previous_session: 330 if previous_session < student['studycourse'].entry_session: 331 return _('The previous session must not fall below ' 332 'your entry session.'), None 333 if previous_session > student['studycourse'].current_session - 1: 334 return _('This is not a previous session.'), None 335 if previous_level == 100: 336 amount = getattr(certificate, 'school_fee_1', 0.0) 337 else: 338 amount = getattr(certificate, 'school_fee_2', 0.0) 339 else: 340 if student.state == CLEARED: 341 amount = getattr(certificate, 'school_fee_1', 0.0) 342 elif student.state == RETURNING: 343 # In case of returning school fee payment the payment session 344 # and level contain the values of the session the student 345 # has paid for. 346 p_session, p_level = self.getReturningData(student) 347 amount = getattr(certificate, 'school_fee_2', 0.0) 348 elif student.is_postgrad and student.state == PAID: 349 # Returning postgraduate students also pay for the next session 350 # but their level always remains the same. 351 p_session += 1 352 amount = getattr(certificate, 'school_fee_2', 0.0) 291 353 elif category == 'clearance': 292 p_item = student['studycourse'].certificate.code 354 try: 355 p_item = student['studycourse'].certificate.code 356 except (AttributeError, TypeError): 357 return _('Study course data are incomplete.'), None 293 358 amount = academic_session.clearance_fee 294 359 elif category == 'bed_allocation': … … 296 361 amount = academic_session.booking_fee 297 362 if amount in (0.0, None): 298 return _(u'Amount could not be determined.'), None 363 return _('Amount could not be determined.' + 364 ' Would you like to pay for a previous session?'), None 299 365 for key in student['payments'].keys(): 300 366 ticket = student['payments'][key] … … 303 369 ticket.p_item == p_item and \ 304 370 ticket.p_session == p_session: 305 return _('This type of payment has already been made.'), None 371 return _('This type of payment has already been made.' + 372 ' Would you like to pay for a previous session?'), None 306 373 payment = createObject(u'waeup.StudentOnlinePayment') 307 timestamp = "%d" % int(time()*1000)374 timestamp = ("%d" % int(time()*10000))[1:] 308 375 payment.p_id = "p%s" % timestamp 309 376 payment.p_category = category … … 311 378 payment.p_session = p_session 312 379 payment.p_level = p_level 380 payment.p_current = p_current 313 381 payment.amount_auth = amount 314 382 return None, payment … … 330 398 entry_session = studycourse.entry_session 331 399 current_level = studycourse.current_level 332 if not (entry_session and current_level andcertificate):333 return 400 if None in (entry_session, current_level, certificate): 401 return d 334 402 end_level = certificate.end_level 335 if entry_session == grok.getSite()['hostels'].accommodation_session: 403 if current_level == 10: 404 bt = 'pr' 405 elif entry_session == grok.getSite()['hostels'].accommodation_session: 336 406 bt = 'fr' 337 407 elif current_level >= end_level: … … 355 425 return available_beds[0] 356 426 427 def renderPDFAdmissionLetter(self, view, student=None): 428 """Render pdf admission letter. 429 """ 430 # XXX: we have to fix the import problems here. 431 from waeup.kofa.browser.interfaces import IPDFCreator 432 from waeup.kofa.browser.pdf import format_html, NOTE_STYLE 433 if student is None: 434 return 435 style = getSampleStyleSheet() 436 creator = getUtility(IPDFCreator) 437 data = [] 438 doc_title = view.label 439 author = '%s (%s)' % (view.request.principal.title, 440 view.request.principal.id) 441 footer_text = view.label 442 if getattr(student, 'student_id', None) is not None: 443 footer_text = "%s - %s - " % (student.student_id, footer_text) 444 445 # Admission text 446 portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE 447 inst_name = grok.getSite()['configuration'].name 448 text = trans(_( 449 'This is to inform you that you have been provisionally' 450 ' admitted into ${a} as follows:', mapping = {'a': inst_name}), 451 portal_language) 452 html = format_html(text) 453 data.append(Paragraph(html, NOTE_STYLE)) 454 data.append(Spacer(1, 20)) 455 456 # Student data 457 data.append(render_student_data(view)) 458 459 # Insert history 460 data.append(Spacer(1, 20)) 461 datelist = student.history.messages[0].split()[0].split('-') 462 creation_date = u'%s/%s/%s' % (datelist[2], datelist[1], datelist[0]) 463 text = trans(_( 464 'Your Kofa student record was created on ${a}.', 465 mapping = {'a': creation_date}), 466 portal_language) 467 html = format_html(text) 468 data.append(Paragraph(html, NOTE_STYLE)) 469 470 # Create pdf stream 471 view.response.setHeader( 472 'Content-Type', 'application/pdf') 473 pdf_stream = creator.create_pdf( 474 data, None, doc_title, author=author, footer=footer_text, 475 note=None) 476 return pdf_stream 477 357 478 def renderPDF(self, view, filename='slip.pdf', student=None, 358 479 studentview=None, tableheader=None, tabledata=None, 359 note=None ):480 note=None, signatures=None): 360 481 """Render pdf slips for various pages. 361 482 """ … … 373 494 footer_text = "%s - %s - " % (student.student_id, footer_text) 374 495 496 # Insert history 497 if not filename.startswith('payment'): 498 data.extend(creator.fromStringList(student.history.messages)) 499 375 500 # Insert student data table 376 501 portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE … … 381 506 382 507 # Insert widgets 383 data.append(Paragraph(view.title, style["Heading3"])) 384 portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE 385 separators = getattr(self, 'SEPARATORS_DICT', {}) 386 table = creator.getWidgetsTable( 387 view.form_fields, view.context, None, lang=portal_language, 388 separators=separators) 389 data.append(table) 508 if view.form_fields: 509 data.append(Paragraph(view.title, style["Heading3"])) 510 portal_language = getUtility(IKofaUtils).PORTAL_LANGUAGE 511 separators = getattr(self, 'SEPARATORS_DICT', {}) 512 table = creator.getWidgetsTable( 513 view.form_fields, view.context, None, lang=portal_language, 514 separators=separators) 515 data.append(table) 390 516 391 517 # Insert scanned docs … … 399 525 contenttable = render_table_data(tableheader,tabledata) 400 526 data.append(contenttable) 527 528 # Insert signatures 529 if signatures: 530 data.append(Spacer(1, 20)) 531 signaturetable = get_signature_table(signatures) 532 data.append(signaturetable) 401 533 402 534 view.response.setHeader( … … 412 544 413 545 VERDICTS_DICT = { 414 ' NY': _('(not yet)'),546 '0': _('(not yet)'), 415 547 'A': 'Successful student', 416 548 'B': 'Student with carryover courses',
Note: See TracChangeset for help on using the changeset viewer.