Git Product home page Git Product logo

emad-2019-accenture / smart-cart Goto Github PK

View Code? Open in Web Editor NEW
1.0 4.0 1.0 6.82 MB

A simple Ionic + Angular Barcode Scan app for grocery stores backed with RESTful Web Services on Spring Boot - Participant of App Challenge 2020 - Outcome of Enterprise Mobile Application Development Master's Degree Course @ UniSA

License: MIT License

JavaScript 0.99% TypeScript 13.93% HTML 3.82% CSS 0.74% Java 66.54% Shell 0.04% Python 13.94%
angular ionic hybrid-app marketbasketanalysis recommender-system capacitor grocery spring-boot jhipster barcode-scanner

smart-cart's Introduction

Smart Cart (ITA)

Il progetto è sviluppato nel contesto del corso di esame Enterprise Mobile Application Development (EMAD) presso l'Università degli Studi di Salerno, in collaborazione con Accenture Itaia.
Il progetto ha come fine ultimo quello di realizzare un'applicazione in ambito enterprise che prenda parte alla competizione App Challange organizzata dalla prof.ssa Rita Francese e il Dipartimento di Informatica.

Sistema proposto

Viene proposta un'app per smartphone a supporto degli acquisti in una singola catena di supermercati. L'app vuole dare la possibilità ai clienti di poter leggere il codice a barre dei prodotti presenti sugli scaffali con il proprio smartphone e di poterne ottenere delle informazioni dettagliate, sia quelle già presenti sull'etichetta (allergeni, valori nutrizionali, ecc.), sia altre aggiuntive, come le valutazioni di altri acquirenti e suggerimenti dei prodotti. Il sistema sarà di supporto sia alle vendite del supermercato, proponendo articoli per i quali è necessario aumentare le vendite, sia al compratore, al quale saranno presentate delle offerte sui prodotti. Il sistema suggerirà prodotti correlati a quelli visionati dal cliente durante la sessione di acquisto corrente, e prodotti da vendere secondo le priorità del supermarket (scadenze vicine, prodotti poco venduti, ecc.)

Il sistema si compone di un back-end, che verrà messo in esercizio sul servizio PaaS Heroku, e di un front-end, un'app mobile multipiattaforma (Android, iOS).

Obiettivi e criteri di successo del progetto

Il progetto si pone i seguenti obiettivi:

  • Migliorare l'esperienza di acquisto dell'acquirente fornendogli tutte le informazioni per la scelta degli articoli con trasparenza;
  • Rendere il sistema prodotto usabile per la maggior parte degli acquirenti tipici del cliente;
  • Migliorare la fidelizzazione degli acquirenti grazie ai sistemi di supporto e di raccomandazione;
  • Incrementare le vendite di Coop grazie al sistema di raccomandazione che favorisce la vendita degli articoli;
  • Realizzare il front-end del sistema come app multipiattaforma (almeno Android e iOS), rivolgendosi alla maggior parte del mercato degli smartphone;

Il progetto sarà di successo se, oltre agli obiettivi, rispetta anche i seguenti criteri di successo:

  • Rispettare tutte le consegne;
  • Implementare le funzionalità a proprità alta prima della consegna finale;
  • Implementare il sistema usando le tecnologie multipiattaforma Angular, Ionic e Capacitor.

Documentazione progetto

Sono riportati di seguito i documenti preliminari alla realizzazione dell'applicativo:

Presentazioni

Sono riportate di seguito le presentazioni realizzate per presentare i vari stadi di avanzamento dell'applicativo:

Presentazione App Challange


Setup

Di seguito sono presentati gli step necessari per la creazione del progetto frontend e successivamente quelli necessari alla compilazione e al run dell'applicazione.

Creazione Progetto

  1. ionic start frontend blank --type=ionic-angular
  2. ionic integrations enable capacitor
  3. npm install @ionic-native/barcode-scanner
  4. npm install phonegap-plugin-barcodescanner

Run App

  1. Assicurarsi di essere nella directory frontend/
  2. Eseguire npm install per installare tutte le dipendenze presenti in package.json. Verrà creata la directory nome_modules/
  3. Eseguire ionic capacitor add e selezionare dal wizard le piattaforme target desiderate
  4. Eseguire ionic build per compilare il progetto col profilo development (ionic build --prod per il profilo production). Verrà creata la directory www/ contenente tutti gli asset necessari per il deployment dell'app (indipendentemente dalla piattaforma target);
  5. Eseguire ionic capacitor sync per copiare i web asset di www/ in tutte le piattaforme installate, con annessa risoluzione di dipendenze e di installazione di plugin Capacitor/Cordova.
  6. Eseguire ionic capacitor run e selezionare la piattaforma target desiderata per aprire l'IDE di riferimento della piattaforma scelta con il profilo development (ionic capacitor run --prod per eseguire con il profilo production se l'app è stata compilata per production).

In caso di esecuzione della piattaforma Android, assicurarsi di avere installato Android Studio. Se ionic capacitor run segnala l'assenza di Android Studio, bisogna inserire nel file capacitor.config.json l'attributo linuxAndroidStudioPath con il path per lo script di Android Studio (ad es. /opt/android-studio/bin/studio.sh).

Fix Icone e Immagini

Per rigenerare le icone è necessario seguire i seguenti passi:

  1. Scegliere un'immagine png 1024x1024px per resources/icon.png.
  2. Scegliere un'immagine png 2732x2732px per resources/splash.png.
  3. In codebase/frontend, eseguire il comando npm run resources.

Con Capacitor, potrebbe essere necessario rimuovere dal manifest principale android:theme="@style/AppTheme.NoActionBarLaunch" dal tag <activity> per rimuovere uno dei due splash screen che compaiono.

Dettagli su: https://gist.github.com/dalezak/a6b1de39091f4ace220695d72717ac71#file-resources-js

Se eventualmente le immagini non sono visualizzate correttamente è necessario aggiungere l'attributo android:usesCleartextTraffic="true" nel tag <application> nel manifest dell'applicazione.

smart-cart's People

Contributors

emaiannone avatar flavio-96 avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar  avatar

smart-cart's Issues

Bozza Problem Statement

Due: 15/10/2019

Fare una prima versione del Problem Statement.
Sulla piattaforma è presente il template (di Breggue) per il Problem Statement

  • 1) Problem Domain
    • Introduzione del dominio
    • Soluzione proposta
  • 2) Scenari
  • 3) Requisiti Funzionali
  • 4) Requisiti Non funzionali

Funzionalità: raccomandazioni prodotti CLIENT

Mostrare all'utente le raccomandazioni.

  • Mostrare una raccomandazione appena si aggiunge al carrello un prodotto scannerizzato. Dovrebbe apparire come un toast/snackbar.
  • Pagina di raccomandazione ha lo storico delle raccomandazioni nella sessione come card, visualizzabili nel dettaglio e cancellabili
  • La raccomandazione nel dettaglio (articolo) presenta un tasto interno di scannerizzazione che dopo averla fatta l'articolo viene aggiunto direttamente nel carrello (fatto, ma va testato su telefono)
  • Introdurre meccanismo (lato client per adesso) che tiene conto del fatto che una raccomandazione può essere accolta, scartata o ignorata.
  • Post scan deve apparire una raccomandazione a seconda di una probabilità. Statica (fissa a 0.5 ad es.) o dinamica?
  • Mandare ID dei prodotti nel carrello ad una API ad hoc che richiede la raccomandazione migliore in quel momento.
  • L'aggiunta di un prodotto al carrello già presente => somma delle quantità
  • Testare la raccomandazione specifica con device
  • Errore: articolo scannerizzato non trovato...
  • Impedire il lancio di una nuova raccomandazione se si è scannerizzato già un certo prodotto (?)

Logo applicazione

Bisognerebbe creare un logo seguendo le linee guida di Marica Rinaldi.

Qui sotto se ci vengono idee possiamo anche fare delle proposte e poi valutarle nel tempo.

Eccezione in https://smart-cart-acenture.herokuapp.com/api/categories

{
"cause": null,
"stackTrace": [
{
"methodName": "build",
"fileName": "ProblemBuilder.java",
"lineNumber": 83,
"className": "org.zalando.problem.ProblemBuilder",
"nativeMethod": false
},
{
"methodName": "process",
"fileName": "ExceptionTranslator.java",
"lineNumber": 74,
"className": "it.unisa.scanapp.web.rest.errors.ExceptionTranslator",
"nativeMethod": false
},
{
"methodName": "create",
"fileName": "AdviceTrait.java",
"lineNumber": 131,
"className": "org.zalando.problem.spring.web.advice.AdviceTrait",
"nativeMethod": false
},
{
"methodName": "create",
"fileName": "AdviceTrait.java",
"lineNumber": 115,
"className": "org.zalando.problem.spring.web.advice.AdviceTrait",
"nativeMethod": false
},
{
"methodName": "create",
"fileName": "AdviceTrait.java",
"lineNumber": 81,
"className": "org.zalando.problem.spring.web.advice.AdviceTrait",
"nativeMethod": false
},
{
"methodName": "handleThrowable",
"fileName": "ThrowableAdviceTrait.java",
"lineNumber": 25,
"className": "org.zalando.problem.spring.web.advice.general.ThrowableAdviceTrait",
"nativeMethod": false
},
{
"methodName": "invoke0",
"fileName": "NativeMethodAccessorImpl.java",
"lineNumber": -2,
"className": "sun.reflect.NativeMethodAccessorImpl",
"nativeMethod": true
},
{
"methodName": "invoke",
"fileName": "NativeMethodAccessorImpl.java",
"lineNumber": 62,
"className": "sun.reflect.NativeMethodAccessorImpl",
"nativeMethod": false
},
{
"methodName": "invoke",
"fileName": "DelegatingMethodAccessorImpl.java",
"lineNumber": 43,
"className": "sun.reflect.DelegatingMethodAccessorImpl",
"nativeMethod": false
},
{
"methodName": "invoke",
"fileName": "Method.java",
"lineNumber": 498,
"className": "java.lang.reflect.Method",
"nativeMethod": false
},
{
"methodName": "doInvoke",
"fileName": "InvocableHandlerMethod.java",
"lineNumber": 190,
"className": "org.springframework.web.method.support.InvocableHandlerMethod",
"nativeMethod": false
},
{
"methodName": "invokeForRequest",
"fileName": "InvocableHandlerMethod.java",
"lineNumber": 138,
"className": "org.springframework.web.method.support.InvocableHandlerMethod",
"nativeMethod": false
},
{
"methodName": "invokeAndHandle",
"fileName": "ServletInvocableHandlerMethod.java",
"lineNumber": 105,
"className": "org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod",
"nativeMethod": false
},
{
"methodName": "doResolveHandlerMethodException",
"fileName": "ExceptionHandlerExceptionResolver.java",
"lineNumber": 409,
"className": "org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver",
"nativeMethod": false
},
{
"methodName": "doResolveException",
"fileName": "AbstractHandlerMethodExceptionResolver.java",
"lineNumber": 61,
"className": "org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver",
"nativeMethod": false
},
{
"methodName": "resolveException",
"fileName": "AbstractHandlerExceptionResolver.java",
"lineNumber": 141,
"className": "org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver",
"nativeMethod": false
},
{
"methodName": "resolveException",
"fileName": "HandlerExceptionResolverComposite.java",
"lineNumber": 80,
"className": "org.springframework.web.servlet.handler.HandlerExceptionResolverComposite",
"nativeMethod": false
},
{
"methodName": "processHandlerException",
"fileName": "DispatcherServlet.java",
"lineNumber": 1299,
"className": "org.springframework.web.servlet.DispatcherServlet",
"nativeMethod": false
},
{
"methodName": "processDispatchResult",
"fileName": "DispatcherServlet.java",
"lineNumber": 1111,
"className": "org.springframework.web.servlet.DispatcherServlet",
"nativeMethod": false
},
{
"methodName": "doDispatch",
"fileName": "DispatcherServlet.java",
"lineNumber": 1057,
"className": "org.springframework.web.servlet.DispatcherServlet",
"nativeMethod": false
},
{
"methodName": "doService",
"fileName": "DispatcherServlet.java",
"lineNumber": 943,
"className": "org.springframework.web.servlet.DispatcherServlet",
"nativeMethod": false
},
{
"methodName": "processRequest",
"fileName": "FrameworkServlet.java",
"lineNumber": 1006,
"className": "org.springframework.web.servlet.FrameworkServlet",
"nativeMethod": false
},
{
"methodName": "doGet",
"fileName": "FrameworkServlet.java",
"lineNumber": 898,
"className": "org.springframework.web.servlet.FrameworkServlet",
"nativeMethod": false
},
{
"methodName": "service",
"fileName": "HttpServlet.java",
"lineNumber": 645,
"className": "javax.servlet.http.HttpServlet",
"nativeMethod": false
},
{
"methodName": "service",
"fileName": "FrameworkServlet.java",
"lineNumber": 883,
"className": "org.springframework.web.servlet.FrameworkServlet",
"nativeMethod": false
},
{
"methodName": "service",
"fileName": "HttpServlet.java",
"lineNumber": 750,
"className": "javax.servlet.http.HttpServlet",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "ServletHandler.java",
"lineNumber": 74,
"className": "io.undertow.servlet.handlers.ServletHandler",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterHandler.java",
"lineNumber": 129,
"className": "io.undertow.servlet.handlers.FilterHandler$FilterChainImpl",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "OncePerRequestFilter.java",
"lineNumber": 113,
"className": "org.springframework.web.filter.OncePerRequestFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "ManagedFilter.java",
"lineNumber": 61,
"className": "io.undertow.servlet.core.ManagedFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterHandler.java",
"lineNumber": 131,
"className": "io.undertow.servlet.handlers.FilterHandler$FilterChainImpl",
"nativeMethod": false
},
{
"methodName": "doFilterInternal",
"fileName": "HttpTraceFilter.java",
"lineNumber": 88,
"className": "org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "OncePerRequestFilter.java",
"lineNumber": 119,
"className": "org.springframework.web.filter.OncePerRequestFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "ManagedFilter.java",
"lineNumber": 61,
"className": "io.undertow.servlet.core.ManagedFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterHandler.java",
"lineNumber": 131,
"className": "io.undertow.servlet.handlers.FilterHandler$FilterChainImpl",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 320,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "invoke",
"fileName": "FilterSecurityInterceptor.java",
"lineNumber": 127,
"className": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterSecurityInterceptor.java",
"lineNumber": 91,
"className": "org.springframework.security.web.access.intercept.FilterSecurityInterceptor",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 334,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "ExceptionTranslationFilter.java",
"lineNumber": 119,
"className": "org.springframework.security.web.access.ExceptionTranslationFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 334,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "SessionManagementFilter.java",
"lineNumber": 137,
"className": "org.springframework.security.web.session.SessionManagementFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 334,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "AnonymousAuthenticationFilter.java",
"lineNumber": 111,
"className": "org.springframework.security.web.authentication.AnonymousAuthenticationFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 334,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "SecurityContextHolderAwareRequestFilter.java",
"lineNumber": 170,
"className": "org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 334,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "RequestCacheAwareFilter.java",
"lineNumber": 63,
"className": "org.springframework.security.web.savedrequest.RequestCacheAwareFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 334,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "doFilterInternal",
"fileName": "BasicAuthenticationFilter.java",
"lineNumber": 158,
"className": "org.springframework.security.web.authentication.www.BasicAuthenticationFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "OncePerRequestFilter.java",
"lineNumber": 119,
"className": "org.springframework.web.filter.OncePerRequestFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 334,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "JWTFilter.java",
"lineNumber": 38,
"className": "it.unisa.scanapp.security.jwt.JWTFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 334,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "doFilterInternal",
"fileName": "CorsFilter.java",
"lineNumber": 97,
"className": "org.springframework.web.filter.CorsFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "OncePerRequestFilter.java",
"lineNumber": 119,
"className": "org.springframework.web.filter.OncePerRequestFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 334,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "LogoutFilter.java",
"lineNumber": 116,
"className": "org.springframework.security.web.authentication.logout.LogoutFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 334,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "doFilterInternal",
"fileName": "HeaderWriterFilter.java",
"lineNumber": 74,
"className": "org.springframework.security.web.header.HeaderWriterFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "OncePerRequestFilter.java",
"lineNumber": 119,
"className": "org.springframework.web.filter.OncePerRequestFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 334,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "SecurityContextPersistenceFilter.java",
"lineNumber": 105,
"className": "org.springframework.security.web.context.SecurityContextPersistenceFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 334,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "doFilterInternal",
"fileName": "WebAsyncManagerIntegrationFilter.java",
"lineNumber": 56,
"className": "org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "OncePerRequestFilter.java",
"lineNumber": 119,
"className": "org.springframework.web.filter.OncePerRequestFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 334,
"className": "org.springframework.security.web.FilterChainProxy$VirtualFilterChain",
"nativeMethod": false
},
{
"methodName": "doFilterInternal",
"fileName": "FilterChainProxy.java",
"lineNumber": 215,
"className": "org.springframework.security.web.FilterChainProxy",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterChainProxy.java",
"lineNumber": 178,
"className": "org.springframework.security.web.FilterChainProxy",
"nativeMethod": false
},
{
"methodName": "invokeDelegate",
"fileName": "DelegatingFilterProxy.java",
"lineNumber": 358,
"className": "org.springframework.web.filter.DelegatingFilterProxy",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "DelegatingFilterProxy.java",
"lineNumber": 271,
"className": "org.springframework.web.filter.DelegatingFilterProxy",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "ManagedFilter.java",
"lineNumber": 61,
"className": "io.undertow.servlet.core.ManagedFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterHandler.java",
"lineNumber": 131,
"className": "io.undertow.servlet.handlers.FilterHandler$FilterChainImpl",
"nativeMethod": false
},
{
"methodName": "filterAndRecordMetrics",
"fileName": "WebMvcMetricsFilter.java",
"lineNumber": 114,
"className": "org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter",
"nativeMethod": false
},
{
"methodName": "doFilterInternal",
"fileName": "WebMvcMetricsFilter.java",
"lineNumber": 104,
"className": "org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "OncePerRequestFilter.java",
"lineNumber": 119,
"className": "org.springframework.web.filter.OncePerRequestFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "ManagedFilter.java",
"lineNumber": 61,
"className": "io.undertow.servlet.core.ManagedFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterHandler.java",
"lineNumber": 131,
"className": "io.undertow.servlet.handlers.FilterHandler$FilterChainImpl",
"nativeMethod": false
},
{
"methodName": "doFilterInternal",
"fileName": "CharacterEncodingFilter.java",
"lineNumber": 201,
"className": "org.springframework.web.filter.CharacterEncodingFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "OncePerRequestFilter.java",
"lineNumber": 119,
"className": "org.springframework.web.filter.OncePerRequestFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "ManagedFilter.java",
"lineNumber": 61,
"className": "io.undertow.servlet.core.ManagedFilter",
"nativeMethod": false
},
{
"methodName": "doFilter",
"fileName": "FilterHandler.java",
"lineNumber": 131,
"className": "io.undertow.servlet.handlers.FilterHandler$FilterChainImpl",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "FilterHandler.java",
"lineNumber": 84,
"className": "io.undertow.servlet.handlers.FilterHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "ServletSecurityRoleHandler.java",
"lineNumber": 62,
"className": "io.undertow.servlet.handlers.security.ServletSecurityRoleHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "ServletChain.java",
"lineNumber": 68,
"className": "io.undertow.servlet.handlers.ServletChain$1",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "ServletDispatchingHandler.java",
"lineNumber": 36,
"className": "io.undertow.servlet.handlers.ServletDispatchingHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "RedirectDirHandler.java",
"lineNumber": 68,
"className": "io.undertow.servlet.handlers.RedirectDirHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "SSLInformationAssociationHandler.java",
"lineNumber": 132,
"className": "io.undertow.servlet.handlers.security.SSLInformationAssociationHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "ServletAuthenticationCallHandler.java",
"lineNumber": 57,
"className": "io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "PredicateHandler.java",
"lineNumber": 43,
"className": "io.undertow.server.handlers.PredicateHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "AbstractConfidentialityHandler.java",
"lineNumber": 46,
"className": "io.undertow.security.handlers.AbstractConfidentialityHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "ServletConfidentialityConstraintHandler.java",
"lineNumber": 64,
"className": "io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "AuthenticationMechanismsHandler.java",
"lineNumber": 60,
"className": "io.undertow.security.handlers.AuthenticationMechanismsHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "CachedAuthenticatedSessionHandler.java",
"lineNumber": 77,
"className": "io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "AbstractSecurityContextAssociationHandler.java",
"lineNumber": 43,
"className": "io.undertow.security.handlers.AbstractSecurityContextAssociationHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "PredicateHandler.java",
"lineNumber": 43,
"className": "io.undertow.server.handlers.PredicateHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "PredicateHandler.java",
"lineNumber": 43,
"className": "io.undertow.server.handlers.PredicateHandler",
"nativeMethod": false
},
{
"methodName": "handleFirstRequest",
"fileName": "ServletInitialHandler.java",
"lineNumber": 269,
"className": "io.undertow.servlet.handlers.ServletInitialHandler",
"nativeMethod": false
},
{
"methodName": "access$100",
"fileName": "ServletInitialHandler.java",
"lineNumber": 78,
"className": "io.undertow.servlet.handlers.ServletInitialHandler",
"nativeMethod": false
},
{
"methodName": "call",
"fileName": "ServletInitialHandler.java",
"lineNumber": 133,
"className": "io.undertow.servlet.handlers.ServletInitialHandler$2",
"nativeMethod": false
},
{
"methodName": "call",
"fileName": "ServletInitialHandler.java",
"lineNumber": 130,
"className": "io.undertow.servlet.handlers.ServletInitialHandler$2",
"nativeMethod": false
},
{
"methodName": "call",
"fileName": "ServletRequestContextThreadSetupAction.java",
"lineNumber": 48,
"className": "io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1",
"nativeMethod": false
},
{
"methodName": "call",
"fileName": "ContextClassLoaderSetupAction.java",
"lineNumber": 43,
"className": "io.undertow.servlet.core.ContextClassLoaderSetupAction$1",
"nativeMethod": false
},
{
"methodName": "dispatchRequest",
"fileName": "ServletInitialHandler.java",
"lineNumber": 249,
"className": "io.undertow.servlet.handlers.ServletInitialHandler",
"nativeMethod": false
},
{
"methodName": "access$000",
"fileName": "ServletInitialHandler.java",
"lineNumber": 78,
"className": "io.undertow.servlet.handlers.ServletInitialHandler",
"nativeMethod": false
},
{
"methodName": "handleRequest",
"fileName": "ServletInitialHandler.java",
"lineNumber": 99,
"className": "io.undertow.servlet.handlers.ServletInitialHandler$1",
"nativeMethod": false
},
{
"methodName": "executeRootHandler",
"fileName": "Connectors.java",
"lineNumber": 376,
"className": "io.undertow.server.Connectors",
"nativeMethod": false
},
{
"methodName": "run",
"fileName": "HttpServerExchange.java",
"lineNumber": 830,
"className": "io.undertow.server.HttpServerExchange$1",
"nativeMethod": false
},
{
"methodName": "runWorker",
"fileName": "ThreadPoolExecutor.java",
"lineNumber": 1149,
"className": "java.util.concurrent.ThreadPoolExecutor",
"nativeMethod": false
},
{
"methodName": "run",
"fileName": "ThreadPoolExecutor.java",
"lineNumber": 624,
"className": "java.util.concurrent.ThreadPoolExecutor$Worker",
"nativeMethod": false
},
{
"methodName": "run",
"fileName": "Thread.java",
"lineNumber": 748,
"className": "java.lang.Thread",
"nativeMethod": false
}
],
"type": "https://www.jhipster.tech/problem/problem-with-message",
"title": "Internal Server Error",
"status": "INTERNAL_SERVER_ERROR",
"detail": "Could not write JSON: failed to lazily initialize a collection of role: it.unisa.scanapp.domain.Category.products, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: it.unisa.scanapp.domain.Category.products, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->it.unisa.scanapp.domain.Category["products"])",
"instance": null,
"parameters": {
"path": "/api/categories",
"message": "error.http.500"
},
"message": "Internal Server Error: Could not write JSON: failed to lazily initialize a collection of role: it.unisa.scanapp.domain.Category.products, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: it.unisa.scanapp.domain.Category.products, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->it.unisa.scanapp.domain.Category["products"])",
"localizedMessage": "Internal Server Error: Could not write JSON: failed to lazily initialize a collection of role: it.unisa.scanapp.domain.Category.products, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: it.unisa.scanapp.domain.Category.products, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->it.unisa.scanapp.domain.Category["products"])",
"suppressed": []
}

Completare requisiti e stilare casi d'uso

Dobbiamo valutare bene se mancano alcune funzionalità o meno e se quelle che abbiamo sono effettivamente giuste per i nostri obiettivi e il nostro contesto.
In base a queste dobbiamo modellare le entity del nostro sistema

Modificare view raccomandazioni?

Le proposte sono le seguenti:

  • Slider di raccomandazione nella view del prodotto singolo
  • Slider per raccomandazione dei soli prodotti nel carrello nella view del carrello
  • La view delle raccomandazioni sono a livello di utente, a seconda del suo profilo

Utilizzo oracle DB

Dobbiamo migrare il db sulla piattaforma oracle che ci hanno fornito e risolvere gli issue relativi ai driver con jhipster/spring

Funzionalità: Consultazione catalogo prodotti SERVER

Per questa funzionalità essenzialmente è necessario permettere la selezione dei prodotti in base alle tipologie di categorie riportate sul sito della coop:

  • Implementare un servizio che restituisca tutte le categorie esistenti
  • Implementare un servizio che restituisca tutti i prodotti di una data categoria (risolto lato client)

Scrivere i requisiti in forma tabellare

Ad esempio:
Alta -> Prima release, analisi, design e implementazione
Media -> Seconda release, solo analisi
Bassa -> Future release. Non ne viene fatta nemmeno l'analisi

Funzionalità: Consultazione catalogo prodotti CLIENT

Per questa funzionalità essenzialmente è necessario permettere la selezione dei prodotti in base alle tipologie di categorie riportate sul sito della coop:

  • Ordine alfabetico dei prodotti ritornati (c'è un coso ionic ad hoc?)
  • Mostrare piccola immagine ad ogni voce dell'elenco un po' come il carrello
  • Recuperare e mostrare le info dei singoli prodotti (stessa visualizzazione del carrello)
  • Creare un check/filtro per i prodotti in offerta (forse)
  • Colore della combobox (forse)

Funzionalità: gestione carrello?

Si può pensare di inserire come nuova funzionalità quella della gestione del carrello dei prodotti. La gestione del carrello darebbe la possibilità all'utente di monitorare i prodotti che ha scansionato e scelto di aggiungere alla propria spesa e l'ammontare totale del costo dei prodotti.
L'utente trae vantaggio da questa funzionalità avendo sempre sotto occhio il costo della spesa, e anche i prodotti che deve ancora acquistare; il sistema invece si avvantaggia di questo "basket" per proporre oggetti utili all'utente o offerte presenti.

Nome applicazione

Bisognerebbe scegliere il nome dell'applicazione in maniera tale che si capisca immediatamente lo scopo e che sia un nome facile da ricordare e di impatto.

Qui sotto se ci vengono idee possiamo anche fare delle proposte e poi valutarle nel tempo.

Attributi prodotti da inserire

Per il successo e il corretto funzionamento del sistema è fondamentale chiarire quali sono gli attributi dei prodotti che vogliamo trattare. Da ciò dipendono sia le informazioni mostrate al momento della scansione dei prodotti, sia un buon sistema di promozioni dei prodotti.

Una prima valutazione degli attributi è stata fatta e può essere visionata qui: Bozza DB.

Conversione nomi

  • Prodotti -> Articoli
  • Offerta -> Promozione
  • Cliente -> Acquirente
  • Tipologia -> Categoria

Front-end: Carrello e Scan

  • CarrelloService: Modifica delle quantità. Il carrello è una cosa solo lato client + checkout
  • ScanService: query per ottenere dati e poi si fa vedere la pagina dell'articolo, così da poterlo inserire nel carrello

Lato client

Logica:

  • Logout: icona "uscita" nel tab delle preferenze
  • Checkout: al click di chiudi sessione, mostrare un popup
  • Logica delle offerte nella pagina dell'articolo
  • Logica delle offerte nella pagina del carrello
  • C'è una request a /null strana
  • Nel catalogo, quando vengono tolti i filtri, il rendering di tutti i prodotti è lento. Ci vorrebbe un caricamento a gruppi
  • Assenza rete (importante)
  • Aggiungere Cognome a Lato Utente e Rimuovere Stato Salute
  • Parse della data nascita di dal server
  • Assenza rete quando dovrebbe arrivare una raccomandazione
  • Controllare se prodotto raccomandato è già presente nel carrello, se si evitare raccomandazione (importante)
  • Data di nascita non viene aggiornata, why? (non molto importante)
  • Lanciare la raccomandazione solo quando un certo prodotto viene aggiunto per la prima volta al carrello (C'è, ma commentata perché poco importante)
  • Al checkout confermato bisogna creare una transazione che mantiene il set di prodotti sul server (non importante)

GUI:

  • Nel catalogo, filtri della categoria renderli a icona in alto a destra invece che con il dropdown (bisognerebbe usare popcontroller, ma c'erano problemi perché la doc diceva una cosa diversa da VS code).
  • Assicurarsi che lo scroll del catalogo non porti con gli altri elementi della GUI
  • Loading screen quando si attendono risposte dal server
  • Alcune pagine, prima che arrivano i dati dal server, mostrano dati che non dovrebbero essere mostrati. Si può risolvere col loading screen
  • Evidenziare meglio graficamente quando un prodotto raccomandato/scannerizzato è in offerta
  • Ingredienti e allergeni nella pagina dell'articolo sono troppo lunghi a volte! Ci vorrebbe un drop down
  • Pagina delle raccomandazioni: card più carine (rimuovere descrizione)
  • Nome Acquirente nella pagina del carrello (CarrelloService->AuthService)
  • Icone e font vari
  • Logo
  • Restringere bordo logo nella login page (utile)
  • Size card raccomandazioni non uguali
  • Splash screen (da verificare)
  • Landscape: blocchiamo a portrait (https://ionicframework.com/docs/enterprise/screen-orientation)

Funzionalità: Impostazioni (e preferenze) utente

Attraverso le informazioni che l'utente ci fornisce dobbiamo targettare le raccomandazioni dei prodotti durante la sessione di acquisto, bisogna quindi:

  • Il client deve fornire tutti i campi necessari (quelli impostati nell'utente nel db e valutare eventuali aggiunte importanti)
  • Nella visualizzazione è necessario aggiungere un bottone per confermare il cambio dei setting e un dialog di conferma ulteriore
  • Sul server bisogna aggiornare le impostazioni dell'utente per escludere le raccomandazioni non pertinenti
  • Verificare se i prodotti permettono di matchare la compatibilità con le impostazioni valutate e risolvere in maniera consistente

Funzionalità: raccomandazioni prodotti SERVER

Creare un servizio ad hoc che il client interrogherà periodicamente per ricevere le raccomandazioni. Il servizio riceverà ID e stato del carrello.

  • Usare filtri preferenze utente

  • Tenere conto se il prodotto è già presente nel carrello

  • Rispondere il prodotto migliore

  • Servizio Fake

  • Servizio funzionante

Lato Scraper e Script

  • Campi nulli (es. image_url)
  • Risolvere il problema del grassetto
  • Aggiungere "price" perché ha vincolo @nonnull (generare randomicamente per molti, mentre per un set di prodotti che useremo per la challenge metterne di realistici)
  • Script SQL per aggiungere tutto il dataset al DB
  • Aggiungere altre categorie

Funzionalità: smart payment?

Per invogliare ulteriormente l'utente a utilizzare la nostra piattaforma, l'ideale sarebbe fornire una finalità successiva all'applicazione: permettere il pagamento tramite essa.
L'utente ha a disposizione un'applicazione che lo assiste nell'esperienza di acquisto nella sua interezza.
Tramite questa funzionalità si potrebbero gestire le transazioni e la fidelizzazione del cliente oltretutto e quindi invogliare l'utente all'utilizzo dell'applicativo anche tramite offerte dedicate per i "clienti fedeli".

La funzionalità è pensata per sviluppi futuri all'app challenge.

Revisione Problem Statement: Aggiunta AR e Chiarimento Raccomandazioni

  • Aggiungere che la scansione del barcode mostra le informazioni tramite realtà aumentata.
  • Chiarire come vengono proposti articoli correlati
  • Chiarire come vengono proposti altri articoli scontati
  • Aggiungere la possibilità di registrazione (cartà fedeltà), sebbene sia a priorità bassa

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.