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

From Wiki**3

< Programação com Objectos‎ | Projecto de Programação com Objectos
(Created page with "{{PRJPOAvisosEN20212022}} {{PRJPOMandatory20212022}} {{TOCright}} '''<font color="red">ÉPOCA NORMAL</font>''' O objectivo do projecto é desenvolver uma aplicação de gest...")
 
(Propriedades e Funcionalidade dos Produtos)
 
(241 intermediate revisions by the same user not shown)
Line 4: Line 4:
 
'''<font color="red">ÉPOCA NORMAL</font>'''
 
'''<font color="red">ÉPOCA NORMAL</font>'''
  
O objectivo do projecto é desenvolver uma aplicação de gestão para uma empresa de distribuição. A empresa concede prémios de fidelização aos bons clientes (baseando-se no volume de compras). A funcionalidade da aplicação inclui, entre outras acções: registar/manipular dados de produtos para venda, registar/manipular dados de clientes, registar/manipular dados de fornecedores de produtos para venda, registar/manipular transacções de venda e encomenda e fazer pesquisas várias sobre a informação armazenada.
+
O objectivo do projecto é desenvolver uma aplicação de gestão do inventário de um entreposto de recursos naturais e seus derivados (formados por um ou mais produtos ou seus derivados). O entreposto concede prémios de fidelização aos bons parceiros (que lhe compram e vendem produtos), baseando-se no volume de negócio (compras e vendas). A funcionalidade da aplicação inclui, entre outras acções, manipular dados de produtos para negociar, registar/manipular dados de parceiros, registar/manipular transacções de compra e venda e outras e fazer pesquisas várias sobre a informação armazenada.
  
 
Neste texto, o tipo '''negrito''' indica um literal (i.e., é exactamente como apresentado); o símbolo ␣ indica um espaço; e o tipo ''itálico'' indica uma parte variável.
 
Neste texto, o tipo '''negrito''' indica um literal (i.e., é exactamente como apresentado); o símbolo ␣ indica um espaço; e o tipo ''itálico'' indica uma parte variável.
  
Empresa, Produtos, Clientes, Fornecedores e Transacções =
+
Entreposto, Produtos, Parceiros e Transacções =
  
Os produtos, clientes e fornecedores possuem uma chave única (cadeia de caracteres, não havendo distinção entre maiúsculas e minúsculas). As transacções (vendas e encomendas) possuem uma chave única inteira.
+
Os produtos e os parceiros possuem uma chave única (cadeia de caracteres, não havendo distinção entre maiúsculas e minúsculas). As transacções possuem uma chave única inteira gerida automaticamente.
  
O saldo inicial da empresa é 0 (zero).
+
O saldo inicial do entreposto é 0 (zero).
 +
<!--
 +
O entreposto tem a noção de sessão: um parceiro tem de iniciar essa sessão, indicando o seu identificador pessoal, antes da abertura do menu principal. Os parceiros podem ser carregados de ficheiros textuais (ver abaixo) ou a partir de sessões anteriores que foram preservadas via persistência Java (ver abaixo). Note-se que a própria sessão não é mantida de forma persistente.-->
  
 
== Propriedades e Funcionalidade dos Produtos ==
 
== Propriedades e Funcionalidade dos Produtos ==
  
Todos os produtos têm um fornecedor, um preço (um número inteiro positivo), um valor crı́tico (utilizado na gestão de existências) e o valor das existências.
+
Um produto pode ser simples ou derivado. Um produto derivado tem uma receita de fabrico. A receita corresponde à discriminação dos identificadores dos componentes (simples ou derivados) que formam o produto e respectivas quantidades. Não é possível a definição de receitas cujos componentes não sejam previamente conhecidos.
  
A empresa vende caixas e contentores de vários tipos. Outros tipos de produtos diversos para venda são disponibilizados à empresa por fornecedores.
+
Os produtos, tanto simples, como derivados, são comprados, vendidos, ou fabricados (no caso dos produtos derivados) em lotes. Cada lote tem um fornecedor (o parceiro a quem é comprado o produto), o número de unidades disponíveis do produto no lote e o preço de cada unidade. Podem existir vários lotes do mesmo produto, com o mesmo fornecedor, com preços iguais ou diferentes. O preço de um produto é sempre um número em vírgula flutuante não negativo. Quando um lote é esgotado, é removido do registo de dados.
  
As caixas são produtos que têm um volume relativamente pequeno e servem para guardar um número relativamente pequeno de itens, por forma a protegê-los durante o seu transporte. As caixas têm um dado nível de serviço: normal, aéreo, expresso e em mão.
+
O preço dos produtos é definido no acto da compra pelo entreposto. Este processo é uniforme para todos os produtos, excepto onde indicado (ver a seguir e abaixo).
  
Os contentores são produtos que têm um volume muito maior que as caixas, permitindo guardar uma maior quantidade de itens. Têm os mesmos 4 níveis de serviço das caixas. Adicionalmente, os contentores têm 4 níveis de qualidade de serviço: B4, C4, C5, DL.
+
O entreposto pode realizar operações de agregação e de desagregação. Uma operação de agregação consiste em criar um produto derivado a partir das existências dos seus componentes. O preço dos produtos derivados é calculado com base nos preços dos componentes, de acordo com a receita, tendo um agravamento multiplicativo (número positivo em vírgula flutuante), definido pela receita, relativo ao valor acrescentado associado à combinação. Por exemplo: a água é feita de hidrogénio (2x) e de oxigénio (1x). O seu preço é: <math>P_{H_2O} = (1 + \alpha) \times (2 \times P_H + P_O)</math> (onde <math>P_x</math> são preços e <math>\alpha</math> é o factor de agravamento, e.g. 0.1, correspondente a um aumento de 10% sobre o valor dos componentes). A reserva de recursos para construção de determinada quantidade de produto derivado contempla a totalidade da construção (e.g., não é possível respeitar um pedido de 10 unidades de água se apenas estiverem disponíveis 8 unidades de oxigénio). Em geral, operações de consumo de existências começam sempre pelas existências de menor preço, consumindo um ou mais lotes, total ou parcialmente, no processo.  
  
Cada livro é caracterizado pelo respectivo tı́tulo, autor e ISBN (cadeias de caracteres).  
+
É possível desagregar um produto derivado e recuperar os seus componentes. Não há perdas de produtos nesta operação, mas pode haver perda de valor: o preço é como indicado na secção de desagregação (ver abaixo). <!--o valor do produto derivado pode ser superior à soma dos valores dos preços dos seus componentes (o preço de um componente resultante de uma operação de desagregação é o preço mais alto conhecido para esse componente, considerando todos os lotes desse produto (passados e presentes). -->O parceiro que pede a operação de desagregação paga o diferencial de valor, caso seja positivo, sendo registada uma transacção de desagregação (com o valor do diferencial, mesmo que negativo).
  
Poderão ser definidos novos tipos de produtos (e.g. discos ou CDs/DVDs), que terão propriedades específicas.
+
== Propriedades e Funcionalidade dos Parceiros ==
  
== Propriedades e Funcionalidade dos Clientes ==
+
Cada parceiro tem um nome (cadeia de caracteres) e uma morada (cadeia de caracteres). Associada a cada parceiro existe ainda informação relativa às suas transacções.
  
Os clientes fazem compras que podem ser pagas mais tarde.
+
Um parceiro tem ainda um estatuto (e.g., '''Elite''', etc- -- ver abaixo), o qual tem impacto na sua relação com o entreposto.
  
Cada cliente tem um nome (cadeia de caracteres) e uma morada (cadeia de caracteres). Associada a cada cliente existe ainda informação relativa às suas compras.  
+
Dado um parceiro, é possível aceder ao historial das suas transacções (ver a seguir).
  
Um cliente tem ainda um estatuto (e.g., cliente "Elite" -- ver abaixo), o qual tem algum impacto na sua relação com a empresa.
+
== Propriedades e Funcionalidade das Transacções ==
 
 
Dado um cliente, é possível aceder ao historial das suas transacções.
 
 
 
== Propriedades e Funcionalidade dos Fornecedores ==
 
 
 
Os fornecedores respondem a encomendas por parte da empresa.
 
  
Cada fornecedor tem um nome (cadeia de caracteres) e uma morada (cadeia de caracteres).  
+
As transacções são identificadas por um número (inteiro), atribuído de forma automática pela aplicação. Este identificador começa em 0 (zero), sendo incrementado quando se regista uma nova transacção. A sequência de identificadores é partilhada por todos os tipos de transacções. Todas as transacções têm uma data de pagamento.
  
Dado um fornecedor, é possı́vel aceder ao seu historial de transacções. É ainda possível activar/desactivar a realização de transacções com um fornecedor. Um fornecedor inactivo não pode realizar transacções.
+
O entreposto realiza com os parceiros transacções de compra (do entreposto aos parceiros), venda (do entreposto aos parceiros) e desagregações (pelo entreposto a pedido dos parceiros). As desagregações: podem ser vistas como compras e vendas combinadas, para efeitos de progressão do estatuto dos parceiros. Uma desagregação corresponde a uma venda do produto a desagregar e à compra dos componentes que resultam da desagregação.
  
== Propriedades e Funcionalidade das Transacções ==
+
As compras são sempre pagas instantaneamente. As vendas podem ser pagas pelos parceiros mais tarde (excepto no contexto de uma desagregação: nesse caso, são pagas imediatamente).
  
Existem dois tipos de transacção: vendas e encomendas. As transacções são identificadas por um número (inteiro), atribuído de forma automática pela aplicação. Este identificador começa em 0 (zero), sendo incrementado quando se regista uma nova transacção. A sequência de identificadores é partilhada por todas as transacções (vendas e encomendas).
+
=== Compras (do entreposto a parceiros) ===
 +
Uma compra está associada a um parceiro e envolve uma ou mais unidades de um produto fornecido pelo parceiro em causa. O custo unitário do produto é definido pelo parceiro no momento da transacção. Quando se faz uma compra deve considerar-se que a compra é paga imediatamente e que as existências do entreposto são actualizadas considerando os produtos comprados. É mantida informação sobre cada produto, o parceiro que o forneceu e o preço que foi pago.
  
Uma encomenda está associada a um fornecedor e envolve uma ou mais unidades de um ou mais produtos fornecidos pelo fornecedor em causa. O custo unitário de cada produto corresponde ao custo do produto em causa. A encomenda guarda o seu custo total, para que futuras alterações no preço de um produto não alterem o valor que foi pago pela encomenda. Quando se faz uma encomenda deve considerar-se que a encomenda foi paga imediatamente e que as existências da empresa foram actualizadas considerando os produtos encomendados.
+
=== Vendas (do entreposto a parceiros) ===
 +
Uma venda está associada a um parceiro e envolve uma ou mais unidades de um único produto. As unidades podem ser provenientes de vários lotes e ter preços diferentes, dependendo dos parceiros que forneceram o produto. Cada venda tem uma data limite de pagamento: primeiro realiza-se a venda e só depois é que se procede ao seu pagamento.
  
Uma venda envolve uma ou mais unidades de um único produto. Cada venda tem uma data limite de pagamento: primeiro realiza-se a venda e só depois é que se procede ao seu pagamento.
+
Se o produto a adquirir for derivado e não existir em quantidade suficiente no entreposto, a quantidade em falta pode ser fabricada a partir de outros produtos, de acordo com a receita correspondente ao produto em venda. O preço a pagar é o definido pela reserva dos componentes individuais (com a selecção do preço mais baixo, etc.) e o correspondente factor de valor acrescentado (ver acima). Note-se que, na venda de múltiplas unidades de um produto derivado, o processo de construção deve ser repetido, pelo que cada uma das unidades do produto derivado pode ter custo diferente das anteriores. Caso falte algum componente da receita, então a operação de agregação deve ser abortada indicando o primeiro produto (pela ordem da receita) que viola a condição de disponibilidade.
  
O preço a pagar por um cliente depende do tempo que demora a realizar o pagamento. São considerados os seguintes perı́odos ('''N''' é 5 para caixas, 8 para contentores e 3 para livros):
+
O preço a pagar por um parceiro (numa operação de venda por parte do entreposto) depende ainda do tempo que demora a realizar o pagamento. São considerados os seguintes períodos ('''N''' é 5 para produtos simples, 3 para produtos derivados):
  
 
* '''P1''' - até '''N''' dias antes do limite de pagamento ('''data_limite_de_pagamento − data_actual ≥ N''').
 
* '''P1''' - até '''N''' dias antes do limite de pagamento ('''data_limite_de_pagamento − data_actual ≥ N''').
Line 70: Line 68:
 
                         prazo - N        prazo        prazo + N
 
                         prazo - N        prazo        prazo + N
 
</source>
 
</source>
 +
 +
Note-se que estes períodos são arbitrários e não correspondem a qualquer conceito especial de tempo, podendo ser redefinidos ou mesmo eliminados em revisões do processo de venda.
 +
 +
=== Desagregações de produtos (pelo entreposto a pedido de parceiros) ===
 +
 +
Uma desagregação é uma transacção associada a um parceiro e envolve um único produto. Um parceiro pode pedir uma desagregação para permitir outras operações sobre os componentes do produto a desagregar. Se o produto a desagregar for atómico, a acção não tem qualquer efeito.
 +
 +
As desagregações são operações sobre o estado do entreposto por parte de um parceiro: a desagregação remove uma quantidade de produto derivado das existências do entreposto (como se fosse uma venda) e introduz nas existências do entreposto os seus componentes (como se fosse uma compra ao parceiro envolvido). O preço de inserção é o menor preço nos lotes disponíveis para esse produto. Se não existirem lotes disponíveis, o preço é o maior preço associado a esse produto no histórico de operações do entreposto.
 +
O parceiro paga ao entreposto a diferença (positiva) entre os valores inicial (o valor da quantidade de produto não desagregado) e final (o valor das quantidades de componentes obtidas com base na desagregação).
  
 
==  Notificações ==
 
==  Notificações ==
  
Quando se regista um novo produto, os clientes devem ser colocados como entidades interessadas em receber notificações sobre eventos a ele associados. Em qualquer momento, um cliente 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 um produto fica mais barato. 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 descidas de preços. As notificações são registadas nos clientes que as recebem.
+
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.
 
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.
<!--
 
Quando as existências de um produto atingem o correspondente valor crı́tico (abaixo do qual há perigo de o produto ficar esgotado), o fornecedor do produto deve ser notificado. Fornecedores inactivos não devem ser notificados. As notificações são compostas pela cadeia de caracteres constituı́da pela identificação do produto e pela descrição da notificação ('''CRITICAL'''), sendo registadas tanto na empresa, como nos fornecedores que as recebem.
 
-->
 
  
==  Contabilização de Pontos (Clientes) ==
+
==  Contabilização de Pontos (Parceiros) ==
 +
 
 +
As multas e os descontos aplicam-se apenas no pagamento de transacções de venda.
  
As multas e os descontos aplicam-se apenas no pagamento de transacções de clientes (vendas).
+
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 clientes: '''Nomal''', '''Selection''' e '''Elite'''. A classificação de um cliente tem impacto nas multas, descontos e prazos de pagamento a aplicar no pagamento de uma transacção (venda).
+
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 cliente paga uma transacção dentro do prazo, acumula um número de pontos correspondente a 10 vezes o valor pago, se o pagamento for realizado dentro do prazo. Não há contabilização de pontos em pagamentos atrasados. A verificação do atraso é realizada quando se realiza o pagamento de uma transacção.
+
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 clientes passam ao nível '''Selection''' se acumularem mais de 2000 pontos. Os clientes passam ao nível '''Elite''' se acumularem mais de 25000 pontos.  
+
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 cliente se atrasa no pagamento da transacções, é despromovido: um cliente '''Elite''' passa a '''Selection''' se o pagamento ocorrer com um atraso de pagamento superior a 15 dias (perde 75% dos pontos acumulados); um cliente '''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 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 cliente e dos prazos associados à venda e ao estatuto.
+
As multas e os descontos dependem do estatuto do parceiro e dos prazos associados à venda e ao estatuto.
  
 
{|
 
{|
Line 105: Line 111:
 
! style="width: 11.25%; background: #ffad99;" |
 
! style="width: 11.25%; background: #ffad99;" |
 
|-
 
|-
|  
+
|
 
| <font color="red">Multa</font>
 
| <font color="red">Multa</font>
 
| <font color="forestgreen">Desconto</font>
 
| <font color="forestgreen">Desconto</font>
Line 148: Line 154:
 
== Data ==
 
== 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 da empresa a partir de um suporte persistente.
+
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 que representam o número de dias.
+
Os avanços de data são valores inteiros positivos que representam o número de dias.
  
 
= Funcionalidade da aplicação =
 
= Funcionalidade da aplicação =
Line 158: Line 164:
 
A base de dados com os conceitos pré-definidos é [[#Leitura de Dados a Partir de Ficheiros Textuais|carregada no início da 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]].
  
É possível saber os saldos da empresa (diferencial entre vendas e compras). Existe um saldo disponível, correspondente à diferença entre as vendas realmente pagas e as encomendas, 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 encomendas.
+
É 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 pela empresa.
+
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.}}
 
{{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 '''woo.Storefront''' 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.}}
+
{{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 ==
 
== Serialização ==
Line 171: Line 177:
 
== Funcionalidade Associada a Entidades do Domínio ==
 
== Funcionalidade Associada a Entidades do Domínio ==
  
A seguinte funcionalidade sobre produtos deve ser suportada pela aplicação: (i) visualizar um produto; (ii) registar um novo produto; (iii) alterar o preço de um produto.
+
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 clientes deve ser suportada pela aplicação: (i) visualizar um ou mais clientes; (ii) registar um novo cliente; (iii) activar/desactivar notificações relativas a produtos; (iv) consultar o histórico de transacções realizadas por um cliente.
 
  
A seguinte funcionalidade sobre fornecedores deve ser suportada pela aplicação: (i) visualizar um fornecedor; (ii) registar um novo fornecedor; (iii) Permitir/inibir um fornecedor; (iv) consultar o histórico de transacções realizados.
+
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 venda; (iii) registar uma nova encomenda; (iv) pagar uma transacção.
+
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 =
 
= 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:
 
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:
* Adicionar novos tipos de produtos;
 
 
* Definir novas entidades que desejem ser notificadas da alteração do estado dos produtos;
 
* Definir novas entidades que desejem ser notificadas da alteração do estado dos produtos;
 
* Adicionar novos modos de entrega de mensagens (notificações);
 
* Adicionar novos modos de entrega de mensagens (notificações);
* Adicionar novas políticas de recompensa de clientes;
+
* Adicionar novas políticas de recompensa de parceiros;
 
* Adicionar novas formas de consulta.
 
* Adicionar novas formas de consulta.
  
Line 194: Line 197:
 
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).
 
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-uuilib''' e '''woo-app'''). As mensagens não podem ser usadas no núcleo da aplicação ('''woo-core'''). Além disso, não podem ser definidas novas. Potenciais omissões devem ser esclarecidas antes de qualquer implementação.
+
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.
  
As excepções usadas na interacção, excepto se indicado, são subclasses de '''pt.tecnico.po.ui.DialogException''', são lançadas pelos comandos e tratadas por '''pt.tecnico.po.ui.Menu'''. Outras excepções não devem substituir as fornecidas nos casos descritos.
+
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 apresentacção de listas (Fornecedores, 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.
+
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'' '''woo.app''', '''woo.app.main''', '''woo.app.products''', '''woo.app.clients''', '''woo.app.suppliers''', '''woo.app.transactions''', '''woo.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 '''woo-app''').}}
+
{{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 ==
 
== 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 Clientes]], [[#Gestão e consulta de dados da aplicação|Gestão de Fornecedores]], [[#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 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 '''woo.app.main.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''woo.app.main.Message'''.
+
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'' '''woo.app.main''' (disponível no CVS), respectivamente: '''DoOpen''', '''DoSave''', '''DoDisplayDate''', '''DoAdvanceDate''', '''DoOpenMenuProducts''', '''DoOpenMenuClients''', '''DoOpenMenuSuppliers''', '''DoOpenMenuTransactions''', '''DoOpenMenuLookups''', '''DoShowGlobalBalance'''.}}
+
{{CVSCode|Estes comandos já estão implementados  nas classes da ''package'' '''ggc.app.main''' (disponível no CVS), respectivamente: '''DoOpen''', '''DoSave''', '''DoDisplayDate''', '''DoAdvanceDate''', '''DoOpenMenuProducts''', '''DoOpenMenuPartners''', '''DoOpenMenuTransactions''', '''DoOpenMenuLookups''', '''DoShowGlobalBalance'''.}}
  
 
=== Salvaguarda do estado actual da aplicação ===
 
=== Salvaguarda do estado actual da aplicação ===
Line 216: Line 219:
 
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:
 
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 ('''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.
+
* '''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 '''newSaveAs()'''. Não é executada nenhuma acção se não existirem alterações desde a última salvaguarda.
+
* '''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).
 
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).
Line 225: Line 228:
 
=== Mostrar data actual ===
 
=== Mostrar data actual ===
  
A data actual do sistema é apresentada através da mensagem '''currentDate()'''.
+
A data actual do sistema é apresentada através da mensagem '''Message.currentDate()'''.
  
 
=== Avançar data actual ===
 
=== Avançar data actual ===
  
O número de dias a avançar é pedido através de '''requestDaysToAdvance()'''. O valor indicado deve ser positivo. Caso contrário, deve ser lançada a excepção '''InvalidDateException'''.
+
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 ===
 
=== 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 Produtos''' -- Abre o menu de gestão de produtos.
* '''Menu de Gestão de Clientes''' -- Abre o menu de gestão de clientes.
+
* '''Menu de Gestão de Parceiros''' -- Abre o menu de gestão de parceiros.
* '''Menu de Gestão de Fornecedores''' -- Abre o menu de gestão de fornecedores.
 
 
* '''Menu de Gestão de Transacções''' -- Abre o menu de gestão de transacções.
 
* '''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).
 
* '''Menu de Consultas''' -- Abre o menu de consultas (pesquisas).
Line 241: Line 243:
 
=== Mostrar saldo global ===
 
=== Mostrar saldo global ===
  
Esta opção apresenta os valores (inteiros) correspondentes aos saldos disponível e contabilístico da empresa. Embora internamente o valor dos saldos esteja representado em vírgula flutuante, a apresentação é arredondada ao inteiro mais próximo.
+
Esta opção apresenta os valores (inteiros) 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 '''currentBalance()'''.
+
A apresentação faz-se através da mensagem '''Message.currentBalance()'''.
  
 
== Menu de Gestão de Produtos ==
 
== 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]], [[#Registar caixa|Registar caixa]], [[#Registar contentor|Registar contentor]], [[#Registar livro|Registar livro]], [[#Alterar preço de produto|Alterar preço de produto]].
+
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 '''woo.app.products.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''woo.app.products.Message'''.
+
<!--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 produto ('''requestProductKey()''') e o produto não existir, é lançada a excepção '''UnknownProductKeyException''' (excepto no processo de registo). No processo de registo, caso o identificador do produto indicado já exista, deve ser lançada a excepção '''DuplicateProductKeyException'''. Na ocorrência de excepções (estas ou outras), as operações não têm efeito.
+
Sempre que é pedido o identificador de um produto ('''Prompt.productKey()''') e o produto não existir, é lançada a excepção '''UnknownProductKeyException''' (excepto no processo de registo). <!--No processo de registo, caso o identificador do produto indicado já exista, deve ser lançada a excepção '''DuplicateProductKeyException'''.--> 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'' '''woo.app.products''' (disponível no CVS), respectivamente: '''DoShowAllProducts''', '''DoRegisterProductBox''', '''DoRegisterProductContainer''', '''DoRegisterProductBook''', '''DoChangePrice'''.}}
+
{{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''ggc.app.products''' (disponível no CVS), respectivamente: '''DoShowAllProducts''', '''DoShowAvailableBatches''', '''DoShowBatchesByPartner''', '''DoShowProductBatches'''.}}
  
 
=== Visualizar todos os produtos ===
 
=== Visualizar todos os produtos ===
 +
O formato de apresentação de cada produto é o seguinte (cada linha indica um produto):
  
O formato de apresentação de cada tipo de produto é o seguinte:
+
Produtos simples:
 
+
  ''idProduto''|''preço-máximo''|''stock-actual-total''
  BOX|''idProduto''|''idFornecedor''|''preço''|''valor-crítico''|''stock-actual''|''tipo-de-serviço''
 
CONTAINER|''idProduto''|''idFornecedor''|''preço''|''valor-crítico''|''stock-actual''|''tipo-de-serviço''|''nível-de-serviço''
 
BOOK|''idProduto''|''idFornecedor''|''preço''|''valor-crítico''|''stock-actual''|''título''|''autor''|''isbn''
 
  
=== Registar caixa ===
+
Exemplo:
 +
  HIDROGÉNIO|200|5000
 +
  OXIGÉNIO|1200|2500
  
O sistema pede o identificador que ficará associado ao produto, o preço ('''requestPrice()'''), o valor crítico ('''requestStockCriticalLevel()''') e o identificador do fornecedor ('''requestSupplierKey()''') e o tipo de serviço de transporte associado ('''requestServiceType()''').
+
Produtos derivados (é apresentado o produto e a lista de componentes e respectivas quantidades da sua receita):
 +
''idProduto''|''preço-máximo''|''stock-actual-total''|''componente-1'':''quantidade-1'':...:''componente-n'':''quantidade-n''
  
Se o fornecedor não existir, deve ser lançada a excepção '''UnknownSupplierKeyException'''. Se a resposta para o tipo de serviço não for '''NORMAL''', '''AIR''', '''EXPRESS''' ou '''PERSONAL''', deve ser lançada a excepção '''UnknownServiceTypeException'''.
+
Exemplo:
 +
  ÁGUA|5000|800|HIDROGÉNIO:2:OXIGÉNIO:1
  
Imediatamente após o registo, o número de existências é zero.
+
Em ambos os casos, ''stock-actual-total'' pode ser 0 (zero).
  
=== Registar contentor ===
+
=== Visualizar todos os lotes ===
  
São pedidas as mesmas informações que para o registo de caixas e verificadas as mesmas condições. Além daquelas informações, é ainda pedida a qualidade de serviço ('''requestServiceLevel()'''). Se a resposta não for '''B4''', '''C4''', '''C5''' ou '''DL''', deve ser lançada a excepção '''UnknownServiceLevelException'''.
+
O formato de apresentação de cada lote de produto é o seguinte (cada linha indica um lote):
  
Imediatamente após o registo, o número de existências é zero.
+
Produtos simples e derivados:
 +
''idProduto''|''idParceiro''|''preço''|''stock-actual''
  
=== Registar livro ===
+
Exemplo:
 +
  ÁGUA|EPAL|1150.00|800
 +
  HIDROGÉNIO|Cryostuffs|110.50|5000
 +
  OXIGÉNIO|Cryostuffs|820.50|2500
  
O sistema pede o identificador único, o título ('''requestBookTitle()'''), o autor ('''requestBookAuthor()'''), o ISBN ('''requestISBN()'''), o preço ('''requestPrice()'''), o valor crítico ('''requestStockCriticalLevel()''') e o identificador do fornecedor ('''requestSupplierKey()'''). Se o fornecedor não existir, deve ser lançada a excepção '''UnknownSupplierKeyException''', tal como para os outros produtos.
+
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.
  
Imediatamente após o registo, o número de existências é zero.
+
=== Visualizar os lotes fornecidos por um dado parceiro ===
  
=== Alterar preço de produto ===
+
É 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).
  
O sistema pede o identificador do produto e o novo preço ('''requestPrice()''').
+
=== Visualizar os lotes de um dado produto ===
  
Tal como mencionado acima, os clientes podem ser notificados quando o preço de um produto varia.
+
É 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.
  
Caso ocorra um erro durante a alteração do preço de um produto existente, a operação falha silenciosamente.
+
== Menu de Gestão de Parceiros ==
  
== Menu de Gestão de Clientes ==
+
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 do parceiro|Mostrar transacções do parceiro]].
  
Este menu permite efectuar operações sobre a base de dados de clientes. A lista completa é a seguinte: [[#Mostrar cliente|Mostrar cliente]], [[#Mostrar todos os clientes|Mostrar todos os clientes]], [[#Registar cliente|Registar cliente]], [[#Activar/desactivar notificações de um produto|Activar/desactivar notificações de um produto]], [[#Mostrar transacções do cliente|Mostrar transacções do cliente]].
+
<!--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'''.
  
As etiquetas das opções deste menu estão definidas na classe '''woo.app.clients.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''woo.app.clients.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'''.
  
Sempre que for pedido o identificador de um cliente ('''requestClientKey()''') e o cliente não existir, é lançada a excepção '''UnknownClientKeyException''' (excepto no processo de registo). No processo de registo, caso o identificador indicado já exista, deve ser lançada a excepção '''DuplicateClientKeyException'''.
+
{{CVSCode|Estes comandos já estão implementados nas classes da ''package'' '''ggc.app.partners''' (disponível no CVS), respectivamente: '''DoShowPartner''', '''DoShowAllPartners''', '''DoRegisterPartner''', '''DoToggleProductNotifications''', '''DoShowPartnerTransactions'''.}}
  
{{CVSCode|Estes comandos já estão implementados  nas classes da ''package'' '''woo.app.clients''' (disponível no CVS), respectivamente: '''DoShowClient''', '''DoShowAllClients''', '''DoRegisterClient''', '''DoToggleProductNotifications'''<!--, '''DoToggleNotifications'''-->, '''DoShowClientTransactions'''.}}
+
=== Mostrar parceiro ===
  
=== Mostrar cliente ===
+
É pedido o identificador do parceiro e apresentada a sua informação. O formato de apresentação é o seguinte (o valor das compras efectuadas refere-se ao momento da compra; o valor das compras pagas refere-se ao valor realmente pago):
  
É pedido o identificador do cliente e apresentada a sua informação. O formato de apresentação é o seguinte (o valor das compras efectuadas refere-se ao momento da compra; o valor das compras pagas refere-se ao valor realmente pago):
+
  ''id''|''nome''|''endereço''|''estatuto''|''valor-vendas''|''valor-compras-efectuadas''|''valor-compras-pagas''
 
 
  ''id''|''nome''|''endereço''|''estatuto''|''valor-compras-efectuadas''|''valor-compras-pagas''
 
  
 
O estatuto corresponde a '''NORMAL''', '''SELECTION''', '''ELITE''', conforme o caso.
 
O estatuto corresponde a '''NORMAL''', '''SELECTION''', '''ELITE''', conforme o caso.
  
Após esta linha, são apresentadas as notificações do cliente (modo de entrega por omissão), pela ordem em que foram enviadas pela aplicação.
+
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''
 
  ''tipo-de-notificação''|''idProduto''|''preço-do-produto''
  
Após esta visualização, considera-se que o cliente fica sem notificações registadas.
+
Após esta visualização, considera-se que o parceiro fica sem notificações registadas.
  
=== Mostrar todos os clientes ===
+
=== Mostrar todos os parceiros ===
  
O formato de apresentação é como para clientes individuais (opção anterior), mas não se apresentam as notificações dos clientes.
+
O formato de apresentação é como para parceiros individuais (opção anterior), mas não se apresentam as notificações dos parceiros.
  
=== Registar cliente ===
+
=== Registar parceiro ===
  
São pedidos o identificador do cliente, o nome ('''requestClientName()''') (cadeia de caracteres) e o endereço do cliente ('''requestClientAddress()''') (cadeia de caracteres) e regista-se o novo cliente. Quando um cliente é registado, aceita notificações relativas a todos os produtos.
+
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 cliente com o mesmo identificador, deve ser lançada a excepção '''DuplicateClientKeyException''', não se realizando o registo.
+
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 ===
 
=== Activar/desactivar notificações de um produto ===
  
São pedidos o identificador do cliente e o identificador do produto ('''requestProductKey()'''). Se as notificações relativas ao produto estavam activas, passam a estar inactivas, e vice-versa. É apresentada na saída o resultado da operação: '''notificationsOn()''' ou '''notificationsOff()'''.
+
É pedido o identificador do parceiro ('''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()'''.-->
  
=== Mostrar transacções do cliente ===
+
Se o produto indicado não existir, é lançada a excepção '''UnknownProductKeyException'''.
  
É pedido o identificador do cliente e apresentadas todas as transacções por ele realizadas. O formato de apresentação é como descrito abaixo (visualização de transacções de venda).
+
=== Mostrar transacções de compra do parceiro ===
  
== Menu de Gestão de Fornecedores ==
+
É pedido o identificador do parceiro e apresentadas todas as transacções de compra por ele realizadas. O formato de apresentação é como descrito abaixo (visualização de transacções).
 +
<!--
 +
=== Permitir/Inibir transacções ===
  
Este menu apresenta as operações disponíveis sobre fornecedores e assuntos relacionados. A lista completa é a seguinte: [[#Mostrar fornecedores|Mostrar fornecedores]], [[#Registar fornecedor|Registar fornecedor]], [[#Permitir/Inibir transacções|Permitir/Inibir transacções]], [[#Mostrar transacções do fornecedor|Mostrar transacções do fornecedor]].
+
Se as transacções estavam activas para o parceiro activo, passam a estar inactivas, e vice-versa.
 +
-->
  
As etiquetas das opções deste menu estão definidas na classe '''woo.app.suppliers.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''woo.app.suppliers.Message'''.
+
=== Mostrar transacções de venda (e desagregação) do parceiro ===
  
Sempre que é pedido o identificador da fornecedor ('''requestSupplierKey()'''), é lançada a excepção '''UnknownSupplierKeyException''', se o fornecedor indicado não existir (excepto no processo de registo). No processo de registo, caso o identificador indicado já exista, deve ser lançada a excepção '''DuplicateSupplierKeyException'''.
+
É pedido o identificador do parceiro e apresentadas todas as transacções de venda por ele realizadas. O formato de apresentação é como descrito abaixo (visualização de transacções).
 +
<!--
 +
=== Permitir/Inibir transacções ===
  
{{CVSCode|Estes comandos já estão implementados  nas classes da ''package'' '''woo.app.suppliers''' (disponível no CVS), respectivamente: '''DoShowSuppliers''', '''DoRegisterSupplier''', '''DoToggleTransactions''', '''DoShowSupplierTransactions'''.}}
+
Se as transacções estavam activas para o parceiro activo, passam a estar inactivas, e vice-versa.
 +
-->
  
=== Mostrar fornecedores ===
+
== 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]].
  
O formato de apresentação é o seguinte:
+
<!--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'''.
  
''id''|''nome''|''endereço''|''activo?''
+
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.-->
  
Os valores para o campo ''activo?'' são '''yes()''' ou '''no()'''.
+
{{CVSCode|Estes comandos já estão implementados  nas classes da ''package'' '''ggc.app.transactions''' (disponível no CVS), respectivamente: '''DoShowTransaction''', '''DoRegisterBreakdownTransaction''', '''DoRegisterSaleTransaction''', '''DoRegisterAcquisitionTransaction''', '''DoReceivePayment'''.}}
  
=== Registar fornecedor ===
+
=== Visualizar ===
  
São pedidos o identificador do fornecedor, o nome ('''requestSupplierName()''') (cadeia de caracteres) e o endereço ('''requestSupplierAddress()''') (cadeia de caracteres), registando-se o novo fornecedor. Quando um fornecedor é registado, fica no estado activo.
+
O sistema pede o identificador da transacção a visualizar.
  
Se já existir um fornecedor com o mesmo identificador, deve ser lançada a excepção '''DuplicateSupplierKeyException''', não se realizando a operação.  
+
Nas apresentações, o campo ''valor-base'' é o valor da transacção sem multas/descontos.
  
=== Permitir/Inibir transacções ===
+
Se a transacção for respeitante a uma venda a um parceiro, apresenta-se com o seguinte formato:
  
É pedido o identificador do fornecedor. Se as transacções estavam activas para esse fornecedor, passam a estar inactivas, e vice-versa. É apresentada na saída o resultado da operação: '''transactionsOn()''' ou '''transactionsOff()'''.
+
'''VENDA'''|''id''|''idParceiro''|''idProduto''|''quantidade''|''valor-base''|''valor-a-pagamento''|''data-limite''|''data-pagamento''
  
=== Mostrar transacções do fornecedor ===
+
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.
  
É pedido o identificador do fornecedor e apresentas todas as transacções por ele realizadas. O formato de apresentação é como descrito abaixo  (visualização de transacções de encomenda).
+
Se a transacção corresponder a uma compra a um parceiro, apresenta-se com o seguinte formato:
  
== Menu de Gestão de Transacções ==
+
'''COMPRA'''|''id''|''idParceiro''|''idProduto''|''quantidade''|''valor-pago''|''data-pagamento''
Este menu apresenta as operações relacionadas com transacções. A lista completa é a seguinte: [[#Visualizar|Visualizar]], [[#Registar Venda|Registar Venda]], [[#Registar Encomenda|Registar Encomenda]], [[#Pagar|Pagar]].
 
  
As etiquetas das opções deste menu estão definidas na classe '''woo.app.transactions.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''woo.app.transactions.Message'''.
+
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:
  
Sempre que é pedido o identificador do fornecedor ('''requestSupplierKey()'''), é lançada a excepção '''UnknownSupplierKeyException''', se o fornecedor indicado não existir. Sempre que é pedido o identificador do cliente ('''requestClientKey()'''), é lançada a excepção '''UnknownClientKeyException''', se o cliente indicado não existir. Sempre que é pedido o identificador de produto ('''requestProductKey()'''), é lançada a excepção '''UnknownProductKeyException''', se o produto indicado não existir. Sempre que é pedido o identificador da transacção ('''requestTransactionKey()'''), é lançada a excepção '''UnknownTransactionKeyException''', se a transacção indicada não existir.
+
'''DESAGREGAÇÃO'''|''id''|''idPa''|''idPr''|''quantidade''|''vbase''|''vpag''|''data''|''idC1'':''q1'':''v1''#...#''idCN'':''qN'':''vN''
  
{{CVSCode|Estes comandos já estão implementados  nas classes da ''package'' '''woo.app.transactions''' (disponível no CVS), respectivamente: '''DoShowTransaction''', '''DoRegisterSaleTransaction''', '''DoRegisterOrderTransaction''', '''DoPay'''.}}
+
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'''. Cada componente é separado do seguinte por '''#'''.
  
=== Visualizar ===
+
=== Registar Desagregação (pelo entreposto a pedido de um parceiro) ===
  
O sistema pede o identificador da transacção a visualizar.  
+
Para registar uma desagregação, é pedido o identificador do parceiro que requisita a transacçã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.
  
Nas apresentações, o campo ''valor-base'' é o valor da transacção sem multas/descontos.
+
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.
  
Se a transacção for respeitante a uma venda a um cliente, apresenta-se com o seguinte formato:
+
Esta transacção regista o produto de origem e os resultantes, bem como os respectivos valores.
  
''id''|''idCliente''|''idProduto''|''quantidade''|''valor-base''|''valor-a-pagamento''|''data-limite''|''data-pagamento''
+
=== Registar Venda (do entreposto a um parceiro) ===
  
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.
+
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).
  
Se a transacção corresponder a uma encomenda a um fornecedor, apresenta-se com um cabeçalho (linha inicial):
+
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.
  
''id''|''idFornecedor''|''valor-base''|''data-pagamento''
+
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 linha inicial é seguida por várias linhas, cada uma com a descrição de cada produto incluído na transacção (por ordem de inserção na encomenda):
+
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.
 
 
''idProduto''|''quantidade''
 
 
 
=== Registar Venda ===
 
 
 
Para registar uma venda, é pedido <!--o identificador da venda,--> o identificador do cliente, a data limite para o pagamento ('''requestPaymentDeadline()'''), o identificador do produto a vender e a respectiva quantidade ('''requestAmount()'''). Se a quantidade for superior às existências actuais, deve ser lançada a excepção '''UnavailableProductException''' (não se realiza a venda).
 
 
 
A actualização dos produtos da empresa tem lugar logo após o registo da venda, ou seja, considera-se que a venda é instantânea.
 
<!--
 
Tal como mencionado acima, os fornecedores são notificados quando um produto atinge o nível crítico. Quando o processo de registo de uma venda termina, o sistema apresenta o número de fornecedores que foram efectivamente notificados (fornecedores inibidos, embora notificáveis, não devem ser contabilizados).
 
-->
 
  
=== Registar Encomenda ===
+
=== Registar Compra (do entreposto a um parceiro) ===
  
Para registar uma encomenda, é pedido o identificador do fornecedor. De seguida, é pedido o identificador do produto a encomendar e a quantidade a encomendar ('''requestAmount()'''). Estas duas perguntas são repetidas para outros produtos enquanto a resposta a '''requestMore()''' (pergunta feita depois de cada quantidade) for afirmativa (leitura de um booleano).
+
É pedido o identificador do parceiro a quem se realiza a compra, o identificador do produto que se está a comprar 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 fornecedor indicado estiver inibido de efectuar transacções, deve ser lançada a excepção '''UnauthorizedSupplierException''' 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.  
+
Se o identificador do produto for desconhecido, então é perguntado ao parceiro se quer introduzir uma receita para um produto derivado. Se a resposta for negativa, trata-se de um produto atómico. Caso contrário, é pedido o número de componentes da receita ('''Prompt.numberOfComponents()''') e, em ciclo, os identificadores e quantidades dos vários componentes: os identificadores são pedidos como para qualquer outro identificador de produto; as quantidades são pedidas com '''Prompt.amount()'''.
  
A actualização de existências dos produtos da empresa tem lugar logo após o registo da encomenda, ou seja, considera-se que a encomenda é instantânea. A actualização do saldo da empresa também é assumida como instantânea, i.e., assume-se que a encomenda é paga a pronto.
+
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.
  
=== Pagar ===
+
=== Receber Pagamento de Venda (do entreposto a um parceiro) ===
  
Apenas é possível pagar vandas. Tentativas de pagamento de encomendas não produzem nenhum resultado.
+
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.
 
É pedido o identificador da venda a pagar. Se a venda já tiver sido paga, não é realizada nenhuma acção.
Line 419: Line 422:
 
== Menu de Consultas ==
 
== 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 cliente|Mostrar facturas pagas por cliente]].
+
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 '''woo.app.lookups.Label'''. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe '''woo.app.lookups.Message'''.
+
<!--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 cliente ('''requestClientKey()'''), é lançada a excepção '''UnknownClientKeyException''', se o cliente indicado não existir. Sempre que é pedido o identificador de produto ('''requestProductKey()'''), é lançada a excepção '''UnknownProductKeyException''', se o produto indicado não existir.
+
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.
 
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'' '''woo.app.lookups''' (disponível no CVS), respectivamente: '''DoLookupProductsUnderTopPrice''', '''DoLookupPaymentsByClient'''.}}
+
{{CVSCode|Estes comandos já estão parcialmente implementados  nas classes da ''package'' '''ggc.app.lookups''' (disponível no CVS), respectivamente: '''DoLookupProductsUnderTopPrice''', '''DoLookupPaymentsByPartner'''.}}
  
=== Mostrar produtos com preço abaixo de limite ===
+
=== Mostrar lotes de produtos com preço abaixo de limite ===
  
Pede-se o valor limite pretendido ('''requestPriceLimit()''') e apresentam-se todos os produtos disponíveis na empresa cujo preço é inferior ao preço indicado. É apresentado um produto por linha.
+
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 facturas pagas por cliente ===
+
=== Mostrar transacções pagas por parceiro ===
  
Pede-se o identificador do cliente e apresentam-se as transacções do cliente que já estão pagas (uma transacção por linha).
+
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 =
 
= Leitura de Dados a Partir de Ficheiros Textuais =
Line 443: Line 446:
 
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.
 
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.
+
Cada linha tem uma descrição distinta, mas que segue os seguintes formatos.
  
  SUPPLIER|''id''|''nome''|''endereço''
+
  PARTNER|''id''|''nome''|''endereço''
CLIENT|''id''|''nome''|''endereço''
 
  
BOX|''id''|''tipo-de-serviço''|''id-fornecedor''|''preço''|''valor-crítico''|''exemplares''
+
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):
CONTAINER|''id''|''tipo-de-serviço''|''nível-de-serviço''|''id-fornecedor''|''preço''|''valor-crítico''|''exemplares''
 
  
  BOOK|''id''|''título''|''autor''|''isbn''|''id-fornecedor''|''preço''|''valor-crítico''|''exemplares''
+
  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 fornecedores e de clientes precedem sempre as dos produtos.
+
As definições de parceiros precedem sempre as dos lotes.
  
 
Um exemplo de conteúdo do ficheiro inicial é como se segue:
 
Um exemplo de conteúdo do ficheiro inicial é como se segue:
Line 459: Line 461:
 
{{CollapsedCode|Exemplo de ficheiro de entrada textual|
 
{{CollapsedCode|Exemplo de ficheiro de entrada textual|
 
<source lang="text">
 
<source lang="text">
SUPPLIER|S1|Toshiba|Tokyo, Japan
+
PARTNER|S1|Toshiba|Tokyo, Japan
SUPPLIER|W2|Papelaria Fernandes|Oeiras, Portugal
+
PARTNER|W2|Pedraria Fonseca|Oeiras, Portugal
SUPPLIER|P1|Publicações Europa-América|Lisboa, Portugal
+
PARTNER|P1|Lages do Chão|Lisboa, Portugal
SUPPLIER|P3|O’Reilly|Köln, Germany
+
PARTNER|P3|O’Brian Rocks|Köln, Germany
CLIENT|R2|Jorge Figueiredo|Lisboa, Portugal
+
PARTNER|R2|Jorge Figueiredo|Lisboa, Portugal
CLIENT|E4|Filomena Figueiredo|Lisboa, Portugal
+
PARTNER|E4|Filomena Figueiredo|Lisboa, Portugal
CLIENT|ER|Abdul Figueiredo|Casablanca, Morocco
+
PARTNER|ER|Abdul Figueiredo|Casablanca, Morocco
CLIENT|O9|Hellen Figueiredo|San Francisco, CA, USA
+
PARTNER|O9|Hellen Figueiredo|San Francisco, CA, USA
CLIENT|H2SO4|John Figueiredo|Wellington, New Zealand
+
PARTNER|MM|John Figueiredo|Wellington, New Zealand
CLIENT|H2O|Rohit Figueiredo|New Delhi, India
+
PARTNER|M1|Rohit Figueiredo|New Delhi, India
BOX|C6H5OH|NORMAL|W2|2|20|100
+
BATCH_S|HIDROGÉNIO|S1|200|5000
BOX|H2|AIR|W2|4|20|100
+
BATCH_S|OXIGÉNIO|P1|1200|2500
BOX|O3|EXPRESS|W2|8|20|100
+
BATCH_M|ÁGUA|P3|800|10000|0.1|HIDROGÉNIO:2:OXIGÉNIO:1
BOX|CO2|PERSONAL|W2|16|20|0
 
CONTAINER|M4|NORMAL|B4|W2|2|20|100
 
CONTAINER|M2|AIR|C4|W2|4|20|100
 
CONTAINER|M5|EXPRESS|B4|W2|8|20|100
 
CONTAINER|M3|PERSONAL|DL|W2|16|20|0
 
BOOK|B1256|Os Lusíadas|Luís de Camões|1234567890|P1|58|2|5
 
BOOK|B9854|Head First Java|Sierra & Bates|9876543210|P3|75|2|5
 
BOOK|B1937|How to fix almost everything|Satoshi Yamada|1928374650|S1|5|2|5
 
 
</source>
 
</source>
 
}}
 
}}
Line 488: Line 482:
 
= Execução dos Programas e Testes Automáticos =
 
= 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 ('''woo.app.App.main'''). As propriedades são tratadas automaticamente pelo código de apoio.
+
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 woo.app.App
+
         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:
 
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:

Latest revision as of 20:34, 25 September 2021

AVISOS - Avaliação em Época Normal

Esclarecimento de dúvidas:

  • Consultar sempre o corpo docente atempadamente: presencialmente ou através do endereço oficial da disciplina [1].
  • Não utilizar fontes de informação não oficialmente associadas ao corpo docente (podem colocar em causa a aprovação à disciplina).
  • Não são aceites justificações para violações destes conselhos: quaisquer consequências nefastas são da responsabilidade do aluno.

Requisitos para desenvolvimento, material de apoio e actualizações do enunciado (ver informação completa em Projecto de Programação com Objectos):

  • O material de apoio é de uso obrigatório e não pode ser alterado.
  • Verificar atempadamente (mínimo de 48 horas antes do final de cada prazo) os requisitos exigidos pelo processo de desenvolvimento.

Processo de avaliação (ver informação completa em Avaliação do Projecto):

  • Datas: 2021/10/08 12:00 (inicial); 2021/10/29 12:00 (intercalar); 2021/11/12 12:00 (final); 2021/11/12 (early bird) 2021/11/15 (normal) (teste prático).
  • Todas as entregas são cruciais para o bom desenvolvimento do projecto, sendo obrigatórias: a não realização de uma entrega implica a exclusão da avaliação do projecto e, por consequência, da avaliação da disciplina.
  • Verificar atempadamente (até 48 horas antes do final de cada prazo) os requisitos exigidos pelo processo de avaliação, incluindo a capacidade de acesso ao repositório.
  • Apenas se consideram para avaliação os projectos existentes no repositório oficial. Apenas se considera para avaliação o ramo 'main'.
  • Trabalhos não presentes no repositório no final do prazo têm classificação 0 (zero) (não são aceites outras formas de entrega). Não são admitidas justificações para atrasos em sincronizações do repositório. A indisponibilidade temporária do repositório ou de outros materiais, desde que inferior a 24 horas, não justifica atrasos na submissão de um trabalho.
  • A avaliação do projecto pressupõe o compromisso de honra de que o trabalho correspondente foi realizado pelos alunos correspondentes ao grupo de avaliação.
  • Fraudes na execução do projecto terão como resultado a exclusão dos alunos implicados do processo de avaliação.
Material de Uso Obrigatório
As bibliotecas po-uilib e o conteúdo inicial do CVS são de uso obrigatório:
  • po-uilib (classes de base) po-uilib-202110212142.tar.bz2 (não pode ser alterada) - javadoc
  • ggc-core (classes do "core") (via CVS) (deve ser completada -- os nomes das classes fornecidas não podem ser alterados)
  • ggc-app (classes de interacção) (via CVS) (deve ser completada -- os nomes das classes fornecidas não podem ser alterados)
A máquina virtual, fornecida para desenvolvimento do projecto, já contém todo o material de apoio.
Uso Obrigatório: Repositório CVS
Apenas se consideram para avaliação os projectos existentes no repositório CVS oficial.

Trabalhos não presentes no repositório no final do prazo têm classificação 0 (zero) (não são aceites outras formas de entrega). Não são admitidas justificações para atrasos em sincronizações do repositório. A indisponibilidade temporária do repositório, desde que inferior a 24 horas, não justifica atrasos na submissão de um trabalho.

Contents

ÉPOCA NORMAL

O objectivo do projecto é desenvolver uma aplicação de gestão do inventário de um entreposto de recursos naturais e seus derivados (formados por um ou mais produtos ou seus derivados). O entreposto concede prémios de fidelização aos bons parceiros (que lhe compram e vendem produtos), baseando-se no volume de negócio (compras e vendas). A funcionalidade da aplicação inclui, entre outras acções, manipular dados de produtos para negociar, registar/manipular dados de parceiros, registar/manipular transacções de compra e venda e outras e fazer pesquisas várias sobre a informação armazenada.

Neste texto, o tipo negrito indica um literal (i.e., é exactamente como apresentado); o símbolo ␣ indica um espaço; e o tipo itálico indica uma parte variável.

Entreposto, Produtos, Parceiros e Transacções

Os produtos e os parceiros possuem uma chave única (cadeia de caracteres, não havendo distinção entre maiúsculas e minúsculas). As transacções possuem uma chave única inteira gerida automaticamente.

O saldo inicial do entreposto é 0 (zero).

Propriedades e Funcionalidade dos Produtos

Um produto pode ser simples ou derivado. Um produto derivado tem uma receita de fabrico. A receita corresponde à discriminação dos identificadores dos componentes (simples ou derivados) que formam o produto e respectivas quantidades. Não é possível a definição de receitas cujos componentes não sejam previamente conhecidos.

Os produtos, tanto simples, como derivados, são comprados, vendidos, ou fabricados (no caso dos produtos derivados) em lotes. Cada lote tem um fornecedor (o parceiro a quem é comprado o produto), o número de unidades disponíveis do produto no lote e o preço de cada unidade. Podem existir vários lotes do mesmo produto, com o mesmo fornecedor, com preços iguais ou diferentes. O preço de um produto é sempre um número em vírgula flutuante não negativo. Quando um lote é esgotado, é removido do registo de dados.

O preço dos produtos é definido no acto da compra pelo entreposto. Este processo é uniforme para todos os produtos, excepto onde indicado (ver a seguir e abaixo).

O entreposto pode realizar operações de agregação e de desagregação. Uma operação de agregação consiste em criar um produto derivado a partir das existências dos seus componentes. O preço dos produtos derivados é calculado com base nos preços dos componentes, de acordo com a receita, tendo um agravamento multiplicativo (número positivo em vírgula flutuante), definido pela receita, relativo ao valor acrescentado associado à combinação. Por exemplo: a água é feita de hidrogénio (2x) e de oxigénio (1x). O seu preço é: [math]P_{H_2O} = (1 + \alpha) \times (2 \times P_H + P_O)[/math] (onde [math]P_x[/math] são preços e [math]\alpha[/math] é o factor de agravamento, e.g. 0.1, correspondente a um aumento de 10% sobre o valor dos componentes). A reserva de recursos para construção de determinada quantidade de produto derivado contempla a totalidade da construção (e.g., não é possível respeitar um pedido de 10 unidades de água se apenas estiverem disponíveis 8 unidades de oxigénio). Em geral, operações de consumo de existências começam sempre pelas existências de menor preço, consumindo um ou mais lotes, total ou parcialmente, no processo.

É possível desagregar um produto derivado e recuperar os seus componentes. Não há perdas de produtos nesta operação, mas pode haver perda de valor: o preço é como indicado na secção de desagregação (ver abaixo). O parceiro que pede a operação de desagregação paga o diferencial de valor, caso seja positivo, sendo registada uma transacção de desagregação (com o valor do diferencial, mesmo que negativo).

Propriedades e Funcionalidade dos Parceiros

Cada parceiro tem um nome (cadeia de caracteres) e uma morada (cadeia de caracteres). Associada a cada parceiro existe ainda informação relativa às suas transacções.

Um parceiro tem ainda um estatuto (e.g., Elite, etc- -- ver abaixo), o qual tem impacto na sua relação com o entreposto.

Dado um parceiro, é possível aceder ao historial das suas transacções (ver a seguir).

Propriedades e Funcionalidade das Transacções

As transacções são identificadas por um número (inteiro), atribuído de forma automática pela aplicação. Este identificador começa em 0 (zero), sendo incrementado quando se regista uma nova transacção. A sequência de identificadores é partilhada por todos os tipos de transacções. Todas as transacções têm uma data de pagamento.

O entreposto realiza com os parceiros transacções de compra (do entreposto aos parceiros), venda (do entreposto aos parceiros) e desagregações (pelo entreposto a pedido dos parceiros). As desagregações: podem ser vistas como compras e vendas combinadas, para efeitos de progressão do estatuto dos parceiros. Uma desagregação corresponde a uma venda do produto a desagregar e à compra dos componentes que resultam da desagregação.

As compras são sempre pagas instantaneamente. As vendas podem ser pagas pelos parceiros mais tarde (excepto no contexto de uma desagregação: nesse caso, são pagas imediatamente).

Compras (do entreposto a parceiros)

Uma compra está associada a um parceiro e envolve uma ou mais unidades de um produto fornecido pelo parceiro em causa. O custo unitário do produto é definido pelo parceiro no momento da transacção. Quando se faz uma compra deve considerar-se que a compra é paga imediatamente e que as existências do entreposto são actualizadas considerando os produtos comprados. É mantida informação sobre cada produto, o parceiro que o forneceu e o preço que foi pago.

Vendas (do entreposto a parceiros)

Uma venda está associada a um parceiro e envolve uma ou mais unidades de um único produto. As unidades podem ser provenientes de vários lotes e ter preços diferentes, dependendo dos parceiros que forneceram o produto. Cada venda tem uma data limite de pagamento: primeiro realiza-se a venda e só depois é que se procede ao seu pagamento.

Se o produto a adquirir for derivado e não existir em quantidade suficiente no entreposto, a quantidade em falta pode ser fabricada a partir de outros produtos, de acordo com a receita correspondente ao produto em venda. O preço a pagar é o definido pela reserva dos componentes individuais (com a selecção do preço mais baixo, etc.) e o correspondente factor de valor acrescentado (ver acima). Note-se que, na venda de múltiplas unidades de um produto derivado, o processo de construção deve ser repetido, pelo que cada uma das unidades do produto derivado pode ter custo diferente das anteriores. Caso falte algum componente da receita, então a operação de agregação deve ser abortada indicando o primeiro produto (pela ordem da receita) que viola a condição de disponibilidade.

O preço a pagar por um parceiro (numa operação de venda por parte do entreposto) depende ainda do tempo que demora a realizar o pagamento. São considerados os seguintes períodos (N é 5 para produtos simples, 3 para produtos derivados):

  • P1 - até N dias antes do limite de pagamento (data_limite_de_pagamento − data_actual ≥ N).
  • P2 - até à data limite (0 ≤ data_limite_de_pagamento − data_actual < N).
  • P3 - até N dias depois da data limite (0 < data_actual − data_limite_de_pagamento ≤ N).
  • P4 - após N dias depois da data limite (data_actual − data_limite_de_pagamento > N).

Intervalos ao longo do tempo:

               ──────────────┬──────────────┬──────────────┬──────────────
 >>> tempo >>>       P1      │      P2      │      P3      │      P4       >>> tempo >>>
               ──────────────┴──────────────┴──────────────┴──────────────
                             ↑              ↑              ↑             
                         prazo - N        prazo        prazo + N

Note-se que estes períodos são arbitrários e não correspondem a qualquer conceito especial de tempo, podendo ser redefinidos ou mesmo eliminados em revisões do processo de venda.

Desagregações de produtos (pelo entreposto a pedido de parceiros)

Uma desagregação é uma transacção associada a um parceiro e envolve um único produto. Um parceiro pode pedir uma desagregação para permitir outras operações sobre os componentes do produto a desagregar. Se o produto a desagregar for atómico, a acção não tem qualquer efeito.

As desagregações são operações sobre o estado do entreposto por parte de um parceiro: a desagregação remove uma quantidade de produto derivado das existências do entreposto (como se fosse uma venda) e introduz nas existências do entreposto os seus componentes (como se fosse uma compra ao parceiro envolvido). O preço de inserção é o menor preço nos lotes disponíveis para esse produto. Se não existirem lotes disponíveis, o preço é o maior preço associado a esse produto no histórico de operações do entreposto. O parceiro paga ao entreposto a diferença (positiva) entre os valores inicial (o valor da quantidade de produto não desagregado) e final (o valor das quantidades de componentes obtidas com base na desagregação).

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.

P1 P2 P3 P4
Multa Desconto Multa Desconto Multa Desconto Multa Desconto
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 é 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.

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.
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 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 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.

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.

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 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: Abrir, Guardar, Mostrar data actual, Avançar data actual, Gestão de Produtos, Gestão de Parceiros, Gestão de Transacções, Consultas, 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.

Estes comandos já estão implementados nas classes da package ggc.app.main (disponível no CVS), respectivamente: DoOpen, DoSave, DoDisplayDate, DoAdvanceDate, DoOpenMenuProducts, DoOpenMenuPartners, DoOpenMenuTransactions, 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 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 (inteiros) 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 disponíveis, Visualizar os lotes fornecidos por um dado parceiro, Visualizar os lotes de um dado produto.

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 produto (Prompt.productKey()) e o produto não existir, é lançada a excepção UnknownProductKeyException (excepto no processo de registo). Na ocorrência de excepções (estas ou outras), as operações não têm efeito.

Estes comandos já estão implementados nas classes da package ggc.app.products (disponível no CVS), respectivamente: DoShowAllProducts, DoShowAvailableBatches, DoShowBatchesByPartner, DoShowProductBatches.

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|componente-1:quantidade-1:...:componente-n:quantidade-n

Exemplo:

 ÁGUA|5000|800|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.00|800
 HIDROGÉNIO|Cryostuffs|110.50|5000
 OXIGÉNIO|Cryostuffs|820.50|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 todos os parceiros, Registar parceiro, Activar/desactivar notificações de um produto, Mostrar transacções do parceiro.

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.

Estes comandos já estão implementados nas classes da package ggc.app.partners (disponível no CVS), respectivamente: DoShowPartner, DoShowAllPartners, DoRegisterPartner, DoToggleProductNotifications, DoShowPartnerTransactions.

Mostrar parceiro

É pedido o identificador do parceiro e apresentada a sua informação. O formato de apresentação é o seguinte (o valor das compras efectuadas refere-se ao momento da compra; o valor das compras pagas refere-se ao valor realmente pago):

id|nome|endereço|estatuto|valor-vendas|valor-compras-efectuadas|valor-compras-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 parceiro (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.

Se o produto indicado não existir, é lançada a excepção UnknownProductKeyException.

Mostrar transacções de compra do parceiro

É pedido o identificador do parceiro e apresentadas todas as transacções de compra por ele realizadas. O formato de apresentação é como descrito abaixo (visualização de transacções).

Mostrar transacções de venda (e desagregação) do parceiro

É pedido o identificador do parceiro e apresentadas todas as transacções de venda por 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, Registar Desagregação, Registar Venda, Registar Compra, Receber Pagamento de Venda.

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.

Estes comandos já estão implementados nas classes da package ggc.app.transactions (disponível no CVS), respectivamente: DoShowTransaction, DoRegisterBreakdownTransaction, DoRegisterSaleTransaction, DoRegisterAcquisitionTransaction, DoReceivePayment.

Visualizar

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. 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 requisita a transacçã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 resultantes, 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 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 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. Se a resposta for negativa, trata-se de um produto atómico. Caso contrário, é pedido o número de componentes da receita (Prompt.numberOfComponents()) e, em ciclo, os identificadores e quantidades dos vários componentes: os identificadores são pedidos como para qualquer outro identificador de produto; as quantidades são pedidas com Prompt.amount().

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 facturas pagas por parceiro.

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.

Estes comandos já estão parcialmente implementados nas classes da package ggc.app.lookups (disponível no CVS), respectivamente: DoLookupProductsUnderTopPrice, 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).

Leitura de Dados a Partir de Ficheiros Textuais

Além das opções de manipulação de ficheiros descritas no menu principal, é possível iniciar a aplicação com um ficheiro de texto especificado pela propriedade Java 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:

Exemplo de ficheiro de entrada textual
PARTNER|S1|Toshiba|Tokyo, Japan
PARTNER|W2|Pedraria Fonseca|Oeiras, Portugal
PARTNER|P1|Lages do Chão|Lisboa, Portugal
PARTNER|P3|O’Brian Rocks|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|MM|John Figueiredo|Wellington, New Zealand
PARTNER|M1|Rohit Figueiredo|New Delhi, India
BATCH_S|HIDROGÉNIO|S1|200|5000
BATCH_S|OXIGÉNIO|P1|1200|2500
BATCH_M|ÁGUA|P3|800|10000|0.1|HIDROGÉNIO:2:OXIGÉNIO:1

A codificação dos ficheiros a ler é garantidamente UTF-8.

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 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 java.io, em particular, a interface java.io.Serializable e as classes de leitura java.io.ObjectInputStream e escrita java.io.ObjectOutputStream (entre outras).