(→Clientes, telemóveis, planos tarifários e chamadas) |
(→Propriedades e funcionalidades) |
||
Line 24: | Line 24: | ||
Cada chamada é identificada por um inteiro, único em toda a rede, e possui ainda informação sobre o telemóvel que originou a chamada, o telemóvel de destino, a duração da chamada e o tipo de comunicação (voz, texto ou vídeo). A primeira chamada tem como identificador “1”, devendo o identificador das chamadas subsequentes ser obtido por incremento unitário do identificador anterior. | Cada chamada é identificada por um inteiro, único em toda a rede, e possui ainda informação sobre o telemóvel que originou a chamada, o telemóvel de destino, a duração da chamada e o tipo de comunicação (voz, texto ou vídeo). A primeira chamada tem como identificador “1”, devendo o identificador das chamadas subsequentes ser obtido por incremento unitário do identificador anterior. | ||
− | Existem 3 tipos de comunicação entre telemóveis: texto (denominada SMS), voz (denominada VOZ) e vídeo (denominada MMS). O custo das chamadas não é uniforme (ver [[#Planos tarifários]]), dependendo do tipo de telefone e do cliente, entre outros factores. Também dependendo do cliente, é possível avisar quem o tentou contactar quando: (i) um telefone desligado é colocado em silêncio; (ii) um telefone desligado é ligado; ou (iii) um telefone em silêncio é ligado. | + | Existem 3 tipos de comunicação entre telemóveis: texto (denominada SMS), voz (denominada VOZ) e vídeo (denominada MMS). O custo das chamadas não é uniforme (ver [[#Planos tarifários|Planos tarifários]]), dependendo do tipo de telefone e do cliente, entre outros factores. Também dependendo do cliente, é possível avisar quem o tentou contactar quando: (i) um telefone desligado é colocado em silêncio; (ii) um telefone desligado é ligado; ou (iii) um telefone em silêncio é ligado. |
A aplicação desenvolvida deve ser suficientemente flexível para permitir modelar novos tipos de chamada, novos planos tarifários e novas políticas de avisos. Também deve permitir a gestão de várias redes de telemóvel. O impacto destas alterações na aplicação a desenvolver deve ser mínimo. | A aplicação desenvolvida deve ser suficientemente flexível para permitir modelar novos tipos de chamada, novos planos tarifários e novas políticas de avisos. Também deve permitir a gestão de várias redes de telemóvel. O impacto destas alterações na aplicação a desenvolver deve ser mínimo. |
AVISOS - Avaliação em Época Normal |
---|
Esclarecimento de dúvidas:
|
Requisitos para desenvolvimento, material de apoio e actualizações do enunciado (ver informação completa em Projecto de Programação com Objectos):
|
Processo de avaliação (ver informação completa em Avaliação do Projecto):
|
Material de Uso Obrigatório |
---|
As bibliotecas po-uilib e o conteúdo inicial do CVS são de uso obrigatório: |
|
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. |
EM PREPARAÇÃO
ÉPOCA NORMAL
O objectivo do projecto e desenvolver um gestor de uma rede de telemóveis, denominado por prr. O programa permite gerir varios serviços: registo de clientes e de telemóveis e controlo das comunicações efectuadas.
O sistema disponibiliza aos seus gestores varios serviços, entre outros: (i) registar dados sobre os clientes; (ii) registar dados sobre os telemóveis pertencentes à rede; (iii) registar dados sobre as chamadas efectuadas; (iv) fazer pesquisas sobre as chamadas já efectuadas; (v) contabilizar o saldo associado a telemóveis.
Os utilizadores podem ter vários telemóveis, cada um deles associado a um número de telefone e um plano tarifário. Nos pontos seguintes, descrevem-se as propriedades de cada entidade da aplicação.
Os clientes, telemóveis e chamadas possuem uma chave única, uma cadeia de caracteres para os clientes e um inteiro para os telemóveis e para as chamadas.
Cada cliente, para além da chave única, é identificado pelo nome (cadeia de caracteres) e número de identificação fiscal (inteiro).
Os telemóveis são identificados por um número (exactamente 6 dígitos) e estão associados a um cliente. Cada telemóvel pode estar ligado, em silêncio, ou desligado. Neste último caso, não é permitido iniciar ou receber chamadas. Quando o telefone está em silêncio, pode iniciar qualquer tipo de chamada, mas só pode receber chamadas de texto. Cada telefone tem uma contabilidade própria, sendo sempre possível saber o saldo que lhe está associado.
Cada chamada é identificada por um inteiro, único em toda a rede, e possui ainda informação sobre o telemóvel que originou a chamada, o telemóvel de destino, a duração da chamada e o tipo de comunicação (voz, texto ou vídeo). A primeira chamada tem como identificador “1”, devendo o identificador das chamadas subsequentes ser obtido por incremento unitário do identificador anterior.
Existem 3 tipos de comunicação entre telemóveis: texto (denominada SMS), voz (denominada VOZ) e vídeo (denominada MMS). O custo das chamadas não é uniforme (ver Planos tarifários), dependendo do tipo de telefone e do cliente, entre outros factores. Também dependendo do cliente, é possível avisar quem o tentou contactar quando: (i) um telefone desligado é colocado em silêncio; (ii) um telefone desligado é ligado; ou (iii) um telefone em silêncio é ligado.
A aplicação desenvolvida deve ser suficientemente flexível para permitir modelar novos tipos de chamada, novos planos tarifários e novas políticas de avisos. Também deve permitir a gestão de várias redes de telemóvel. O impacto destas alterações na aplicação a desenvolver deve ser mínimo.
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 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):
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.
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 simples, 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).
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.
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 |
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.
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.
É possível guardar e recuperar o estado actual da aplicação, preservando toda a informação relevante, descrita acima.
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.
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:
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.
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.
A apresentação de valores monetários (preços, saldos, etc.) é sempre feita com arredondamento ao inteiro mais próximo.
As excepções usadas na interacção (subclasses de pt.tecnico.uilib.menus.CommandException), excepto se indicado, são lançadas pelos comandos (subclasses de pt.tecnico.uilib.menus.Command) e tratadas pelos menus (instâncias de subclasses de pt.tecnico.uilib.menus.Menu). Outras excepções não devem substituir as fornecidas nos casos descritos.
A apresentação de listas de entidades do domínio (parceiros, transacções, etc.) faz-se por ordem crescente da respectiva chave: dependendo dos casos, a ordem pode ser numérica ou lexicográfica (UTF-8), não havendo distinção entre maiúsculas e minúsculas.
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.
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:
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.
A data actual do sistema é apresentada através da mensagem Message.currentDate().
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.
Esta opção apresenta os valores correspondentes aos saldos disponível e contabilístico do entreposto. Embora internamente o valor dos saldos estejam representados em vírgula flutuante, a apresentação é arredondada ao inteiro mais próximo.
A apresentação faz-se através da mensagem Message.currentBalance().
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 parceiro (Prompt.partnerKey()) e o parceiro não existir, é lançada a excepção UnknownPartnerKeyException. Sempre que é pedido o identificador de um produto (Prompt.productKey()) e o produto não existir, é lançada a excepção UnknownProductKeyException. Na ocorrência de excepções (estas ou outras), as operações não têm efeito.
O formato de apresentação de cada produto é o seguinte (cada linha indica um produto):
Produtos simples:
idProduto|preço-máximo|stock-actual-total
Exemplo:
HIDROGÉNIO|200|5000 OXIGÉNIO|1200|2500
Produtos derivados (é apresentado o produto e a lista de componentes e respectivas quantidades da sua receita):
idProduto|preço-máximo|stock-actual-total|agravamento|componente-1:quantidade-1#...#componente-n:quantidade-n
Exemplo:
ÁGUA|5000|800|0.1|HIDROGÉNIO:2#OXIGÉNIO:1
Em ambos os casos, stock-actual-total pode ser 0 (zero).
O formato de apresentação de cada lote de produto é o seguinte (cada linha indica um lote):
Produtos simples e derivados:
idProduto|idParceiro|preço|stock-actual
Exemplo:
ÁGUA|EPAL|1150|800 HIDROGÉNIO|Cryostuffs|110|5000 OXIGÉNIO|Cryostuffs|650|2500 OXIGÉNIO|Cryostuffs|650|5000 OXIGÉNIO|Cryostuffs|820|2500 OXIGÉNIO|EPAL|820|2500
Note-se que podem existir vários lotes para o mesmo produto. Neste caso, a ordenação é, primeiro, pelo identificador do produto e, depois, pelo identificador do parceiro. Se um parceiro fornecer vários lotes do mesmo produto, apresentam-se por ordem crescente de preço e existências.
É 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).
É 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.
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 de compra com parceiro, Mostrar transacções de venda (e desagregação) com 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.
É pedido o identificador do parceiro e apresentada a sua informação. O formato de apresentação é o seguinte (o valor das vendas efectuadas -- não inclui desagregações -- refere-se ao momento da venda; o valor das vendas pagas refere-se ao valor realmente pago): Note-se que compras e vendas são ponto de vista do entreposto e não do parceiro. Os valores dos pontos e dos preços são apresentados como inteiros (valores arredondados ao inteiro mais próximo).
id|nome|endereço|estatuto|pontos|valor-compras|valor-vendas-efectuadas|valor-vendas-pagas
O estatuto corresponde a NORMAL, SELECTION, ELITE, conforme o caso.
Após esta linha, são apresentadas as notificações do parceiro (modo de entrega por omissão), pela ordem em que foram enviadas pela aplicação.
tipo-de-notificação|idProduto|preço-do-produto
Após esta visualização, considera-se que o parceiro fica sem notificações registadas.
O formato de apresentação é como para parceiros individuais (opção anterior), mas não se apresentam as notificações dos parceiros.
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.
É pedido o identificador do produto (Prompt.partnerKey()) e o identificador do produto (Prompt.productKey()). Se as notificações relativas ao produto estavam activas para o parceiro em causa, passam a estar inactivas, e vice-versa.
Se o produto indicado não existir, é lançada a excepção UnknownProductKeyException.
É pedido o identificador do parceiro e apresentadas todas as compras com ele realizadas. O formato de apresentação é como descrito abaixo (visualização de transacções).
É pedido o identificador do parceiro e apresentadas todas as vendas (e desagregações) com ele realizadas. O formato de apresentação é como descrito abaixo (visualização de transacções).
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.
O sistema pede o identificador da transacção a visualizar.
Nas apresentações, o campo valor-base é o valor da transacção sem multas/descontos.
Se a transacção for respeitante a uma venda a um parceiro, apresenta-se com o seguinte formato:
VENDA|id|idParceiro|idProduto|quantidade|valor-base|valor-a-pagamento|data-limite|data-pagamento
O campo valor-a-pagamento corresponde ao valor que será realmente pago (considerando possíveis multas/descontos à data da visualização). A data de pagamento (e o separador correspondente) só é apresentada se a venda tiver sido paga.
Se a transacção corresponder a uma compra a um parceiro, apresenta-se com o seguinte formato:
COMPRA|id|idParceiro|idProduto|quantidade|valor-pago|data-pagamento
Se a transacção for uma desagregação, então deve ser apresentada, primeiro a "venda" do produto derivado, seguida da "compra" dos componentes obtidos na desagregação. O formato para N componentes é o seguinte:
DESAGREGAÇÃO|id|idPa|idPr|quantidade|vbase|vpag|data|idC1:q1:v1#...#idCN:qN:vN
O valor base de uma desagregação corresponde à diferença entre a compra e a venda. O valor pago corresponde ao valor realmente pago pelo parceito (é um valor não negativo, podendo ser 0 caso o valor base seja negativo. Nesta linha, idPa é o identificador do parceiro; idPr é o identificador do produto; vbase é o valor real da transacção (diferencial); vpag é o valor a pagar (não negativo); data é a data da transacção; idCx, qx, vx, são (respectivamente) o identificador, a quantidade e o valor do componente x (não confundir com valor unitário). Cada componente é separado do seguinte por #.
Para registar uma desagregação, é pedido o identificador do parceiro que pede a operação e o identificador do produto a desagregar e a respectiva quantidade (Prompt.amount()). Se a quantidade for superior às existências actuais, deve ser lançada a excepção UnavailableProductException (não se realiza a desagregação). Se o produto a desagregar não for derivado, a acção não tem efeito.
A actualização dos produtos do entreposto, bem como o respectivo valor, tem lugar logo após o registo da desagregação, ou seja, considera-se que a operação é instantânea.
Esta transacção regista o produto de origem e os lotes dos resultantes (associados ao parceiro que pede a operação), bem como os respectivos valores.
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.
É pedido o identificador do parceiro a quem se realiza a compra, o identificador do produto que se está a comprar, o preço do produto (Prompt.price()) e a respectiva quantidade (Prompt.amount()). O produto comprado mantém informação sobre o processo de aquisição: em particular, se vários parceiros fornecerem o mesmo produto, podem fazê-lo com preços diferentes. O entreposto poderá, então, vender um dado produto com diferentes preços.
Se o identificador do produto for desconhecido, então é perguntado ao parceiro se quer introduzir uma receita para um produto derivado (Prompt.addRecipe()). Se a resposta for negativa, trata-se de um produto simples. Caso contrário, é pedido o número de componentes da receita (Prompt.numberOfComponents()), o valor do agravamento (Prompt.alpha()) e, em ciclo, os identificadores (Prompt.productkey()) e quantidades (Prompt.amount()) dos vários componentes.
A actualização de existências dos produtos do entreposto tem lugar logo após o registo da compra, ou seja, considera-se que a compra é instantânea. A actualização do saldo do entreposto também é assumida como instantânea, i.e., assume-se que a compra é paga a pronto.
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.
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.
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.
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.
Pede-se o identificador do parceiro e apresentam-se as transacções do parceiro que já estão pagas (uma transacção por linha).
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|Papelaria Fernandes|Oeiras, Portugal
PARTNER|P1|Publicações Europa-América|Lisboa, Portugal
PARTNER|P3|O’Reilly|Köln, Germany
PARTNER|R2|Jorge Figueiredo|Lisboa, Portugal
PARTNER|E4|Filomena Figueiredo|Lisboa, Portugal
PARTNER|ER|Abdul Figueiredo|Casablanca, Morocco
PARTNER|O9|Hellen Figueiredo|San Francisco, CA, USA
PARTNER|H2SO4|John Figueiredo|Wellington, New Zealand
PARTNER|H2O|Rohit Figueiredo|New Delhi, India
BATCH_S|HIDROGÉNIO|S1|200|5000
BATCH_S|OXIGÉNIO|S1|1200|2500
BATCH_M|ÁGUA|R2|800|5000|0.1|HIDROGÉNIO:2#OXIGÉNIO:1
|
A codificação dos ficheiros a ler é garantidamente UTF-8.
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.
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).