[Task]: add comments + comment quality saving
This commit is contained in:
		
							parent
							
								
									d38839c4f9
								
							
						
					
					
						commit
						99d62fcb47
					
				
							
								
								
									
										16
									
								
								README.md
								
								
								
								
							
							
						
						
									
										16
									
								
								README.md
								
								
								
								
							| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
# Stock-Microservice
 | 
					# Stock-Microservice
 | 
				
			||||||
This is a microservice cutted out of a [Monolith](https://gitlab.com/matthiasstock/monolith).
 | 
					This microservice is cut out of a [Monolith](https://gitlab.com/matthiasstock/monolith).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[](https://travis-ci.org/genofire/hs_master-kss-monolith)  [](https://circleci.com/gh/genofire/hs_master-kss-monolith/tree/master) [](https://coveralls.io/github/genofire/hs_master-kss-monolith?branch=master) [](https://godoc.org/github.com/genofire/hs_master-kss-monolith)
 | 
					[](https://travis-ci.org/genofire/hs_master-kss-monolith)  [](https://circleci.com/gh/genofire/hs_master-kss-monolith/tree/master) [](https://coveralls.io/github/genofire/hs_master-kss-monolith?branch=master) [](https://godoc.org/github.com/genofire/hs_master-kss-monolith)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,14 +9,14 @@ This is a microservice cutted out of a [Monolith](https://gitlab.com/matthiassto
 | 
				
			||||||
* [Easy dummy Shop-Cart in browser-cache](https://stock.pub.warehost.de/dummy_cart/)
 | 
					* [Easy dummy Shop-Cart in browser-cache](https://stock.pub.warehost.de/dummy_cart/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Features of this stock mircoservice
 | 
					## Features of this stock mircoservice
 | 
				
			||||||
* The main functionality of the microservice is to store the goods with their storage location and the date, when they are too old to be sell.
 | 
					* The main functionality of the microservice is to store goods with their storage location and the date, when they are too old to sell.
 | 
				
			||||||
* Functionality of the admin frontend
 | 
					* Functionality of the admin frontend
 | 
				
			||||||
  * Add new goods to the stock
 | 
					  * Add new goods to the stock
 | 
				
			||||||
  * Manually remove a single goods from the stock, for example when they are rancid
 | 
					  * Manually remove a single good from the stock, for example when it is fouled
 | 
				
			||||||
  * Remove single goods from the stock, when they are send to a costumer
 | 
					  * Remove a single good from the stock, when it is send to a costumer
 | 
				
			||||||
  * Block goods from the stock, when a costumer adds them to his cart
 | 
					  * Block goods from the stock, when a costumer adds them to his shop-cart
 | 
				
			||||||
* Functionality of the costumer frontend
 | 
					* Functionality of the costumer frontend
 | 
				
			||||||
  * Show the store with a traffic light food labelling
 | 
					  * Show the stock of a product with a traffic light food labelling system
 | 
				
			||||||
* Optional Features
 | 
					* Optional Features
 | 
				
			||||||
  * Admin frontend: display of a statistic on the amount and average of goods in the stock
 | 
					  * Admin frontend: display of a statistic of the current and average amount of goods in the stock
 | 
				
			||||||
  * Admin frontend: display a traffic light food labelling for each good, which indicates whether the good is too old
 | 
					  * Admin frontend: display a traffic light food labelling system for each good, which indicates whether the good is too old
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
// Package that containts the cmd binary of the microservice to run it
 | 
					// Package that contains the cmd binary of the microservice to run it
 | 
				
			||||||
package main
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
| 
						 | 
					@ -50,13 +50,15 @@ func main() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	grw := runtime.NewGoodReleaseWorker(config.GoodRelease)
 | 
						grw := runtime.NewGoodReleaseWorker(config.GoodRelease)
 | 
				
			||||||
	cw := runtime.NewCacheWorker()
 | 
						cw := runtime.NewCacheWorker()
 | 
				
			||||||
	fw := worker.NewWorker(config.FouledDeleter.Duration, func() { runtime.GoodFouled() })
 | 
						fw := worker.NewWorker(config.FouledDeleter.Duration, func() {
 | 
				
			||||||
 | 
							runtime.GoodFouled()
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
	go grw.Start()
 | 
						go grw.Start()
 | 
				
			||||||
	go cw.Start()
 | 
						go cw.Start()
 | 
				
			||||||
	if config.FouledDeleter.Duration != time.Duration(0) {
 | 
						if config.FouledDeleter.Duration != time.Duration(0) {
 | 
				
			||||||
		go fw.Start()
 | 
							go fw.Start()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Startwebsrver
 | 
						// Start webserver
 | 
				
			||||||
	router := goji.NewMux()
 | 
						router := goji.NewMux()
 | 
				
			||||||
	web.BindAPI(router)
 | 
						web.BindAPI(router)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,24 +0,0 @@
 | 
				
			||||||
# bind the webserver to a dynamic ports
 | 
					 | 
				
			||||||
webserver_bind = ":65000"
 | 
					 | 
				
			||||||
webroot = "webroot"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
good_availablity_template = "contrib/good_availablity.svg"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[database]
 | 
					 | 
				
			||||||
type = "sqlite3"
 | 
					 | 
				
			||||||
# logging = true
 | 
					 | 
				
			||||||
connection = "file::memory:?mode=memory&cache=shared"
 | 
					 | 
				
			||||||
# For Master-Slave cluster
 | 
					 | 
				
			||||||
# read_connection = ""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[good_release]
 | 
					 | 
				
			||||||
every = "5m"
 | 
					 | 
				
			||||||
after = "30m"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[cache_clean]
 | 
					 | 
				
			||||||
every = "5m"
 | 
					 | 
				
			||||||
after = "30m"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[microservice_dependencies]
 | 
					 | 
				
			||||||
product = "http://localhost:65000/api-test/product/%d/"
 | 
					 | 
				
			||||||
permission = "http://localhost:65000/api-test/session/%s/%d/"
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,7 @@
 | 
				
			||||||
<!-- SVG to show the current stock with a traffic light food labeling system -->
 | 
					<!-- SVG to show the current stock with a traffic light food labeling system -->
 | 
				
			||||||
<!-- Used functions -->
 | 
					<!-- Used functions -->
 | 
				
			||||||
<!--   process_radius ANZAHL MAXANZAHL RADIUS -->
 | 
					<!--  process_radius ANZAHL MAXANZAHL RADIUS -->
 | 
				
			||||||
<!--   procent ANZAHL MAXANZAHL -->
 | 
					<!--  procent ANZAHL MAXANZAHL ex. {procent .Count 10}%-->
 | 
				
			||||||
<!--    ex. {procent .Count 10}%-->
 | 
					 | 
				
			||||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
 | 
					<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
 | 
				
			||||||
    <g class="arcs">
 | 
					    <g class="arcs">
 | 
				
			||||||
        {{if eq .Count 0}}
 | 
					        {{if eq .Count 0}}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
		 Before Width: | Height: | Size: 854 B After Width: | Height: | Size: 840 B  | 
| 
						 | 
					@ -58,8 +58,9 @@ Die Packages und Go-Files des Application Layers umfassen die Logik des Microser
 | 
				
			||||||
\paragraph{http:} Go-Files, die die Anwendungslogik (Funktionen) und die API-Routen beinhalten
 | 
					\paragraph{http:} Go-Files, die die Anwendungslogik (Funktionen) und die API-Routen beinhalten
 | 
				
			||||||
	\begin{itemize}
 | 
						\begin{itemize}
 | 
				
			||||||
	\item \texttt{bindapi.go}: Funktionen, die für das Binden der URL-Pfade notwendig sind
 | 
						\item \texttt{bindapi.go}: Funktionen, die für das Binden der URL-Pfade notwendig sind
 | 
				
			||||||
	\item \texttt{good.go}: Funktionen für die Verwaltung der Waren im Warenbestand
 | 
						\item \texttt{good.go}: Funktionen für das Hinzufügen von Waren zum Warenbestand und die Anzeige, ob eine Ware abgelaufen ist
 | 
				
			||||||
	\item \texttt{good\_show.go}: Funktionen für die Auflistung und Zählung der vorhandenen Waren sowie die Feststellung ihrer Verfügbarkeit
 | 
						\item \texttt{good\_lock.go}: Funktionen für das Blockieren von Waren, die sich im Warenkorb befinden
 | 
				
			||||||
 | 
							\item \texttt{good\_show.go}: Funktionen für die Auflistung und Zählung der vorhandenen Waren sowie die Feststellung ihrer Verfügbarkeit
 | 
				
			||||||
	\item \texttt{good\_temp.go}: Hilfsfunktionen, die für die Darstellung des Warenbestandes als Ampel im Kunden-Frontend benötigt werden
 | 
						\item \texttt{good\_temp.go}: Hilfsfunktionen, die für die Darstellung des Warenbestandes als Ampel im Kunden-Frontend benötigt werden
 | 
				
			||||||
	\item \texttt{status.go}: Funktion, die den Status des Microservice abfragt 
 | 
						\item \texttt{status.go}: Funktion, die den Status des Microservice abfragt 
 | 
				
			||||||
	\end{itemize}
 | 
						\end{itemize}
 | 
				
			||||||
| 
						 | 
					@ -77,9 +78,9 @@ Die Packages und Go-Files des Application Layers umfassen die Logik des Microser
 | 
				
			||||||
	\begin{itemize}	
 | 
						\begin{itemize}	
 | 
				
			||||||
	\item \texttt{auth.go}: Hilfsfunktionen zur Prüfung, ob eine Berechtigung für den Zugriff vorliegt
 | 
						\item \texttt{auth.go}: Hilfsfunktionen zur Prüfung, ob eine Berechtigung für den Zugriff vorliegt
 | 
				
			||||||
	\item \texttt{cache\_worker.go}: Hilfsfunktionen für das Löschen und Anlegen von Cache-Workers
 | 
						\item \texttt{cache\_worker.go}: Hilfsfunktionen für das Löschen und Anlegen von Cache-Workers
 | 
				
			||||||
 | 
						\item \texttt{good\_fouled.go}: Hilfsfunktion, um abgelaufene Waren automatisch aus dem Warenbestand zu entfernen
 | 
				
			||||||
	\item \texttt{good\_release.go}: Hilfsfunktionen zum Blockieren und Entsperren von Waren
 | 
						\item \texttt{good\_release.go}: Hilfsfunktionen zum Blockieren und Entsperren von Waren
 | 
				
			||||||
	\item \texttt{productcache.go}: Hilfsfunktionen zum Anlegen eines Caches für Produkte
 | 
						\item \texttt{productcache.go}: Hilfsfunktionen zum Anlegen eines Caches für Produkte
 | 
				
			||||||
	\item \texttt{runtime.go}: Übergreifende Hintergrundfunktionalitäten	
 | 
					 | 
				
			||||||
	\end{itemize}
 | 
						\end{itemize}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -122,7 +123,7 @@ connection = "file::memory:?mode=memory&cache=shared"
 | 
				
			||||||
\newpage
 | 
					\newpage
 | 
				
			||||||
\subsection{Integrierte Tests}
 | 
					\subsection{Integrierte Tests}
 | 
				
			||||||
\label{subsec: Integrierte Test}
 | 
					\label{subsec: Integrierte Test}
 | 
				
			||||||
Neben den bisherigen Packages, die bereits Whitebox-Tests umfassen, ist in dem Package \textbf{\texttt{test}} ein weiteres Go-File (\texttt{testRest.go}) enthalten. Dieses setzt einen Test des Webservers um, bei dem auf Testdaten eines Produktkataloges zurückgegriffen wird. Mit Hilfe der integrierten Tests wird in der hier beschriebenen Version eine Code-Coverage von 100\% erreicht, das heißt jedes Stück Code wird mindestens einmal zur Ausführung gebracht.
 | 
					Neben den bisherigen Packages, die bereits Whitebox-Tests umfassen, ist in dem Package \textbf{\texttt{test}} ein weiteres Go-File (\texttt{testrest.go}) enthalten. Dieses setzt einen Test des Webservers um, bei dem auf Testdaten eines Produktkataloges zurückgegriffen wird. Mit Hilfe der integrierten Tests wird in der hier beschriebenen Version eine Code-Coverage von 100\% erreicht, das heißt jedes Stück Code wird mindestens einmal zur Ausführung gebracht.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
\subsection{Anpassung des Monolithen}
 | 
					\subsection{Anpassung des Monolithen}
 | 
				
			||||||
\label{subsec: Anpassung des Monolithen}
 | 
					\label{subsec: Anpassung des Monolithen}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										18
									
								
								http/good.go
								
								
								
								
							
							
						
						
									
										18
									
								
								http/good.go
								
								
								
								
							| 
						 | 
					@ -28,8 +28,8 @@ func addGood(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	id, err := strconv.ParseInt(pat.Param(r, "productid"), 10, 64)
 | 
						id, err := strconv.ParseInt(pat.Param(r, "productid"), 10, 64)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Warn("false productid format")
 | 
							log.Warn("false product id format")
 | 
				
			||||||
		http.Error(w, "the product id is false", http.StatusNotAcceptable)
 | 
							http.Error(w, "the product id has a false format", http.StatusNotAcceptable)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	log = log.WithField("productid", id)
 | 
						log = log.WithField("productid", id)
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,7 @@ func addGood(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !ok {
 | 
						if !ok {
 | 
				
			||||||
		log.Warn("false product, product not found")
 | 
							log.Warn("product not found")
 | 
				
			||||||
		http.Error(w, "the product was not found", http.StatusNotFound)
 | 
							http.Error(w, "the product was not found", http.StatusNotFound)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -66,7 +66,7 @@ func addGood(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if db.Error != nil {
 | 
						if db.Error != nil {
 | 
				
			||||||
		log.Error("database not able to write", db.Error)
 | 
							log.Error("database unable to write", db.Error)
 | 
				
			||||||
		http.Error(w, "the product could not be written into the database", http.StatusInternalServerError)
 | 
							http.Error(w, "the product could not be written into the database", http.StatusInternalServerError)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	lib.Write(w, &obj)
 | 
						lib.Write(w, &obj)
 | 
				
			||||||
| 
						 | 
					@ -79,7 +79,7 @@ func delGood(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	log := logger.HTTP(r)
 | 
						log := logger.HTTP(r)
 | 
				
			||||||
	id, err := strconv.ParseInt(pat.Param(r, "goodid"), 10, 64)
 | 
						id, err := strconv.ParseInt(pat.Param(r, "goodid"), 10, 64)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Warn("wrong goodid format")
 | 
							log.Warn("wrong good id format")
 | 
				
			||||||
		http.Error(w, "the good id has a false format", http.StatusNotAcceptable)
 | 
							http.Error(w, "the good id has a false format", http.StatusNotAcceptable)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -90,8 +90,8 @@ func delGood(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	good.ID = id
 | 
						good.ID = id
 | 
				
			||||||
	db := good.FilterAvailable(database.Read).First(&good)
 | 
						db := good.FilterAvailable(database.Read).First(&good)
 | 
				
			||||||
	if db.RecordNotFound() {
 | 
						if db.RecordNotFound() {
 | 
				
			||||||
		log.Warnf("good could not found: %s", db.Error)
 | 
							log.Warnf("could not find good: %s", db.Error)
 | 
				
			||||||
		http.Error(w, "the good could not found", http.StatusNotFound)
 | 
							http.Error(w, "the good was not found", http.StatusNotFound)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	good.ManuelleDelete = true
 | 
						good.ManuelleDelete = true
 | 
				
			||||||
| 
						 | 
					@ -99,8 +99,8 @@ func delGood(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	db = database.Write.Save(&good)
 | 
						db = database.Write.Save(&good)
 | 
				
			||||||
	if db.Error != nil {
 | 
						if db.Error != nil {
 | 
				
			||||||
		log.Warnf("good could not delete: %s", db.Error)
 | 
							log.Warnf("could not delete good: %s", db.Error)
 | 
				
			||||||
		http.Error(w, "the good could not delete", http.StatusInternalServerError)
 | 
							http.Error(w, "the good could not be deleted", http.StatusInternalServerError)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	log.Info("done")
 | 
						log.Info("done")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
 | 
					// Package that contains all api routes of this microservice
 | 
				
			||||||
package http
 | 
					package http
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
| 
						 | 
					@ -14,6 +15,7 @@ type LockGood struct {
 | 
				
			||||||
	Count     int   `json:"count"`
 | 
						Count     int   `json:"count"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function to lock goods
 | 
				
			||||||
func lockGoods(w http.ResponseWriter, r *http.Request) {
 | 
					func lockGoods(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	log := logger.HTTP(r)
 | 
						log := logger.HTTP(r)
 | 
				
			||||||
	secret := r.Header.Get("secret")
 | 
						secret := r.Header.Get("secret")
 | 
				
			||||||
| 
						 | 
					@ -37,8 +39,8 @@ func lockGoods(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(goods) <= 0 {
 | 
						if len(goods) <= 0 {
 | 
				
			||||||
		log.Warn("try to log nothing")
 | 
							log.Warn("tried to log nothing")
 | 
				
			||||||
		http.Error(w, "try to log nothing", http.StatusBadRequest)
 | 
							http.Error(w, "tried to log nothing", http.StatusBadRequest)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,9 +49,9 @@ func lockGoods(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, good := range goods {
 | 
						for _, good := range goods {
 | 
				
			||||||
		if good.ProductID <= 0 {
 | 
							if good.ProductID <= 0 {
 | 
				
			||||||
			log.Warn("try to log nothing")
 | 
								log.Warn("tried to log nothing")
 | 
				
			||||||
			tx.Rollback()
 | 
								tx.Rollback()
 | 
				
			||||||
			http.Error(w, "try to log nothing", http.StatusBadRequest)
 | 
								http.Error(w, "tried to log nothing", http.StatusBadRequest)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for i := 0; i < good.Count; i++ {
 | 
							for i := 0; i < good.Count; i++ {
 | 
				
			||||||
| 
						 | 
					@ -68,7 +70,7 @@ func lockGoods(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
			if db.Error != nil || db.RowsAffected != 1 {
 | 
								if db.Error != nil || db.RowsAffected != 1 {
 | 
				
			||||||
				http.Error(w, "the good was not found in database", http.StatusInternalServerError)
 | 
									http.Error(w, "the good was not found in database", http.StatusInternalServerError)
 | 
				
			||||||
				tx.Rollback()
 | 
									tx.Rollback()
 | 
				
			||||||
				log.Panic("more then one good locked: ", db.Error)
 | 
									log.Panic("there is more than one good locked: ", db.Error)
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			count += 1
 | 
								count += 1
 | 
				
			||||||
| 
						 | 
					@ -81,6 +83,7 @@ func lockGoods(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function to release locked goods
 | 
				
			||||||
func releaseGoods(w http.ResponseWriter, r *http.Request) {
 | 
					func releaseGoods(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	log := logger.HTTP(r)
 | 
						log := logger.HTTP(r)
 | 
				
			||||||
	secret := r.Header.Get("secret")
 | 
						secret := r.Header.Get("secret")
 | 
				
			||||||
| 
						 | 
					@ -91,14 +94,14 @@ func releaseGoods(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	result := db.RowsAffected
 | 
						result := db.RowsAffected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Warn("database error during release goods: ", err)
 | 
							log.Warn("database error during the release of goods: ", err)
 | 
				
			||||||
		http.Error(w, "secret could not validate", http.StatusInternalServerError)
 | 
							http.Error(w, "the secret could not be validated", http.StatusInternalServerError)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if result <= 0 {
 | 
						if result <= 0 {
 | 
				
			||||||
		log.Warn("no goods found")
 | 
							log.Warn("no goods found")
 | 
				
			||||||
		http.Error(w, "no goods found to release", http.StatusNotFound)
 | 
							http.Error(w, "there are no goods to release", http.StatusNotFound)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@ import (
 | 
				
			||||||
	"github.com/genofire/hs_master-kss-monolith/test"
 | 
						"github.com/genofire/hs_master-kss-monolith/test"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function to test lockGoods()
 | 
				
			||||||
func TestLockGoods(t *testing.T) {
 | 
					func TestLockGoods(t *testing.T) {
 | 
				
			||||||
	assertion, router := test.Init(t)
 | 
						assertion, router := test.Init(t)
 | 
				
			||||||
	good := &models.Good{
 | 
						good := &models.Good{
 | 
				
			||||||
| 
						 | 
					@ -58,6 +59,7 @@ func TestLockGoods(t *testing.T) {
 | 
				
			||||||
	test.Close()
 | 
						test.Close()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function to test releaseGoods()
 | 
				
			||||||
func TestReleaseGoods(t *testing.T) {
 | 
					func TestReleaseGoods(t *testing.T) {
 | 
				
			||||||
	now := time.Now()
 | 
						now := time.Now()
 | 
				
			||||||
	assertion, router := test.Init(t)
 | 
						assertion, router := test.Init(t)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,7 +38,7 @@ func TestListGood(t *testing.T) {
 | 
				
			||||||
	test.Close()
 | 
						test.Close()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Function to getGoodAvailability() and getGoodAvailabilityCount()
 | 
					// Function to test getGoodAvailability() and getGoodAvailabilityCount()
 | 
				
			||||||
func TestGetGoodAvailable(t *testing.T) {
 | 
					func TestGetGoodAvailable(t *testing.T) {
 | 
				
			||||||
	now := time.Now()
 | 
						now := time.Now()
 | 
				
			||||||
	assertion, router := test.Init(t)
 | 
						assertion, router := test.Init(t)
 | 
				
			||||||
| 
						 | 
					@ -99,7 +99,7 @@ func TestGetGoodAvailable(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Function to getGoodFreshness()
 | 
					// Function to test getGoodFreshness()
 | 
				
			||||||
func TestGetGoodFreshness(t *testing.T) {
 | 
					func TestGetGoodFreshness(t *testing.T) {
 | 
				
			||||||
	now := time.Now().Add(36 * time.Hour)
 | 
						now := time.Now().Add(36 * time.Hour)
 | 
				
			||||||
	assertion, router := test.Init(t)
 | 
						assertion, router := test.Init(t)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,19 +9,19 @@ import (
 | 
				
			||||||
	"text/template"
 | 
						"text/template"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Path to the svg image template, that shows the availablity or freshness of a given good
 | 
					// Path to the svg image template, that shows the availability or freshness of a given good
 | 
				
			||||||
// with a traffic light food labeling system
 | 
					// with a traffic light food labeling system
 | 
				
			||||||
var GoodAvailabilityTemplate string
 | 
					var GoodAvailabilityTemplate string
 | 
				
			||||||
var GoodFreshnessTemplate string
 | 
					var GoodFreshnessTemplate string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Function to calculate a percent value from a given value and an maximum value
 | 
					// Function to calculate a percent value from a given value and a maximum value
 | 
				
			||||||
func tempPercent(value, max int) int {
 | 
					func tempPercent(value, max int) int {
 | 
				
			||||||
	return value * 100 / max
 | 
						return value * 100 / max
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Function to calculate a partial radius, depending on a percentage value
 | 
					// Function to calculate a partial radius, depending on a percentage value
 | 
				
			||||||
func tempProcessRadius(value, max, radius int) float64 {
 | 
					func tempProcessRadius(value, max, radius int) float64 {
 | 
				
			||||||
	return (1 - float64(value)/float64(max)) * float64(radius) * 2 * 3.14
 | 
						return (1 - float64(value) / float64(max)) * float64(radius) * 2 * 3.14
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Function to get the SVG, that shows the availability with a traffic light food labeling system for a given good
 | 
					// Function to get the SVG, that shows the availability with a traffic light food labeling system for a given good
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,14 +73,14 @@ func TestAddGood(t *testing.T) {
 | 
				
			||||||
	runtime.HasPermission("testsessionkey", runtime.PermissionCreateGood)
 | 
						runtime.HasPermission("testsessionkey", runtime.PermissionCreateGood)
 | 
				
			||||||
	runtime.CleanCache()
 | 
						runtime.CleanCache()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test gatewaytimeout on product exists
 | 
						// Test the gatewaytimeout on product exists
 | 
				
			||||||
	_, w = session.JSONRequest("POST", "/api/good/1", good)
 | 
						_, w = session.JSONRequest("POST", "/api/good/1", good)
 | 
				
			||||||
	assertion.Equal(http.StatusGatewayTimeout, w.StatusCode)
 | 
						assertion.Equal(http.StatusGatewayTimeout, w.StatusCode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	time.Sleep(time.Duration(10) * time.Millisecond)
 | 
						time.Sleep(time.Duration(10) * time.Millisecond)
 | 
				
			||||||
	runtime.CleanCache()
 | 
						runtime.CleanCache()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Test gatewaytimeout on permission exists
 | 
						// Test the gatewaytimeout on permission exists
 | 
				
			||||||
	_, w = session.JSONRequest("POST", "/api/good/1", good)
 | 
						_, w = session.JSONRequest("POST", "/api/good/1", good)
 | 
				
			||||||
	assertion.Equal(http.StatusGatewayTimeout, w.StatusCode)
 | 
						assertion.Equal(http.StatusGatewayTimeout, w.StatusCode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,14 +23,14 @@ var (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Configuration of the database connection
 | 
					// Configuration of the database connection
 | 
				
			||||||
type Config struct {
 | 
					type Config struct {
 | 
				
			||||||
	// type of the database, currently supports sqlite and postgres
 | 
						// Type of the database (currently supports sqlite and postgres)
 | 
				
			||||||
	Type string
 | 
						Type           string
 | 
				
			||||||
	// connection configuration
 | 
						// Connection configuration
 | 
				
			||||||
	Connection string
 | 
						Connection     string
 | 
				
			||||||
	// create another connection for reading only
 | 
						// Create another connection for reading only
 | 
				
			||||||
	ReadConnection string
 | 
						ReadConnection string
 | 
				
			||||||
	// enable logging of the generated sql string
 | 
						// Enable logging of the generated sql string
 | 
				
			||||||
	Logging bool
 | 
						Logging        bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Function to open a database and set the given configuration
 | 
					// Function to open a database and set the given configuration
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,7 @@ func Read(r *http.Request, to interface{}) (err error) {
 | 
				
			||||||
func Write(w http.ResponseWriter, data interface{}) {
 | 
					func Write(w http.ResponseWriter, data interface{}) {
 | 
				
			||||||
	js, err := json.Marshal(data)
 | 
						js, err := json.Marshal(data)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		http.Error(w, "failed to encode response: "+err.Error(), http.StatusInternalServerError)
 | 
							http.Error(w, "failed to encode response: " + err.Error(), http.StatusInternalServerError)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	w.Header().Set("Content-Type", "application/json")
 | 
						w.Header().Set("Content-Type", "application/json")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
// Package with a lib for cronjobs to run in background
 | 
					// Package with a lib for cronjobs to run in the background
 | 
				
			||||||
package worker
 | 
					package worker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "time"
 | 
					import "time"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
// Package with a lib for cronjobs to run in background
 | 
					// Package with a lib for cronjobs to run in the background
 | 
				
			||||||
package worker
 | 
					package worker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@ func TestWorker(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	runtime := 0
 | 
						runtime := 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	w := NewWorker(time.Duration(5)*time.Millisecond, func() {
 | 
						w := NewWorker(time.Duration(5) * time.Millisecond, func() {
 | 
				
			||||||
		runtime = runtime + 1
 | 
							runtime = runtime + 1
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	go w.Start()
 | 
						go w.Start()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,27 +13,27 @@ import (
 | 
				
			||||||
// Config file for this daemon (more information at the config_example.conf in this git repository)
 | 
					// Config file for this daemon (more information at the config_example.conf in this git repository)
 | 
				
			||||||
type Config struct {
 | 
					type Config struct {
 | 
				
			||||||
	// address under which the api and static content of the webserver runs
 | 
						// address under which the api and static content of the webserver runs
 | 
				
			||||||
	WebserverBind string `toml:"webserver_bind"`
 | 
						WebserverBind            string `toml:"webserver_bind"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// path to deliver static content
 | 
						// path to deliver static content
 | 
				
			||||||
	Webroot string `toml:"webroot"`
 | 
						Webroot                  string `toml:"webroot"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Database    database.Config   `toml:"database"`
 | 
						Database                 database.Config   `toml:"database"`
 | 
				
			||||||
	GoodRelease GoodReleaseConfig `toml:"good_release"`
 | 
						GoodRelease              GoodReleaseConfig `toml:"good_release"`
 | 
				
			||||||
	CacheClean  CacheWorkerConfig `toml:"cache_clean"`
 | 
						CacheClean               CacheWorkerConfig `toml:"cache_clean"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// path to the svg image templates to show the availablity and freshness
 | 
						// path to the SVG image templates to show the availability and freshness
 | 
				
			||||||
	// of a given good with a traffic light food labeling system
 | 
						// of a given good with a traffic light food labeling system
 | 
				
			||||||
	GoodAvailabilityTemplate string `toml:"good_availablity_template"`
 | 
						GoodAvailabilityTemplate string `toml:"good_availablity_template"`
 | 
				
			||||||
	GoodFreshnessTemplate    string `toml:"good_freshness_template"`
 | 
						GoodFreshnessTemplate    string `toml:"good_freshness_template"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	FouledDeleter Duration `toml:"fouled_deleted"`
 | 
						FouledDeleter            Duration `toml:"fouled_deleted"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// URLs to other microservices that this services uses
 | 
						// URLs to other microservices, which this service uses
 | 
				
			||||||
	MicroserviceDependencies struct {
 | 
						MicroserviceDependencies struct {
 | 
				
			||||||
		Product    string `toml:"product"`
 | 
										 Product    string `toml:"product"`
 | 
				
			||||||
		Permission string `toml:"permission"`
 | 
										 Permission string `toml:"permission"`
 | 
				
			||||||
	} `toml:"microservice_dependencies"`
 | 
									 } `toml:"microservice_dependencies"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Configuration of the Worker to clean the cache from values of other microservice
 | 
					// Configuration of the Worker to clean the cache from values of other microservice
 | 
				
			||||||
| 
						 | 
					@ -48,7 +48,7 @@ type CacheWorkerConfig struct {
 | 
				
			||||||
type GoodReleaseConfig struct {
 | 
					type GoodReleaseConfig struct {
 | 
				
			||||||
	// Run worker every Duration
 | 
						// Run worker every Duration
 | 
				
			||||||
	Every Duration `toml:"every"`
 | 
						Every Duration `toml:"every"`
 | 
				
			||||||
	// Unlock those which are not used since Duration
 | 
						// Unlock those, which are not used since Duration
 | 
				
			||||||
	After Duration `toml:"after"`
 | 
						After Duration `toml:"after"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@ import (
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Duration is a TOML datatype
 | 
					// Duration is a TOML datatype
 | 
				
			||||||
// A duration string is a possibly signed sequence of decimal numbers  and a unit suffix,
 | 
					// A duration string is a possibly signed sequence of decimal numbers and a unit suffix,
 | 
				
			||||||
// such as "300s", "1.5h" or "5d". Valid time units are "s", "m", "h", "d", "w".
 | 
					// such as "300s", "1.5h" or "5d". Valid time units are "s", "m", "h", "d", "w".
 | 
				
			||||||
type Duration struct {
 | 
					type Duration struct {
 | 
				
			||||||
	time.Duration
 | 
						time.Duration
 | 
				
			||||||
| 
						 | 
					@ -28,8 +28,8 @@ func (d *Duration) UnmarshalTOML(dataInterface interface{}) error {
 | 
				
			||||||
		return fmt.Errorf("invalid duration: \"%s\"", data)
 | 
							return fmt.Errorf("invalid duration: \"%s\"", data)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unit := data[len(data)-1]
 | 
						unit := data[len(data) - 1]
 | 
				
			||||||
	value, err := strconv.Atoi(string(data[:len(data)-1]))
 | 
						value, err := strconv.Atoi(string(data[:len(data) - 1]))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("unable to parse duration %s: %s", data, err)
 | 
							return fmt.Errorf("unable to parse duration %s: %s", data, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,18 +10,18 @@ import (
 | 
				
			||||||
	"github.com/genofire/hs_master-kss-monolith/lib/database"
 | 
						"github.com/genofire/hs_master-kss-monolith/lib/database"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Goods managed in this stock microservice
 | 
					// Type of goods managed in this stock microservice
 | 
				
			||||||
type Good struct {
 | 
					type Good struct {
 | 
				
			||||||
	ID        int64      `json:"id"`
 | 
						ID             int64      `json:"id"`
 | 
				
			||||||
	ProductID int64      `json:"product_id"`
 | 
						ProductID      int64      `json:"product_id"`
 | 
				
			||||||
	Position  string     `json:"position"`
 | 
						Position       string     `json:"position"`
 | 
				
			||||||
	Comment   string     `json:"comment"`
 | 
						Comment        string     `json:"comment"`
 | 
				
			||||||
	FouledAt  *time.Time `json:"fouled_at"`
 | 
						FouledAt       *time.Time `json:"fouled_at"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RecievedAt *time.Time `sql:"default:current_timestamp" json:"recieved_at"`
 | 
						RecievedAt     *time.Time `sql:"default:current_timestamp" json:"recieved_at"`
 | 
				
			||||||
	// Make it temporary unusable
 | 
						// Make it temporary unusable
 | 
				
			||||||
	LockedAt     *time.Time `json:"-"`
 | 
						LockedAt       *time.Time `json:"-"`
 | 
				
			||||||
	LockedSecret string     `json:"-"`
 | 
						LockedSecret   string     `json:"-"`
 | 
				
			||||||
	// Make it unusable
 | 
						// Make it unusable
 | 
				
			||||||
	DeletedAt      *time.Time `json:"-"`
 | 
						DeletedAt      *time.Time `json:"-"`
 | 
				
			||||||
	ManuelleDelete bool       `json:"-"`
 | 
						ManuelleDelete bool       `json:"-"`
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +0,0 @@
 | 
				
			||||||
// Package with the mostly static content (models) of this microservice
 | 
					 | 
				
			||||||
package models
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Store all the structs
 | 
					 | 
				
			||||||
| 
						 | 
					@ -16,108 +16,109 @@ import de.mstock.monolith.web.ReviewDTO;
 | 
				
			||||||
public class DataTransferObjectFactory {
 | 
					public class DataTransferObjectFactory {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					    /**
 | 
				
			||||||
   * Creates a Data Transfer Object (DTO).
 | 
					     * Creates a Data Transfer Object (DTO).
 | 
				
			||||||
   * 
 | 
					     *
 | 
				
			||||||
   * @param category database entity
 | 
					     * @param category database entity
 | 
				
			||||||
   * @param locale the requested locale
 | 
					     * @param locale   the requested locale
 | 
				
			||||||
   * @return DTO
 | 
					     * @return DTO
 | 
				
			||||||
   */
 | 
					     */
 | 
				
			||||||
  public CategoryDTO createCategoryDTO(Category category, Locale locale) {
 | 
					    public CategoryDTO createCategoryDTO(Category category, Locale locale) {
 | 
				
			||||||
    CategoryI18n i18n = category.getI18n().get(locale.getLanguage());
 | 
					        CategoryI18n i18n = category.getI18n().get(locale.getLanguage());
 | 
				
			||||||
    CategoryDTO categoryDTO = new CategoryDTO();
 | 
					        CategoryDTO categoryDTO = new CategoryDTO();
 | 
				
			||||||
    categoryDTO.setName(i18n.getName());
 | 
					        categoryDTO.setName(i18n.getName());
 | 
				
			||||||
    categoryDTO.setPrettyUrlFragment(i18n.getPrettyUrlFragment());
 | 
					        categoryDTO.setPrettyUrlFragment(i18n.getPrettyUrlFragment());
 | 
				
			||||||
    return categoryDTO;
 | 
					        return categoryDTO;
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * Creates a Data Transfer Object (DTO).
 | 
					 | 
				
			||||||
   * 
 | 
					 | 
				
			||||||
   * @param product database entity
 | 
					 | 
				
			||||||
   * @param locale the requested locale
 | 
					 | 
				
			||||||
   * @return DTO
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  public ProductDTO createProductDTO(Product product, Locale locale) {
 | 
					 | 
				
			||||||
    return createProductDTO(product, locale, NumberFormat.getCurrencyInstance(locale));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private ProductDTO createProductDTO(Product product, Locale locale, NumberFormat numberFormat) {
 | 
					 | 
				
			||||||
    ProductDTO productDTO = createProductWithoutReviewsDTO(product, locale, numberFormat);
 | 
					 | 
				
			||||||
    ProductI18n i18n = product.getI18n().get(locale.getLanguage());
 | 
					 | 
				
			||||||
    productDTO.setReviews(createReviewDTOs(i18n.getReviews()));
 | 
					 | 
				
			||||||
    return productDTO;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /**
 | 
					 | 
				
			||||||
   * Creates Data Transfer Objects (DTOs).
 | 
					 | 
				
			||||||
   * 
 | 
					 | 
				
			||||||
   * @param products database entities
 | 
					 | 
				
			||||||
   * @param locale the requested locale
 | 
					 | 
				
			||||||
   * @return DTOs
 | 
					 | 
				
			||||||
   */
 | 
					 | 
				
			||||||
  public List<ProductDTO> createProductDTOs(List<Product> products, Locale locale) {
 | 
					 | 
				
			||||||
    List<ProductDTO> productDTOs = new ArrayList<>(products.size());
 | 
					 | 
				
			||||||
    NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
 | 
					 | 
				
			||||||
    for (Product product : products) {
 | 
					 | 
				
			||||||
      productDTOs.add(createProductDTO(product, locale, numberFormat));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return productDTOs;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					    /**
 | 
				
			||||||
   * Creates Data Transfer Objects (DTOs) without loading their reviews.
 | 
					     * Creates a Data Transfer Object (DTO).
 | 
				
			||||||
   * 
 | 
					     *
 | 
				
			||||||
   * @param products database entities
 | 
					     * @param product database entity
 | 
				
			||||||
   * @param locale the requested locale
 | 
					     * @param locale  the requested locale
 | 
				
			||||||
   * @return DTOs
 | 
					     * @return DTO
 | 
				
			||||||
   */
 | 
					     */
 | 
				
			||||||
  public List<ProductDTO> createProductWithoutReviewsDTOs(List<Product> products, Locale locale) {
 | 
					    public ProductDTO createProductDTO(Product product, Locale locale) {
 | 
				
			||||||
    List<ProductDTO> productDTOs = new ArrayList<>(products.size());
 | 
					        return createProductDTO(product, locale, NumberFormat.getCurrencyInstance(locale));
 | 
				
			||||||
    NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
 | 
					 | 
				
			||||||
    for (Product product : products) {
 | 
					 | 
				
			||||||
      productDTOs.add(createProductWithoutReviewsDTO(product, locale, numberFormat));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return productDTOs;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private ProductDTO createProductWithoutReviewsDTO(Product product, Locale locale,
 | 
					    private ProductDTO createProductDTO(Product product, Locale locale, NumberFormat numberFormat) {
 | 
				
			||||||
      NumberFormat numberFormat) {
 | 
					        ProductDTO productDTO = createProductWithoutReviewsDTO(product, locale, numberFormat);
 | 
				
			||||||
    ProductI18n i18n = product.getI18n().get(locale.getLanguage());
 | 
					        ProductI18n i18n = product.getI18n().get(locale.getLanguage());
 | 
				
			||||||
    String price = numberFormat.format(i18n.getPrice());
 | 
					        productDTO.setReviews(createReviewDTOs(i18n.getReviews()));
 | 
				
			||||||
    ProductDTO productDTO = new ProductDTO();
 | 
					        return productDTO;
 | 
				
			||||||
    productDTO.setId(product.getId());
 | 
					    }
 | 
				
			||||||
    productDTO.setItemNumber(product.getItemNumber());
 | 
					
 | 
				
			||||||
    productDTO.setUnit(product.getUnit());
 | 
					    /**
 | 
				
			||||||
    productDTO.setName(i18n.getName());
 | 
					     * Creates Data Transfer Objects (DTOs).
 | 
				
			||||||
    productDTO.setPrettyUrlFragment(i18n.getPrettyUrlFragment());
 | 
					     *
 | 
				
			||||||
    productDTO.setPrice(price);
 | 
					     * @param products database entities
 | 
				
			||||||
    productDTO.setDescription(i18n.getDescription());
 | 
					     * @param locale   the requested locale
 | 
				
			||||||
    return productDTO;
 | 
					     * @return DTOs
 | 
				
			||||||
  }
 | 
					     */
 | 
				
			||||||
 | 
					    public List<ProductDTO> createProductDTOs(List<Product> products, Locale locale) {
 | 
				
			||||||
  /**
 | 
					        List<ProductDTO> productDTOs = new ArrayList<>(products.size());
 | 
				
			||||||
   * Creates a Data Transfer Object (DTO).
 | 
					        NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
 | 
				
			||||||
   * 
 | 
					        for (Product product : products) {
 | 
				
			||||||
   * @param review database entity
 | 
					            productDTOs.add(createProductDTO(product, locale, numberFormat));
 | 
				
			||||||
   * @return DTO
 | 
					        }
 | 
				
			||||||
   */
 | 
					        return productDTOs;
 | 
				
			||||||
  public ReviewDTO createReviewDTO(Review review) {
 | 
					    }
 | 
				
			||||||
    ReviewDTO dto = new ReviewDTO();
 | 
					
 | 
				
			||||||
    dto.setLanguage(review.getLocaleLanguage());
 | 
					    /**
 | 
				
			||||||
    dto.setRatingStars(review.getRatingStars());
 | 
					     * Creates Data Transfer Objects (DTOs) without loading their reviews.
 | 
				
			||||||
    dto.setFirstName(review.getFirstName());
 | 
					     *
 | 
				
			||||||
    dto.setLastName(review.getLastName());
 | 
					     * @param products database entities
 | 
				
			||||||
    dto.setText(review.getText());
 | 
					     * @param locale   the requested locale
 | 
				
			||||||
    return dto;
 | 
					     * @return DTOs
 | 
				
			||||||
  }
 | 
					     */
 | 
				
			||||||
 | 
					    public List<ProductDTO> createProductWithoutReviewsDTOs(List<Product> products, Locale locale) {
 | 
				
			||||||
  private List<ReviewDTO> createReviewDTOs(List<Review> reviews) {
 | 
					        List<ProductDTO> productDTOs = new ArrayList<>(products.size());
 | 
				
			||||||
    List<ReviewDTO> ratingDTOs = new ArrayList<>(reviews.size());
 | 
					        NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
 | 
				
			||||||
    for (Review review : reviews) {
 | 
					        for (Product product : products) {
 | 
				
			||||||
      ratingDTOs.add(createReviewDTO(review));
 | 
					            productDTOs.add(createProductWithoutReviewsDTO(product, locale, numberFormat));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return productDTOs;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private ProductDTO createProductWithoutReviewsDTO(Product product, Locale locale,
 | 
				
			||||||
 | 
					                                                      NumberFormat numberFormat) {
 | 
				
			||||||
 | 
					        ProductI18n i18n = product.getI18n().get(locale.getLanguage());
 | 
				
			||||||
 | 
					        String price = numberFormat.format(i18n.getPrice());
 | 
				
			||||||
 | 
					        ProductDTO productDTO = new ProductDTO();
 | 
				
			||||||
 | 
					        // Addition: productDTO.setID()
 | 
				
			||||||
 | 
					        productDTO.setId(product.getId());
 | 
				
			||||||
 | 
					        productDTO.setItemNumber(product.getItemNumber());
 | 
				
			||||||
 | 
					        productDTO.setUnit(product.getUnit());
 | 
				
			||||||
 | 
					        productDTO.setName(i18n.getName());
 | 
				
			||||||
 | 
					        productDTO.setPrettyUrlFragment(i18n.getPrettyUrlFragment());
 | 
				
			||||||
 | 
					        productDTO.setPrice(price);
 | 
				
			||||||
 | 
					        productDTO.setDescription(i18n.getDescription());
 | 
				
			||||||
 | 
					        return productDTO;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Creates a Data Transfer Object (DTO).
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param review database entity
 | 
				
			||||||
 | 
					     * @return DTO
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public ReviewDTO createReviewDTO(Review review) {
 | 
				
			||||||
 | 
					        ReviewDTO dto = new ReviewDTO();
 | 
				
			||||||
 | 
					        dto.setLanguage(review.getLocaleLanguage());
 | 
				
			||||||
 | 
					        dto.setRatingStars(review.getRatingStars());
 | 
				
			||||||
 | 
					        dto.setFirstName(review.getFirstName());
 | 
				
			||||||
 | 
					        dto.setLastName(review.getLastName());
 | 
				
			||||||
 | 
					        dto.setText(review.getText());
 | 
				
			||||||
 | 
					        return dto;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private List<ReviewDTO> createReviewDTOs(List<Review> reviews) {
 | 
				
			||||||
 | 
					        List<ReviewDTO> ratingDTOs = new ArrayList<>(reviews.size());
 | 
				
			||||||
 | 
					        for (Review review : reviews) {
 | 
				
			||||||
 | 
					            ratingDTOs.add(createReviewDTO(review));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return Collections.unmodifiableList(ratingDTOs);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return Collections.unmodifiableList(ratingDTOs);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,16 +17,18 @@ public class HomepageController {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Autowired
 | 
					    @Autowired
 | 
				
			||||||
    private ShopService shopService;
 | 
					    private ShopService shopService;
 | 
				
			||||||
 | 
					    // Addition: contant with the address of the stock microservice adminfrontend
 | 
				
			||||||
    private final String STOCKADMINFRONTENDTEMPLATE = "https://stock.pub.warehost.de/index.html";
 | 
					    private final String STOCKADMINFRONTENDTEMPLATE = "https://stock.pub.warehost.de/index.html";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Redirect
 | 
					     * Redirect to stock admin frontend
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param model  Template model
 | 
					     * @param model Template model
 | 
				
			||||||
     * @return The constant template name for the stock admin frontend.
 | 
					     * @return The constant template name for the stock admin frontend.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    @RequestMapping(value = "/stockadmin", method = RequestMethod.GET)
 | 
					    @RequestMapping(value = "/stockadmin", method = RequestMethod.GET)
 | 
				
			||||||
    public String redirect(Model model) {return "redirect:"+ this.STOCKADMINFRONTENDTEMPLATE;
 | 
					    public String redirect(Model model) {
 | 
				
			||||||
 | 
					        return "redirect:" + this.STOCKADMINFRONTENDTEMPLATE;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,7 @@ public class ProductDTO {
 | 
				
			||||||
  private String description;
 | 
					  private String description;
 | 
				
			||||||
  private List<ReviewDTO> reviews;
 | 
					  private List<ReviewDTO> reviews;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Addition: int id, getId() and setID()
 | 
				
			||||||
  public int getId() {
 | 
					  public int getId() {
 | 
				
			||||||
    return id;
 | 
					    return id;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,10 @@
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="col-md-8">
 | 
					      <div class="col-md-8">
 | 
				
			||||||
        <h2 th:text="${product.name}">Product Name</h2>
 | 
					        <h2 th:text="${product.name}">Product Name</h2>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- Addition: traffic light food labeling system of the stock microservice -->
 | 
				
			||||||
        <img width="10%" class="icon" th:src="${'https://stock.pub.warehost.de/api/good/availablity/'+product.id}"/>
 | 
					        <img width="10%" class="icon" th:src="${'https://stock.pub.warehost.de/api/good/availablity/'+product.id}"/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <p class="text-info text-uppercase" th:text="${product.price}">0,00 Euro</p>
 | 
					        <p class="text-info text-uppercase" th:text="${product.price}">0,00 Euro</p>
 | 
				
			||||||
        <p class="lead" th:text="${product.description}">Description.</p>
 | 
					        <p class="lead" th:text="${product.description}">Description.</p>
 | 
				
			||||||
        <div th:replace="fragments/reviews :: reviews"></div>
 | 
					        <div th:replace="fragments/reviews :: reviews"></div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,32 +0,0 @@
 | 
				
			||||||
<!DOCTYPE html>
 | 
					 | 
				
			||||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
 | 
					 | 
				
			||||||
<head th:replace="fragments/skeleton :: head">
 | 
					 | 
				
			||||||
    <meta charset="utf-8" />
 | 
					 | 
				
			||||||
    <meta http-equiv="refresh" content="5; URL=http://localhost:65000/"/>
 | 
					 | 
				
			||||||
    <meta name="viewport" content="width=device-width, initial-scale=1" />
 | 
					 | 
				
			||||||
    <link href="../static/css/bootstrap.min.css" rel="stylesheet" />
 | 
					 | 
				
			||||||
    <link href="../static/css/mosh.css" rel="stylesheet" />
 | 
					 | 
				
			||||||
</head>
 | 
					 | 
				
			||||||
<body>
 | 
					 | 
				
			||||||
<div th:replace="fragments/skeleton :: navigation">
 | 
					 | 
				
			||||||
    <div class="container">
 | 
					 | 
				
			||||||
        <nav>Navigation</nav>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
<div class="container product">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <div class="row info">
 | 
					 | 
				
			||||||
        <p align="center"><a href="http://localhost:65000/">If the automatic redirection to the stock management admin
 | 
					 | 
				
			||||||
            front end does not work, click here.</a></p>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
    <footer th:replace="fragments/skeleton :: footer">
 | 
					 | 
				
			||||||
        <p>© 2017</p>
 | 
					 | 
				
			||||||
    </footer>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
<script src="../static/js/jquery-3.1.1.min.js"
 | 
					 | 
				
			||||||
        th:src="@{/js/jquery-3.1.1.min.js}"></script>
 | 
					 | 
				
			||||||
<!-- Include all compiled plugins (below), or include individual files as needed -->
 | 
					 | 
				
			||||||
<script src="../static/js/bootstrap.min.js"
 | 
					 | 
				
			||||||
        th:src="@{/js/bootstrap.min.js}"></script>
 | 
					 | 
				
			||||||
</body>
 | 
					 | 
				
			||||||
</html>
 | 
					 | 
				
			||||||
| 
						 | 
					@ -10,20 +10,20 @@ import (
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// URL to the microservice which manages permissions
 | 
					// URL to the microservice, which manages permissions
 | 
				
			||||||
var PermissionURL string
 | 
					var PermissionURL string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Type of permission
 | 
					// Type of permission
 | 
				
			||||||
type Permission int
 | 
					type Permission int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Some permissions (the real permissions need to come from the permission microservice)
 | 
					// Some permissions (the real permissions need to come from a permission microservice)
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	// permission to add goods to the stock
 | 
						// permission to add goods to the stock
 | 
				
			||||||
	// e.g. if a good is received and now available to sell
 | 
						// e.g. if a good is received and now available for selling
 | 
				
			||||||
	PermissionCreateGood = 1
 | 
						PermissionCreateGood = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// permission to delete goods from the stock
 | 
						// permission to delete goods from the stock
 | 
				
			||||||
	// e.g. if a good becomes fouled and has to be removed
 | 
						// e.g. if a good becomes fouled and has to be removed manually
 | 
				
			||||||
	PermissionDeleteGood = 2
 | 
						PermissionDeleteGood = 2
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@ import (
 | 
				
			||||||
	"github.com/genofire/hs_master-kss-monolith/models"
 | 
						"github.com/genofire/hs_master-kss-monolith/models"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Function to test the cache Worker
 | 
					// Function to test the cacheWorker
 | 
				
			||||||
func TestCacheWorker(t *testing.T) {
 | 
					func TestCacheWorker(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	productExistCache[2] = boolMicroServiceCache{LastCheck: time.Now(), Value: true}
 | 
						productExistCache[2] = boolMicroServiceCache{LastCheck: time.Now(), Value: true}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@ import (
 | 
				
			||||||
	"github.com/genofire/hs_master-kss-monolith/models"
 | 
						"github.com/genofire/hs_master-kss-monolith/models"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Function to remove automaticle goods after the are fouled
 | 
					// Function to automatically remove goods, if they are fouled
 | 
				
			||||||
func GoodFouled() int {
 | 
					func GoodFouled() int {
 | 
				
			||||||
	var goods []*models.Good
 | 
						var goods []*models.Good
 | 
				
			||||||
	var g models.Good
 | 
						var g models.Good
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@ import (
 | 
				
			||||||
	"github.com/genofire/hs_master-kss-monolith/models"
 | 
						"github.com/genofire/hs_master-kss-monolith/models"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Function to test the unlocking of goods
 | 
					// Function to test fouledDelete()
 | 
				
			||||||
func TestFouledDelete(t *testing.T) {
 | 
					func TestFouledDelete(t *testing.T) {
 | 
				
			||||||
	assert := assert.New(t)
 | 
						assert := assert.New(t)
 | 
				
			||||||
	database.Open(database.Config{
 | 
						database.Open(database.Config{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@ import (
 | 
				
			||||||
	"github.com/genofire/hs_master-kss-monolith/models"
 | 
						"github.com/genofire/hs_master-kss-monolith/models"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Function to test the unlocking of goods
 | 
					// Function to test goodRelease()
 | 
				
			||||||
func TestGoodRelease(t *testing.T) {
 | 
					func TestGoodRelease(t *testing.T) {
 | 
				
			||||||
	assert := assert.New(t)
 | 
						assert := assert.New(t)
 | 
				
			||||||
	database.Open(database.Config{
 | 
						database.Open(database.Config{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,7 @@ import (
 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Function to test, if and which products exist (get information from the products catalogue)
 | 
					// Function to test, if and which products exist (get information from the product catalogue)
 | 
				
			||||||
func TestProductExists(t *testing.T) {
 | 
					func TestProductExists(t *testing.T) {
 | 
				
			||||||
	assert := assert.New(t)
 | 
						assert := assert.New(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +0,0 @@
 | 
				
			||||||
// Package with supporting functionality to run the microservice
 | 
					 | 
				
			||||||
package runtime
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// some mingled functionality to handle in background
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@ type MockTransport struct {
 | 
				
			||||||
	running bool
 | 
						running bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function to use the http handler
 | 
				
			||||||
func (t *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
					func (t *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
	if !t.running {
 | 
						if !t.running {
 | 
				
			||||||
		return nil, errors.New("mock a error")
 | 
							return nil, errors.New("mock a error")
 | 
				
			||||||
| 
						 | 
					@ -33,9 +34,13 @@ func (t *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
	t.Handler.ServeHTTP(w, req)
 | 
						t.Handler.ServeHTTP(w, req)
 | 
				
			||||||
	return w.Result(), nil
 | 
						return w.Result(), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function to start the http handler
 | 
				
			||||||
func (t *MockTransport) Start() {
 | 
					func (t *MockTransport) Start() {
 | 
				
			||||||
	t.running = true
 | 
						t.running = true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Function to close/stop the http handler
 | 
				
			||||||
func (t *MockTransport) Close() {
 | 
					func (t *MockTransport) Close() {
 | 
				
			||||||
	t.running = false
 | 
						t.running = false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -73,7 +78,7 @@ func Close() {
 | 
				
			||||||
	mock.Close()
 | 
						mock.Close()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Handle a test session with cookies
 | 
					// Struct to dandle a test session with cookies
 | 
				
			||||||
type Request struct {
 | 
					type Request struct {
 | 
				
			||||||
	req     *http.Request
 | 
						req     *http.Request
 | 
				
			||||||
	cookies []*http.Cookie
 | 
						cookies []*http.Cookie
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "id": 1,
 | 
					"id": 1,
 | 
				
			||||||
  "title": "Kiwi"
 | 
					"title": "Kiwi"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "id": 2,
 | 
					"id": 2,
 | 
				
			||||||
  "title": "Blueberries"
 | 
					"title": "Blueberries"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "id": 3,
 | 
					"id": 3,
 | 
				
			||||||
  "title": "Cherries"
 | 
					"title": "Cherries"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "id": 4,
 | 
					"id": 4,
 | 
				
			||||||
  "title": "Potatoes"
 | 
					"title": "Potatoes"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "id": 5,
 | 
					"id": 5,
 | 
				
			||||||
  "title": "Tomatoes"
 | 
					"title": "Tomatoes"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "id": 6,
 | 
					"id": 6,
 | 
				
			||||||
  "title": "Rhubarb"
 | 
					"title": "Rhubarb"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,8 @@
 | 
				
			||||||
[
 | 
					[
 | 
				
			||||||
  {"id":1, "title": "Kiwi"},
 | 
					{"id":1, "title": "Kiwi"},
 | 
				
			||||||
  {"id":2, "title": "Blueberries"},
 | 
					{"id":2, "title": "Blueberries"},
 | 
				
			||||||
  {"id":3, "title": "Cherries"},
 | 
					{"id":3, "title": "Cherries"},
 | 
				
			||||||
  {"id":4, "title": "Potatoes"},
 | 
					{"id":4, "title": "Potatoes"},
 | 
				
			||||||
  {"id":5, "title": "Tomatoes"},
 | 
					{"id":5, "title": "Tomatoes"},
 | 
				
			||||||
  {"id":6, "title": "Rhubarb"}
 | 
					{"id":6, "title": "Rhubarb"}
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,79 +1,81 @@
 | 
				
			||||||
<!DOCTYPE html>
 | 
					<!DOCTYPE html>
 | 
				
			||||||
<html lang="en">
 | 
					<html lang="en">
 | 
				
			||||||
<head>
 | 
					<head>
 | 
				
			||||||
	<meta charset="utf-8" />
 | 
					    <meta charset="utf-8"/>
 | 
				
			||||||
	<meta http-equiv="X-UA-Compatible" content="IE=edge" />
 | 
					    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 | 
				
			||||||
	<meta name="viewport" content="width=device-width, initial-scale=1" />
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1"/>
 | 
				
			||||||
	<link href="/node_modules/semantic-ui-css/semantic.min.css" rel="stylesheet" />
 | 
					    <link href="/node_modules/semantic-ui-css/semantic.min.css" rel="stylesheet"/>
 | 
				
			||||||
	<link href="/static/css/main.css" rel="stylesheet" />
 | 
					    <link href="/static/css/main.css" rel="stylesheet"/>
 | 
				
			||||||
	<title>microStock Dummy Cart</title>
 | 
					    <title>microStock Dummy Cart</title>
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body ng-app="microStockDummieCare" ng-controller="MainCtrl">
 | 
					<body ng-app="microStockDummieCare" ng-controller="MainCtrl">
 | 
				
			||||||
	<nav class="ui stackable inverted menu">
 | 
					<nav class="ui stackable inverted menu">
 | 
				
			||||||
		<div class="ui container">
 | 
					    <div class="ui container">
 | 
				
			||||||
			<div class="header item">Dummy Cart</div>
 | 
					        <div class="header item">Dummy Cart</div>
 | 
				
			||||||
			<div class="right menu">
 | 
					        <div class="right menu">
 | 
				
			||||||
				<a class="ui item" ng-click="reset()">
 | 
					            <a class="ui item" ng-click="reset()">
 | 
				
			||||||
					<i class="undo icon"></i>
 | 
					                <i class="undo icon"></i>
 | 
				
			||||||
					Reset
 | 
					                Reset
 | 
				
			||||||
				</a>
 | 
					            </a>
 | 
				
			||||||
			</div>
 | 
					        </div>
 | 
				
			||||||
		</div>
 | 
					 | 
				
			||||||
	</nav>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <div class="ui container">
 | 
					 | 
				
			||||||
		<form class="ui form" ng-submit="add()">
 | 
					 | 
				
			||||||
			<div class="three fields">
 | 
					 | 
				
			||||||
				<div class="field">
 | 
					 | 
				
			||||||
					<div class="ui fluid search selection dropdown">
 | 
					 | 
				
			||||||
						<input name="country" type="hidden">
 | 
					 | 
				
			||||||
						<i class="dropdown icon"></i>
 | 
					 | 
				
			||||||
						<div class="default text">Select Product</div>
 | 
					 | 
				
			||||||
						<div class="menu">
 | 
					 | 
				
			||||||
							<div class="item" ng-repeat="item in products" data-value="{{item.id}}"><img class="icon" ng-src="{{'/api/good/availablity/'+item.id| reloadSrc}}"/>{{item.title}}</div>
 | 
					 | 
				
			||||||
						</div>
 | 
					 | 
				
			||||||
					</div>
 | 
					 | 
				
			||||||
				</div>
 | 
					 | 
				
			||||||
				<div class="field">
 | 
					 | 
				
			||||||
					<input placeholder="Count" type="number" min="1" max="50"  ng-model="goods.count">
 | 
					 | 
				
			||||||
				</div>
 | 
					 | 
				
			||||||
				<div class="field">
 | 
					 | 
				
			||||||
				 	<button type="submit" class="ui button" tabindex="0">Add</button>
 | 
					 | 
				
			||||||
				</div>
 | 
					 | 
				
			||||||
			</div>
 | 
					 | 
				
			||||||
		</form>
 | 
					 | 
				
			||||||
		<table class="ui table">
 | 
					 | 
				
			||||||
			<thead>
 | 
					 | 
				
			||||||
				<tr>
 | 
					 | 
				
			||||||
					<th>Count</th>
 | 
					 | 
				
			||||||
					<th>Product</th>
 | 
					 | 
				
			||||||
					<th></th>
 | 
					 | 
				
			||||||
				</tr>
 | 
					 | 
				
			||||||
			</thead>
 | 
					 | 
				
			||||||
			<tbody>
 | 
					 | 
				
			||||||
				<tr ng-repeat="item in cart">
 | 
					 | 
				
			||||||
					<td>{{item.count}}</td>
 | 
					 | 
				
			||||||
					<td>{{getProduct(item.product_id).title}}</td>
 | 
					 | 
				
			||||||
					<td>
 | 
					 | 
				
			||||||
						<div class="ui button icon" ng-click="del(item)"><i class="icon trash"></i></div>
 | 
					 | 
				
			||||||
					</td>
 | 
					 | 
				
			||||||
				</tr>
 | 
					 | 
				
			||||||
			</tbody>
 | 
					 | 
				
			||||||
		</table>
 | 
					 | 
				
			||||||
	</div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <footer class="ui vertical footer segment">
 | 
					 | 
				
			||||||
    <div class="ui center aligned container">
 | 
					 | 
				
			||||||
      <p>© 2017 MM / Go - Team</p>
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </footer>
 | 
					</nav>
 | 
				
			||||||
	<script src="/node_modules/jquery/dist/jquery.min.js"></script>
 | 
					
 | 
				
			||||||
	<script src="/node_modules/semantic-ui-css/semantic.min.js"></script>
 | 
					<div class="ui container">
 | 
				
			||||||
  <script src="/node_modules/angular/angular.min.js"></script>
 | 
					    <form class="ui form" ng-submit="add()">
 | 
				
			||||||
  <script src="/node_modules/angular-animate/angular-animate.min.js"></script>
 | 
					        <div class="three fields">
 | 
				
			||||||
  <script src="/node_modules/angular-ui-router/release/angular-ui-router.min.js"></script>
 | 
					            <div class="field">
 | 
				
			||||||
  <script src="/node_modules/angular-loading-bar/build/loading-bar.min.js"></script>
 | 
					                <div class="ui fluid search selection dropdown">
 | 
				
			||||||
	<script>
 | 
					                    <input name="country" type="hidden">
 | 
				
			||||||
 | 
					                    <i class="dropdown icon"></i>
 | 
				
			||||||
 | 
					                    <div class="default text">Select Product</div>
 | 
				
			||||||
 | 
					                    <div class="menu">
 | 
				
			||||||
 | 
					                        <div class="item" ng-repeat="item in products" data-value="{{item.id}}"><img class="icon"
 | 
				
			||||||
 | 
					                                                                                                     ng-src="{{'/api/good/availablity/'+item.id| reloadSrc}}"/>{{item.title}}
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="field">
 | 
				
			||||||
 | 
					                <input placeholder="Count" type="number" min="1" max="50" ng-model="goods.count">
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="field">
 | 
				
			||||||
 | 
					                <button type="submit" class="ui button" tabindex="0">Add</button>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </form>
 | 
				
			||||||
 | 
					    <table class="ui table">
 | 
				
			||||||
 | 
					        <thead>
 | 
				
			||||||
 | 
					        <tr>
 | 
				
			||||||
 | 
					            <th>Count</th>
 | 
				
			||||||
 | 
					            <th>Product</th>
 | 
				
			||||||
 | 
					            <th></th>
 | 
				
			||||||
 | 
					        </tr>
 | 
				
			||||||
 | 
					        </thead>
 | 
				
			||||||
 | 
					        <tbody>
 | 
				
			||||||
 | 
					        <tr ng-repeat="item in cart">
 | 
				
			||||||
 | 
					            <td>{{item.count}}</td>
 | 
				
			||||||
 | 
					            <td>{{getProduct(item.product_id).title}}</td>
 | 
				
			||||||
 | 
					            <td>
 | 
				
			||||||
 | 
					                <div class="ui button icon" ng-click="del(item)"><i class="icon trash"></i></div>
 | 
				
			||||||
 | 
					            </td>
 | 
				
			||||||
 | 
					        </tr>
 | 
				
			||||||
 | 
					        </tbody>
 | 
				
			||||||
 | 
					    </table>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<footer class="ui vertical footer segment">
 | 
				
			||||||
 | 
					    <div class="ui center aligned container">
 | 
				
			||||||
 | 
					        <p>© 2017 MM / Go - Team</p>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</footer>
 | 
				
			||||||
 | 
					<script src="/node_modules/jquery/dist/jquery.min.js"></script>
 | 
				
			||||||
 | 
					<script src="/node_modules/semantic-ui-css/semantic.min.js"></script>
 | 
				
			||||||
 | 
					<script src="/node_modules/angular/angular.min.js"></script>
 | 
				
			||||||
 | 
					<script src="/node_modules/angular-animate/angular-animate.min.js"></script>
 | 
				
			||||||
 | 
					<script src="/node_modules/angular-ui-router/release/angular-ui-router.min.js"></script>
 | 
				
			||||||
 | 
					<script src="/node_modules/angular-loading-bar/build/loading-bar.min.js"></script>
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
	var config = {
 | 
						var config = {
 | 
				
			||||||
		'microservice_dependencies': {
 | 
							'microservice_dependencies': {
 | 
				
			||||||
			'products': '/api-test/product/',
 | 
								'products': '/api-test/product/',
 | 
				
			||||||
| 
						 | 
					@ -192,6 +194,7 @@
 | 
				
			||||||
			};
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}]);
 | 
							}]);
 | 
				
			||||||
	</script>
 | 
					
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,48 +1,49 @@
 | 
				
			||||||
<!DOCTYPE html>
 | 
					<!DOCTYPE html>
 | 
				
			||||||
<html lang="en">
 | 
					<html lang="en">
 | 
				
			||||||
<head>
 | 
					<head>
 | 
				
			||||||
  <meta charset="utf-8" />
 | 
					    <meta charset="utf-8"/>
 | 
				
			||||||
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
 | 
					    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
 | 
				
			||||||
  <meta name="viewport" content="width=device-width, initial-scale=1" />
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1"/>
 | 
				
			||||||
  <link href="/node_modules/semantic-ui-css/semantic.min.css" rel="stylesheet" />
 | 
					    <link href="/node_modules/semantic-ui-css/semantic.min.css" rel="stylesheet"/>
 | 
				
			||||||
  <link href="/static/css/main.css" rel="stylesheet" />
 | 
					    <link href="/static/css/main.css" rel="stylesheet"/>
 | 
				
			||||||
  <title>Stock Admin</title>
 | 
					    <title>Stock Admin</title>
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
<body ng-app="microStock">
 | 
					<body ng-app="microStock">
 | 
				
			||||||
  <nav class="ui stackable inverted menu" ng-controller="GlobalCtrl">
 | 
					<nav class="ui stackable inverted menu" ng-controller="GlobalCtrl">
 | 
				
			||||||
    <div class="ui container">
 | 
					    <div class="ui container">
 | 
				
			||||||
      <div class="header item">Stock Admin</div>
 | 
					        <div class="header item">Stock Admin</div>
 | 
				
			||||||
      <a class="item" ui-sref="list" ui-active="active">List</a>
 | 
					        <a class="item" ui-sref="list" ui-active="active">List</a>
 | 
				
			||||||
      <a class="item" ui-sref="statistics" ui-active="active">Statistics</a><
 | 
					        <a class="item" ui-sref="statistics" ui-active="active">Statistics</a><
 | 
				
			||||||
      <div class="right menu">
 | 
					        <div class="right menu">
 | 
				
			||||||
        <a class="ui item" ng-click="login()">
 | 
					            <a class="ui item" ng-click="login()">
 | 
				
			||||||
          <i class="icon" ng-class="{'unlock':!loggedIn,'lock':loggedIn}"></i>
 | 
					                <i class="icon" ng-class="{'unlock':!loggedIn,'lock':loggedIn}"></i>
 | 
				
			||||||
        </a>
 | 
					            </a>
 | 
				
			||||||
      </div>
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </nav>
 | 
					</nav>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div class="ui container" ui-view=""></div>
 | 
					<div class="ui container" ui-view=""></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <footer class="ui vertical footer segment">
 | 
					<footer class="ui vertical footer segment">
 | 
				
			||||||
    <div class="ui center aligned container">
 | 
					    <div class="ui center aligned container">
 | 
				
			||||||
      <p>© 2017 MM / Go - Team</p>
 | 
					        <p>© 2017 MM / Go - Team</p>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </footer>
 | 
					</footer>
 | 
				
			||||||
  <script src="//cdn.jsdelivr.net/webshim/1.14.5/polyfiller.js"></script>
 | 
					<script src="//cdn.jsdelivr.net/webshim/1.14.5/polyfiller.js"></script>
 | 
				
			||||||
  <script>
 | 
					<script>
 | 
				
			||||||
    webshims.setOptions('forms-ext', {types: 'date'});
 | 
					    webshims.setOptions('forms-ext', {types: 'date'});
 | 
				
			||||||
    webshims.polyfill('forms forms-ext');
 | 
					    webshims.polyfill('forms forms-ext');
 | 
				
			||||||
  </script>
 | 
					
 | 
				
			||||||
  <script src="/node_modules/angular/angular.min.js"></script>
 | 
					</script>
 | 
				
			||||||
  <script src="/node_modules/angular-animate/angular-animate.min.js"></script>
 | 
					<script src="/node_modules/angular/angular.min.js"></script>
 | 
				
			||||||
  <script src="/node_modules/angular-ui-router/release/angular-ui-router.min.js"></script>
 | 
					<script src="/node_modules/angular-animate/angular-animate.min.js"></script>
 | 
				
			||||||
  <script src="/node_modules/angular-loading-bar/build/loading-bar.min.js"></script>
 | 
					<script src="/node_modules/angular-ui-router/release/angular-ui-router.min.js"></script>
 | 
				
			||||||
  <script src="/static/js/main.js"></script>
 | 
					<script src="/node_modules/angular-loading-bar/build/loading-bar.min.js"></script>
 | 
				
			||||||
  <script src="/static/js/item.controller.js"></script>
 | 
					<script src="/static/js/main.js"></script>
 | 
				
			||||||
  <script src="/static/js/item-add.controller.js"></script>
 | 
					<script src="/static/js/item.controller.js"></script>
 | 
				
			||||||
  <script src="/static/js/global.js"></script>
 | 
					<script src="/static/js/item-add.controller.js"></script>
 | 
				
			||||||
  <script src="/static/js/list.controller.js"></script>
 | 
					<script src="/static/js/global.js"></script>
 | 
				
			||||||
  <script src="/static/js/statistics.controller.js"></script>
 | 
					<script src="/static/js/list.controller.js"></script>
 | 
				
			||||||
 | 
					<script src="/static/js/statistics.controller.js"></script>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
		 Before Width: | Height: | Size: 434 KiB After Width: | Height: | Size: 451 KiB  | 
| 
						 | 
					@ -1,31 +1,31 @@
 | 
				
			||||||
<h1>
 | 
					<h1>
 | 
				
			||||||
  {{product.title}}
 | 
					    {{product.title}}
 | 
				
			||||||
  <a ui-sref="item({productid:product.id})">
 | 
					    <a ui-sref="item({productid:product.id})">
 | 
				
			||||||
    <i class="icon linkify"></i>
 | 
					        <i class="icon linkify"></i>
 | 
				
			||||||
  </a>
 | 
					    </a>
 | 
				
			||||||
</h1>
 | 
					</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<form class="ui form segment" ng-submit="submit()" ng-class="{'top attached':msg.type}">
 | 
					<form class="ui form segment" ng-submit="submit()" ng-class="{'top attached':msg.type}">
 | 
				
			||||||
  <div class="field">
 | 
					    <div class="field">
 | 
				
			||||||
    <label>Expiration Date</label>
 | 
					        <label>Expiration Date</label>
 | 
				
			||||||
      <input type="date" name="fouled_at" placeholder="Fouled at date (e.g. 2017-06-30)" ng-model="obj.fouled_at"
 | 
					        <input type="date" name="fouled_at" placeholder="Fouled at date (e.g. 2017-06-30)" ng-model="obj.fouled_at"
 | 
				
			||||||
             required="" pattern="((?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|
 | 
					               required="" pattern="((?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|
 | 
				
			||||||
             1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31)))?">
 | 
					             1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31)))?">
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  <div class="field">
 | 
					    <div class="field">
 | 
				
			||||||
    <label>Position</label>
 | 
					        <label>Position</label>
 | 
				
			||||||
    <input type="text" name="position" placeholder="Location in Store", ng-model="obj.position">
 | 
					        <input type="text" name="position" placeholder="Location in Store" , ng-model="obj.position">
 | 
				
			||||||
  </div>
 | 
					    </div>
 | 
				
			||||||
  <div class="field">
 | 
					    <div class="field">
 | 
				
			||||||
    <label>Comment</label>
 | 
					        <label>Comment</label>
 | 
				
			||||||
    <input type="text" name="comment" placeholder="Comment for this good", ng-model="obj.comment">
 | 
					        <input type="text" name="comment" placeholder="Comment for this good" , ng-model="obj.comment">
 | 
				
			||||||
  </div>
 | 
					    </div>
 | 
				
			||||||
  <div class="field">
 | 
					    <div class="field">
 | 
				
			||||||
    <label>Count</label>
 | 
					        <label>Count</label>
 | 
				
			||||||
    <input type="number" name="count" ng-model="count" min="1">
 | 
					        <input type="number" name="count" ng-model="count" min="1">
 | 
				
			||||||
  </div>
 | 
					    </div>
 | 
				
			||||||
  <button class="ui button" type="submit">Submit</button>
 | 
					    <button class="ui button" type="submit">Submit</button>
 | 
				
			||||||
</form>
 | 
					</form>
 | 
				
			||||||
<div class="ui bottom attached message {{msg.type}}" ng-show="msg.type">
 | 
					<div class="ui bottom attached message {{msg.type}}" ng-show="msg.type">
 | 
				
			||||||
  {{msg.text}}
 | 
					    {{msg.text}}
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,37 +1,37 @@
 | 
				
			||||||
<h1>
 | 
					<h1>
 | 
				
			||||||
  {{obj.title}}
 | 
					    {{obj.title}}
 | 
				
			||||||
  <img class="icon" src="/api/good/availablity/{{obj.id}}"/>
 | 
					    <img class="icon" src="/api/good/availablity/{{obj.id}}"/>
 | 
				
			||||||
  <a class="ui icon button mini right floated" ui-sref="item-add({productid: obj.id})"><i class="icon plus"></i></a>
 | 
					    <a class="ui icon button mini right floated" ui-sref="item-add({productid: obj.id})"><i class="icon plus"></i></a>
 | 
				
			||||||
</h1>
 | 
					</h1>
 | 
				
			||||||
<table class="ui table very basic">
 | 
					<table class="ui table very basic">
 | 
				
			||||||
  <tr>
 | 
					    <tr>
 | 
				
			||||||
    <td>Product ID</td>
 | 
					        <td>Product ID</td>
 | 
				
			||||||
    <td>{{obj.id}}</td>
 | 
					        <td>{{obj.id}}</td>
 | 
				
			||||||
  </tr>
 | 
					    </tr>
 | 
				
			||||||
  <tr>
 | 
					    <tr>
 | 
				
			||||||
    <td>Count</td>
 | 
					        <td>Count</td>
 | 
				
			||||||
    <td>{{list.length}}</td>
 | 
					        <td>{{list.length}}</td>
 | 
				
			||||||
  </tr>
 | 
					    </tr>
 | 
				
			||||||
</table>
 | 
					</table>
 | 
				
			||||||
<h2>Goods of this product</h2>
 | 
					<h2>Goods of this product</h2>
 | 
				
			||||||
<div class="ui warning message"  ng-if="list.length <= 0">
 | 
					<div class="ui warning message" ng-if="list.length <= 0">
 | 
				
			||||||
  <p>There are no goods for this product.</p>
 | 
					    <p>There are no goods for this product.</p>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
<table class="ui table list" ng-if="list.length > 0">
 | 
					<table class="ui table list" ng-if="list.length > 0">
 | 
				
			||||||
  <thead>
 | 
					    <thead>
 | 
				
			||||||
    <tr>
 | 
					    <tr>
 | 
				
			||||||
      <th>Status of Freshness</th>
 | 
					        <th>Status of Freshness</th>
 | 
				
			||||||
      <th>Location</th>
 | 
					        <th>Location</th>
 | 
				
			||||||
      <th>Comment</th>
 | 
					        <th>Comment</th>
 | 
				
			||||||
      <th></th>
 | 
					        <th></th>
 | 
				
			||||||
    </tr>
 | 
					    </tr>
 | 
				
			||||||
  </thead>
 | 
					    </thead>
 | 
				
			||||||
  <tbody>
 | 
					    <tbody>
 | 
				
			||||||
    <tr ng-repeat="item in list">
 | 
					    <tr ng-repeat="item in list">
 | 
				
			||||||
      <td><img class="icon" ng-src="{{'/api/good/freshness/'+item.id| reloadSrc}}"/></td>
 | 
					        <td><img class="icon" ng-src="{{'/api/good/freshness/'+item.id| reloadSrc}}"/></td>
 | 
				
			||||||
      <td>{{item.position}}</td>
 | 
					        <td>{{item.position}}</td>
 | 
				
			||||||
      <td>{{item.comment}}</td>
 | 
					        <td>{{item.comment}}</td>
 | 
				
			||||||
      <td><a class="ui icon button mini" ng-click="delete(item.id)"><i class="trash icon"></i></a></td>
 | 
					        <td><a class="ui icon button mini" ng-click="delete(item.id)"><i class="trash icon"></i></a></td>
 | 
				
			||||||
    </tr>
 | 
					    </tr>
 | 
				
			||||||
  </tbody>
 | 
					    </tbody>
 | 
				
			||||||
</table>
 | 
					</table>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,23 +1,23 @@
 | 
				
			||||||
<h1>List of Products</h1>
 | 
					<h1>List of Products</h1>
 | 
				
			||||||
<table class="ui very compact table">
 | 
					<table class="ui very compact table">
 | 
				
			||||||
  <thead>
 | 
					    <thead>
 | 
				
			||||||
    <tr>
 | 
					    <tr>
 | 
				
			||||||
      <th class="two wide">#</th>
 | 
					        <th class="two wide">#</th>
 | 
				
			||||||
      <th class="twelve wide">Productname</th>
 | 
					        <th class="twelve wide">Productname</th>
 | 
				
			||||||
      <th class="one wide">Amount</th>
 | 
					        <th class="one wide">Amount</th>
 | 
				
			||||||
      <th class="one wide"></th>
 | 
					        <th class="one wide"></th>
 | 
				
			||||||
    </tr>
 | 
					    </tr>
 | 
				
			||||||
  </thead>
 | 
					    </thead>
 | 
				
			||||||
  <tbody>
 | 
					    <tbody>
 | 
				
			||||||
    <tr ng-repeat="item in list">
 | 
					    <tr ng-repeat="item in list">
 | 
				
			||||||
      <td>{{item.id}}</td>
 | 
					        <td>{{item.id}}</td>
 | 
				
			||||||
      <td><a ui-sref="item({productid: item.id})">{{item.title}}</a></td>
 | 
					        <td><a ui-sref="item({productid: item.id})">{{item.title}}</a></td>
 | 
				
			||||||
      <td>
 | 
					        <td>
 | 
				
			||||||
          <img class="icon" ng-src="{{'/api/good/availablity/'+item.id| reloadSrc}}"/>
 | 
					            <img class="icon" ng-src="{{'/api/good/availablity/'+item.id| reloadSrc}}"/>
 | 
				
			||||||
      </td>
 | 
					        </td>
 | 
				
			||||||
      <td>
 | 
					        <td>
 | 
				
			||||||
        <a class="ui icon button" ui-sref="item-add({productid: item.id})"><i class="icon plus"></i></a>
 | 
					            <a class="ui icon button" ui-sref="item-add({productid: item.id})"><i class="icon plus"></i></a>
 | 
				
			||||||
      </td>
 | 
					        </td>
 | 
				
			||||||
    </tr>
 | 
					    </tr>
 | 
				
			||||||
  </tbody>
 | 
					    </tbody>
 | 
				
			||||||
</table>
 | 
					</table>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,21 +1,21 @@
 | 
				
			||||||
<h1>Statistics</h1>
 | 
					<h1>Statistics</h1>
 | 
				
			||||||
<div class="ui statistics two">
 | 
					<div class="ui statistics two">
 | 
				
			||||||
  <div class="statistic">
 | 
					    <div class="statistic">
 | 
				
			||||||
    <div class="value">
 | 
					        <div class="value">
 | 
				
			||||||
      <i class="cube icon"></i>
 | 
					            <i class="cube icon"></i>
 | 
				
			||||||
      {{obj.good.count}}
 | 
					            {{obj.good.count}}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="label">
 | 
				
			||||||
 | 
					            Total Count of Goods
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="label">
 | 
					    <div class="statistic">
 | 
				
			||||||
      Total Count of Goods
 | 
					        <div class="value">
 | 
				
			||||||
 | 
					            <i class="cubes icon"></i>
 | 
				
			||||||
 | 
					            {{obj.good.avg}}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="label">
 | 
				
			||||||
 | 
					            Avg Goods per Product
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
  <div class="statistic">
 | 
					 | 
				
			||||||
    <div class="value">
 | 
					 | 
				
			||||||
      <i class="cubes icon"></i>
 | 
					 | 
				
			||||||
      {{obj.good.avg}}
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
    <div class="label">
 | 
					 | 
				
			||||||
      Avg Goods per Product
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
  </div>
 | 
					 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Reference in New Issue