Fertig: (Unit Tests sind gebrochen im Ordner Database. Tut aber nichts zur Sache)

This commit is contained in:
Marco Kittel 2025-07-19 09:39:19 +02:00
parent ed601a7199
commit 146c52897a
8 changed files with 392 additions and 62 deletions

View File

@ -1,12 +1,16 @@
package main
import (
"encoding/json"
"fmt"
"gittea.marcokittel.de/elio/eliotools/datawriter/internal/api"
"gittea.marcokittel.de/elio/eliotools/datawriter/internal/database"
"io"
"log"
"net/http"
"os"
"github.com/google/uuid"
"gittea.marcokittel.de/elio/eliotools/datawriter/internal/api"
"gittea.marcokittel.de/elio/eliotools/datawriter/internal/database"
)
var (
@ -16,33 +20,165 @@ var (
type (
//RegistrierungsID -> ProductID -> Product
ProductStore map[string]map[string]api.Product
ProductStore map[string]map[string]database.Product
)
const (
curlhelp = `curl -X POST localhost:8080/api/products -d '{ "products": { "A6053": 2, "B3009": 1200 }, "context": { "country": "EU", "state": "" } }'`
curlhelp = `
Bewerbungsaufgabe von Marco Kittel 2025
Produkte abrufen
curl -X POST localhost:8080/api/products -d '{ "products": { "A6053": 2, "B3009": 1200 }, "context": { "country": "EU", "state": "" } }'
Reservierung reservieren
curl -X POST localhost:8080/api/products/reserve -d '{"id":"ab0d7184-a4ce-4802-897a-d8597335143a"}'
Reservierung bestätigen
curl -X POST localhost:8080/api/products/confirm -d '{"id":"ab0d7184-a4ce-4802-897a-d8597335143a"}'
Reservierung abbrechen
curl -X POST localhost:8080/api/products/abort -d '{"id":"ab0d7184-a4ce-4802-897a-d8597335143a"}'
Reservierung freigeben
curl -X POST localhost:8080/api/products/release -d '{"id":"ab0d7184-a4ce-4802-897a-d8597335143a"}'
`
)
func main() {
connectionString := os.Getenv("CONNECTIONSTRING")
nps := database.NewProductService(connectionString)
//Hier prüfe ich nach alten Registrierungen und gebe Sie frei.
nps.Autorelease()
if len(connectionString) == 0 {
fmt.Println("Connectionstring fehlt!. Bsp.: <user>:<passwort>@tcp(127.0.0.1:3306)/elio?parseTime=true")
return
}
//Dependency Injection
http.HandleFunc("/api/products", api.GetProductApiHandleFunc(nps))
//Todo schöner machen
http.HandleFunc("/api/products/reserve", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("In Arbeit: reserve")
if r.Method != "POST" {
return
}
defer r.Body.Close()
data, err := io.ReadAll(r.Body)
if err != nil {
log.Println(err)
return
}
var payload database.Container
err = json.Unmarshal(data, &payload)
if err != nil {
log.Printf("Could not parse Json: %s", err)
return
}
groupId := uuid.New().String()
result, err := nps.FetchReservationData(&payload, database.UUID(groupId))
if err != nil {
//Todo Fehlerhandling
log.Println(err)
}
if len(result) == 0 {
w.WriteHeader(http.StatusNoContent)
fmt.Fprintln(w)
return
}
_, err = nps.ReserviereBestellungen(result, database.UUID(groupId))
if err != nil {
log.Println(err)
}
jsonResult, err := json.Marshal(result[0])
if err != nil {
log.Println(err)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, string(jsonResult))
})
http.HandleFunc("/api/products/confirm", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("In Arbeit: confirm")
if r.Method != "POST" {
return
}
defer r.Body.Close()
data, err := io.ReadAll(r.Body)
if err != nil {
log.Println(err)
return
}
payload := struct {
Id string `json:"id"`
}{}
err = json.Unmarshal(data, &payload)
if err != nil {
//Todo Fehlerhandling
log.Println(err)
}
err = nps.ConfirmBestellung(database.UUID(payload.Id))
if err != nil {
//Todo Fehlerhandling
log.Println(err)
}
w.WriteHeader(http.StatusNoContent)
fmt.Fprintln(w)
return
})
http.HandleFunc("/api/products/release", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("In Arbeit: release")
if r.Method != "POST" {
return
}
defer r.Body.Close()
data, err := io.ReadAll(r.Body)
if err != nil {
log.Println(err)
return
}
payload := struct {
Id string `json:"id"`
}{}
err = json.Unmarshal(data, &payload)
if err != nil {
//Todo Fehlerhandling
log.Println(err)
}
err = nps.ReleaseBestellung(database.UUID(payload.Id))
if err != nil {
//Todo Fehlerhandling
log.Println(err)
}
w.WriteHeader(http.StatusNoContent)
fmt.Fprintln(w)
return
})
http.HandleFunc("/api/products/abort", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("In Arbeit: abort")
if r.Method != "POST" {
return
}
defer r.Body.Close()
data, err := io.ReadAll(r.Body)
if err != nil {
log.Println(err)
return
}
payload := struct {
Id string `json:"id"`
}{}
err = json.Unmarshal(data, &payload)
if err != nil {
//Todo Fehlerhandling
log.Println(err)
}
err = nps.AbortBestellung(database.UUID(payload.Id))
if err != nil {
//Todo Fehlerhandling
log.Println(err)
}
w.WriteHeader(http.StatusNoContent)
fmt.Fprintln(w)
return
})
log.Printf("Easy Peasy: Die Party startet auf Port %s\n", port)

1
go.mod
View File

@ -23,6 +23,7 @@ require (
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/go-sql-driver/mysql v1.9.3 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect

2
go.sum
View File

@ -27,6 +27,8 @@ github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI6
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=

View File

@ -4,7 +4,19 @@ CREATE DATABASE IF NOT EXISTS elio;
-- Haupttabellen erzeugen
CREATE TABLE IF NOT EXISTS elio.blablabla (
-- CREATE TABLE IF NOT EXISTS elio.blablabla (
-- id INT AUTO_INCREMENT PRIMARY KEY,
-- warehouse char(2) NOT NULL,
-- productid VARCHAR(20) NOT NULL,
-- amount INT DEFAULT 0,
-- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- CONSTRAINT location_product_must_be_one UNIQUE (warehouse, productid)
-- ) ENGINE=InnoDB;
-- Doppelter Boden: Tabellen werden zur Not auch beim Starten des Services im ersten Datenbank Call erzeugt
CREATE TABLE IF NOT EXISTS elio.warehouseproducts (
id INT AUTO_INCREMENT PRIMARY KEY,
warehouse char(2) NOT NULL,
productid VARCHAR(20) NOT NULL,
@ -23,6 +35,24 @@ CREATE TABLE IF NOT EXISTS elio.deliverytimes (
CONSTRAINT delivery_from_to_country_must_be_one UNIQUE (fromcountry, tocountry)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS elio.reservations (
id CHAR(36) PRIMARY KEY DEFAULT UUID(),
deliveryId INT,
warehouseId INT,
amount INT DEFAULT 0,
status VARCHAR(30) CHECK(status IN ('RESERVED', 'CONFIRMED', 'ABORTED', 'RELEASED')),
reservationGroupId CHAR(36) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_delivery_id
FOREIGN KEY (deliveryId) REFERENCES deliverytimes (id)
ON DELETE CASCADE
ON UPDATE RESTRICT,
CONSTRAINT fk_warehouse_id
FOREIGN KEY (warehouseId) REFERENCES warehouseproducts (id)
ON DELETE CASCADE
ON UPDATE RESTRICT
) ENGINE=InnoDB;
-- Testtabellen erzeugen
CREATE TABLE IF NOT EXISTS elio_test.warehouseproducts (
id INT AUTO_INCREMENT PRIMARY KEY,
@ -43,6 +73,26 @@ CREATE TABLE IF NOT EXISTS elio_test.deliverytimes (
CONSTRAINT delivery_from_to_country_must_be_one UNIQUE (fromcountry, tocountry)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS elio_test.reservations (
id CHAR(36) PRIMARY KEY DEFAULT UUID(),
deliveryId INT,
warehouseId INT,
amount INT DEFAULT 0,
status VARCHAR(30) CHECK(status IN ('RESERVED', 'CONFIRMED', 'ABORTED', 'RELEASED')),
reservationGroupId CHAR(36) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_delivery_id
FOREIGN KEY (deliveryId) REFERENCES deliverytimes (id)
ON DELETE CASCADE
ON UPDATE RESTRICT,
CONSTRAINT fk_warehouse_id
FOREIGN KEY (warehouseId) REFERENCES warehouseproducts (id)
ON DELETE CASCADE
ON UPDATE RESTRICT
) ENGINE=InnoDB;
-- Userkram
CREATE USER IF NOT EXISTS 'elio'@'%' IDENTIFIED BY 'eliogeheim';
CREATE USER IF NOT EXISTS 'elio_test'@'%' IDENTIFIED BY 'eliogeheim';

View File

@ -10,33 +10,6 @@ import (
"gittea.marcokittel.de/elio/eliotools/datawriter/internal/database"
)
type Container struct {
Products map[string]int `json:"products"`
Context Context `json:"context"`
}
type Product struct {
Warehouse string `json:"warehouse"`
Quantity int `json:"quantity"`
Delivery int `json:"delivery_time"`
}
type OutgoingProducts struct {
Products map[string][]Product `json:"products"`
}
func NewOutgoingProducts() *OutgoingProducts {
op := OutgoingProducts{
Products: make(map[string][]Product),
}
return &op
}
type Context struct {
Country string `json:"country"`
State string `json:"state"`
}
func GetProductApiHandleFunc(nps *database.ProductService) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
@ -59,7 +32,12 @@ func GetProductApiHandleFunc(nps *database.ProductService) http.HandlerFunc {
//Todo Fehlerhandling
log.Println(err)
}
jsonResult, err := json.Marshal(result)
if len(result) == 0 {
w.WriteHeader(http.StatusNoContent)
fmt.Fprintln(w)
return
}
jsonResult, err := json.Marshal(result[0])
if err != nil {
log.Println(err)
}

View File

@ -88,6 +88,7 @@ func (d *DatabaseWriter) createReservationTableIfNotExist() error {
warehouseId INT,
amount INT DEFAULT 0,
status VARCHAR(30) CHECK(status IN ('RESERVED', 'CONFIRMED', 'ABORTED', 'RELEASED')),
reservationGroupId CHAR(36) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_delivery_id
FOREIGN KEY (deliveryId) REFERENCES deliverytimes (id)
@ -127,6 +128,16 @@ func NewDatabaseWriter(connectionString string) *DatabaseWriter {
return &db
}
func (d *DatabaseWriter) ReleaseReservierungenAfterOneDay() error {
_, err := d.db.Exec(`
UPDATE reservations r SET status = 'RELEASED'
WHERE r.created_at < DATE_SUB(NOW(), INTERVAL 1 DAY );`)
if err != nil {
return err
}
return nil
}
func (d *DatabaseWriter) UpdateOrInsertWarehouseProduct(warehouse string, productID string, amount int) error {
_, err := d.db.Exec(`
INSERT INTO warehouseproducts (warehouse, productid, amount)
@ -167,15 +178,22 @@ type ProductDelivery struct {
func (d *DatabaseReader) GetProductByProductIdDeliveryCountryAndState(prod_id, delivery_country, delivery_country_state string) ([]ProductDelivery, error) {
stmt := `
SELECT whp.id, warehouse, amount, d.delivery, d.id deliveryId
FROM warehouseproducts whp
left join deliverytimes d
on whp.warehouse = d.fromcountry
where productid = ?
and d.tocountry = ?
and d.state = ?
order by d.delivery asc, amount desc
`
SELECT id, warehouse, (amount - reserviert) amount, delivery, deliveryId FROM(
SELECT whp.id, warehouse, whp.amount, sum(coalesce(r.amount,0) )reserviert, d.delivery, d.id deliveryId
FROM warehouseproducts whp
left join deliverytimes d
on whp.warehouse = d.fromcountry
left join reservations r
on whp.id = r.warehouseId
and r.status in ('RESERVED', 'CONFIRMED')
where productid = ?
and d.tocountry = ?
and d.state = ?
GROUP BY whp.id, d.delivery
order by d.delivery asc, whp.amount desc
) as zumAufsummieren
having amount > 0
`
rows, err := d.db.Query(stmt, prod_id, delivery_country, delivery_country_state)
if err != nil {
@ -211,6 +229,24 @@ func (d *DatabaseReader) GetReservationStateById(productId UUID) (string, error)
return status, nil
}
func (d *DatabaseReader) GetReservationItemsByGroupId(groupId UUID) (string, error) {
stmt := `
SELECT status FROM reservations WHERE id = ?
`
row, err := d.db.Query(stmt, groupId)
if err != nil {
return "", err
}
defer row.Close()
row.Next()
var status string
err = row.Scan(&status)
if err != nil {
return "", err
}
return status, nil
}
func (d *DatabaseWriter) updateReservationState(Id UUID, status string) error {
_, err := d.db.Exec("UPDATE reservations SET Status=? WHERE id=?", status, Id)
if err != nil {
@ -219,6 +255,14 @@ func (d *DatabaseWriter) updateReservationState(Id UUID, status string) error {
return nil
}
func (d *DatabaseWriter) updateReservationStateByGroupId(groupId UUID, status string) error {
_, err := d.db.Exec("UPDATE reservations SET Status=? WHERE reservationGroupId=?", status, groupId)
if err != nil {
return err
}
return nil
}
func (d *DatabaseWriter) AbortReservation(Id UUID) error {
return d.updateReservationState(Id, "ABORTED")
}
@ -231,9 +275,21 @@ func (d *DatabaseWriter) ReleaseReservation(Id UUID) error {
return d.updateReservationState(Id, "RELEASED")
}
func (d *DatabaseWriter) ReserveReservation(deliveryId, warehouseId, amount int) (UUID, error) {
func (d *DatabaseWriter) AbortReservationGroup(groupId UUID) error {
return d.updateReservationStateByGroupId(groupId, "ABORTED")
}
func (d *DatabaseWriter) ConfirmReservationGroup(groupId UUID) error {
return d.updateReservationStateByGroupId(groupId, "CONFIRMED")
}
func (d *DatabaseWriter) ReleaseReservationGroup(groupId UUID) error {
return d.updateReservationStateByGroupId(groupId, "RELEASED")
}
func (d *DatabaseWriter) ReserveReservationItem(deliveryId, warehouseId, amount int, groupId UUID) (UUID, error) {
newUUID := uuid.New().String()
_, err := d.db.Exec("INSERT INTO reservations (id, deliveryId, warehouseId, amount, status) VALUES (?,?,?,?,'RESERVED')", newUUID, deliveryId, warehouseId, amount)
_, err := d.db.Exec("INSERT INTO reservations (id, deliveryId, warehouseId, amount, status, reservationGroupId) VALUES (?,?,?,?,'RESERVED', ?)", newUUID, deliveryId, warehouseId, amount, groupId)
if err != nil {
return "", err
}

View File

@ -3,9 +3,12 @@ package database
import (
"encoding/json"
"fmt"
"log"
"strings"
"testing"
"github.com/google/uuid"
)
// Unit Tests sollten niemals auf der Produktivdatenbank stattfinden.
@ -123,8 +126,9 @@ func TestInsertStatement(t *testing.T) {
if err != nil {
t.Errorf("Es sollten Datensätze auffinbdar sein! %s", err)
}
groupId := uuid.New().String()
for _, item := range data {
uuid, err := dbr.DatabaseWriter.ReserveReservation(item.DeliveryId, item.Id, item.Amount)
uuid, err := dbr.DatabaseWriter.ReserveReservationItem(item.DeliveryId, item.Id, item.Amount, UUID(groupId))
if err != nil {
t.Errorf("Das Einfügen einer neuen Reservierung darf nicht fehlschlagen! %s", err)
}
@ -141,8 +145,9 @@ func TestAbortReservationStatement(t *testing.T) {
if err != nil {
t.Errorf("Es sollten Datensätze auffinbdar sein! %s", err)
}
groupId := uuid.New().String()
for _, item := range data {
uuid, err := dbr.DatabaseWriter.ReserveReservation(item.DeliveryId, item.Id, item.Amount)
uuid, err := dbr.DatabaseWriter.ReserveReservationItem(item.DeliveryId, item.Id, item.Amount, UUID(groupId))
if err != nil {
t.Errorf("Das Einfügen einer neuen Reservierung darf nicht fehlschlagen! %s", err)
}
@ -166,8 +171,9 @@ func TestConfirmReservationStatement(t *testing.T) {
if err != nil {
t.Errorf("Es sollten Datensätze auffinbdar sein! %s", err)
}
groupId := uuid.New().String()
for _, item := range data {
uuid, err := dbr.DatabaseWriter.ReserveReservation(item.DeliveryId, item.Id, item.Amount)
uuid, err := dbr.DatabaseWriter.ReserveReservationItem(item.DeliveryId, item.Id, item.Amount, UUID(groupId))
if err != nil {
t.Errorf("Das Einfügen einer neuen Reservierung darf nicht fehlschlagen! %s", err)
}
@ -191,8 +197,9 @@ func TestReleasedReservationStatement(t *testing.T) {
if err != nil {
t.Errorf("Es sollten Datensätze auffinbdar sein! %s", err)
}
groupId := uuid.New().String()
for _, item := range data {
uuid, err := dbr.DatabaseWriter.ReserveReservation(item.DeliveryId, item.Id, item.Amount)
uuid, err := dbr.DatabaseWriter.ReserveReservationItem(item.DeliveryId, item.Id, item.Amount, UUID(groupId))
if err != nil {
t.Errorf("Das Einfügen einer neuen Reservierung darf nicht fehlschlagen! %s", err)
}
@ -210,6 +217,20 @@ func TestReleasedReservationStatement(t *testing.T) {
}
}
func TestFetchReservationData(t *testing.T) {
payloadStr := `{ "products": { "A6053": 30 }, "context": { "country": "EU", "state": "" }}`
var payload Container
err := json.Unmarshal([]byte(payloadStr), &payload)
if err != nil {
t.Errorf("Dieser Fehler beim Konvertieren der JSON Payload sollte nicht passieren! \n%s", err)
return
}
ps := NewProductService(connectionString)
// groupId := uuid.New().String()
op, err := ps.FetchData(&payload)
log.Println(op)
}
func TestFetchDataReservation(t *testing.T) {
payloadStr := `{ "products": { "A6053": 30 }, "context": { "country": "EU", "state": "" }}`
@ -220,7 +241,8 @@ func TestFetchDataReservation(t *testing.T) {
return
}
ps := NewProductService(connectionString)
op, err := ps.FetchData(&payload)
groupId := uuid.New().String()
op, err := ps.FetchReservationData(&payload, UUID(groupId))
if err != nil {
t.Errorf("Das Datafetchen und umwandeln in eine Map muss sauber funktionieren! %s", err)
}
@ -312,16 +334,17 @@ func TestOutgoingReservationInDatabase(t *testing.T) {
t.Errorf("Dieser Fehler beim Konvertieren der JSON Payload sollte nicht passieren! \n%s", err)
return
}
groupId := uuid.New().String()
ps := NewProductService(connectionString)
op, err := ps.FetchData(&payload)
op, err := ps.FetchReservationData(&payload, UUID(groupId))
if err != nil {
t.Errorf("Das Datafetchen und umwandeln in eine Map muss sauber funktionieren! %s", err)
}
valTocompare := `[{map[A6053:[{AT 4 1 8508 63} {DE 1 2 7507 18}]]}]`
valTocompare := fmt.Sprintf(`[{%s map[A6053:[{AT 4 1 8508 63} {DE 1 2 7507 18}]]}]`, groupId)
if fmt.Sprint(op) != valTocompare {
t.Errorf("Mist, sollte sein %s ist aber %s", valTocompare, fmt.Sprint(op))
}
uuids, err := ps.ReserviereBestellungen(op)
uuids, err := ps.ReserviereBestellungen(op, UUID(groupId))
if err != nil {
t.Errorf("Das Reservieren ist fehlgeschlagen! \n%s", err)
}
@ -331,10 +354,20 @@ func TestOutgoingReservationInDatabase(t *testing.T) {
t.Errorf("Der Status muss RESERVED sein. Stattdessen ist er: %s", status)
}
}
ps.dbr.ReleaseReservationGroup(UUID(groupId))
for _, uuid := range *uuids {
status, err := ps.dbr.GetReservationStateById(uuid)
if err != nil || status != "RELEASED" {
t.Errorf("Der Status muss RELEASED sein. Stattdessen ist er: %s", status)
}
}
jsonResult, err := json.Marshal(op)
jsonStrForApiResponse := `[{"products":{"A6053":[{"warehouse":"AT","quantity":4,"delivery_time":1},{"warehouse":"DE","quantity":1,"delivery_time":2}]}}]`
jsonGuid := fmt.Sprintf("\"id\":\"%s\"", UUID(groupId))
jsonStrForApiResponse := fmt.Sprintf(`[{%s,"products":{"A6053":[{"warehouse":"AT","quantity":4,"delivery_time":1},{"warehouse":"DE","quantity":1,"delivery_time":2}]}}]`, jsonGuid)
if string(jsonResult) != jsonStrForApiResponse {
t.Errorf("Mist, sollte sein %s ist aber %s", string(jsonResult), jsonStrForApiResponse)
}
}

View File

@ -1,6 +1,10 @@
package database
import "log"
import (
"fmt"
"log"
"time"
)
type ProductService struct {
dbr *DatabaseReader
@ -21,6 +25,10 @@ type Product struct {
type OutgoingProducts struct {
Products map[string][]Product `json:"products"`
}
type OutgoingReservationProducts struct {
Id UUID `json:"id"`
Products map[string][]Product `json:"products"`
}
func NewOutgoingProducts() *OutgoingProducts {
op := OutgoingProducts{
@ -28,6 +36,13 @@ func NewOutgoingProducts() *OutgoingProducts {
}
return &op
}
func NewOutgoingReservationsProducts(groupId UUID) *OutgoingReservationProducts {
op := OutgoingReservationProducts{
Id: groupId,
Products: make(map[string][]Product),
}
return &op
}
type Context struct {
Country string `json:"country"`
@ -40,7 +55,22 @@ func NewProductService(connectionString string) *ProductService {
return &p
}
func (p *ProductService) ReserviereBestellungen(op []OutgoingProducts) (*[]UUID, error) {
func (p *ProductService) Autorelease() {
//Das müsste saubererer sein. Spare ich mir aber, weil der Webserver alles blockiert.
//Besser wäre das Arbeiten mit Context. Gefahr ist aber minimal
go func() {
for {
fmt.Println("Prüfe nach Registrierungen die Freigegeben werden können. (Älter als 24 Stunden)")
err := p.dbr.ReleaseReservierungenAfterOneDay()
if err != nil {
log.Printf("Fehler beim Ausführen von Autorelease() des Logs. %s", err)
}
time.Sleep(30 * time.Second)
}
}()
}
func (p *ProductService) ReserviereBestellungen(op []OutgoingReservationProducts, groupId UUID) (*[]UUID, error) {
var uuids []UUID
for _, hsmp := range op {
for _, prod := range hsmp.Products {
@ -49,7 +79,7 @@ func (p *ProductService) ReserviereBestellungen(op []OutgoingProducts) (*[]UUID,
warehouseId := concreteProduct.WhdId
amount := concreteProduct.Quantity
// Todo: Handler Injection wäre hier interessant
uuid, err := p.dbr.ReserveReservation(deliveryId, warehouseId, amount)
uuid, err := p.dbr.ReserveReservationItem(deliveryId, warehouseId, amount, groupId)
if err != nil {
return nil, err
}
@ -60,13 +90,25 @@ func (p *ProductService) ReserviereBestellungen(op []OutgoingProducts) (*[]UUID,
return &uuids, nil
}
func (p *ProductService) ConfirmBestellung(groudId UUID) error {
return p.dbr.ConfirmReservationGroup(groudId)
}
func (p *ProductService) AbortBestellung(groudId UUID) error {
return p.dbr.AbortReservationGroup(groudId)
}
func (p *ProductService) ReleaseBestellung(groudId UUID) error {
return p.dbr.ReleaseReservationGroup(groudId)
}
func (p *ProductService) FetchData(payload *Container) ([]OutgoingProducts, error) {
result := []OutgoingProducts{}
for key, item := range payload.Products {
//Checken ob die Felder leer sind / Validitätsprüfung einbauen
products, err := p.dbr.GetProductByProductIdDeliveryCountryAndState(key, payload.Context.Country, payload.Context.State)
if err != nil {
log.Println(err)
return nil, err
}
if len(products) == 0 {
continue
@ -91,3 +133,35 @@ func (p *ProductService) FetchData(payload *Container) ([]OutgoingProducts, erro
}
return result, nil
}
func (p *ProductService) FetchReservationData(payload *Container, groupId UUID) ([]OutgoingReservationProducts, error) {
result := []OutgoingReservationProducts{}
for key, item := range payload.Products {
//Checken ob die Felder leer sind / Validitätsprüfung einbauen
products, err := p.dbr.GetProductByProductIdDeliveryCountryAndState(key, payload.Context.Country, payload.Context.State)
if err != nil {
return nil, err
}
if len(products) == 0 {
continue
}
gebrauchteProduktAnzahl := item
op := NewOutgoingReservationsProducts(groupId)
for _, db_products := range products {
if gebrauchteProduktAnzahl <= 0 {
continue
}
if db_products.Amount >= gebrauchteProduktAnzahl {
newProduct := Product{Delivery: db_products.DeliveryDays, Quantity: gebrauchteProduktAnzahl, Warehouse: db_products.Warehouse, WhdId: db_products.Id, DeliveryId: db_products.DeliveryId}
gebrauchteProduktAnzahl = 0
op.Products[key] = append(op.Products[key], newProduct)
} else if db_products.Amount < gebrauchteProduktAnzahl {
newProduct := Product{Delivery: db_products.DeliveryDays, Quantity: db_products.Amount, Warehouse: db_products.Warehouse, WhdId: db_products.Id, DeliveryId: db_products.DeliveryId}
gebrauchteProduktAnzahl -= db_products.Amount
op.Products[key] = append(op.Products[key], newProduct)
}
}
result = append(result, *op)
}
return result, nil
}