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

From Wiki**3

Root (talk | contribs)
Root (talk | contribs)
 
(349 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 telemóveis, denominado por '''prr'''. O programa permite gerir varios serviços: registo de clientes e de telemóveis e controlo das comunicações efectuadas.
 
O sistema disponibiliza aos seus gestores varios serviços, entre outros: (i) registar dados sobre os clientes; (ii) registar dados sobre os telemóveis pertencentes à rede; (iii) registar dados sobre as chamadas efectuadas; (iv) fazer pesquisas sobre as chamadas já efectuadas; (v) contabilizar o saldo associado a telemóveis.
 
=  Clientes, telemóveis, planos tarifários e chamadas =
 
Os utilizadores podem ter vários telemóveis, cada um deles associado a um número de telefone e um plano tarifário. Nos pontos seguintes, descrevem-se as propriedades de cada entidade da aplicação.
 
== Propriedades e funcionalidades ==
 
Os clientes, telemóveis e chamadas possuem uma chave única, uma cadeia de caracteres para os clientes e um inteiro para os telemóveis e para as chamadas.
 
Cada cliente, para além da chave única, é identificado pelo nome (cadeia de caracteres) e número de identificação fiscal (inteiro).
 
Os telemóveis são identificados por um número (exactamente 6 dígitos) e estão associados a um cliente. Cada telemóvel pode estar ligado, em silêncio, ou desligado. Neste último caso, não é permitido iniciar ou receber chamadas. Quando o telefone está em silêncio, pode iniciar qualquer tipo de chamada, mas só pode receber chamadas de texto. Cada telefone tem uma contabilidade própria, sendo sempre possível saber o saldo que lhe está associado.
 
Cada chamada é identificada por um inteiro, único em toda a rede, e possui ainda informação sobre o telemóvel que originou a chamada, o telemóvel de destino, a duração da chamada e o tipo de comunicação (voz, texto ou vídeo). A primeira chamada tem como identificador “1”, devendo o identificador das chamadas subsequentes ser obtido por incremento unitário do identificador anterior.
 
Existem 3 tipos de comunicação entre telemóveis: texto (denominada SMS), voz (denominada VOZ) e vídeo (denominada MMS). O custo das chamadas não é uniforme (ver [[#Planos tarifários|Planos tarifários]]), dependendo do tipo de telefone e do cliente, entre outros factores. Também dependendo do cliente, é possível avisar quem o tentou contactar quando: (i) um telefone desligado é colocado em silêncio; (ii) um telefone desligado é ligado; ou (iii) um telefone em silêncio é ligado.
 
A aplicação desenvolvida deve ser suficientemente flexível para permitir modelar novos tipos de chamada, novos planos tarifários e novas políticas de avisos. Também deve permitir a gestão de várias redes de telemóvel. O impacto destas alterações na aplicação a desenvolver deve ser mínimo.
 
== Gestão de clientes ==
 
== Gestão de telemóveis ==
 
== Planos tarifários ==
 
== Pesquisas ==
 
==  Notificações ==
 
Quando o entreposto recebe um novo produto, os parceiros devem ser colocados como entidades interessadas em receber notificações sobre eventos a ele associados. Em qualquer momento, um parceiro pode activar ou desactivar as notificações relativas a um produto. Os eventos a considerar são os seguintes: (i) quando o produto passa de stock 0 (zero) para outro valor (positivo); (ii) quando aparece um lote mais barato de um produto. As notificações são compostas pelo identificador do produto e pela descrição da notificação: '''NEW''', para novas existências de produtos, mas não quando se regista um novo produto; e '''BARGAIN''', para disponibilidade de preços mais baixos. As notificações são registadas nos parceiros que as recebem.
 
A entrega de notificações deve ser flexível e prever vários meios de entrega, e.g., correio postal, SMS, email, entre outras. O meio de entrega por omissão corresponde a registar a notificação na aplicação.
 
==  Contabilização de Pontos (Parceiros) ==
 
As multas e os descontos aplicam-se apenas no pagamento de transacções de venda.
 
Os valores pagos (instantaneamente) nas transacções de desagregação também dão direito à contabilização de pontos (apenas quando é positivo).
 
Existem três classificações distintas de parceiros: '''Nomal''', '''Selection''' e '''Elite'''. A classificação de um parceiro tem impacto nas multas e descontos a aplicar no pagamento de uma venda.
 
Quando um parceiro paga uma venda dentro do prazo, acumula um número de pontos correspondente a 10 vezes o valor pago. Não há contabilização de pontos em pagamentos atrasados. A verificação do atraso é realizada quando se realiza o pagamento de uma venda.
 
Os parceiros passam ao nível '''Selection''' se acumularem mais de 2000 pontos. Os parceiros passam ao nível '''Elite''' se acumularem mais de 25000 pontos.
 
Se um parceiro se atrasa no pagamento da venda, é despromovido: um parceiro '''Elite''' passa a '''Selection''' se o pagamento ocorrer com um atraso de pagamento superior a 15 dias (perde 75% dos pontos acumulados); um parceiro '''Selection''' passa a '''Normal''' se o pagamento ocorrer com um atraso de pagamento superior a 2 dias (perde 90% dos pontos acumulados). Se um parceiro '''Normal''' se atrasa num pagamento, perde os pontos que tem.
 
As multas e os descontos dependem do estatuto do parceiro e dos prazos associados à venda e ao estatuto.
 
{|
|
! style="width: 11.25%; background: #ccddff;" | '''P1'''
! style="width: 11.25%; background: #ccddff;" |
! style="width: 11.25%; background: #e6eeff;" | '''P2'''
! style="width: 11.25%; background: #e6eeff;" |
! style="width: 11.25%; background: #ffe6cc;" | '''P3'''
! style="width: 11.25%; background: #ffe6cc;" |
! style="width: 11.25%; background: #ffad99;" | '''P4'''
! style="width: 11.25%; background: #ffad99;" |
|-
|
| <font color="red">Multa</font>
| <font color="forestgreen">Desconto</font>
| <font color="red">Multa</font>
| <font color="forestgreen">Desconto</font>
| <font color="red">Multa</font>
| <font color="forestgreen">Desconto</font>
| <font color="red">Multa</font>
| <font color="forestgreen">Desconto</font>
|-
| '''Normal'''
| 0
| 10%
| 0
| 0
| 5% diários
| 0
| 10% diários
| 0
|-
| '''Selection'''
| 0
| 10%
| 0
| ≥ 2 dias antes da data limite: 5%; depois, sem desconto
| > 1 dia depois da data limite: 2% diários (0, caso contrário)
| 0
| 5% diários
| 0
|-
| '''Elite'''
| 0
| 10%
| 0
| 10%
| 0
| 5%
| 0
| 0
|}
 
== Data ==
 
A data é representada por um número inteiro e tem inicialmente o valor 0 (zero). A data pode começar com outro valor se se recuperar o estado do entreposto a partir de um suporte persistente.
 
Os avanços de data são valores inteiros positivos que representam o número de dias.
 
= 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).
 
A base de dados com os conceitos pré-definidos é [[#Leitura de Dados a Partir de Ficheiros Textuais|carregada no início da aplicação]].
 
É possível saber os saldos do entreposto (diferencial entre vendas e compras). Existe um saldo disponível, correspondente à diferença entre as vendas realmente pagas e as compras, e um saldo contabilístico, correspondente à diferença entre o valor contabilístico das vendas (pagas ou não e considerando descontos/penalizações à data da consulta de saldo) e as compras. Note-se que as desagregações são consideradas combinações de compras e vendas, pelo que também influenciam o saldo do entreposto.
 
Deve ser possível efectuar pesquisas sujeitas a vários critérios e sobre as diferentes entidades geridas pelo entreposto.
 
{{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 '''ggc.WharehouseManager''' 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 ==
 
A seguinte funcionalidade sobre produtos deve ser suportada pela aplicação: (i) visualizar produtos e lotes de produtos; (ii) visualizar lotes específicos.
 
A seguinte funcionalidade sobre parceiros deve ser suportada pela aplicação: (i) visualizar um ou mais parceiros; (ii) registar um novo parceiro; (iii) activar/desactivar notificações relativas a produtos; (iv) consultar o histórico de transacções realizadas por um parceiro.
 
A seguinte funcionalidade sobre transacções deve ser suportada: (i) visualizar uma transacção; (ii) registar uma nova compra; (ii) registar uma nova venda; (iii) registar uma desagregação; (iv) receber pagamento de uma venda.
 
= 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 novas entidades que desejem ser notificadas da alteração do estado dos produtos;
* Adicionar novos modos de entrega de mensagens (notificações);
* Adicionar novas políticas de recompensa de parceiros;
* Adicionar novas formas de consulta.
 
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 '''ggc-app'''). As mensagens não podem ser usadas no núcleo da aplicação ('''ggc-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.
 
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 (parceiros, transacções, 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'' '''ggc.app''', '''ggc.app.main''', '''ggc.app.products''', '''ggc.app.partners''', '''ggc.app.transactions''', '''ggc.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 '''ggc-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.
 
PARTNER|''id''|''nome''|''endereço''
 
Os lotes têm as seguintes definições (respectivamente, para produtos simples e derivados). Produtos derivados (é apresentado o produto e a lista de componentes e respectivas quantidades da sua receita):
 
BATCH_S|''idProduto''|''idParceiro''|''preço''|''stock-actual''
BATCH_M|''idProduto''|''idParceiro''|''preço''|''stock-actual''|''agravamento''|''componente-1'':''quantidade-1''#...#''componente-n'':''quantidade-n''
 
As definições de parceiros precedem sempre as dos lotes.
 
Um exemplo de conteúdo do ficheiro inicial é como se segue:
 
{{CollapsedCode|Exemplo de ficheiro de entrada textual|
<source lang="text">
PARTNER|S1|Toshiba|Tokyo, Japan
PARTNER|W2|Papelaria Fernandes|Oeiras, Portugal
PARTNER|P1|Publicações Europa-América|Lisboa, Portugal
PARTNER|P3|O’Reilly|Köln, Germany
PARTNER|R2|Jorge Figueiredo|Lisboa, Portugal
PARTNER|E4|Filomena Figueiredo|Lisboa, Portugal
PARTNER|ER|Abdul Figueiredo|Casablanca, Morocco
PARTNER|O9|Hellen Figueiredo|San Francisco, CA, USA
PARTNER|H2SO4|John Figueiredo|Wellington, New Zealand
PARTNER|H2O|Rohit Figueiredo|New Delhi, India
BATCH_S|HIDROGÉNIO|S1|200|5000
BATCH_S|OXIGÉNIO|S1|1200|2500
BATCH_M|ÁGUA|R2|800|5000|0.1|HIDROGÉNIO:2#OXIGÉNIO:1
</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 ('''ggc.app.App.main'''). As propriedades são tratadas automaticamente pelo código de apoio.
 
        java -Dimport=test.import -Din=test.in -Dout=test.outhyp ggc.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 15:49, 14 September 2022