|
|
| (317 intermediate revisions by the same user not shown) |
| Line 1: |
Line 1: |
| {{PRJPOAvisosEN20222023}}
| | #REDIRECT [[Programação com Objectos/Projecto de Programação com Objectos/Enunciado do Projecto de 2022-2023]] |
| {{PRJPOMandatory20222023}}
| |
| {{TOCright}}
| |
| '''<font color="red">EM PREPARAÇÃO</font>'''
| |
| | |
| '''<font color="red">ÉPOCA NORMAL</font>'''
| |
| | |
| O objectivo do projecto e desenvolver um gestor de uma rede de terminais de comunicação, denominado por '''prr'''. Genericamente, o programa permite a gestão e consulta de clientes, terminais e comunicações.
| |
| | |
| Especificamente, o sistema disponibiliza aos seus gestores varios serviços, entre outros: (i) registar dados sobre os clientes; (ii) registar dados sobre os terminais; (iii) registar dados sobre comunicações efectuadas; (iv) fazer pesquisas sobre comunicações efectuadas; (v) contabilizar o saldo associado a terminais.
| |
| | |
| = Clientes, terminais, comunicações, planos tarifários =
| |
| | |
| Os utilizadores podem ter vários terminais, cada um deles associado a um número e a um plano tarifário. Nos pontos seguintes, descrevem-se as propriedades de cada entidade da aplicação.
| |
| | |
| Os clientes, terminais e comunicações possuem chaves únicas, uma cadeia de caracteres para os clientes e um inteiro para os terminais e para as comunicações.
| |
| | |
| == Propriedades e funcionalidade dos clientes ==
| |
| | |
| Cada cliente, para além da chave única, é identificado pelo nome (cadeia de caracteres) e número de identificação fiscal (inteiro).
| |
| | |
| Existem três tipos de clientes: '''Normal''' (situação inicial, após o registo), '''Ouro''' e '''Platina'''. O custo das comunicações está indexado ao tipo de cliente (ver [[#Planos tarifários|planos tarifários]]). Um cliente transita de tipo nas seguintes condições:
| |
| | |
| {|
| |
| | '''Antes'''
| |
| | '''Depois'''
| |
| | '''Condições'''
| |
| |-
| |
| | Normal
| |
| | Ouro
| |
| | o saldo (após realizar um pagamento) é superior a 500 cêntimos
| |
| |-
| |
| | Normal
| |
| | Platina
| |
| | (não é possível)
| |
| |-
| |
| | Ouro
| |
| | Normal
| |
| | o saldo (após realizar uma comunicação) é inferior a 0 cêntimos
| |
| |-
| |
| | Ouro
| |
| | Platina
| |
| | após realizar 5 comunicações consecutivas do tipo MMS (a contabilização da 5ª comunicação ainda considera que o cliente é do tipo Ouro)
| |
| |-
| |
| | Platina
| |
| | Ouro
| |
| | após realizar 2 comunicações consecutivas do tipo SMS (a contabilização da 2ª comunicação ainda considera que o cliente é do tipo Platina)
| |
| |-
| |
| | Platina
| |
| | Normal
| |
| | tentativa de realizar uma comunicação MMS para um terminal 2G
| |
| |}
| |
| | |
| == Propriedades e funcionalidade dos terminais ==
| |
| | |
| Os terminais são identificados por um número (exactamente 6 dígitos) e estão associados a um cliente. Cada terminal pode estar ligado, em silêncio, ou desligado. Neste último caso, não é permitido iniciar ou receber comunicações. Quando o terminal está em silêncio, pode iniciar qualquer tipo de comunicação, mas só pode receber comunicações de texto. Cada terminal tem uma contabilidade própria, sendo sempre possível saber o saldo que lhe está associado.
| |
| | |
| Os terminais 2G só conseguem realizar comunicações SMS e de VOZ, não podendo nem iniciar nem receber comunicações MMS. Quando um terminal está em silêncio, não pode receber comunicações de VOZ ou MMS.
| |
| | |
| Para promover as comunicações, quando uma comunicação não se efectua por o terminal de destino estar em silêncio ou desligado, regista-se a tentativa de contacto, para que, assim que seja possível a realização do contacto pretendido, se enviarem mensagens aos terminais de origem. O registo da tentativa de contactos só tem lugar quando o cliente do terminal de destino tem activa a recepção de contactos falhados no instante em que se tentou efectuar a comunicação (que não teve lugar por o terminal de destino o não permitir).
| |
| | |
| == Propriedades das comunicações ==
| |
| | |
| Cada comunicação, além do identificador único, possui ainda informação sobre o terminal que a originou, o terminal de destino, a sua duração (no caso do texto, esta duração é zero) e o tipo de comunicação (voz, texto ou vídeo). A primeira comunicação tem como identificador “1”, devendo o identificador das comunicações subsequentes ser obtido por incremento unitário do identificador anterior.
| |
| | |
| Existem 3 tipos de comunicação entre terminais: texto (denominada SMS), voz (denominada VOZ) e vídeo (denominada MMS). O custo das comunicações não é uniforme (ver [[#Planos tarifários|Planos tarifários]]), dependendo do terminal e do cliente, entre outros factores. Também dependendo do cliente, é possível avisar quem o tentou contactar quando: (i) um terminal desligado é colocado em silêncio; (ii) um terminal desligado é ligado; ou (iii) um terminal em silêncio é ligado.
| |
| | |
| == Planos tarifários ==
| |
| | |
| Os custos de uma comunicação dependem do tipo de utilizador que inicia a comunicação e do tipo da comunicação: SMS, VOZ ou MMS.
| |
| | |
| Quando é efectuada uma comunicação do tipo SMS, o custo ou é fixo ou depende do número (representado na tabela por '''N''') de caracteres enviados:
| |
| | |
| {|
| |
| |
| |
| | '''Normal'''
| |
| | '''Ouro'''
| |
| | '''Platina'''
| |
| |-
| |
| | '''N''' < 50 caracteres
| |
| | 10 cêntimos
| |
| | 10 cêntimos
| |
| | 0 cêntimos
| |
| |-
| |
| | 50 caracteres <= '''N''' < 100 caracteres
| |
| | 16 cêntimos
| |
| | 10 cêntimos
| |
| | 4 cêntimos
| |
| |-
| |
| | '''N''' >= 100 caracteres
| |
| | 2 * '''N''' cêntimos
| |
| | 2 * '''N''' cêntimos
| |
| | 4 cêntimos
| |
| |}
| |
| | |
| Quando é efectuada uma comunicação do tipo VOZ ou MMS, o custo é proporcional ao tempo de conversação e quando se liga para um terminal registado como amigo é aplicado um desconto de 50%. O custo, em cêntimos por minuto, é o seguinte para terminais não registados como amigos:
| |
| | |
| {|
| |
| |
| |
| | '''Normal'''
| |
| | '''Ouro'''
| |
| | '''Platina'''
| |
| |-
| |
| | VOZ
| |
| | 20 cêntimos
| |
| | 10 cêntimos
| |
| | 10 cêntimos
| |
| |-
| |
| | MMS
| |
| | 30 cêntimos
| |
| | 20 cêntimos
| |
| | 10 cêntimos
| |
| |}
| |
| | |
| Por questões fiscais, todos os cálculos envolvendo os custos das comunicações devem ser apresentados em cêntimos, não sendo possível fazer arredondamentos. Por exemplo, uma comunicação de VOZ que dure 6 minutos tem um custo de 120 cêntimos para um cliente Normal e 60 cêntimos para clientes Ouro ou Platina.
| |
| | |
| = Funcionalidade da aplicação =
| |
| | |
| A aplicação permite manter informação sobre as entidades do modelo. Possui ainda a capacidade de preservar o seu estado (não é possível manter várias versões do estado da aplicação em simultâneo).
| |
| | |
| Deve ser possível efectuar pesquisas sujeitas a vários critérios e sobre as diferentes entidades geridas pela aplicação.
| |
| | |
| A base de dados com os conceitos pré-definidos é [[#Leitura de Dados a Partir de Ficheiros Textuais|carregada no início da aplicação]].
| |
| | |
| {{Suggestion|Note-se que não é necessário/desejável implementar de raiz a aplicação: já existem classes que representam e definem a interface geral da funcionalidade do ''core'' da aplicação, tal como é visível pelos comandos da aplicação.}}
| |
| {{CVSCode|A interface geral do ''core'' já está parcialmente implementada na classe '''prr.Manager''' e outras fornecidas (cujos nomes devem ser mantidos), devendo ser adaptadas onde necessário. É ainda necessário criar e implementar as restantes classes que suportam a operação da aplicação.}}
| |
| | |
| == Serialização ==
| |
| | |
| É possível guardar e recuperar o estado actual da aplicação, preservando toda a informação relevante, descrita [[#Conceitos e Relações do Modelo|acima]].
| |
| | |
| == Funcionalidade Associada a Entidades do Domínio ==
| |
| | |
| === Funcionalidade associadas aos clientes ===
| |
| A seguinte funcionalidade sobre clientes deve ser suportada pela aplicação: (i) visualizar um cliente; (ii) registar um novo cliente; (iii) permitir o registo de contactos falhados; (iv) inibir o registo de contactos falhados; (v) calcular o saldo de um cliente.
| |
| | |
| Um cliente não pode ser removido, sendo sempre possível aceder a todo o seu historial.
| |
| | |
| === Funcionalidade associadas aos terminais ===
| |
| A seguinte funcionalidade sobre terminais deve ser suportada pela aplicação: (i) visualizar um terminal; (ii) registar um novo terminal; (iii) ligar, desligar e colocar no silêncio um terminal; (iv) adicionar e remover telefones da lista dos telefones amigos de um terminal; (v) proceder a um pagamento; (vi) calcular o saldo de um terminal.
| |
| | |
| Um terminal não pode ser removido, sendo sempre possível aceder a todo o seu historial.
| |
| | |
| === Funcionalidade associada a comunicações ===
| |
| A seguinte funcionalidade de pesquisa deve ser suportada: (i) comunicações efectuadas por um cliente; (ii) terminais que iniciaram comunicações para um determinado terminal; (iii) terminais que iniciaram uma comunicação para um determinado cliente; (iv) terminais com um determinado plano tarifário; (v) clientes com pagamentos em atraso.
| |
| | |
| = Requisitos de Desenho =
| |
|
| |
| Devem ser possíveis extensões ou alterações de funcionalidade com impacto mínimo no código já produzido para a aplicação. O objectivo é aumentar a flexibilidade da aplicação relativamente ao suporte de novas funções. Assim, deve ser possível:
| |
| * Definir novos tipos de clientes;
| |
| * Definir novos tipos de comunicação;
| |
| * Adicionar novos planos tarifários;
| |
| * Adicionar novas políticas de facturação;
| |
| * Adicionar novas políticas de avisos;
| |
| * Adicionar novas formas de pesquisa;
| |
| * Permitir a gestão de várias redes de terminais.
| |
| | |
| Embora na especificação actual não seja possível remover entidades, a inclusão desta funcionalidade deve ser prevista, por forma a minimizar o impacto da sua futura inclusão.
| |
| | |
| = Interacção com o utilizador =
| |
| | |
| Descreve-se nesta secção a '''funcionalidade máxima''' da interface com o utilizador. Em geral, os comandos pedem toda a informação antes de procederem à sua validação (excepto onde indicado). Todos os menus têm automaticamente a opção '''Sair''' (fecha o menu).
| |
| | |
| As operações de pedido e apresentação de informação ao utilizador '''devem''' realizar-se através dos objectos ''form'' e ''display'', respectivamente, presentes em cada comando. As mensagens são produzidas pelos métodos das [[Programação com Objectos/Projecto de Programação com Objectos/Material de Apoio ao Desenvolvimento|bibliotecas de suporte]] ('''po-uilib''' e '''prr-app'''). As mensagens não podem ser usadas no núcleo da aplicação ('''prr-core'''). Além disso, não podem ser definidas novas. Potenciais omissões devem ser esclarecidas antes de qualquer implementação.
| |
| | |
| A apresentação de valores monetários (preços, saldos, etc.) é sempre feita com arredondamento ao inteiro mais próximo (note-se que a representação interna não deve ser arredondada).
| |
| | |
| As excepções usadas na interacção (subclasses de '''pt.tecnico.uilib.menus.CommandException'''), excepto se indicado, são lançadas pelos comandos (subclasses de '''pt.tecnico.uilib.menus.Command''') e tratadas pelos menus (instâncias de subclasses de '''pt.tecnico.uilib.menus.Menu'''). Outras excepções não devem substituir as fornecidas nos casos descritos.
| |
| | |
| A apresentação de listas de entidades do domínio (clientes, etc.) faz-se por ordem crescente da respectiva chave: dependendo dos casos, a ordem pode ser numérica ou lexicográfica (UTF-8), não havendo distinção entre maiúsculas e minúsculas.
| |
| | |
| {{CVSCode|Note-se que o programa principal e os comandos e menus, a seguir descritos, já estão parcialmente implementados nas ''packages'' '''prr.app''', '''prr.app.main''', '''prr.app.clients''', '''ggc.app.terminals''', '''prr.app.communications''', '''prr.app.lookups'''. Estas classes são de uso obrigatório e estão disponíveis no [[Programação com Objectos/Projecto de Programação com Objectos/Repositório CVS|CVS]] (módulo '''prr-app''').}}
| |
| | |
| == Menu Principal ==
| |
| | |
| As acções deste menu permitem gerir a salvaguarda do estado da aplicação, abrir submenus e aceder a alguma informação global. A lista completa é a seguinte: [[#Salvaguarda do estado actual da aplicação|Abrir]], [[#Salvaguarda do estado actual da aplicação|Guardar]], [[#Mostrar data actual|Mostrar data actual]], [[#Avançar data actual|Avançar data actual]], [[#Gestão e consulta de dados da aplicação|Gestão de Produtos]], [[#Gestão e consulta de dados da aplicação|Gestão de Parceiros]], [[#Gestão e consulta de dados da aplicação|Gestão de Transacções]], [[#Gestão e consulta de dados da aplicação|Consultas]], [[#Menu Principal|Mostrar Saldo Global]].
| |
| | |
| As etiquetas das opções deste menu estão definidas na classe '''ggc.app.main.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''ggc.app.main.Message'''.
| |
| | |
| {{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''ggc.app.main''' (disponível no CVS), respectivamente: '''DoOpenFile''', '''DoSaveFile''', '''DoDisplayDate''', '''DoAdvanceDate''', '''DoShowGlobalBalance'''.}}
| |
| | |
| === Salvaguarda do estado actual da aplicação ===
| |
| | |
| Inicialmente, a aplicação está vazia ou tem apenas informação sobre as entidades que foram carregados no arranque (via [[#Leitura de Dados a Partir de Ficheiros Textuais|ficheiro textual]]).
| |
| | |
| O conteúdo da aplicação (toda a informação actualmente em memória) pode ser guardado para posterior recuperação (via serialização Java: '''java.io.Serializable'''). Na leitura e escrita do estado da aplicação, devem ser tratadas as excepções associadas. A funcionalidade é a seguinte:
| |
| | |
| * '''Abrir''' -- Carrega os dados de uma sessão anterior a partir de um ficheiro previamente guardado (ficando este ficheiro associado à aplicação, para futuras operações de salvaguarda). Pede-se o nome do ficheiro a abrir ('''Prompt.openFile()'''). Caso ocorra um problema na abertura ou processamento do ficheiro, deve ser lançada a excepção '''FileOpenFailedException'''. A execução bem-sucedida desta opção substitui toda a informação da aplicação.
| |
| * '''Guardar''' -- Guarda o estado actual da aplicação no ficheiro associado. Se não existir associação, pede-se o nome do ficheiro a utilizar, ficando a ele associado. Esta interacção realiza-se através do método '''Prompt.newSaveAs()'''. Não é executada nenhuma acção se não existirem alterações desde a última salvaguarda.
| |
| | |
| Note-se que a opção '''Abrir''' não permite a leitura de ficheiros de texto (estes apenas são utilizados na inicialização da aplicação).
| |
| | |
| A opção '''Sair''' nunca implica a salvaguarda do estado da aplicação, mesmo que existam alterações.
| |
| | |
| === Mostrar data actual ===
| |
| | |
| A data actual do sistema é apresentada através da mensagem '''Message.currentDate()'''.
| |
| | |
| === Avançar data actual ===
| |
| | |
| O número de dias a avançar é pedido através de '''Prompt.daysToAdvance()'''. Deve ser lançada a excepção '''InvalidDateException''' se o número de dias a avançar for inválido.
| |
| | |
| === Gestão e consulta de dados da aplicação ===
| |
| | |
| * '''Menu de Gestão de Produtos''' -- Abre o menu de gestão de produtos.
| |
| * '''Menu de Gestão de Parceiros''' -- Abre o menu de gestão de parceiros.
| |
| * '''Menu de Gestão de Transacções''' -- Abre o menu de gestão de transacções.
| |
| * '''Menu de Consultas''' -- Abre o menu de consultas (pesquisas).
| |
| | |
| === Mostrar saldo global ===
| |
| | |
| Esta opção apresenta os valores correspondentes aos saldos disponível e contabilístico do entreposto. Embora internamente o valor dos saldos estejam representados em vírgula flutuante, a apresentação é arredondada ao inteiro mais próximo.
| |
| | |
| A apresentação faz-se através da mensagem '''Message.currentBalance()'''.
| |
| | |
| == Menu de Gestão de Produtos ==
| |
| | |
| Este menu permite efectuar operações sobre a base de dados de produtos. A lista completa é a seguinte: [[#Visualizar todos os produtos|Visualizar todos os produtos]], [[#Visualizar todos os produtos disponíveis|Visualizar todos os produtos disponíveis]], [[#Visualizar os lotes fornecidos por um dado parceiro|Visualizar os lotes fornecidos por um dado parceiro]], [[#Visualizar os lotes de um dado produto|Visualizar os lotes de um dado produto]].
| |
| | |
| <!--As etiquetas das opções deste menu estão definidas na classe '''ggc.app.products.Label'''. -->Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''ggc.app.products.Message'''.
| |
| | |
| Sempre que é pedido o identificador de um parceiro ('''Prompt.partnerKey()''') e o parceiro não existir, é lançada a excepção '''UnknownPartnerKeyException'''. Sempre que é pedido o identificador de um produto ('''Prompt.productKey()''') e o produto não existir, é lançada a excepção '''UnknownProductKeyException'''. Na ocorrência de excepções (estas ou outras), as operações não têm efeito.
| |
| | |
| {{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''ggc.app.products''' (disponível no CVS), respectivamente: '''DoShowAllProducts''', '''DoShowAvailableBatches''', '''DoShowBatchesByPartner''', '''DoShowBatchesByProduct'''.}}
| |
| | |
| === Visualizar todos os produtos ===
| |
| O formato de apresentação de cada produto é o seguinte (cada linha indica um produto):
| |
| | |
| Produtos simples:
| |
| ''idProduto''|''preço-máximo''|''stock-actual-total''
| |
| | |
| Exemplo:
| |
| HIDROGÉNIO|200|5000
| |
| OXIGÉNIO|1200|2500
| |
| | |
| Produtos derivados (é apresentado o produto e a lista de componentes e respectivas quantidades da sua receita):
| |
| ''idProduto''|''preço-máximo''|''stock-actual-total''|''agravamento''|''componente-1'':''quantidade-1''#...#''componente-n'':''quantidade-n''
| |
| | |
| Exemplo:
| |
| ÁGUA|5000|800|0.1|HIDROGÉNIO:2#OXIGÉNIO:1
| |
| | |
| Em ambos os casos, ''stock-actual-total'' pode ser 0 (zero).
| |
| | |
| === Visualizar todos os lotes ===
| |
| | |
| O formato de apresentação de cada lote de produto é o seguinte (cada linha indica um lote):
| |
| | |
| Produtos simples e derivados:
| |
| ''idProduto''|''idParceiro''|''preço''|''stock-actual''
| |
| | |
| Exemplo:
| |
| ÁGUA|EPAL|1150|800
| |
| HIDROGÉNIO|Cryostuffs|110|5000
| |
| OXIGÉNIO|Cryostuffs|650|2500
| |
| OXIGÉNIO|Cryostuffs|650|5000
| |
| OXIGÉNIO|Cryostuffs|820|2500
| |
| OXIGÉNIO|EPAL|820|2500
| |
| | |
| Note-se que podem existir vários lotes para o mesmo produto. Neste caso, a ordenação é, primeiro, pelo identificador do produto e, depois, pelo identificador do parceiro. Se um parceiro fornecer vários lotes do mesmo produto, apresentam-se por ordem crescente de preço e existências.
| |
| | |
| === Visualizar os lotes fornecidos por um dado parceiro ===
| |
| | |
| É pedido o identificador do parceiro e são apresentados os lotes por ele fornecidos. A ordenação é como indicada para a listagem de todos os produtos disponíveis (lotes).
| |
| | |
| === Visualizar os lotes de um dado produto ===
| |
| | |
| É pedido o identificador do produto e são apresentados os lotes conhecidos para esse produto. A ordenação é como indicada para a listagem de todos os produtos.
| |
| | |
| == Menu de Gestão de Parceiros ==
| |
| | |
| Este menu permite efectuar operações sobre a base de dados de parceiros. A lista completa é a seguinte: [[#Mostrar parceiro|Mostrar parceiro]], [[#Mostrar todos os parceiros|Mostrar todos os parceiros]], [[#Registar parceiro|Registar parceiro]], [[#Activar/desactivar notificações de um produto|Activar/desactivar notificações de um produto]], [[#Mostrar transacções de compra com parceiro|Mostrar transacções de compra com parceiro]], [[#Mostrar transacções de venda (e desagregação) com parceiro|Mostrar transacções de venda (e desagregação) com parceiro]].
| |
| | |
| <!--As etiquetas das opções deste menu estão definidas na classe '''ggc.app.partners.Label'''. -->Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''ggc.app.partners.Message'''.
| |
| | |
| Sempre que for pedido o identificador de um parceiro ('''Prompt.partnerKey()''') e o parceiro não existir, é lançada a excepção '''UnknownPartnerKeyException''' (excepto no processo de registo). No processo de registo, caso o identificador indicado já exista, deve ser lançada a excepção '''DuplicatePartnerKeyException'''.
| |
| | |
| {{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''ggc.app.partners''' (disponível no CVS), respectivamente: '''DoShowPartner''', '''DoShowAllPartners''', '''DoRegisterPartner''', '''DoToggleProductNotifications''', '''DoShowPartnerAcquisitions''', '''DoShowPartnerSales'''.}}
| |
| | |
| === Mostrar parceiro ===
| |
| | |
| É pedido o identificador do parceiro e apresentada a sua informação. O formato de apresentação é o seguinte (o valor das vendas efectuadas -- não inclui desagregações -- refere-se ao momento da venda; o valor das vendas pagas refere-se ao valor realmente pago): Note-se que compras e vendas são ponto de vista do entreposto e não do parceiro. Os valores dos pontos e dos preços são apresentados como inteiros (valores arredondados ao inteiro mais próximo).
| |
| | |
| ''id''|''nome''|''endereço''|''estatuto''|''pontos''|''valor-compras''|''valor-vendas-efectuadas''|''valor-vendas-pagas''
| |
| | |
| O estatuto corresponde a '''NORMAL''', '''SELECTION''', '''ELITE''', conforme o caso.
| |
| | |
| Após esta linha, são apresentadas as notificações do parceiro (modo de entrega por omissão), pela ordem em que foram enviadas pela aplicação.
| |
| | |
| ''tipo-de-notificação''|''idProduto''|''preço-do-produto''
| |
| | |
| Após esta visualização, considera-se que o parceiro fica sem notificações registadas.
| |
| | |
| === Mostrar todos os parceiros ===
| |
| | |
| O formato de apresentação é como para parceiros individuais (opção anterior), mas não se apresentam as notificações dos parceiros.
| |
| | |
| === Registar parceiro ===
| |
| | |
| São pedidos o identificador do parceiro, o nome ('''Prompt.partnerName()''') (cadeia de caracteres) e o endereço do parceiro ('''Prompt.partnerAddress()''') (cadeia de caracteres) e regista-se o novo parceiro. Quando um parceiro é registado, aceita notificações relativas a todos os produtos.
| |
| | |
| Se já existir um parceiro com o mesmo identificador, deve ser lançada a excepção '''DuplicatePartnerKeyException''', não se realizando o registo.
| |
| | |
| === Activar/desactivar notificações de um produto ===
| |
| | |
| É pedido o identificador do produto ('''Prompt.partnerKey()''') e o identificador do produto ('''Prompt.productKey()'''). Se as notificações relativas ao produto estavam activas para o parceiro em causa, passam a estar inactivas, e vice-versa. <!--É apresentada na saída o resultado da operação: '''notificationsOn()''' ou '''notificationsOff()'''.-->
| |
| | |
| Se o produto indicado não existir, é lançada a excepção '''UnknownProductKeyException'''.
| |
| | |
| === Mostrar transacções de compra com parceiro ===
| |
| | |
| É pedido o identificador do parceiro e apresentadas todas as compras com ele realizadas. O formato de apresentação é como descrito abaixo (visualização de transacções).
| |
| | |
| === Mostrar transacções de venda (e desagregação) com parceiro ===
| |
| | |
| É pedido o identificador do parceiro e apresentadas todas as vendas (e desagregações) com ele realizadas. O formato de apresentação é como descrito abaixo (visualização de transacções).
| |
| | |
| == Menu de Gestão de Transacções ==
| |
| Este menu apresenta as operações relacionadas com transacções. A lista completa é a seguinte: [[#Visualizar|Visualizar]], [[#Registar Desagregação (pelo entreposto a pedido de um parceiro)|Registar Desagregação]], [[#Registar Venda (do entreposto a um parceiro)|Registar Venda]], [[#Registar Compra (do entreposto a um parceiro)|Registar Compra]], [[#Receber Pagamento de Venda (do entreposto a um parceiro)|Receber Pagamento de Venda]].
| |
| | |
| <!--As etiquetas das opções deste menu estão definidas na classe '''ggc.app.transactions.Label'''. -->Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''ggc.app.transactions.Message'''.
| |
| | |
| Sempre que é pedido o identificador do parceiro ('''Prompt.partnerKey()'''), é lançada a excepção '''UnknownPartnerKeyException''', se o parceiro indicado não existir. Sempre que é pedido o identificador de produto ('''Prompt.productKey()'''), é lançada a excepção '''UnknownProductKeyException''', se o produto indicado não existir. Sempre que é pedido o identificador da transacção ('''Prompt.transactionKey()'''), é lançada a excepção '''UnknownTransactionKeyException''', se a transacção indicada não existir.
| |
| <!--
| |
| Se o parceiro indicado estiver inibido de efectuar transacções, deve ser lançada a excepção '''UnauthorizedPartnerException''' e o comando não tem efeito. --><!--Se o identificador de um produto não corresponder ao fornecedor indicado, deve ser lançada a excepção '''WrongSupplierException''' e o comando não tem efeito.-->
| |
| | |
| {{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''ggc.app.transactions''' (disponível no CVS), respectivamente: '''DoShowTransaction''', '''DoRegisterBreakdownTransaction''', '''DoRegisterSaleTransaction''', '''DoRegisterAcquisitionTransaction''', '''DoReceivePayment'''.}}
| |
| | |
| === Visualizar transacção ===
| |
| | |
| O sistema pede o identificador da transacção a visualizar.
| |
| | |
| Nas apresentações, o campo ''valor-base'' é o valor da transacção sem multas/descontos.
| |
| | |
| Se a transacção for respeitante a uma venda a um parceiro, apresenta-se com o seguinte formato:
| |
| | |
| '''VENDA'''|''id''|''idParceiro''|''idProduto''|''quantidade''|''valor-base''|''valor-a-pagamento''|''data-limite''|''data-pagamento''
| |
| | |
| O campo ''valor-a-pagamento'' corresponde ao valor que será realmente pago (considerando possíveis multas/descontos à data da visualização). A data de pagamento (e o separador correspondente) só é apresentada se a venda tiver sido paga.
| |
| | |
| Se a transacção corresponder a uma compra a um parceiro, apresenta-se com o seguinte formato:
| |
| | |
| '''COMPRA'''|''id''|''idParceiro''|''idProduto''|''quantidade''|''valor-pago''|''data-pagamento''
| |
| | |
| Se a transacção for uma desagregação, então deve ser apresentada, primeiro a "venda" do produto derivado, seguida da "compra" dos componentes obtidos na desagregação. O formato para N componentes é o seguinte:
| |
| | |
| '''DESAGREGAÇÃO'''|''id''|''idPa''|''idPr''|''quantidade''|''vbase''|''vpag''|''data''|''idC1'':''q1'':''v1''#...#''idCN'':''qN'':''vN''
| |
| | |
| O valor base de uma desagregação corresponde à diferença entre a compra e a venda. O valor pago corresponde ao valor realmente pago pelo parceito (é um valor não negativo, podendo ser 0 caso o valor base seja negativo. Nesta linha, '''idPa''' é o identificador do parceiro; '''idPr''' é o identificador do produto; '''vbase''' é o valor real da transacção (diferencial); '''vpag''' é o valor a pagar (não negativo); '''data''' é a data da transacção; '''idCx''', '''qx''', '''vx''', são (respectivamente) o identificador, a quantidade e o valor do componente '''x''' (não confundir com valor unitário). Cada componente é separado do seguinte por '''#'''.
| |
| | |
| === Registar Desagregação (pelo entreposto a pedido de um parceiro) ===
| |
| | |
| Para registar uma desagregação, é pedido o identificador do parceiro que pede a operação e o identificador do produto a desagregar e a respectiva quantidade ('''Prompt.amount()'''). Se a quantidade for superior às existências actuais, deve ser lançada a excepção '''UnavailableProductException''' (não se realiza a desagregação). Se o produto a desagregar não for derivado, a acção não tem efeito.
| |
| | |
| A actualização dos produtos do entreposto, bem como o respectivo valor, tem lugar logo após o registo da desagregação, ou seja, considera-se que a operação é instantânea.
| |
| | |
| Esta transacção regista o produto de origem e os lotes dos resultantes (associados ao parceiro que pede a operação), bem como os respectivos valores.
| |
| | |
| === Registar Venda (do entreposto a um parceiro) ===
| |
| | |
| Para registar uma venda, é pedido o identificador do parceiro, a data limite para o pagamento ('''Prompt.paymentDeadline()'''), o identificador do produto a vender e a respectiva quantidade ('''Prompt.amount()'''). Se a quantidade for superior às existências actuais, deve ser lançada a excepção '''UnavailableProductException''' (não se realiza a venda).
| |
| | |
| A determinação das existências começa com o preço mais baixo e vai prosseguindo por todos os parceiros que tenham o produto disponível. O preço a pagar é determinado pelo preço das várias fracções.
| |
| | |
| Se a venda corresponder a um produto derivado e não existir produto suficiente nos lotes disponíveis, o produto pode ser fabricado a partir de componentes de outros lotes. As existências dos componentes têm de ser suficientes para satisfazer a totalidade das necessidades de produto derivado a fabricar. <!--O produto fabricado é colocado num lote associado ao parceiro comprador. -->O preço é calculado como descrito acima.
| |
| | |
| A actualização dos produtos do entreposto tem lugar logo após o registo da venda, ou seja, considera-se que a venda é instantânea.
| |
| | |
| === Registar Compra (do entreposto a um parceiro) ===
| |
| | |
| É pedido o identificador do parceiro a quem se realiza a compra, o identificador do produto que se está a comprar, o preço do produto ('''Prompt.price()''') e a respectiva quantidade ('''Prompt.amount()'''). O produto comprado mantém informação sobre o processo de aquisição: em particular, se vários parceiros fornecerem o mesmo produto, podem fazê-lo com preços diferentes. O entreposto poderá, então, vender um dado produto com diferentes preços.
| |
| | |
| Se o identificador do produto for desconhecido, então é perguntado ao parceiro se quer introduzir uma receita para um produto derivado ('''Prompt.addRecipe()'''). Se a resposta for negativa, trata-se de um produto simples. Caso contrário, é pedido o número de componentes da receita ('''Prompt.numberOfComponents()'''), o valor do agravamento ('''Prompt.alpha()''') e, em ciclo, os identificadores ('''Prompt.productkey()''') e quantidades ('''Prompt.amount()''') dos vários componentes.
| |
| | |
| A actualização de existências dos produtos do entreposto tem lugar logo após o registo da compra, ou seja, considera-se que a compra é instantânea. A actualização do saldo do entreposto também é assumida como instantânea, i.e., assume-se que a compra é paga a pronto.
| |
| | |
| === Receber Pagamento de Venda (do entreposto a um parceiro) ===
| |
| | |
| Apenas é permitido o pagamento de vendas a parceiros. Tentativas de pagamento de transacções que não correspondam a vendas não produzem nenhum resultado.
| |
| | |
| É pedido o identificador da venda a pagar. Se a venda já tiver sido paga, não é realizada nenhuma acção.
| |
| | |
| == Menu de Consultas ==
| |
| | |
| Este menu apresenta as operações relacionadas com consultas. A lista completa é a seguinte: [[#Mostrar produtos com preço abaixo de limite|Mostrar produtos com preço abaixo de limite]], [[#Mostrar facturas pagas por parceiro|Mostrar facturas pagas por parceiro]].
| |
| | |
| <!--As etiquetas das opções deste menu estão definidas na classe '''ggc.app.lookups.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''ggc.app.lookups.Message'''.
| |
| -->
| |
| Sempre que é pedido o identificador do parceiro ('''Prompt.partnerKey()'''), é lançada a excepção '''UnknownPartnerKeyException''', se o parceiro indicado não existir. Sempre que é pedido o identificador de produto ('''Prompt.productKey()'''), é lançada a excepção '''UnknownProductKeyException''', se o produto indicado não existir.
| |
| | |
| A apresentação de resultados é como indicado nos casos já descritos de apresentação das várias entidades.
| |
| | |
| {{CVSCode|Estes comandos já estão parcialmente implementados nas classes da ''package'' '''ggc.app.lookups''' (disponível no CVS), respectivamente: '''DoLookupProductBatchesUnderGivenPrice''', '''DoLookupPaymentsByPartner'''.}}
| |
| | |
| === Mostrar lotes de produtos com preço abaixo de limite ===
| |
| | |
| Pede-se o valor limite pretendido ('''Prompt.priceLimit()''') e apresentam-se todos os lotes cujo preço é inferior ao preço indicado. É apresentado um lote por linha.
| |
| | |
| === Mostrar transacções pagas por parceiro ===
| |
| | |
| Pede-se o identificador do parceiro e apresentam-se as transacções do parceiro que já estão pagas (uma transacção por linha).<!-- Não são considerados pagamentos de desagregações.-->
| |
| | |
| = Leitura de Dados a Partir de Ficheiros Textuais =
| |
|
| |
| Além das opções de manipulação de ficheiros descritas no [[#Salvaguarda do Documento Actual|menu principal]], é possível iniciar a aplicação com um ficheiro de texto especificado pela propriedade Java '''[[#Execução dos Programas e Testes Automáticos|import]]'''.
| |
| | |
| As várias entidades têm os formatos descritos abaixo. Assume-se que os títulos não podem conter o carácter '''|''' e que o preço é um número inteiro (sugere-se a utilização do método '''String.split''' para o processamento preliminar destas linhas). Não existem entradas mal-formadas.
| |
| | |
| Cada linha tem uma descrição distinta, mas que segue os seguintes formatos:
| |
| | |
| CLIENT|''id''|''nome''|''xxx''|''nível''
| |
| TERMINAL|''idTerminal''|''idClient''|''type''|''state''|''balance''
| |
| FRIENDS|''idTerminal''|''idTerminal1'',...,''idTerminalN''
| |
| | |
| As definições de clientes precedem sempre as dos terminais. As ligações entre amigos estão sempre após a definição das restantes entidades.
| |
| | |
| Um exemplo de conteúdo do ficheiro inicial é como se segue:
| |
| | |
| {{CollapsedCode|Exemplo de ficheiro de entrada textual|
| |
| <source lang="text">
| |
| CLIENT|cli001|Manuel Pinheiro|103443|NORMAL
| |
| CLIENT|cli002|Pedro Pinheiro|103447|NORMAL
| |
| CLIENT|Cli201|Ludgero Oliveira|103440|NORMAL
| |
| CLIENT|cli Es|Maria Eucalipto|103441|GOLD
| |
| CLIENT|01|Oliveira Preto|103547|NORMAL
| |
| CLIENT|cli003|Pedro Oliveira|103449|PLATINUM
| |
| TERMINAL|969001|cli001|2G|ON|-900
| |
| TERMINAL|969003|cli002|2G|ON|0
| |
| TERMINAL|969002|cli002|3G|SILENCE|330
| |
| TERMINAL|969007|cli Es|3G|ON|700
| |
| TERMINAL|969008|cli003|2G|OFF|2500
| |
| TERMINAL|969009|cli003|2G|OFF|1200
| |
| TERMINAL|969010|cli003|2G|ON|-2100
| |
| TERMINAL|969006|cli003|3G|ON|4800
| |
| TERMINAL|969005|cli003|3G|ON|3400
| |
| TERMINAL|969004|cli003|2G|ON|1000
| |
| FRIENDS|969001|969008,969009,969004
| |
| FRIENDS|969004|969001
| |
| FRIENDS|969003|969008
| |
| </source>
| |
| }}
| |
| A codificação dos ficheiros a ler é garantidamente [[wp:UTF-8|UTF-8]].
| |
| | |
| {{Suggestion|Note-se que o programa nunca produz ficheiros com este formato.}}
| |
| | |
| = Execução dos Programas e Testes Automáticos =
| |
| | |
| Usando os ficheiros '''test.import''', '''test.in''' e '''test.out''', é possível verificar automaticamente o resultado correcto do programa. Note-se que é necessária a definição apropriada da variável '''CLASSPATH''' (ou da opção equivalente '''-cp''' do comando '''java'''), para localizar as classes do programa, incluindo a que contém o método correspondente ao ponto de entrada da aplicação ('''prr.app.App.main'''). As propriedades são tratadas automaticamente pelo código de apoio.
| |
| | |
| java -Dimport=test.import -Din=test.in -Dout=test.outhyp prr.app.App
| |
| | |
| Assumindo que aqueles ficheiros estão no directório onde é dado o comando de execução, o programa produz o ficheiro de saída '''test.outhyp'''. Em caso de sucesso, os ficheiros das saídas esperada ('''test.out''') e obtida ('''test.outhyp''') devem ser iguais. A comparação pode ser feita com o comando:
| |
| | |
| diff -b test.out test.outhyp
| |
| | |
| Este comando não deve produzir qualquer resultado quando os ficheiros são iguais. Note-se, contudo, que este teste não garante o correcto funcionamento do código desenvolvido, apenas verificando alguns aspectos da sua funcionalidade.
| |
| | |
| = Notas de Implementação =
| |
| | |
| Tal como indicado acima, algumas classes fornecidas como [[Programação com Objectos/Projecto de Programação com Objectos/Material de Apoio ao Desenvolvimento|material de apoio]], são de uso obrigatório e não podem ser alteradas. Outras dessas classes são de uso obrigatório e têm de ser alteradas.
| |
| | |
| A serialização Java usa as classes da ''package'' '''[https://docs.oracle.com/javase/8/docs/api/java/io/package-summary.html java.io]''', em particular, a interface '''[https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html java.io.Serializable]''' e as classes de leitura '''[https://docs.oracle.com/javase/8/docs/api/java/io/ObjectInputStream.html java.io.ObjectInputStream]''' e escrita '''[https://docs.oracle.com/javase/8/docs/api/java/io/ObjectOutputStream.html java.io.ObjectOutputStream]''' (entre outras).
| |
| <!--
| |
| A representação e manipulação de datas e tempos deve ser realizada através das classes da ''package'' '''[https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html java.time]''', em particular, através das classes '''[https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html java.time.LocalDate]''' e '''[https://docs.oracle.com/javase/8/docs/api/java/time/LocalTime.html java.time.LocalTime]'''. Diferenças entre tempos são representadas pela classe '''[https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html java.time.Duration]'''.
| |
| -->
| |
| <!--
| |
| [[category:Ensino]]
| |
| [[category:PO]]
| |
| [[category:Projecto de PO]]
| |
| [[en:Object-Oriented Programming]]
| |
| -->
| |