Difference between revisions of "Programação com Objectos/Projecto de Programação com Objectos/Enunciado do Projecto de 2022-2023 (rascunho)"

From Wiki**3

< Programação com Objectos‎ | Projecto de Programação com Objectos
(Visualizar os lotes de um dado produto)
 
(304 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''', '''prr.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]], [[#Gestão e consulta de dados da aplicação|Gestão de clientes]], [[#Gestão e consulta de dados da aplicação|Gestão de terminais]], [[#Gestão e consulta de dados da aplicação|Consultas]], [[#Gestão e consulta de dados da aplicação|Consultas]], [[#Mostrar saldo global|Mostrar saldo global]].
 
 
 
As etiquetas das opções deste menu estão definidas na classe '''prr.app.main.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''prr.app.main.Message'''.
 
 
 
{{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''prr.app.main''' (disponível no CVS), respectivamente: '''DoOpenFile''', '''DoSaveFile''', '''DoOpenMenuClients''', '''DoOpenMenuTerminals''', '''DoOpenMenuLookups''', '''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.
 
 
 
=== Gestão e consulta de dados da aplicação ===
 
 
 
* '''Menu de Gestão de Clientes''' -- Abre o menu de gestão de clientes.
 
* '''Menu de Gestão de Terminais''' -- Abre o menu de gestão de terminais.
 
* '''Menu de Consultas''' -- Abre o menu de consultas (pesquisas).
 
 
 
=== Mostrar saldo global ===
 
 
 
Esta opção apresenta o valor correspondente ao saldo global (soma dos sados de todos os clientes registados na rede). Embora internamente os valores 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 clientes ==
 
 
 
Este menu permite efectuar operações sobre a base de dados de clientes. A lista completa é a seguinte: [[#Visualizar todos os clientes|Visualizar todos os clientes]], [[#Registar cliente|Registar cliente]], [[#Activar recepção de contactos falhados|Activar recepção de contactos falhados]], [[#Desactivar recepção de contactos falhados|Desactivar recepção de contactos falhados]], [[#Calcular saldo|Calcular saldo]].
 
 
 
<!--As etiquetas das opções deste menu estão definidas na classe '''prr.app.products.Label'''. -->Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''prr.app.products.Message'''.
 
 
 
Sempre que é pedido o identificador de um cliente ('''Prompt.clientKey()''') e o identificador não existir (excepto no processo de registo), é lançada a excepção '''UnknownClientKeyException'''. 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'' '''prr.app.clients''' (disponível no CVS), respectivamente: '''DoShowAllClients''', '''DoRegisterClient''', '''DoSetFailedContactsOn''', '''DoSetFailedContactsOff''', '''DoComputeBalance'''.}}
 
 
 
=== Visualizar todos os clientes ===
 
O formato de apresentação de cada cliente é o seguinte, em que ''nTerminals'' é o número de terminais activos associados ao cliente e ''balance'' é o somatório do saldo de cada um desses terminais (valor arredondado ao inteiro mais próximo). Os valores para ''clientType'' são '''NORMAL''', '''GOLD''', ou '''PLATINUM'''. Os valores para ''answeringStatus'' são '''ON''' ou '''OFF'''. Se o cliente não tiver terminais, o saldo é 0 (zero).
 
 
 
CLIENTE|''clientId''|''clientName''|''NIF''|''clientType''|''answeringStatus''|''nTerminals''|''balance''
 
 
 
=== Registar cliente ===
 
 
 
O sistema pede o identificador que ficará associado ao cliente (identificador único}. De seguida, pede o nome do cliente ('''requestClientName()''') e o número de identificação fiscal ('''requestNIF()'''). Após o registo, o cliente fica no estado '''Normal''' e o registo de contactos falhados fica activo.
 
 
 
Caso o identificador indicado já exista, deve ser lançada a excepção '''DuplicateClientKeyException''', não se realizando o registo.
 
 
 
=== 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).
 
 
 
=== Calcular saldo de cliente ===
 
 
 
O sistema pede o identificador do cliente, apresentando o seu saldo.
 
 
 
== 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 '''prr.app.partners.Label'''. -->Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''prr.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'' '''prr.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 '''prr.app.transactions.Label'''. -->Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''prr.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'' '''prr.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 '''prr.app.lookups.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''prr.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'' '''prr.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]]
 
-->
 

Latest revision as of 17:49, 14 September 2022