def main(server=None, input=None):
    """
    The main function of the custom script. The entire script was copied
    and pasted into the body of the try statement in order to add some
    error handling. It's all legacy code, so edit with caution.

    :param server: the TacticServerStub object
    :param input: a dict with data like like search_key, search_type, sobject, and update_data
    :return: None
    """
    if not input:
        input = {}

    try:
        # CUSTOM_SCRIPT00103
        # Matthew Tyler Misenhimer
        # Sends an email when a External Rejection is updated
        
        def fix_note_chars(note):
            if isinstance(note, bool):
                note2 = 'False'
                if note:
                    note2 = 'True'
                note = note2
            else:
                import sys
                from json import dumps as jsondumps
                if note not in [None,'']:
                    if sys.stdout.encoding:
                        note = note.decode(sys.stdout.encoding)
                note = jsondumps(note)
                note = note.replace('||t','        ')
                note = note.replace('\\\\t','        ')
                note = note.replace('\\\t','        ')
                note = note.replace('\\t','        ')
                note = note.replace('\t','        ')
                note = note.replace('\\"','"')
                note = note.replace('\"','"')
                note = note.replace('||n','<br/>')
                note = note.replace('\\\\n','<br/>')
                note = note.replace('\\\n','<br/>')
                note = note.replace('\\n','<br/>')
                note = note.replace('\n','<br/>')
            return note
        
        import os, time
        from pyasm.common import Environment
        import common_tools.utils as ctu
        internal_template_file = '/opt/spt/custom/formatted_emailer/internal_general_fillin_template.html'
        trigger_sobject = input.get('trigger_sobject')
        event = trigger_sobject.get('event')
        is_insert = False
        if 'insert' in event:
            is_insert = True
        if not is_insert:
            er_dict = input.get('sobject')
            login = er_dict.get('login')
            order_code = er_dict.get('order_code')
            title_code = er_dict.get('title_code')
        
            reported_issue = er_dict.get('reported_issue')
            if reported_issue not in [None,'']:
                reported_issue = reported_issue.replace('\n','<br/>').replace(' ','&nbsp;')
            reported_issue = fix_note_chars(reported_issue)
            
            rcnq = "@SOBJECT(sthpw/note['search_id','%s']['process','Root Cause']['search_type','twog/external_rejection?project=twog'])" % (er_dict.get('id'))
            root_cause_notes = server.eval(rcnq)
            root_cause = ''
            for rc in root_cause_notes:
                root_cause = '%s\n%s -- %s\n<b>Note: %s</b>\n' % (root_cause, rc.get('login'), rc.get('timestamp').split('.')[0], rc.get('note'))
            if root_cause not in [None,'']:
                root_cause = root_cause.replace('\n','<br/>').replace(' ','&nbsp;')
            root_cause = fix_note_chars(root_cause)
        
            corrective_action_notes = server.eval("@SOBJECT(sthpw/note['search_id','%s']['process','Corrective Action']['search_type','twog/external_rejection?project=twog'])" % (er_dict.get('id')))
            corrective_action = ''
            for ca in corrective_action_notes:
                corrective_action = '%s\n%s -- %s\n<b>Note:%s</b>\n' % (corrective_action, ca.get('login'), ca.get('timestamp').split('.')[0], ca.get('note'))
            if corrective_action not in [None,'']:
                corrective_action = corrective_action.replace('\n','<br/>').replace(' ','&nbsp;')
            corrective_action = fix_note_chars(corrective_action)

            title = er_dict.get('title')
            episode = er_dict.get('episode')
            po_number = er_dict.get('po_number')
            assigned = er_dict.get('assigned')
            status = er_dict.get('status')
            root_cause_type = er_dict.get('root_cause_type')
            corrective_action_assigned = er_dict.get('corrective_action_assigned')
            email_list = er_dict.get('email_list')
            addressed_to = email_list
            sources = er_dict.get('sources')
            replacement_order_code = er_dict.get('replacement_order_code')
            replacement_title_code = er_dict.get('replacement_title_code')
            
            reasons = ['video_cropping_reason','video_digihits_reason','video_dropped_frames_reason','video_dropout_reason','video_duplicate_frames_reason','video_interlacing_progressive_reason','video_motion_lag_reason','video_missing_elements_reason','video_corrupt_file_reason','video_bad_aspect_ratio_reason','video_bad_resolution_reason','video_bad_pixel_aspect_ratio_reason','video_bad_specifications_reason','video_bad_head_tail_reason','video_other_reason','audio_bad_mapping_reason','audio_missing_audio_channel_reason','audio_crackle_reason','audio_distortion_reason','audio_dropouts_reason','audio_sync_reason','audio_missing_elements_reason','audio_corrupt_missing_file_reason','audio_bad_specifications_reason','audio_other_reason','metadata_missing_info_reason','metadata_bad_info_reason','metadata_bad_formatting_reason','metadata_other_reason','subtitle_interlacing_reason','subtitle_bad_subtitles_reason','subtitle_sync_issue_reason','subtitle_overlapping_reason','subtitle_other_reason','cc_sync_issue_reason','cc_bad_cc_reason','cc_overlapping_reason','cc_other_reason']
            
            order_obj = server.eval("@SOBJECT(twog/order['code','%s'])" % order_code)
            order_name = ''
            client_name = ''
            scheduler = ''
            if order_obj:
                order_obj = order_obj[0]
                order_name = order_obj.get('name')
                client_name = order_obj.get('client_name')
                scheduler = order_obj.get('login')

            order_builder_url = ctu.get_order_builder_url(order_code, server)
            href = '<a href="{0}">{1}</a>'
            order_hyperlink = href.format(order_builder_url, order_name)

            title_obj = server.eval("@SOBJECT(twog/title['code','%s'])" % title_code)
            title_due_date = ''
            title_expected_delivery = ''
            title_full_name = title
            if episode not in [None,'']:
                title_full_name = '%s: %s' % (title, episode)
            if title_obj:
                title_obj = title_obj[0]
                title_due_date = title_obj.get('due_date')
                title_expected_delivery = title_obj.get('expected_delivery_date')
                if client_name in [None,'']:
                    client_name = title_obj.get('client_name')
                if scheduler in [None,'']:
                    scheduler = order_obj.get('login')
                
            update_data = None
            main_message = ''
            head_message = ''
            head_detail = ''
            is_an_update = False
            if 'update_data' in input.keys():
                update_data = input.get('update_data')
                prev_data = input.get('prev_data')
                if prev_data not in [None,{},'']:
                    ukeys = update_data.keys()
                    if len(ukeys) > 0:
                        is_an_update = True
                        head_message = 'Update for External Rejection on %s (%s) [%s PO#: %s]:' % (title_full_name, title_code, order_code, po_number)
                        if 'status' in ukeys and update_data['status'] == 'Closed':
                            head_message += '<br/><br/>THIS EXTERNAL REJECTION IS NOW CLOSED'
                        else:
                            return
                    main_message = '<table style="font-size: 14px;"><tr><td colspan="2"><br/><hr></td><td> </td></tr>'
                    main_message += '<tr><td valign="top"><b><u>Reported Issue:</u></b></td><td valign="top">{0}</td></tr>'.format(reported_issue)
                    main_message += '<tr><td valign="top"><b><u>Root Cause:</u></b></td><td valign="top">{0}</td></tr>'.format(root_cause)
                    main_message += '<tr><td valign="top"><b><u>Corrective Action:</u></b></td><td valign="top">{0}</td></tr>'.format(corrective_action)
                    main_message += '</table>'

            if is_an_update:
                subject_int = 'NEW - URGENT External Rejection Closed for %s (%s) - Status: %s Scheduler: %s PO#: %s' % (title_full_name, title_code, status, scheduler, po_number)
            else:
                return
            
            head_detail = '<tr><td align="left" style="font-size: 16px;">Replacement Order Code: <strong>%s</strong></td></tr><tr><td align="left" style="font-size: 16px;">Replacement Title Code: <strong>%s</strong></td></tr>' % (replacement_order_code, replacement_title_code)
            
            from formatted_emailer import EmailDirections
            
            ed = EmailDirections(order_code=order_code)
            int_data = ed.get_internal_data()
            
            int_template = open(internal_template_file, 'r')
            filled = ''
            for line in int_template:
                line = line.replace('[ORDER_CODE]', order_code)
                line = line.replace('[ORDER_NAME]', order_hyperlink)
                line = line.replace('[PO_NUMBER]', po_number)
                line = line.replace('[MAIN_MESSAGE]', main_message)
                line = line.replace('[TOP_MESSAGE]', head_message)
                line = line.replace('[EXTRA_HEAD_DETAIL]', head_detail)
                line = line.replace('[CLIENT_NAME]', client_name)
                line = line.replace('[TITLE_CODE]', title_code)
                line = line.replace('[TITLE_FULL_NAME]', title_full_name)
                line = line.replace('[TITLE_DUE_DATE]', title_due_date)
                line = line.replace('[TITLE_EXPECTED_DELIVERY]', title_expected_delivery)
                filled = '%s%s' % (filled, line)
            int_template.close()
            filled_in_email = '/var/www/html/formatted_emails/int_note_inserted_%s.html' % er_dict.get('code')
            filler = open(filled_in_email, 'w')
            filler.write(filled)
            filler.close()
            if addressed_to not in [None,'']:
                adt = addressed_to.split(',')
                for adta in adt:
                    if '@2gdigital' in adta and adta not in int_data['int_ccs']:
                        if int_data['int_ccs'] == '':
                            int_data['int_ccs'] = adta
                        else:
                            int_data['int_ccs'] = '%s;%s' % (int_data['int_ccs'], adta)
            if int_data['int_ccs'] in [None,'']:
                int_data['int_ccs'] = '[email protected];[email protected]'
            else:
                int_data['int_ccs'] = '%s;[email protected];[email protected]' % int_data['int_ccs']
            int_data['int_ccs'] = '%s;[email protected]' % (int_data['int_ccs']) 
            login_email = server.eval("@GET(sthpw/login['login','%s'].email)" % login)
            if login_email:
                int_data['from_email'] = login_email[0] 
            #NEW WAY TO SET THE FROM FOR THE EMAIL
            login_obj = Environment.get_login()
            sender_email = login_obj.get_value('email')
            sender_name = '%s %s' % (login_obj.get_value('first_name'), login_obj.get_value('last_name'))
            subject_int = subject_int.replace(' ','..')
            #the_command = "php /opt/spt/custom/formatted_emailer/trusty_emailer.php '''%s''' '''%s''' '''%s''' '''%s''' '''%s''' '''%s'''" % (filled_in_email, int_data['to_email'], int_data['from_email'], int_data['from_name'], subject_int, int_data['int_ccs'].replace(';','#Xs*'))
            the_command = "php /opt/spt/custom/formatted_emailer/trusty_emailer.php '''%s''' '''%s''' '''%s''' '''%s''' '''%s''' '''%s'''" % (filled_in_email, int_data['to_email'], sender_email, sender_name, subject_int, int_data['int_ccs'].replace(';','#Xs*'))
            if int_data['to_email'] not in [None,''] and int_data['int_ccs'] not in [None,'',';']:
                os.system(the_command)
    except AttributeError as e:
        traceback.print_exc()
        print str(e) + '\nMost likely the server object does not exist.'
        raise e
    except KeyError as e:
        traceback.print_exc()
        print str(e) + '\nMost likely the input dictionary does not exist.'
        raise e
    except Exception as e:
        traceback.print_exc()
        print str(e)
        raise e
Example #2
0
    def get_internal_data(my):
        login_email = ''
        sched_team = ''
        int_list = []
        
        # Figure out who the email should say it is from
        from_email = ''
        if my.client:
            sched_team = my.client.get('scheduling_team_email')
            if sched_team:
                from_email = sched_team
        if my.scheduler_email not in [None,''] and from_email == '':
            from_email = my.scheduler_email
        if my.logged_in_login.get('location') == 'internal':
            if my.logged_in_login.get('email') not in [None,'']:
                login_email = my.logged_in_login.get('email')
        if from_email == '':
            if login_email not in [None,'']:
                from_email = login_email
        if from_email == '':
            from_email = '*****@*****.**'
       
        #Figure out who we want to send the email to
        to_email = ''
        if sched_team not in [None,'']:
            to_email = sched_team
        if to_email == '' and my.scheduler_email not in [None,'']:
            to_email = my.scheduler_email
        elif my.scheduler_email not in [None,'']:
            int_list.append(my.scheduler_email)
        if my.logged_in_login.get('location') == 'internal':
            if login_email not in [None,'']:
                if to_email == '':
                    to_email = login_email
                else:
                    if login_email not in int_list:
                        int_list.append(login_email)
        if to_email == '':
            to_email = '*****@*****.**'
        
        #If the client has people that they want alerted all the time for their notifications, get those email addresses too - as long as it's not the client themself that's writing the note (or whatever) 
        internal_email_list1 = my.logged_in_login.get('internal_notification_list')
        internal_email_list2 = ''
        if my.client_login_obj:
            if my.client_login_obj.get('internal_notification_list') not in [None,''] and my.client_login_obj.get('login') != my.logged_in_login.get('login'):
                internal_email_list2 = my.client_login_obj.get('internal_notification_list')
        internal_email_list3 = ''
        if my.client:
            if my.client.get('internal_notification_list'):
                internal_email_list3 = my.client.get('internal_notification_list')
        list1_arr = internal_email_list1.split(',')
        list2_arr = internal_email_list2.split(',')
        list3_arr = internal_email_list3.split(',')
        all_lists = list1_arr + list2_arr + list3_arr
        for email in all_lists:
            if email not in int_list:
                int_list.append(email)

        order_builder_url = ctu.get_order_builder_url(my.order_code, my.server)
        href = '<a href="{0}">{1}</a>'
        order_hyperlink = href.format(order_builder_url, my.order_name)

        client_hyperlink = ctu.get_edit_wdg_hyperlink('twog/client', my.client_code,
                                                      sobject_name=my.client_name, server=my.server)

        clean_data = {}
        for key, val in my.data.iteritems():
            if key != 'ext_ccs':
                clean_data[key] = val    
        send_data = clean_data
        send_data['order_hyperlink'] = order_hyperlink
        send_data['client_hyperlink'] = client_hyperlink
        send_data['from_email'] = from_email
        send_data['to_email'] = to_email
        #print "int list = %s" % int_list
        final_int_list = []
        for thing in int_list:
            if thing not in [None,'',[]]:
                final_int_list.append(thing)
        cc_list = ';'.join(final_int_list)
        if cc_list not in [None,'']:
            if cc_list[0] == ';':
                cc_list = cc_list[1:]
        send_data['int_ccs'] = cc_list
        send_data['ccs'] = send_data.get('int_ccs')
        return send_data 
def main(server=None, input=None):
    """
    The main function of the custom script. The entire script was copied
    and pasted into the body of the try statement in order to add some
    error handling. It's all legacy code, so edit with caution.

    :param server: the TacticServerStub object
    :param input: a dict with data like like search_key, search_type, sobject, and update_data
    :return: None
    """
    if not input:
        input = {}

    try:
        # CUSTOM_SCRIPT00078
        from pyasm.common import Environment
        from pyasm.biz import Note
        from pyasm.search import Search
        import common_tools.utils as ctu
        login = Environment.get_login()
        user_name = login.get_login()
        delim = '#Xs*'
        all_ccs = '[email protected]%[email protected]' % delim
        #This is for production_error operator_description update
        sobject = input.get('sobject')
        operator_description = sobject.get('operator_description')
        title_code = sobject.get('title_code')
        wo_code = sobject.get('work_order_code')
        title_id_pre = title_code.split('TITLE')[1]
        found_non_zero = False
        title_id = ''
        note = ''
        for ch in title_id_pre:
            if ch != '0':
                found_non_zero = True
            if ch == '0' and found_non_zero or (ch != '0'):
                title_id = '%s%s' % (title_id, ch)
        wo_code = sobject.get('work_order_code')
        expr = "@SOBJECT(sthpw/note['search_id','%s']['search_type','~','twog/title']['process','QC Rejected']['@ORDER_BY','timestamp desc'])" % (title_id)
        last_note = server.eval(expr)
        if last_note:
            last_note = last_note[0]
            # Now just need to update it with the operator description, wo code and title
            note = last_note.get('note')
            note = '%s\n%s' % (note, operator_description)
            server.update(last_note.get('__search_key__'), {'note': note}, triggers=False)
            wo_obj2 = Search.get_by_search_key(server.build_search_key('twog/work_order',wo_code))   #This is the type of object required for Note creation
            note2 = Note.create(wo_obj2, note, context='QC Rejected', process='QC Rejected')
        
        
        wo = server.eval("@SOBJECT(twog/work_order['code','%s'])" % wo_code)[0]
        proj = server.eval("@SOBJECT(twog/proj['code','%s'])" % wo.get('proj_code'))[0]
        title = server.eval("@SOBJECT(twog/title['code','%s'])" % proj.get('title_code'))[0]
        order = server.eval("@SOBJECT(twog/order['code','%s'])" % title.get('order_code'))[0]
        scheduler_name = order.get('login')
        scheduler = server.eval("@SOBJECT(sthpw/login['login','%s']['location','internal'])" % scheduler_name)
        if scheduler:
            scheduler = scheduler[0]
            all_ccs = '%s%s%s' % (all_ccs, delim, scheduler.get('email'))
            
        group = ''
        process = ''
        client_name = ''
        po_number = order.get('po_number')
        order_name = order.get('name')
        title_name = title.get('title')
        episode = title.get('episode')
        if wo:
            group = wo.get('work_group')
            process = wo.get('process')
            client_name = wo.get('client_name')
        error_type = sobject.get('error_type')
        rejection_cause = sobject.get('rejection_cause')
        time_spent = sobject.get('time_spent')
        client_description = sobject.get('client_description')
        client_description = client_description.replace('\t','        ')
        client_description = client_description.replace('\n','<br/>')
        client_description = client_description.replace('  ', '  ')
        operator_description = operator_description.replace('\t','        ')
        operator_description = operator_description.replace('\n','<br/>')
        operator_description = operator_description.replace('  ', '  ')
        action_taken = sobject.get('action_taken')

        order_builder_url = ctu.get_order_builder_url(order.get('code'), server)
        href = '<a href="{0}">{1}</a>'
        order_hyperlink = href.format(order_builder_url, order_name)

        title_row = ''
        proj_row = ''
        if title:
            full_title = title.get('title')
            if title.get('episode') not in [None,'']:
                full_title = '%s: %s' % (full_title, title.get('episode'))
            title_row = "<tr><td align='left' style='color: #06C; font-size: 16px;'>Title: <strong>%s</strong> | Title Code: <strong>%s</strong></td></tr>" % (full_title, title.get('code')) 
        if proj:
            proj_row = "<tr><td align='left' style='color: #06C; font-size: 16px;'>Project: <strong>%s</strong> | Project Code: <strong>%s</strong></td></tr>" % (proj.get('process'), proj.get('code'))
        template_path = '/opt/spt/custom/formatted_emailer/error_msg.html'
        filled_in_path = '/var/www/html/formatted_emails/error_msg_%s.html' % wo_code
        template = open(template_path, 'r')
        filled = ''
        for line in template:
            line = line.replace('[WORK_ORDER_CODE]', wo_code)
            line = line.replace('[TITLE_CODE]', title.get('code'))
            line = line.replace('[PROJ_CODE]', proj.get('code'))
            line = line.replace('[TITLE_ROW]', title_row)
            line = line.replace('[PROJ_ROW]', proj_row)
            line = line.replace('[ORDER_CODE]', order.get('code'))
            line = line.replace('[LOGIN]', user_name)
            line = line.replace('[GROUP]', group)
            line = line.replace('[PROCESS]', process)
            line = line.replace('[CLIENT_NAME]', client_name)
            line = line.replace('[PO_NUMBER]', po_number)
            line = line.replace('[ORDER_NAME]', order_hyperlink)
            line = line.replace('[TITLE]', title_name)
            line = line.replace('[EPISODE]', episode)
            line = line.replace('[ERROR_TYPE]', error_type)
            line = line.replace('[REJECTION_CAUSE]', rejection_cause)
            line = line.replace('[TIME_SPENT]', time_spent)
            line = line.replace('[CLIENT_DESCRIPTION]', client_description)
            line = line.replace('[OPERATOR_DESCRIPTION]', operator_description)
            line = line.replace('[ACTION_TAKEN]', action_taken)
            filled = '%s%s' % (filled, line)
        template.close()
        filler = open(filled_in_path, 'w')
        filler.write(filled)
        filler.close()
        server.insert('twog/bundled_message', {'filled_in_path': filled_in_path, 'message': 'New Error', 'from_email': '*****@*****.**', 'to_email': '*****@*****.**', 'from_name': 'Tech Alert', 'subject': 'Error: %s, %s, %s: %s' % (wo_code, po_number, title_name, episode), 'all_ccs': all_ccs, 'object_code': wo_code})
    except AttributeError as e:
        traceback.print_exc()
        print str(e) + '\nMost likely the server object does not exist.'
        raise e
    except KeyError as e:
        traceback.print_exc()
        print str(e) + '\nMost likely the input dictionary does not exist.'
        raise e
    except Exception as e:
        traceback.print_exc()
        print str(e)
        raise e
Example #4
0
    def get_display(my):
        import common_tools.utils as ctu
        from common_tools.copy_url_button import CopyUrlButton

        my.sk = str(my.kwargs.get('sk'))
        my.sid = str(my.kwargs.get('search_id'))
        allowed_search_titles = ''
        if 'user' in my.kwargs.keys():
            my.user = my.kwargs.get('user')
        else:
            my.user = Environment.get_user_name()
        if 'groups_str' in my.kwargs.keys():
            my.groups_str = my.kwargs.get('groups_str')
        if my.groups_str in [None,'']:
            user_group_names = Environment.get_group_names()
            for mg in user_group_names:
                if my.groups_str == '':
                    my.groups_str = mg
                else:
                    my.groups_str = '%s,%s' % (my.groups_str, mg)
        user_is_scheduler = False
        if 'scheduling' in my.groups_str or 'onboarding' in my.groups_str:
            user_is_scheduler = True
        if 'display_mode' in my.kwargs.keys():
            my.disp_mode = my.kwargs.get('display_mode')
        if my.disp_mode == 'Small':
            my.small = True
        my.code = my.sk.split('code=')[1]
        if 'allowed_titles' in my.kwargs.keys():
            my.allowed_titles_str = str(my.kwargs.get('allowed_titles'))
            split_allow = my.allowed_titles_str.split('|')
            for sa in split_allow:
                if allowed_search_titles == '':
                    allowed_search_titles = "('%s'" % sa
                else:
                    allowed_search_titles = "%s,'%s'" % (allowed_search_titles, sa)
            if allowed_search_titles != '':
                allowed_search_titles = '%s)' % allowed_search_titles
        if my.allowed_titles_str == '':
            my.allowed_titles_str = 'NOTHING|NOTHING'
        main_search = Search("twog/order")
        main_search.add_filter('code', my.code)
        main_obj = main_search.get_sobject()
        if 'is_master' in my.kwargs.keys():
            my.is_master_str = my.kwargs.get('is_master')
            if my.is_master_str == 'true':
                my.is_master = True
        else:
            if main_obj.get_value('classification') in ['master', 'Master']:
                my.is_master = True
                my.is_master_str = 'true'
        sched_full_name = ''
        if main_obj.get_value('login') not in [None,'']:
            sched_s = Search('sthpw/login')
            sched_s.add_filter('location', 'internal')
            sched_s.add_filter('login', main_obj.get_value('login'))
            sched = sched_s.get_sobject()
            if sched:
                sched_full_name = '%s %s' % (sched.get_value('first_name'), sched.get_value('last_name'))

        sales_full_name = ''
        if main_obj.get_value('sales_rep') not in [None,'']:
            sales_s = Search('sthpw/login')
            sales_s.add_filter('location', 'internal')
            sales_s.add_filter('login', main_obj.get_value('sales_rep'))
            sales = sales_s.get_sobject()
            if sales:
                sales_full_name = '%s %s' % (sales.get_value('first_name'), sales.get_value('last_name'))

        title_search = Search("twog/title")
        title_search.add_filter('order_code', main_obj.get_value('code'))
        if allowed_search_titles != '':
            title_search.add_where("\"code\" in %s" % allowed_search_titles)
        titles = title_search.get_sobjects()
        table = Table()
        table.add_attr('I_AM', 'ORDER TABLE')
        if user_is_scheduler:
            table.add_attr('SOY', 'ORDER-O TABLE-O')

        table.add_attr('cellpadding', '0')
        table.add_attr('cellspacing', '0')
        table.add_style('border-collapse', 'separate')
        table.add_style('border-spacing', '25px 0px')
        table.add_style('color: #00033a;')
        table.add_style('background-color: #d9edf7;')
        table.add_style('width: 100%;')
        table.add_style('border-bottom-right-radius', '10px')
        table.add_style('border-bottom-left-radius', '10px')
        table.add_style('border-top-right-radius', '10px')
        table.add_style('border-top-left-radius', '10px')
        order_name_row = table.add_row()
        full_o_name = main_obj.get('name')
        if main_obj.get('details') not in [None,'']:
            full_o_name = '%s - %s' % (full_o_name, main_obj.get('details'))
        order_name_cell = table.add_cell('<b><u>Order: %s</u><b>' % full_o_name)
        order_name_cell.add_attr('nowrap','nowrap')
        order_name_cell.add_style('cursor: pointer;')
        order_name_cell.add_behavior(get_panel_change_behavior('twog/order', my.code, my.sk, my.sk, my.title, '',
                                                               'builder/refresh_from_save', '', my.sk,
                                                               main_obj.get_value('name'), user_is_scheduler))
        order_due_cell = table.add_cell("Due: %s" % fix_date(main_obj.get_value('due_date')).split(' ')[0])
        order_due_cell.add_attr('nowrap', 'nowrap')
        long_cell1 = table.add_cell('Scheduler: %s' % sched_full_name)
        long_cell1.add_style('width: 100%')
        order_sales_row = table.add_row()
        order_po_cell = table.add_cell("Code: %s &nbsp; &nbsp; PO Number: %s" % (my.code,
                                                                                 main_obj.get_value('po_number')))
        order_po_cell.add_attr('nowrap', 'nowrap')
        order_sales_cell = table.add_cell('Sales Rep: %s' % sales_full_name)
        order_sales_cell.add_attr('nowrap', 'nowrap')
        bottom_buttons = Table()
        bottom_buttons.add_row()

        order_builder_url = ctu.get_order_builder_url(my.code)
        copy_url_button = CopyUrlButton(title='Copy URL to Clipboard', url=order_builder_url)
        copy_url_cell = bottom_buttons.add_cell(copy_url_button)
        copy_url_cell.add_attr('align', 'right')

        instructions_button = FullInstructionsLauncherWdg(title='View Instructions', search_key=my.sk)
        instructions_cell = bottom_buttons.add_cell(instructions_button)
        instructions_cell.add_attr('align', 'right')

        if user_is_scheduler:
            tcloner = ButtonSmallNewWdg(title="Title Cloner", icon=CustomIconWdg.icons.get('STAR'))
            tcloner.add_behavior(get_launch_title_cloner_behavior(my.sk, main_obj.get_value('name'), my.user))
            dcl = bottom_buttons.add_cell(tcloner)
            dcl.add_attr('align', 'right')

            tchanger = ButtonSmallNewWdg(title="Title Changer", icon=CustomIconWdg.icons.get('CALENDAR'))
            tchanger.add_behavior(get_launch_title_changer_behavior(my.sk, main_obj.get_value('name'), my.user))
            dcal = bottom_buttons.add_cell(tchanger)
            dcal.add_attr('align', 'right')

            tdeletor = ButtonSmallNewWdg(title="Title Deletor", icon=CustomIconWdg.icons.get('TABLE_ROW_DELETE'))
            tdeletor.add_behavior(get_launch_title_deletor_behavior(my.sk, main_obj.get_value('name'), my.user))
            dfilt = bottom_buttons.add_cell(tdeletor)
            dfilt.add_attr('align', 'right')

        tfilter = ButtonSmallNewWdg(title="Filter Titles", icon=CustomIconWdg.icons.get('CONTENTS'))
        tfilter.add_behavior(get_launch_title_filter_behavior(my.sk, main_obj.get_value('name'), my.user))
        filt = bottom_buttons.add_cell(tfilter)
        filt.add_attr('align', 'right')

        upload = ButtonSmallNewWdg(title="Upload", icon=CustomIconWdg.icons.get('PUBLISH'))
        upload.add_behavior(get_upload_behavior(my.sk))
        up = bottom_buttons.add_cell(upload)
        up.add_attr('align', 'right')

        note_adder = ButtonSmallNewWdg(title="Add Note", icon=CustomIconWdg.icons.get('NOTE_ADD'))
        note_adder.add_behavior(get_launch_note_behavior(my.sk, main_obj.get_value('name')))
        nadd = bottom_buttons.add_cell(note_adder)
        nadd.add_attr('align', 'right')
        nadd.add_style('cursor: pointer;')

        if user_is_scheduler or 'onboarding' in my.groups_str:
            title_adder = ButtonSmallNewWdg(title="Add Titles", icon=CustomIconWdg.icons.get('INSERT_MULTI'))
            title_adder.add_behavior(get_title_add_behavior(my.sk, my.sid, main_obj.get_value('client_code'),
                                                            main_obj.get_value('name')))
            tadd = bottom_buttons.add_cell(title_adder)
            tadd.add_attr('align', 'right')
            tadd.add_style('cursor: pointer;')

        long_cell2 = table.add_cell(bottom_buttons)
        long_cell2.add_attr('align', 'right')
        long_cell2.add_attr('valign', 'bottom')
        long_cell2.add_style('width: 100%')
        bottom = Table()
        bottom.add_attr('width', '100%')
        bottom.add_attr('cellpadding', '0')
        bottom.add_attr('cellspacing', '0')
        for title in titles:
            title_sk = title.get_search_key()
            title_row = bottom.add_row()
            title_row.add_attr('width', '100%')
            title_row.add_attr('class', 'row_%s' % title_sk)
            title_obj = TitleRow(sk=title_sk, parent_sk=my.sk, parent_sid=my.sid, groups_str=my.groups_str,
                                 user=my.user, display_mode=my.disp_mode, is_master=my.is_master_str, main_obj=title)
            content_cell = bottom.add_cell(title_obj)
            content_cell.add_attr('width', '100%')
            content_cell.add_attr('sk', title_sk)
            content_cell.add_attr('order_sk', my.sk)
            content_cell.add_attr('parent_sk', my.sk)
            content_cell.add_attr('parent_sid', my.sid)
            content_cell.add_attr('call_me', title.get_value('title'))
            content_cell.add_attr('episode', title.get_value('episode'))
            content_cell.add_attr('my_class', 'TitleRow')
            content_cell.add_attr('client_code', title.get_value('client_code'))
            content_cell.add_attr('class', 'cell_%s' % title_sk)
        tab2ret = Table()
        tab2ret.add_attr('width', '100%')
        tab2ret.add_row()
        tab2ret.add_cell(table)
        tab2ret.add_row()
        bot = tab2ret.add_cell(bottom)
        bot.add_style('padding-left: 40px;')

        return tab2ret