Programação com Objectos/Projecto de Programação com Objectos/Enunciado do Projecto de 2020-2021 (rascunho de trabalho)

From Wiki**3

< Programação com Objectos‎ | Projecto de Programação com Objectos
Revision as of 18:17, 21 September 2020 by Root (talk | contribs) (Produtos, Clientes, Fornecedores e Transacções)

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: 2020/10/23 12:00 (inicial); 2020/11/09 12:00 (intercalar); 2020/12/11 12:00 (final); 2020/12/14-2019/12/18 (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-uuilib e o conteúdo inicial do CVS são de uso obrigatório:
  • po-uuilib (classes de base) po-uuilib-201708311009.tar.bz2 (não pode ser alterada) - javadoc
  • woo-core (classes do "core") (via CVS) (deve ser completada -- os nomes das classes fornecidas não podem ser alterados)
  • woo-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 um gestor para o balcão de uma transportadora de mercadorias. O programa deve permitir gerir vários serviços: venda de caixas e contentores; produtos de fornecedores associados; e pagamento de transacções. O balcão concede prémios de fidelização aos bons clientes (volume de compras). Assim, o sistema deverá permitir, entre outras acções: registar dados de produtos para venda, registar dados de clientes, registar dados de fornecedores de produtos para venda e fazer pesquisas várias sobre a informação armazenada. A lista completa encontra-se abaixo.

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 (i.e., uma descrição).

Produtos, Clientes, Fornecedores e Transacções

Os produtos, clientes e fornecedores possuem uma chave única (cadeia de caracteres). As transacções possuem uma chave inteira.

Propriedades e Funcionalidade dos Produtos

O balcão vende caixas e contentores de vários tipos, consoante o nı́vel de serviço de transporte a realizar. Outros tipos de produtos disponı́veis incluem seguros e protecções especiais, disponibilizados à transportadora por fornecedores. Também podem ser colocados para venda produtos diversos, como forma de promover os fornecedores (e.g., livros ou outras obras culturais).

Todos os produtos são caracterizados pelo seu fornecedor. Todos os produtos são ainda caracterizados pelo preço (um número inteiro). Os produtos têm associada informação sobre um valor crı́tico (utilizado na gestão de existências).

As caixas são de vários tipos, consoante o nı́vel de serviço associado: normal, aéreo, expresso e em mão.

Os contentores, tal como as caixas, são caracterizados pelo nı́vel de serviço (idêntico ao das caixas) e pela qualidade de serviço (quatro níveis disponı́veis: B4, C4, C5, DL).

Os livros são caracterizados pelo respectivo tı́tulo, autor e ISBN (cadeias de caracteres). Poderão ser definidos novos tipos de produtos (e.g. discos ou CDs/DVDs), que terão as suas próprias propriedades.

O operador do balcão deve poder realizar as seguintes operações sobre produtos: (i) visualizar um produto; (ii) registar um novo produto; (iii) alterar o preço de um produto; (iv) reforçar as existências de um produto; (v) inibir a venda de um produto.

Um produto não pode ser vendido se estiver inibido. Quando se registar um novo produto ou se reactivar um previamente inibido, os clientes que não tiverem inibido as notificações devem ser avisados, o mesmo se passando com alterações ao preço do produto. As notificações são compostas pela cadeia de caracteres constituı́da pela identificação do cliente e pela identificação do produto, sendo registadas tanto no balcão, como nos clientes que as recebem.

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. Estas notificações não podem ser inibidas, mas não devem produzir efeitos se o fornecedor estiver inactivo. As notificações são compostas pela cadeia de caracteres constituı́da pela identificação do fornecedor e pela identificação do produto, sendo registadas tanto no balcão, como nos fornecedores que as recebem.

Propriedades e Funcionalidade dos Clientes

Os clientes fazem compras que podem ser pagas mais tarde.

Cada cliente é identificado pelo nome (cadeia de caracteres) e possui ainda informação acerca da morada (cadeia de caracteres). Associado a cada cliente existe ainda a informação relativa a compras efectuadas e facturas pagas, assim como o seu estatuto (e.g., cliente "Elite").

O operador do balcão deve poder realizar as seguintes operações sobre clientes: (i) visualizar um cliente; (ii) registar um novo cliente; (iii) inibir o envio de notificações a um cliente; (iv) activar/desactivar um cliente; (v) consultar o histórico de transacções realizadas por um cliente.

Um cliente não pode ser removido, sendo sempre possı́vel aceder a todo o historial de transacções. Um cliente que iniba as notificações não pode ser considerado preferencial (ver abaixo). Um cliente inactivo não pode realizar transacções (este aspecto é independente da recepção de notificações). A inactivação/reactivação do cliente não afecta o seu estatuto (ver abaixo).

Propriedades e Funcionalidade dos Fornecedores

Os fornecedores respondem a encomendas por parte da transportadora.

Cada fornecedor é identificado pelo nome (cadeia de caracteres) e possui ainda informação acerca da morada (cadeia de caracteres). Associado a cada fornecedor existe ainda a informação relativa a fornecimentos efectuados e dos pagamentos recebidos.

O operador do balcão deve poder realizar as seguintes operações sobre fornecedores: (i) visualizar um fornecedor; (ii) registar um novo fornecedor; (iii) inibir/activar um fornecedor; (iv) consultar o histórico de transacções realizados.

Um fornecedor não pode ser removido, sendo sempre possı́vel aceder a todo o historial de transacções. Um fornecedor inactivo não pode realizar transacções.

Propriedades e Funcionalidade das Transacções

Existem dois tipos de transacção: vendas e encomendas. As transacções são caracterizados pelo respectivo número (inteiro) e pela data limite de pagamento.

As encomendas do balcão a fornecedores podem ser de produtos individuais de vários produtos (idem para múltiplos exemplares de um item). Cada encomenda possui um número de identificação e informação acerca do total a pagar.

O operador deve poder realizar as seguintes operações sobre transacções: (i) visualizar uma transacção; (ii) registar uma nova transacção; (iii) pagar uma transacção.

Para as vendas, são considerados os seguintes perı́odos:

  • Até 5 dias antes do limite de pagamento (data_limite_de_pagamento − data_actual ≥ 5): sem penalização (transacções não pagas); desconto de 10%;
  • Até à data limite (0 ≤ data_limite_de_pagamento − data_actual < 5): sem penalização (transacções não pagas); sem desconto;
  • Até 5 dias depois da data limite (1 < data_actual − data_limite_de_pagamento ≤ 5): multa de 5% por cada dia de atraso; sem desconto.
  • Após 5 dias depois da data limite (data_actual − data_limite_de_pagamento > 5): multa de 10% por cada dia de atraso; sem desconto.

Aspectos Adicionais

O balcão, além de manter informação relativa a todos aos conceitos acima, mantém ainda informação relativa ao estado dos clientes e fornecedores (activo/inactivo) e relativa ao volume de negócios realizado (i.e., contabilização do total de vendas e pagamentos a fornecedores: número em vı́rgula flutuante de dupla precisão – double). Inicialmente, o balcão tem saldo zero.

A aplicação desenvolvida deve ser suficientemente flexı́vel, por forma a permitir acrescentar novos tipos de produtos, novos tipos de cobrança e novas polı́ticas de recompensa de clientes e fornecedores, com um impacto mı́nimo no código já feito.

Contabilização de Pontos (Clientes)

Nesta secção, as penalizações e os descontos aplicam-se apenas no pagamento de facturas por clientes.

A contabilização de pontos é realizada quando se paga a factura, correspondendo a 10 vezes o valor pago. Não há contabilização de pontos em pagamentos atrasados.

Além dos clientes normais, existem clientes “Selection” (com mais de 2000 pontos), que podem pagar facturas sem penalização até 1 dia depois da data limite (depois dessa data, são penalizados em 2% diários), e obter descontos até 2 dias antes da data limite (5%, depois do limite normal dos 5 dias). Clientes “Elite” (com mais de 25000 pontos) nunca são penalizados e têm descontos de 10%, mesmo após a data limite (depois de 5 dias, os descontos baixam para 5%, até ao limite de 10 dias, em que deixa de haver descontos).

Pesquisas

Deve ser possı́vel efectuar pesquisas sob vários critérios e sobre as diferentes entidades geridas pelo balcão: (i) produtos comprados por um determinado cliente; (ii) clientes que compram determinado produto; (iii) facturas pagas por um determinado cliente; (iv) facturas pagas com um atraso determinado; (v) produtos com um preço inferior a um dado valor. Deve ser possı́vel introduzir novos métodos de pesquisa com um impacto mı́nimo na implementação desenvolvida.

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 balcão a partir de um suporte persistente.

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:

  • Adicionar novos tipos de produtos ao catálogo;
  • Adicionar novas políticas de processamento de transacções (pagamentos e pontos);
  • Adicionar novas formas de consulta.

Embora na especificação actual não seja possível a remoção de produtos ou de clientes, a inclusão destas funcionalidades deve ser prevista, por forma a minimizar o impacto da sua futura inclusão.

Funcionalidade da aplicação

A aplicação permite manter informação sobre as entidades do modelo, permitindo, em particular, gerir clientes, obras e empréstimos. 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. Não é possível remover clientes ou obras durante a execução da aplicação.

Note-se que não é necessário 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 woo.StoreManager 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.

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

A apresentacção de listas (e.g., Fornecedores, Transacções, etc.) faz-se por ordem crescente da respectiva chave. 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 woo.app, woo.app.main, woo.app.requests e woo.app.users. Estas classes são de uso obrigatório e estão disponíveis no CVS (módulo woo-app).

Menu Principal

As acções deste menu permitem gerir a salvaguarda do estado da aplicação e abrir submenus. A lista completa é a seguinte: Abrir, Guardar, Mostrar data actual, Avançar data actual, Gestão de Produtos, Gestão de Clientes, Gestão de Fornecedores, Gestão de Transacções, Consultas, Mostrar Saldo do Balcão.

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.

Estes comandos já estão implementados nas classes da package woo.app.main (disponível no CVS), respectivamente: DoOpen, DoSave, DoDisplayDate, DoAdvanceDate, DoOpenProductsMenu, DoOpenClientsMenu, DoOpenSuppliersMenu, DoOpenTransactionsMenu, DoOpenSearchMenu, DoShowGlobalBalance.

Salvaguarda do estado actual da aplicação

Inicialmente, a aplicação apenas tem informação sobre as entidades que foram carregados no arranque.

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

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 guarda o estado da aplicação, mesmo que existam alterações.

Mostrar data actual

A data actual do sistema é apresentada através da mensagem currentDate().

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, a operação não tem efeito.

Além da data, o sistema deve actualizar, caso seja necessário, outros aspectos que dela dependam, designadamente, a situação dos clientes e fornecedores relativa a prazos e notificações.

Gestão e consulta de dados da aplicação

  • Menu de Gestão de Produtos -- Abre o menu de gestão de produtos e operações associadas.
  • Menu de Gestão de Clientes -- Abre o menu de gestão de clientes e operações associadas.
  • Menu de Gestão de Fornecedores -- Abre o menu de gestão de fornecedores e operações associadas.
  • Menu de Gestão de Transacções -- Abre o menu de gestão de transacções e operações associadas.
  • Menu de Consultas -- Abre o menu de consultas (pesquisas)..

Mostrar saldo global

Esta opção apresenta o valor inteiro correspondente ao saldo do balcão. Embora internamento o valor do saldo esteja representado em vírgula flutuante, a apresentação é arredondada ao inteiro mais próximo.

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, Registar produto, Alterar preço de produto, Inibir vendas de produto, Permitir vendas de 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.

Sempre que for pedido o identificador de um cliente (requestProductId()) e o produto não existir, é lançada a excepção NoSuchProductException (excepto no processo de registo).

Estes comandos já estão implementados nas classes da package woo.app.products (disponível no CVS), respectivamente: DoShowProducts, DoRegisterProduct, 'DoChangePrice, DoDeactivateProduct, DoActivateProduct.

Visualizar todos os produtos

O formato de apresentação de cada tipo de produto é o seguinte:

BOX|id'|tipo|idFornecedor|preço|valor-crítico
CONTAINER|id|tipo|formato|idFornecedor|preço|valor-crítico
BOOK|id|título|autor|isbn|idFornecedor|preço|valor-crítico

Registar produto

O sistema pede o tipo de produto a registar (requestProductType()): a resposta deve ser BOX, CONTAINER ou BOOK. Se for dada outra resposta, deve ser apresentada a mensagem unknownType(), não se realizando qualquer acção. De seguida, é pedido o identificador que ficará associado ao produto.

Para registar uma caixa, o sistema pede o tipo de serviço de transporte associado (requestServiceType()). A resposta deve ser NORMAL, AIR, EXPRESS ou PERSONAL. Se for dada outra resposta, deve ser apresentada a mensagem unknownServiceType(), repetindo-se a pergunta inicial (requestServiceType()), até se obter uma resposta válida.

Para registar um contentor, o sistema pede o tipo de serviço de transporte associado (requestServiceType()). A resposta deve ser NORMAL, AIR, EXPRESS ou PERSONAL. Se for dada outra resposta, deve ser apresentada a mensagem unknownServiceType(), repetindo-se a pergunta inicial (requestServiceType()), até se obter uma resposta válida. De seguida, é pedida a qualidade de serviço (requestServiceLevel()): a resposta deve ser B4, C4, C5 ou DL. Se for dada outra resposta, deve ser apresentada a mensagem unknownServiceLevel(), apresentando-se o pedido inicial (requestServiceLevel()), até se obter uma resposta válida.

Para registar um livro, o sistema pede o título (requestBookTitle()), o autor (requestBookAuthor()) e o ISBN (requestISBN()).

Independentemente do produto, são também pedidos o preço (requestPrice()), o valor crítico (requestStockCriticalLevel()) e o identificador do fornecedor (requestSupplierId()). Se o fornecedor não existir, deve ser apresentada a mensagem unknownSupplier(), não se registando o produto.

Tal como mencionado acima, os clientes podem ser notificados quando um novo produto fica disponível. Quando o processo de registo termina, o sistema apresenta o número de clientes que foram efectivamente notificados.

Alterar preço de produto

O sistema pede o identificador do produto e o novo preço (requestPrice()). Em caso de erro, o preço não é alterado.

Tal como mencionado acima, os clientes podem ser notificados quando o preço de um produto varia. Quando o processo de alteração de preço termina, o sistema apresenta o número de clientes que foram efectivamente notificados.

Inibir vendas de produto

O sistema pede o identificador do produto, e executa o pedido silenciosamente, ou seja, sem pedir qualquer confirmação ou enviar mensagens, mesmo quando a venda já estava inibida. No entanto, não devem ser enviadas notificações se não ocorrer uma mudança no estado do produto.

Permitir vendas de produto

O sistema pede o identificador do produto, e executa o pedido silenciosamente, ou seja, sem pedir qualquer confirmação ou enviar mensagens, mesmo quando a venda já estava autorizada. No entanto, não devem ser enviadas notificações se não ocorrer uma mudança no estado do produto.

Tal como mencionado acima, os clientes podem ser notificados quando um novo produto fica disponível. Quando o processo de reactivação termina, o sistema apresenta o número de clientes que foram efectivamente notificados.

Menu de Gestão de Clientes

Este menu permite efectuar operações sobre a base de dados de clientes. A lista completa é a seguinte: Mostrar clientes, Registar cliente, Activar/desactivar cliente, Autorizar/inibir notificações, Mostrar transacções do cliente.

As etiquetas das opções deste menu estão definidas na classe woo.app.clientes.Label. Todos os métodos correspondentes às mensagens de diálogo para este menu estão definidos na classe woo.app.clientes.Message.

Sempre que for pedido o identificador de um cliente (requestClientId()) e o cliente não existir, é lançada a excepção NoSuchClientException (excepto no processo de registo).

Estes comandos já estão implementados nas classes da package woo.app.clients (disponível no CVS), respectivamente: DoShowClients, DoRegisterClient, DoToggleClientActivation, DoToggleNotifications, DoShowClientTransactions.

Mostrar clientes

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|activo?|notificações?|valor-compras-efectuadas|valor-compras-pagas

Os valores para os campos activo? e notificações? são SIM ou NÃO.

Registar cliente

O sistema pede o identificador do cliente. Se já existir um cliente com o mesmo identificador, deve ser apresentada a mensagem duplicateClient(), não se realizando qualquer acção. Caso contrário, pede-se o nome (requestName()) (cadeia de caracteres) e o endereço do cliente (requestAddress()) (cadeia de caracteres) e cria-se e regista-se o novo cliente. Quando um cliente é registado, fica no estado activo e aceita notificações.

Activar/desactivar cliente

O sistema pede o identificador do cliente e a confirmação de mudança de estado: confirmDeactivation(), na passagem de activo a inactivo; confirmActivation(), na passagem de inactivo a activo.

A resposta é um valor booleano. A acção é realizada apenas em caso de resposta afirmativa.

Autorizar/inibir notificações

O sistema pede o identificador do cliente e a confirmação de mudança de estado: disableNotifications(), para deixar de receber notificações; enableNotifications(), para passar a receber notificações.

A resposta é um valor booleano. A acção é realizada apenas em caso de resposta afirmativa.

Mostrar transacções do cliente

O sistema pede o identificador do cliente e apresenta todas as transacções por ele realizadas. O formato de apresentação é como descrito abaixo.

Menu de Gestão de Fornecedores

Este menu apresenta as operações disponíveis sobre fornecedores e assuntos relacionados. A lista completa é a seguinte: Mostrar fornecedores, Registar fornecedor, Permitir/Inibir transacções, Consultar transacções.

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.

Sempre que é pedido o identificador da fornecedor (requestSupplierId()), é lançada a excepção NoSuchSupplierException, se o fornecedor indicado não existir.

Estes comandos já estão implementados nas classes da package woo.app.suppliers (disponível no CVS), respectivamente: DoShowSuppliers, DoRegisterSupplier, DoToggleTransactions, DoLookupTransactions.

Mostrar fornecedores

O formato de apresentação é o seguinte:

id|nome|endereço|activo?

Os valores para o campo activo? são SIM ou NÃO.

Registar fornecedor

O sistema pede o identificador do fornecedor. Se já existir um fornecedor com o mesmo identificador, deve ser apresentada a mensagem duplicateSupplier(), não se realizando qualquer acção. Caso contrário, pede-se o nome (requestName()) (cadeia de caracteres) e o endereço do fornecedor (requestAddress()) (cadeia de caracteres) e cria-se e regista-se o novo fornecedor. Quando um fornecedor é registado, fica no estado activo.

Permitir/Inibir transacções

O sistema pede o identificador do fornecedor e a confirmação de mudança de estado: confirmDeactivation(), na passagem de activo a inactivo; confirmActivation(), na passagem de inactivo a activo.

A resposta corresponde à leitura de um valor booleano. A acção é realizada apenas em caso de resposta afirmativa.

Consultar transacções

O sistema pede o identificador do fornecedor e apresenta todas as transacções por ele realizadas. O formato de apresentação é como descrito abaixo.

Menu de Gestão de Transacções

Este menu apresenta as operações relacionadas com transacções. A lista completa é a seguinte: Visualizar, Registar Venda, Registar Encomenda, 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.

Sempre que é pedido o identificador do fornecedor (requestSupplierId()), é lançada a excepção NoSuchSupplierException, se o cliente indicado não existir. Sempre que é pedido o identificador do cliente (requestClientId()), é lançada a excepção NoSuchClientException, se o cliente indicado não existir. Sempre que é pedido o identificador de produto (requestProductId()), é lançada a excepção NoSuchProductException, se o produto indicado não existir. Sempre que é pedido o identificador da transacção (requestTransactionId()), é lançada a excepção NoSuchTransactionException, se a transacção indicada não existir.

Estes comandos já estão implementados nas classes da package woo.app.transactions (disponível no CVS), respectivamente: DoShowTransaction, DoRegisterSaleTransaction, DoRegisterOrderTransaction, DoPay.

Visualizar

O sistema pede o identificador da factura a visualizar.

Nas apresentações, o campo valor-base é o valor da factura sem descontos nem penalizações e os valores para o campo paga? são SIM ou NÃO.

Se a factura for respeitante a uma venda a um cliente, apresenta-a com o seguinte formato:

idFactura|idCliente|idProduto|quantidade|valor-base|data-limite|paga?|data-pagamento

Se a factura corresponder a uma encomenda a um fornecedor, apresenta-a com um cabeçalho (linha inicial):

idFactura|idFornecedor|valor-base|data-limite|paga?|data-pagamento

A linha inicial é seguida de várias linhas, cada uma com a descrição de cada produto incluído na encomenda:

idProduto|quantidade

Se uma factura ainda não foi paga, o últmo separador (|) e a data-pagamento são omitidos.

Registar Venda

Para registar uma venda, é pedido o identificador da factura e o identificador do cliente. Se o cliente estiver inibido de efectuar transacçõees, deve ser apresentada a mensagem unauthorizedClient(). Caso contrério, é pedida a data limite para o pagamento (requestDate()) e o identificador do produto a vender. Se o produto especificado tiver as vendas inibidas, deve ser apresentada a mensagem unauthorizedProduct(). Caso contrário, é pedida a quantidade vendida (requestAmount()). Se a quantidade for superior `as existências actuais, deve ser apresentada a mensagem unavailable() (não se realiza a venda).

A actualização dos produtos do balcão 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

Para registar uma encomenda, é pedido o identificador da factura e o identificador do fornecedor. Se o fornecedor estiver inibido de efectuar transacções, deve ser apresentada a mensagem unauthorizedSupplier(). Caso contrário, é pedida a data limite para o pagamento (requestDate()) e 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).

A actualização dos produtos do balcão tem lugar logo após o registo da encomenda, ou seja, considera-se que a encomenda é instantânea.

Pagar

O sistema pede o identificador da factura a pagar. Se a factura já tiver sido paga, não é realizada nenhuma acção. Os pagamentos de encomendas são efectuados sobre o valor facial com um agravamento de 10% por cada dia de atraso.

Menu de Consultas

Este menu apresenta as operações relacionadas com consultas. A lista completa é a seguinte: Procurar produtos com preço abaixo de limite, Procurar produtos comprados por cliente, Procurar clientes que compram produto, Procurar facturas pagas por cliente, Procurar facturas pagas com atraso.

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.

Sempre que é pedido o identificador do cliente (requestClientId()), é lançada a excepção NoSuchClientException, se o cliente indicado não existir. Sempre que é pedido o identificador de produto (requestProductId()), é lançada a excepção NoSuchProductException, se o produto indicado não existir.

A apresentação de resultados é como indicado nos casos já descritos de apresentação dos vários casos.

Estes comandos já estão parcialmente implementados nas classes da package woo.app.lookups (disponível no CVS), respectivamente: DoLookupProductsBoughtByClient, DoLookupClientsBuyingProduct, DoLookupPaymentsByClient, DoLookupLatePayments.

Procurar produtos com preço abaixo de limite

O sistema pede o valor pretendido (requestPriceLimit()), apresentando os produtos relevantes.

Procurar produtos comprados por cliente

O sistema pede o código do cliente, apresentando os produtos relevantes.

Procurar clientes que compram produto

O sistema pede o código do produto, apresentando os clientes relevantes.

Procurar facturas pagas por cliente

O sistema pede o código do cliente, apresentando as facturas pagas por ele.

Procurar facturas pagas com atraso

O sistema pede o atraso pretendido (requestDelay()), apresentando as facturas que foram pagas com, pelo menos, o atraso especificado.

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 tem uma descrição distinta mas que segue os seguintes formatos.

BOX|id|tipo|nome-fornecedor|preço|valor-crítico|exemplares
CONTAINER|id|tipo|formato|nome-fornecedor|preço|valor-crítico|exemplares
BOOK|id|título|autor|isbn|nome-fornecedor|preço|valor-crítico|exemplares

É ainda possível definir fornecedores e clientes, de acordo com os seguintes formatos:

SUPPLIER|id|nome|endereço
CLIENT|id|nome|endereço

Um exemplo de conteúdo do ficheiro inicial é como se segue:

Exemplo de ficheiro de entrada textual
SUPPLIER|S1|Toshiba|Tokyo, Japan
SUPPLIER|W2|Papelaria Fernandes|Oeiras, Portugal
SUPPLIER|P1|Publicac¸˜oes Europa-Am´erica|Lisboa, Portugal
SUPPLIER|P3|O’Reilly|K¨oln, Germany
CLIENT|R2|Jorge Figueiredo|Lisboa, Portugal
CLIENT|E4|Filomena Figueiredo|Lisboa, Portugal
CLIENT|ER|Abdul Figueiredo|Casablanca, Morocco
CLIENT|O9|Hellen Figueiredo|San Francisco, CA, USA
CLIENT|H2SO4|John Figueiredo|Wellington, New Zealand
CLIENT|H2O|Rohit Figueiredo|New Delhi, India
BOX|C6H5OH|NORMAL|Papelaria Fernandes|2|20|100
BOX|H2|AIR|Papelaria Fernandes|4|20|100
BOX|O3|EXPRESS|Papelaria Fernandes|8|20|100
BOX|CO2|PERSONAL|Papelaria Fernandes|16|20|0
CONTAINER|M4|NORMAL|B4|Papelaria Fernandes|2|20|100
CONTAINER|M2|AIR|C4|Papelaria Fernandes|4|20|100
CONTAINER|M5|EXPRESS|B4|Papelaria Fernandes|8|20|100
CONTAINER|M3|PERSONAL|DL|Papelaria Fernandes|16|20|0
BOOK|B1256|Os Lusíadas|Luís de Camões|1234567890|Publicações Europa-América|58|2|5
BOOK|B9854|Head First Java|Sierra & Bates|9876543210|O’Reilly|75|2|5
BOOK|B1937|How to fix almost everything|Satoshi Yamada|1928374650|Toshiba|5|2|5

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

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