Esempio n. 1
0
def devolver_reservas(app, reservas):
    actions = 0
    app.linhas.selection_set(*[])
    for _, reserva in reservas:
        estado.reservas.discard(reserva)
        app.reservas.delete(reserva)

        onibus = reserva[:-6]
        linha = onibus[:-7]

        if onibus in estado.linhas_entradas[linha].onibus:
            del estado.linhas_entradas[linha].onibus[onibus][
                decodificar_id_reserva(reserva).assento]

            prev_values = app.linhas.set(onibus)
            prev_values['assentos livres'] = int(
                prev_values['assentos livres']) + 1
            app.linhas.see(onibus)
            app.linhas.selection_add(onibus)
            app.linhas.item(onibus, values=tuple(prev_values.values()))

        actions += 1

    app.contador_reservas['text'] = fm.form_cont_reservas(len(estado.reservas))

    return actions
Esempio n. 2
0
def rereservar_reservas(app, reservas):
    actions = 0
    app.reservas.selection_set(*[])
    app.linhas.selection_set(*[])
    for indice, reserva in reservas:
        estado.reservas.add(reserva)
        app.reservas.insert(parent='',
                            index=indice,
                            values=campos_reserva_formatados(reserva),
                            iid=reserva)
        app.reservas.selection_add(reserva)

        onibus = reserva[:-6]
        linha = onibus[:-7]
        if onibus in estado.linhas_entradas[linha].onibus:
            info_reserva = decodificar_id_reserva(reserva)
            assento, passagem = info_reserva.assento, info_reserva.passagem.tipo
            estado.linhas_entradas[linha].onibus[onibus][assento] = passagem

            prev_values = app.linhas.set(onibus)
            prev_values['assentos livres'] = int(
                prev_values['assentos livres']) - 1
            app.linhas.see(onibus)
            app.linhas.selection_add(onibus)
            app.linhas.item(onibus, values=tuple(prev_values.values()))
        actions += 1

    app.contador_reservas['text'] = fm.form_cont_reservas(len(estado.reservas))

    return actions
Esempio n. 3
0
    def undo_reserva(event):
        historico_undo = monitoradas.historico_undo
        historico_redo = monitoradas.historico_redo
        try:
            evento = chave, *dados = historico_undo.pop(-1)
            historico_redo.append(evento)
            actions = hst.desfazer[chave](app, *dados)
            try:
                close = dados[0][:-6] != onibus
            except (IndexError, TypeError):
                close = True
            if not close:
                info_reserva = decodificar_id_reserva(dados[0])
                assento = info_reserva.assento
                nonlocal selected
                if selected['text'] != 'None':
                    selected['style'] = 'available.TLabel'
                labels[assento]['style'] = 'selected.TLabel'
                labels[assento]['cursor'] = 'hand2'
                labels[assento].bind('<Button-1>', selecionar)
                selected = labels[assento]
                button_state()
                if len(estado.linhas_entradas[linha].onibus[onibus]) == 0:
                    shift = (sum(coordenadas_assento(assento)) + 1) % 2
                    assentos_invisiveis = {
                        assento_coordenadas(i, 2 * j + (i + shift) % 2)
                        for j in range(2) for i in range(num_fileiras)
                    }
                    for assento_indisponivel in assentos_invisiveis:
                        labels[assento_indisponivel] = labels.get(
                            assento_indisponivel,
                            ttk.Label(painel_assentos,
                                      text=assento_indisponivel,
                                      anchor='center',
                                      takefocus=True,
                                      width=4,
                                      style='available.TLabel',
                                      cursor='hand2'))
                        i, j = coordenadas_assento(assento_indisponivel)
                        labels[assento_indisponivel].grid(
                            row=i,
                            column=j,
                            padx=(0, 10) if j == 1 else
                            (10, 0) if j == 2 else 0)
                        painel_assentos.rowconfigure(i, weight=1)

            if actions == 0:
                hst.undo(app)
            else:
                ctrl.update_action(app,
                                   cte.ACOES_COMPLEMENTARES.get(chave, chave))
        except IndexError:
            close = False
        if close:
            monitoradas.janela_reservas.destroy()
Esempio n. 4
0
def reserva_to_csv(reserva):
    '''
        Retorna uma string com os dados da reserva separados por vírgula.
        O argumento é o id da reserva.
    '''
    reserva = decodificar_id_reserva(reserva)

    campus = reserva.campus.title()
    partida = reserva.partida.strftime('%d/%m/%y %H:%M')
    assento = str(reserva.assento)
    passagem = cte.INDICE_PASSAGEM[reserva.passagem.tipo]

    linha = ', '.join([campus, partida, assento, passagem])+'\n'
    return linha
Esempio n. 5
0
def devolver(app):
    '''
        Remove as reservas selecionadas, devolvendo as vagas.
    '''
    selecao = app.reservas.selection()
    if len(selecao) == 0:
        texto = 'Selecione reservas cujos ônibus ainda não partiram.'
        messagebox.showwarning(title='Não Há O Que Devolver', message=texto)
        return

    devolviveis = [
        reserva for reserva in selecao if app.linhas.exists(reserva[:-6])
    ]
    if len(devolviveis) < len(selecao):
        if len(devolviveis) == 0:
            texto = 'Ônibus já partiram. Impossível devolver.'
            messagebox.showwarning(title='Impossível Devolver', message=texto)
            return
        else:
            texto = 'Os ônibus de algumas reservas já partiram, deseja devolver as demais?'
            resposta = messagebox.askyesno(title='ônibus Partiram',
                                           message=texto,
                                           default='yes')
            if not resposta:
                return
    reservas = []
    app.linhas.selection_set(*[])
    for reserva in devolviveis:
        reservas.insert(0, [app.reservas.index(reserva), reserva])
        estado.reservas.discard(reserva)
        app.reservas.delete(reserva)

        onibus = reserva[:-6]
        linha = onibus[:-7]

        del estado.linhas_entradas[linha].onibus[onibus][
            decodificar_id_reserva(reserva).assento]

        prev_values = app.linhas.set(onibus)
        prev_values['assentos livres'] = int(
            prev_values['assentos livres']) + 1
        app.linhas.see(onibus)
        app.linhas.selection_add(onibus)
        app.linhas.item(onibus, values=tuple(prev_values.values()))

    app.contador_reservas['text'] = fm.form_cont_reservas(len(estado.reservas))
    monitoradas.historico_redo.clear()
    monitoradas.historico_undo.append(['refund', reservas])
Esempio n. 6
0
    def redo_reserva(event):
        historico_undo = monitoradas.historico_undo
        historico_redo = monitoradas.historico_redo
        try:
            evento = chave, *dados = historico_redo.pop(-1)
            historico_undo.append(evento)
            actions = hst.refazer[chave](app, *dados)
            try:
                close = dados[0][:-6] != onibus
            except (IndexError, TypeError):
                close = True
            if not close:
                info_reserva = decodificar_id_reserva(dados[0])
                assento, tipo = info_reserva.assento, info_reserva.passagem.tipo
                labels[assento]['cursor'] = 'X_cursor'
                labels[assento]['style'] = estilo[tipo]
                labels[assento].unbind('<Button-1>')
                nonlocal selected
                selected = ttk.Label(painel_assentos, text='None')
                button_state()
                if len(estado.linhas_entradas[linha].onibus[onibus]) == 1:
                    shift = (sum(coordenadas_assento(assento)) + 1) % 2
                    assentos_invisiveis = {
                        assento_coordenadas(i, 2 * j + (i + shift) % 2)
                        for j in range(2) for i in range(num_fileiras)
                    }
                    for assento_indisponivel in assentos_invisiveis:
                        labels[assento_indisponivel].grid_remove()

            if actions == 0:
                hst.redo(app)
            else:
                ctrl.update_action(app, chave)
        except IndexError:
            close = False
        if close:
            monitoradas.janela_reservas.destroy()
Esempio n. 7
0
def exibir_relatorio(app):
    '''
        Constrói e exibe a janela do relatório.
    '''
    data_atual = monitoradas.data_atual

    janela = tk.Toplevel()
    janela.grab_set()
    janela.title('Relatório')
    janela.resizable(True, True)
    janela.minsize(700, 700)
    janela.transient(app.root)

    frame = ttk.Frame(janela, padding=10)
    frame.pack(fill='both', expand=True)

    def toggle_states(master, children):
        master_value = master.get()
        for state in children:
            state.set(master_value)
        if master_value:
            janela.minsize(700, 700)
            botao_exportar.state(['!disabled'])
            painel_arrecadado.grid()
            painel_passagens.grid()
            painel_ocupacao.grid()
        else:
            janela.minsize(700, 250)
            botao_exportar.state(['disabled'])
            painel_arrecadado.grid_remove()
            painel_passagens.grid_remove()
            painel_ocupacao.grid_remove()

    master_state = tk.IntVar(value=1)
    checkbox_master = ttk.Checkbutton(frame, variable=master_state)
    descriptive_label = ttk.Label(frame, text='Informações', anchor='center')

    distribuicao_passageiros = [0, 0, 0]  # [gratuita, meia, inteira]
    linha_dia_reservas = dict()
    monitoradas.arrecadado = dict()
    monitoradas.ocupacao_media_semanal = dict()

    total_passageiros = len(estado.reservas)

    def hide_widget(widget, show=False):
        x, y = janela.minsize()
        if not show:
            janela.minsize(x, y - 150)
            widget.grid_remove()
            if not any(x.get() for x in
                       [arrecadado_state, passagens_state, ocupacao_state]):
                botao_exportar.state(['disabled'])
            return
        botao_exportar.state(['!disabled'])
        janela.minsize(x, y + 150)
        widget.grid()

    def form_arrecadado(n):
        return '  Total Arrecadado: R$ %s  ' % fm.separar_milhares_decimal(n)

    painel_arrecadado = ttk.LabelFrame(frame,
                                       text='Total Arrecadado',
                                       padding=10)
    arrecadado_state = tk.IntVar(value=1)
    checkbox_arrecadado = ttk.Checkbutton(
        frame,
        variable=arrecadado_state,
        command=lambda: hide_widget(painel_arrecadado, arrecadado_state.get()))
    treeview_arrecadado = ttk.Treeview(painel_arrecadado,
                                       columns=('Linha', 'Arrecadado'),
                                       show='headings',
                                       selectmode='none',
                                       name='arrecadado')

    for i, coluna in enumerate(('Linha', 'Arrecadado (R$)')):
        treeview_arrecadado.heading(
            i,
            text=coluna.title(),
            command=lambda col=i: util.treeview_sort_column(
                app, treeview_arrecadado, col, False))
        treeview_arrecadado.column(i,
                                   width=0,
                                   minwidth=len(coluna) * 15,
                                   anchor='center')

    treeview_arrecadado.bind(
        '<Motion>', lambda ev: util.last_separator(ev, treeview_arrecadado))
    treeview_arrecadado.bind(
        '<1>', lambda ev: util.last_separator(ev, treeview_arrecadado))

    treeview_arrecadado_scroller_v = ttk.Scrollbar(
        painel_arrecadado,
        orient='vertical',
        command=treeview_arrecadado.yview)
    treeview_arrecadado_scroller_h = ttk.Scrollbar(
        painel_arrecadado,
        orient='horizontal',
        command=treeview_arrecadado.xview)

    treeview_arrecadado['yscrollcommand'] = treeview_arrecadado_scroller_v.set
    treeview_arrecadado['xscrollcommand'] = treeview_arrecadado_scroller_h.set

    passagens_state = tk.IntVar(value=1)
    painel_passagens = ttk.LabelFrame(frame,
                                      text='  Distribuição de Passagens  ',
                                      padding=10)
    checkbox_passagens = ttk.Checkbutton(
        frame,
        variable=passagens_state,
        command=lambda: hide_widget(painel_passagens, passagens_state.get()))
    label_passageiros = ttk.Label(painel_passagens,
                                  text='Total de Passageiros: %s' %
                                  fm.separar_milhares(total_passageiros),
                                  anchor='center')
    label_inteira = ttk.Label(painel_passagens, anchor='center')
    label_meia = ttk.Label(painel_passagens, anchor='center')
    label_gratuita = ttk.Label(painel_passagens, anchor='center')

    def form_ocupacao(n):
        return '  Ocupação Média: %s%%  ' % fm.separar_milhares_decimal(n)

    painel_ocupacao = ttk.LabelFrame(frame, text=form_ocupacao(0), padding=10)
    ocupacao_state = tk.IntVar(value=1)
    checkbox_ocupacao = ttk.Checkbutton(
        frame,
        variable=ocupacao_state,
        command=lambda: hide_widget(painel_ocupacao, ocupacao_state.get()))

    treeview_ocupacao = ttk.Treeview(painel_ocupacao,
                                     columns=('Linha', 'Dom', 'Seg', 'Ter',
                                              'Qua', 'Qui', 'Sex', 'Sab'),
                                     show='headings',
                                     selectmode='none',
                                     name='ocupacao')

    for i, coluna in enumerate(
        ('Linha', 'Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab')):
        treeview_ocupacao.heading(
            i,
            text=coluna.title(),
            command=lambda col=i: util.treeview_sort_column(
                app, treeview_ocupacao, col, False))
        treeview_ocupacao.column(i,
                                 width=0,
                                 minwidth=len(coluna) * 15,
                                 anchor='center')

    treeview_ocupacao.bind(
        '<Motion>', lambda ev: util.last_separator(ev, treeview_ocupacao))
    treeview_ocupacao.bind(
        '<1>', lambda ev: util.last_separator(ev, treeview_ocupacao))

    treeview_ocupacao_scroller_v = ttk.Scrollbar(
        painel_ocupacao, orient='vertical', command=treeview_ocupacao.yview)
    treeview_ocupacao_scroller_h = ttk.Scrollbar(
        painel_ocupacao, orient='horizontal', command=treeview_ocupacao.xview)

    treeview_ocupacao['yscrollcommand'] = treeview_ocupacao_scroller_v.set
    treeview_ocupacao['xscrollcommand'] = treeview_ocupacao_scroller_h.set

    checkbox_master['command'] = lambda: toggle_states(
        master_state, [arrecadado_state, passagens_state, ocupacao_state])

    def exportar_relatorio():
        '''
            Exporta o relatório como um arquivo .txt
        '''
        # pede um caminho ao usuário
        endereco = filedialog.asksaveasfilename(title='Exportar Relatório',
                                                defaultextension='.txt',
                                                filetypes=[('txt', '*.txt'),
                                                           ('csv', '*.csv'),
                                                           ('todos', '*')],
                                                parent=janela)
        if endereco == '':
            return
        # cria o arquivo no endereço especificado pelo usuário
        with open(endereco, 'w') as arquivo_relatorio:
            # as variáveis *_state são IntVar, que possuem valor 1 se o check está selecionado, e 0 caso contrário
            # vamos escrever no arquivo .txt apenas as seções em que os checks estão marcados
            if arrecadado_state.get():
                arquivo_relatorio.write('{:*^101}\n'.format(' ARRECADAÇÃO '))
                arquivo_relatorio.write('%s\n' % painel_arrecadado['text'])
                arquivo_relatorio.write('{:*^49} | {:*^49}\n'.format(
                    ' LINHA ', ' ARRECADADO (R$) '))
                for linha in treeview_arrecadado.get_children():
                    arquivo_relatorio.write(
                        '{Linha:^50}|{Arrecadado:^50}\n'.format_map(
                            treeview_arrecadado.set(linha)))
            if passagens_state.get():
                if arrecadado_state.get():
                    arquivo_relatorio.write('\n\n')
                arquivo_relatorio.write(
                    '{:*^101}\n'.format(' DISTRIBUIÇÃO DE PASSAGENS '))
                arquivo_relatorio.write('{:^49} : {:^49}\n'.format(
                    'TOTAL', fm.separar_milhares(total_passageiros)))
                arquivo_relatorio.write('{:^49} : {:^49}\n'.format(
                    'INTEIRA',
                    fm.separar_milhares_precisao(percentual_inteira) + ' %'))
                arquivo_relatorio.write('{:^49} : {:^49}\n'.format(
                    'MEIA',
                    fm.separar_milhares_precisao(percentual_meia) + ' %'))
                arquivo_relatorio.write('{:^49} : {:^49}\n'.format(
                    'GRATUITA',
                    fm.separar_milhares_precisao(percentual_gratuita) + ' %'))
            if ocupacao_state.get():
                if passagens_state.get():
                    arquivo_relatorio.write('\n\n')
                arquivo_relatorio.write(
                    '{:*^167}\n'.format(' OCUPAÇÃO MÉDIA SEMANAL (%) '))
                arquivo_relatorio.write(
                    ('|'.join(['{:*^20}'] * 8) + '\n').format(
                        ' LINHA ', ' DOM ', ' SEG ', ' TER ', ' QUAR ',
                        ' QUI ', ' SEX ', ' SAB '))
                for linha in treeview_ocupacao.get_children():
                    nome_linha = treeview_ocupacao.set(linha, 'Linha')
                    arquivo_relatorio.write(
                        ('|'.join(['{:*^20}'] * 8) + '\n').format(
                            f' {nome_linha} ',
                            *map(
                                lambda x: ' ' + fm.separar_milhares_decimal(
                                    100 * x) + ' ',
                                monitoradas.ocupacao_media_semanal[linha])))

    botao_exportar = ttk.Button(frame,
                                text='Exportar',
                                command=exportar_relatorio)

    checkbox_master.grid(row=0, column=0)
    descriptive_label.grid(row=0, column=1)

    checkbox_arrecadado.grid(row=1, column=0)
    painel_arrecadado.grid(row=1, column=1, sticky='news')
    treeview_arrecadado.grid(row=0, column=0, sticky='news')
    treeview_arrecadado_scroller_v.grid(row=0, column=1, sticky='ns')
    treeview_arrecadado_scroller_h.grid(row=1, column=0, sticky='we')
    painel_arrecadado.rowconfigure(0, weight=1)
    painel_arrecadado.columnconfigure(0, weight=1)

    checkbox_passagens.grid(row=2, column=0)
    painel_passagens.grid(row=2, column=1, sticky='ns')
    label_passageiros.grid(pady=(0, 10))
    label_inteira.grid()
    label_meia.grid()
    label_gratuita.grid()
    for i in range(4):
        painel_passagens.rowconfigure(i, weight=1)
    painel_passagens.columnconfigure(0, weight=1)

    checkbox_ocupacao.grid(row=3, column=0)
    painel_ocupacao.grid(row=3, column=1, sticky='news')
    treeview_ocupacao.grid(row=0, column=0, sticky='news')
    treeview_ocupacao_scroller_v.grid(row=0, column=1, sticky='ns')
    treeview_ocupacao_scroller_h.grid(row=1, column=0, sticky='we')
    painel_ocupacao.rowconfigure(0, weight=1)
    painel_ocupacao.columnconfigure(0, weight=1)

    botao_exportar.grid(row=4, column=0, columnspan=2)

    for i in range(3):
        frame.rowconfigure(i + 1, weight=1)

    frame.columnconfigure(1, weight=1)

    for reserva in estado.reservas:
        onibus = reserva[:-6]
        linha = onibus[:-7]
        dados_reserva = decodificar_id_reserva(reserva)
        passagem, inteira = dados_reserva[-1]
        monitoradas.arrecadado[linha] = monitoradas.arrecadado.get(
            linha, 0) + it.centavos(inteira, passagem)
        distribuicao_passageiros[passagem] += 1
        linha_dia_reservas[linha] = linha_dia_reservas.get(linha, [0] * 7)
        linha_dia_reservas[linha][decodificar_id_onibus(onibus).isoweekday() %
                                  7] += 1

    if total_passageiros == 0:
        percentual_inteira = percentual_meia = percentual_gratuita = 0
    else:
        (percentual_gratuita, percentual_meia, percentual_inteira) = [
            100 * distribuicao_passageiros[i] / total_passageiros
            for i in range(3)
        ]

    label_inteira['text'] = 'Inteira: %s%%' % fm.separar_milhares_decimal(
        percentual_inteira)
    label_meia['text'] = 'Meia: %s%%' % fm.separar_milhares_decimal(
        percentual_meia)
    label_gratuita['text'] = 'Gratuita: %s%%' % fm.separar_milhares_decimal(
        percentual_gratuita)

    total_arrecadado = 0

    def onibus_por_dia(linha):
        data_cadastro = estado.linhas_entradas[linha].horario
        dia_da_semana = data_cadastro.isoweekday()
        intervalo = (data_atual +
                     dt.timedelta(cte.MAXIMO_NUMERO_DE_DIAS_ATE_RESERVA) -
                     data_cadastro).days
        onibus_diarios = [0] * 7

        for i in range(7):
            if i in range((intervalo + 1) % 7):
                num_onibus = (intervalo + 1) // 7 + 1
            else:
                num_onibus = (intervalo + 1) // 7

            onibus_diarios[(dia_da_semana + i) % 7] = num_onibus

        return onibus_diarios.copy()

    vagas_ofertadas_totais = 0
    for linha in estado.linhas_entradas:
        destino, horario = estado.linhas_entradas[linha][:2]
        nome_linha = '%s-%s' % (destino.upper(), fm.form_tempo(horario))
        monitoradas.arrecadado[linha] = monitoradas.arrecadado.get(linha, 0)
        quantia = monitoradas.arrecadado[linha] / 100
        total_arrecadado += quantia
        treeview_arrecadado.insert(
            '',
            0,
            linha,
            values=(nome_linha, fm.separar_milhares_decimal(quantia)))
        onibus_diarios = onibus_por_dia(linha)
        capacidade_linha = estado.linhas_entradas[linha].fileiras * 2
        vagas_ofertadas_totais += sum(onibus_diarios) * capacidade_linha
        # print(f'Ônibus diários: {onibus_diarios}\nCapacidade linha: {capacidade_linha}')
        monitoradas.ocupacao_media_semanal[linha] = [
            linha_dia_reservas.get(linha, {d: 0})[d] /
            (onibus_diarios[d] * capacidade_linha)
            if onibus_diarios[d] != 0 else 0 for d in range(7)
        ]
        treeview_ocupacao.insert(
            '',
            0,
            linha,
            values=(nome_linha, *map(
                lambda x: '%s%%' % fm.separar_milhares_decimal(100 * x),
                monitoradas.ocupacao_media_semanal[linha])))
    painel_ocupacao['text'] = form_ocupacao(
        100 * len(estado.reservas) /
        vagas_ofertadas_totais if vagas_ofertadas_totais != 0 else 0)

    painel_arrecadado['text'] = form_arrecadado(total_arrecadado)