def descadastrar_linhas(app, dados): actions = 0 reservas_changed = False for dados_linha, reservas in dados: linha = gerar_id_linha(*dados_linha[:2]) for reserva in reservas: estado.reservas.discard(reserva) app.reservas.delete(reserva) reservas_changed = True app.contador_reservas['text'] = fm.form_cont_reservas( len(estado.reservas)) t = minutos_dia(dados_linha.horario) del estado.linhas_entradas[linha] estado.linhas_possiveis.add((dados_linha.destino.title(), t)) estado.horarios_linhas[t].remove(linha) estado.linhas_visiveis.remove(linha) app.contador_linhas['text'] = fm.form_cont_linhas( len(estado.linhas_visiveis)) onibus_filhos = dados_linha.onibus.keys() monitoradas.onibus_visiveis -= onibus_filhos estado.onibus_invisiveis -= onibus_filhos app.contador_onibus['text'] = fm.form_cont_onibus( len(monitoradas.onibus_visiveis)) app.linhas.delete(linha) actions += 1 if not reservas_changed: app.abas.select(app.aba_linhas) return actions
def csv_to_linha(app, linha, data_atual=monitoradas.data_atual): ''' Cria e retorna um wrapper sobre a linha com base na string linha. Aqui está o formato do wrapper: atributos = { 'validez': valor_booleano, 'texto': 'Ok', 'id': id_da_linha, 'campus': campus, 'horario': horario, 'fileiras': fileiras, 'inteira': inteira } Mas as propriedades são acessíveis pela sintaxe de objeto (wrapper.validez) em vez da sintaxe de dict (wrapper['validez']) Caso a reserva não seja válida, essa função verifica o erro e coloca uma mensagem de erro na propriedade "texto" do wrapper, além de atribuir False para a propriedade "validez". ''' # note que type('', (), DICIONARIO) é utilizado para que possamos nos referir às propriedades com a sintaxe de # objeto, em vez da sintaxe de dicionário. # Ou seja, podemos usar OBJETO.PROPRIEDADE em vez de DICIONARIO['PROPRIEDADE'], o que ajuda no desenvolvimento, # já que a IDE é capaz de detectar propriedades inexistentes antes mesmo de o código rodar. try: campus, horario, assentos, inteira = map( str.strip, linha.split(',', 4)[:4]) except ValueError: return type('', (), {'validez': False, 'texto': 'quantidade insuficiente de campos, esperava-se 4'}) campus = campus.replace('-', ' ').strip() if campus == '': return type('', (), {'validez': False, 'texto': 'destino vazio'}) try: horario = dt.datetime.strptime(horario, '%H:%M') except ValueError: return type('', (), {'validez': False, 'texto': f'horário não segue formato previsto: {data_atual.strftime("%H:%M")}'}) try: fileiras = int(assentos)//2 if fileiras not in range(1, cte.MAXIMO_NUMERO_DE_FILEIRAS + 1): return type('', (), {'validez': False, 'texto': f'número máximo de assentos livres fora do intervalo previsto: [1, {cte.MAXIMO_NUMERO_DE_FILEIRAS*4}]'}) except ValueError: return type('', (), {'validez': False, 'texto': f'número máximo de assentos livres não é inteiro em [1, {4*cte.MAXIMO_NUMERO_DE_FILEIRAS}]'}) try: inteira = round(float(inteira)*100 - 300) if inteira not in range(301): return type('', (), {'validez': False, 'texto': f'valor inteira fora do intervalo previsto: [3.0, 6.0]'}) except ValueError: return type('', (), {'validez': False, 'texto': f'valor inteira não é float em [3.0, 6.0]'}) linha = gerar_id_linha(campus, horario) if linha in estado.linhas_visiveis: return type('', (), {'validez': False, 'texto': 'linha existente'}) elif linha in estado.linhas_entradas: return type('', (), {'validez': False, 'texto': 'linha desabilitada'}) atributos = {'validez': True, 'texto': 'Ok', 'id': linha, 'campus': campus, 'horario': horario, 'fileiras': fileiras, 'inteira': inteira} return type('linha', (), atributos)
def adicionar_linha(app): ''' Adiciona uma linha com base nos campos de texto. ''' # lemos todos os campos de texto campos = [ dest.atualizar_destino(), date.update(app), vg.atualizar_vagas(), it.atualizar_inteira() ] for campo in campos: if popup.campos_invalidos[campo](): return # aqui, todos os campos de texto possuem valores válidos, então vamos criar a linha linhas = app.linhas destino = monitoradas.destino.get() tempo_exibido = monitoradas.tempo_exibido vagas = monitoradas.vagas.get() inteira = monitoradas.inteira.get() linha = gerar_id_linha(destino, tempo_exibido) # antes de inseri-la graficamente, temos que verificar se ela já existe if linha in estado.linhas_entradas: # Linha desabilitada. Deseja reabilitá-la? if linha not in estado.linhas_visiveis: texto = 'Linha desabilitada, deseja reabilitá-la?.' resposta = messagebox.askyesno(title='Linha existe', message=texto, default='yes') if resposta: app.linhas.reattach(linha, '', 0) estado.linhas_visiveis.add(linha) onibus_filhos_visiveis = set(app.linhas.get_children(linha)) estado.onibus_invisiveis -= onibus_filhos_visiveis monitoradas.onibus_visiveis.update(onibus_filhos_visiveis) ctrl.update_action(app, 'Restaurar') monitoradas.historico_redo.clear() monitoradas.historico_undo.append(['show', [0], [linha]]) app.linhas.selection_set(linha) app.contador_linhas['text'] = fm.form_cont_linhas( len(estado.linhas_visiveis)) app.contador_onibus['text'] = fm.form_cont_onibus( len(monitoradas.onibus_visiveis)) # nova ação: reabilitar else: app.linhas.see(linha) app.linhas.selection_set(linha) return h = minutos_dia(tempo_exibido) estado.linhas_possiveis.discard((destino, h)) estado.horarios_linhas[h] = estado.horarios_linhas.get(h, set()).union( {linha}) dest.add_destino(app) ctrl.update_action(app, 'add') linhas.insert(parent='', index=0, values=(destino, fm.form_tempo(tempo_exibido), vagas, inteira), iid=linha) estado.linhas_visiveis.add(linha) app.contador_linhas['text'] = fm.form_cont_linhas( len(estado.linhas_visiveis)) estado.linhas_entradas[linha] = cte.ESTRUTURA_LINHA( destino, tempo_exibido, int(vagas) // 2, round(float(inteira) * 100 - 300), dict()) data_atual = monitoradas.data_atual.replace(second=0, microsecond=0) for d in range(cte.MAXIMO_NUMERO_DE_DIAS_ATE_RESERVA + 1): partida = (data_atual + dt.timedelta(d)).replace( hour=tempo_exibido.hour, minute=tempo_exibido.minute) if data_atual <= partida <= data_atual + dt.timedelta( cte.MAXIMO_NUMERO_DE_DIAS_ATE_RESERVA): onibus = gerar_id_onibus(linha, partida) linhas.insert(parent=linha, index='end', values=('-', fm.form_data(partida), vagas, '-'), iid=onibus) monitoradas.onibus_visiveis.add(onibus) estado.linhas_entradas[linha].onibus[onibus] = dict() app.contador_onibus['text'] = fm.form_cont_onibus( len(monitoradas.onibus_visiveis)) app.contador_linhas['text'] = fm.form_cont_linhas( len(estado.linhas_visiveis)) app.contador_onibus['text'] = fm.form_cont_onibus( len(monitoradas.onibus_visiveis)) historico_undo = monitoradas.historico_undo historico_redo = monitoradas.historico_redo historico_redo.clear() historico_undo.append(['add', [[estado.linhas_entradas[linha], list()]]]) linhas.selection_set(linha)
def editar_linha(app): ''' Edita informações sobre uma linha. ''' selecao = app.linhas.selection() if len(selecao) != 1 or app.linhas.parent(selecao[0]) != '': texto = 'Selecione uma única linha.' messagebox.showwarning(title='Impossível Editar', message=texto) return [linha] = selecao dados_linha = estado.linhas_entradas[linha] # a condição a seguir é True sse existe algum ônibus com reservas na linha selecionada. if any(len(x) != 0 for x in dados_linha.onibus.values()): texto = 'Linha possui reservas.' messagebox.showwarning(title='Impossível Editar', message=texto) return campos = [ dest.atualizar_destino(), date.update(app), vg.atualizar_vagas(), it.atualizar_inteira() ] for campo in campos: if popup.campos_invalidos[campo](): return destino_alterada = monitoradas.destino.get() tempo_exibido = monitoradas.tempo_exibido vagas_alterada = monitoradas.vagas.get() inteira_alterada = monitoradas.inteira.get() linha_alterada = gerar_id_linha(destino_alterada, tempo_exibido) h = minutos_dia(estado.linhas_entradas[linha].horario) if linha_alterada in estado.linhas_entradas: if linha_alterada in estado.linhas_visiveis: if linha != linha_alterada: texto = 'Linha já existe.' messagebox.showwarning(title='Impossível Editar', message=texto) elif dados_linha[2:4] != [ int(vagas_alterada) // 2, round(float(inteira_alterada) * 100 - 300) ]: dados_linha_alterada = estado.linhas_entradas[ linha] = cte.ESTRUTURA_LINHA( *dados_linha[:2], int(vagas_alterada) // 2, round(float(inteira_alterada) * 100 - 300), dados_linha[-1]) app.linhas.item( linha, values=campos_linha_formatados(dados_linha_alterada)) app.linhas.selection_set(linha_alterada) monitoradas.historico_redo.clear() monitoradas.historico_undo.append( ['change', dados_linha, dados_linha_alterada, False]) app.contador_linhas['text'] = fm.form_cont_linhas( len(estado.linhas_visiveis)) app.contador_onibus['text'] = fm.form_cont_onibus( len(monitoradas.onibus_visiveis)) else: texto = 'Linha desabilitada, deseja reabilitá-la?' resposta = messagebox.askyesno(title='Impossível Editar', message=texto, default='no') if resposta: app.linhas.reattach(linha_alterada, '', app.linhas.index(linha)) app.linhas.item(linha_alterada, open=app.linhas.item(linha, 'open')) estado.linhas_visiveis.add(linha_alterada) onibus_filhos_visiveis = set( app.linhas.get_children(linha_alterada)) estado.onibus_invisiveis -= onibus_filhos_visiveis monitoradas.onibus_visiveis.update(onibus_filhos_visiveis) ctrl.update_action(app, 'Restaurar') estado.horarios_linhas[h].remove(linha) app.linhas.delete(linha) estado.linhas_visiveis.remove(linha) for onibus in estado.linhas_entradas[linha].onibus: monitoradas.onibus_visiveis.discard(onibus) estado.onibus_invisiveis.discard(onibus) monitoradas.historico_redo.clear() monitoradas.historico_undo.append([ 'change', estado.linhas_entradas[linha], estado.linhas_entradas[linha_alterada], True ]) estado.linhas_possiveis.add((dados_linha.destino.title(), h)) del estado.linhas_entradas[linha] app.linhas.selection_set(linha_alterada) app.contador_linhas['text'] = fm.form_cont_linhas( len(estado.linhas_visiveis)) app.contador_onibus['text'] = fm.form_cont_onibus( len(monitoradas.onibus_visiveis)) return h_alt = tempo_exibido.hour * 60 + tempo_exibido.minute estado.linhas_possiveis.remove((destino_alterada, h_alt)) estado.linhas_possiveis.add((dados_linha.destino.title(), h)) estado.horarios_linhas[h].remove(linha) estado.horarios_linhas[h_alt] = estado.horarios_linhas.get( h_alt, set()).union({linha_alterada}) dest.add_destino(app) ctrl.update_action(app, 'change') indice = app.linhas.index(linha) app.linhas.insert(parent='', index=indice, values=(destino_alterada, fm.form_tempo(tempo_exibido), vagas_alterada, inteira_alterada), iid=linha_alterada, open=app.linhas.item(linha, 'open')) app.linhas.delete(linha) estado.linhas_visiveis.remove(linha) estado.linhas_visiveis.add(linha_alterada) onibus_filhos = dict() data_atual = monitoradas.data_atual.replace(second=0, microsecond=0) for d in range(cte.MAXIMO_NUMERO_DE_DIAS_ATE_RESERVA + 1): partida = (data_atual + dt.timedelta(d)).replace( hour=tempo_exibido.hour, minute=tempo_exibido.minute) if data_atual <= partida <= data_atual + dt.timedelta( cte.MAXIMO_NUMERO_DE_DIAS_ATE_RESERVA): onibus = gerar_id_onibus(linha_alterada, partida) app.linhas.insert(parent=linha_alterada, index='end', values=('-', fm.form_data(partida), vagas_alterada, '-'), iid=onibus) monitoradas.onibus_visiveis.add(onibus) onibus_filhos[onibus] = dict() estado.linhas_entradas[linha_alterada] = cte.ESTRUTURA_LINHA( destino_alterada, tempo_exibido, int(vagas_alterada) // 2, round(float(inteira_alterada) * 100 - 300), onibus_filhos) for onibus in estado.linhas_entradas[linha].onibus: monitoradas.onibus_visiveis.discard(onibus) estado.onibus_invisiveis.discard(onibus) monitoradas.historico_redo.clear() monitoradas.historico_undo.append([ 'change', estado.linhas_entradas[linha], estado.linhas_entradas[linha_alterada], False ]) del estado.linhas_entradas[linha] app.contador_linhas['text'] = fm.form_cont_linhas( len(estado.linhas_visiveis)) app.contador_onibus['text'] = fm.form_cont_onibus( len(monitoradas.onibus_visiveis)) ctrl.update_action(app, 'change') app.linhas.selection_set(linha_alterada)
def csv_to_reserva(app, linha, data_presente=monitoradas.data_atual, data_maxima=monitoradas.data_atual + dt.timedelta(cte.MAXIMO_NUMERO_DE_DIAS_ATE_RESERVA)): ''' Cria e retorna um wrapper sobre a reserva com base na string linha. Aqui está o formato do wrapper: wrapper = { 'validez': valor_booleano, 'texto': 'Ok', 'reserva': id_da_reserva, 'campus': id_do_campus, 'partida': partida, 'assento': assento, 'passagem': passagem, 'inteira': inteira, 'linha': id_da_linha, 'onibus': id_do_onibus } Mas as propriedades são acessíveis pela sintaxe de objeto (wrapper.validez) em vez da sintaxe de dict (wrapper['validez']) Caso a reserva não seja válida, essa função verifica o erro e coloca uma mensagem de erro na propriedade "texto" do wrapper, além de atribuir False para a propriedade "validez". ''' # note que type('', (), DICIONARIO) é utilizado para que possamos nos referir às propriedades com a sintaxe de # objeto, em vez da sintaxe de dicionário. # Ou seja, podemos usar OBJETO.PROPRIEDADE em vez de DICIONARIO['PROPRIEDADE'], o que ajuda no desenvolvimento, # já que a IDE é capaz de detectar propriedades inexistentes antes mesmo de o código rodar. try: campus, partida, assento, * \ passagem = map(str.strip, linha.split(',', 4)[:4]) except ValueError: return type('', (), {'validez': False, 'texto': 'quantidade insuficiente de campos, esperava-se ao menos 3'}) campus = campus.replace('-', ' ').strip() if campus == '': return type('', (), {'validez': False, 'texto': 'destino vazio'}) try: partida = dt.datetime.strptime(partida, '%d/%m/%y %H:%M') if not data_presente <= partida <= data_maxima: return type('', (), {'validez': False, 'texto': 'data fora do intervalo previsto'}) except ValueError: return type('', (), {'validez': False, 'texto': f'data não segue formato previsto: {data_maxima.strftime("%d/%m/%y %H:%M")}'}) try: assento = int(assento) if assento not in range(1, 4*cte.MAXIMO_NUMERO_DE_FILEIRAS + 1): return type('', (), {'validez': False, 'texto': 'assento fora do intervalo previsto'}) except ValueError: return type('', (), {'validez': False, 'texto': f'assento não é inteiro em [1, {4*cte.MAXIMO_NUMERO_DE_FILEIRAS}]'}) if passagem == []: passagem = cte.PASSAGEM_INDICE['inteira'] else: passagem = cte.PASSAGEM_INDICE.get(passagem[0].lower(), None) if passagem is None: return type('', (), {'validez': False, 'texto': 'tipo de passagem inválida'}) linha = gerar_id_linha(campus, partida) if linha not in estado.linhas_entradas: return type('', (), {'validez': False, 'texto': 'linha inexistente'}) elif linha not in estado.linhas_visiveis: return type('', (), {'validez': False, 'texto': 'linha desabilitada'}) onibus = gerar_id_onibus(linha, partida) if onibus in estado.onibus_invisiveis: return type('', (), {'validez': False, 'texto': 'ônibus desabilitado'}) if assento in estado.linhas_entradas[linha].onibus[onibus]: return type('', (), {'validez': False, 'texto': 'assento reservado'}) num_fileiras = estado.linhas_entradas[linha].fileiras shift = (sum(coordenadas_assento(assento, num_fileiras)) + 1) % 2 assentos_indisponiveis = {assento_coordenadas( i, 2 * j + (i + shift) % 2, num_fileiras) for j in range(2) for i in range(num_fileiras)} if assento in assentos_indisponiveis: return type('', (), {'validez': False, 'texto': 'assento indisponível'}) reserva = gerar_id_reserva(onibus, assento, passagem) inteira = estado.linhas_entradas[linha].inteira atributos = {'validez': True, 'texto': 'Ok', 'reserva': reserva, 'campus': campus, 'partida': partida, 'assento': assento, 'passagem': passagem, 'inteira': inteira, 'linha': linha, 'onibus': onibus} return type('reserva', (), atributos)
def mudar(app, dados_anterior, dados_alterada, existia): app.abas.select(app.aba_linhas) linha_anterior = gerar_id_linha(*dados_anterior[:2]) linha_alterada = gerar_id_linha(*dados_alterada[:2]) if linha_anterior == linha_alterada: app.linhas.item(linha_anterior, values=campos_linha_formatados(dados_alterada)) app.linhas.selection_set(linha_alterada) app.contador_linhas['text'] = fm.form_cont_linhas( len(estado.linhas_visiveis)) app.contador_onibus['text'] = fm.form_cont_onibus( len(monitoradas.onibus_visiveis)) return 1 indice = app.linhas.index(linha_anterior) expanded = app.linhas.item(linha_anterior, 'open') t = minutos_dia(dados_anterior.horario) estado.horarios_linhas[t].remove(linha_anterior) estado.linhas_visiveis.remove(linha_anterior) onibus_filhos = dados_anterior.onibus.keys() monitoradas.onibus_visiveis -= onibus_filhos estado.onibus_invisiveis -= onibus_filhos del estado.linhas_entradas[linha_anterior] app.linhas.delete(linha_anterior) estado.linhas_possiveis.add((dados_anterior.destino.title(), t)) if existia: app.linhas.reattach(linha_alterada, '', indice) app.linhas.item(linha_alterada, open=expanded) estado.linhas_visiveis.add(linha_alterada) onibus_filhos_visiveis = set(app.linhas.get_children(linha_alterada)) estado.onibus_invisiveis -= onibus_filhos_visiveis monitoradas.onibus_visiveis.update(onibus_filhos_visiveis) else: t = minutos_dia(dados_alterada.horario) assentos = dados_alterada.fileiras * 2 estado.horarios_linhas[t] = estado.horarios_linhas.get(t, set()).union( {linha_alterada}) app.linhas.insert(parent='', index=indice, values=campos_linha_formatados(dados_alterada), iid=linha_alterada, open=expanded) estado.linhas_visiveis.add(linha_alterada) estado.linhas_possiveis.remove((dados_alterada.destino.title(), t)) estado.linhas_entradas[linha_alterada] = cte.ESTRUTURA_LINHA( *dados_alterada[:-1], dict()) data_atual = monitoradas.data_atual.replace(second=0, microsecond=0) for d in range(cte.MAXIMO_NUMERO_DE_DIAS_ATE_RESERVA + 1): partida = (data_atual + dt.timedelta(d)).replace( hour=dados_alterada.horario.hour, minute=dados_alterada.horario.minute) if data_atual <= partida <= data_atual + dt.timedelta( cte.MAXIMO_NUMERO_DE_DIAS_ATE_RESERVA): onibus = gerar_id_onibus(linha_alterada, partida) app.linhas.insert(parent=linha_alterada, index='end', values=('-', fm.form_data(partida), assentos, '-'), iid=onibus) monitoradas.onibus_visiveis.add(onibus) estado.linhas_entradas[linha_alterada].onibus[onibus] = dict() app.contador_onibus['text'] = fm.form_cont_onibus( len(monitoradas.onibus_visiveis)) app.contador_linhas['text'] = fm.form_cont_linhas( len(estado.linhas_visiveis)) app.linhas.selection_set(linha_alterada) return 1
def recadastrar_linhas(app, dados): actions = 0 reservas_changed = False app.linhas.selection_set(*[]) app.reservas.selection_set(*[]) for dados_linha, reservas in dados: linha = gerar_id_linha(*dados_linha[:2]) estado.linhas_entradas[linha] = cte.ESTRUTURA_LINHA( *dados_linha[:-1], dict()) for reserva in reservas: estado.reservas.add(reserva) app.reservas.insert(parent='', index=0, values=campos_reserva_formatados(reserva), iid=reserva) reservas_changed = True app.contador_reservas['text'] = fm.form_cont_reservas( len(estado.reservas)) t = minutos_dia(dados_linha.horario) estado.linhas_possiveis.remove((dados_linha.destino.title(), t)) estado.horarios_linhas[t] = estado.horarios_linhas.get(t, set()).union( {linha}) estado.linhas_visiveis.add(linha) app.contador_linhas['text'] = fm.form_cont_linhas( len(estado.linhas_visiveis)) app.linhas.insert(parent='', index=0, values=campos_linha_formatados(dados_linha), iid=linha) data_atual = monitoradas.data_atual.replace(second=0, microsecond=0) minutos_atual = data_atual.hour * 60 + data_atual.minute if t == minutos_atual: periodo = range(cte.MAXIMO_NUMERO_DE_DIAS_ATE_RESERVA + 1) elif t < minutos_atual: periodo = range(1, cte.MAXIMO_NUMERO_DE_DIAS_ATE_RESERVA + 1) else: periodo = range(cte.MAXIMO_NUMERO_DE_DIAS_ATE_RESERVA) for d in periodo: partida = (data_atual + dt.timedelta(d)).replace( hour=dados_linha.horario.hour, minute=dados_linha.horario.minute) onibus = gerar_id_onibus(linha, partida) assentos = dados_linha.onibus.get(onibus, dict()) app.linhas.insert( parent=linha, index='end', values=('-', fm.form_data(partida), 2 * int(dados_linha.fileiras) - len(assentos), '-'), iid=onibus) monitoradas.onibus_visiveis.add(onibus) app.contador_onibus['text'] = fm.form_cont_onibus( len(monitoradas.onibus_visiveis)) estado.linhas_entradas[linha].onibus[onibus] = assentos app.linhas.selection_add(linha) app.reservas.selection_add(*reservas) actions += 1 if not reservas_changed: app.abas.select(app.aba_linhas) return actions