Skip to content
Snippets Groups Projects
Commit 8f7bd7ca authored by meskio's avatar meskio :tent:
Browse files

Add inventary API

parent cb50f841
No related branches found
No related tags found
No related merge requests found
......@@ -51,6 +51,10 @@ func Init(dbPath string, signKey string, mail *Mail, r *mux.Router) error {
r.HandleFunc("/supplier", a.auth(a.ListSuppliers)).Methods("GET")
r.HandleFunc("/supplier", a.authAdmin(a.AddSupplier)).Methods("POST")
r.HandleFunc("/inventary", a.authAdmin(a.ListInventary)).Methods("GET")
r.HandleFunc("/inventary/{id:[0-9]+}", a.authAdmin(a.GetInventary)).Methods("GET")
r.HandleFunc("/inventary", a.authAdminNum(a.AddInventary)).Methods("POST")
r.HandleFunc("/transaction", a.authAdmin(a.ListTransactions)).Methods("GET")
r.HandleFunc("/transaction/{id:[0-9]+}", a.authNumRole(a.GetTransaction)).Methods("GET")
r.HandleFunc("/transaction/mine", a.authNum(a.getTransactionsByMember)).Methods("GET")
......
......@@ -16,6 +16,7 @@ func Init(dbPath string) (*DB, error) {
}
db.AutoMigrate(&Member{}, &Product{}, &Purchase{}, &Topup{}, &Transaction{},
&OrderPurchase{}, &Order{}, &PasswordReset{}, &Supplier{})
&OrderPurchase{}, &Order{}, &PasswordReset{}, &Supplier{},
&Inventary{}, &InventaryProduct{})
return &DB{db}, err
}
package db
import (
"time"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type Supplier struct {
gorm.Model
Name string `json:"name"`
Name string `json:"name" gorm:"unique;index"`
}
func (d *DB) AddSupplier(supplier Supplier) error {
return d.db.Create(&supplier).Error
type Inventary struct {
gorm.Model
MemberNum int `json:"-" gorm:"column:member"`
Member *Member `json:"member,omitempty" gorm:"foreignKey:MemberNum;references:Num"`
Date time.Time `json:"date"`
SupplierID *uint `json:"-"`
Supplier *Supplier `json:"supplier"`
Comment string `json:"comment"`
Products []InventaryProduct `json:"products"`
}
type InventaryProduct struct {
gorm.Model
InventaryID uint `json:"-"`
ProductCode int `json:"code" gorm:"column:product"`
Product *Product `json:"product" gorm:"foreignKey:ProductCode;references:Code"`
StockUpdate *int `json:"stock"`
Price *int `json:"price"`
}
func (d *DB) AddSupplier(supplier *Supplier) error {
return d.db.Create(supplier).Error
}
func (d *DB) ListSuppliers() (suppliers []Supplier, err error) {
err = d.db.Find(&suppliers).Error
return
}
func (d *DB) AddInventary(num int, inventary *Inventary) error {
inventary.Date = time.Now()
inventary.MemberNum = num
return d.db.Transaction(func(tx *gorm.DB) error {
for _, product := range inventary.Products {
query := tx.Model(&Product{}).
Where("code = ?", product.ProductCode)
if product.StockUpdate != nil {
query = query.Update("stock", gorm.Expr("stock + ?", *product.StockUpdate))
}
if product.Price != nil {
query = query.Update("price", *product.Price)
}
err := query.Error
if err != nil {
return err
}
}
return tx.Create(inventary).Error
})
}
func (d *DB) GetInventary(id int) (inventary Inventary, err error) {
err = d.db.Preload("Products.Product").
Preload(clause.Associations).
First(&inventary, id).
Error
return
}
func (d *DB) ListInventary() (inventaries []Inventary, err error) {
err = d.db.Preload("Products.Product").
Preload(clause.Associations).
Find(&inventaries).
Error
return
}
......@@ -4,8 +4,10 @@ import (
"encoding/json"
"log"
"net/http"
"strconv"
"0xacab.org/meskio/cicer/api/db"
"github.com/gorilla/mux"
)
func (a *api) AddSupplier(w http.ResponseWriter, req *http.Request) {
......@@ -16,7 +18,7 @@ func (a *api) AddSupplier(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
return
}
err = a.db.AddSupplier(supplier)
err = a.db.AddSupplier(&supplier)
if err != nil {
log.Printf("Can't create supplier: %v\n%v", err, supplier)
w.WriteHeader(http.StatusInternalServerError)
......@@ -49,3 +51,64 @@ func (a *api) ListSuppliers(w http.ResponseWriter, req *http.Request) {
return
}
}
func (a *api) AddInventary(num int, w http.ResponseWriter, req *http.Request) {
var inventary db.Inventary
err := json.NewDecoder(req.Body).Decode(&inventary)
if err != nil {
log.Printf("Can't decode inventary: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
err = a.db.AddInventary(num, &inventary)
if err != nil {
log.Printf("Can't create inventary: %v\n%v", err, inventary)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
err = json.NewEncoder(w).Encode(inventary)
if err != nil {
log.Printf("Can't encode added inventary: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
}
func (a *api) GetInventary(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req)
id, _ := strconv.Atoi(vars["id"])
inventary, err := a.db.GetInventary(id)
if err != nil {
log.Printf("Can't get inventary: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(inventary)
if err != nil {
log.Printf("Can't encode inventary: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
}
func (a *api) ListInventary(w http.ResponseWriter, req *http.Request) {
inventary, err := a.db.ListInventary()
if err != nil {
log.Printf("Can't list inventary: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
err = json.NewEncoder(w).Encode(inventary)
if err != nil {
log.Printf("Can't encode inventary: %v", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
}
package api
import (
"fmt"
"net/http"
"testing"
......@@ -30,9 +31,139 @@ func TestSupplierAddList(t *testing.T) {
}
}
func (tapi *testAPI) addTestSuppliers() {
resp := tapi.doAdmin("POST", "/supplier", testSupplier, nil)
func TestInventaryUpdateStock(t *testing.T) {
tapi := newTestAPI(t)
defer tapi.close()
supplierID := tapi.addTestSuppliers()
tapi.addTestProducts()
update := -5
inventary := db.Inventary{
SupplierID: &supplierID,
Comment: "Got aceite",
Products: []db.InventaryProduct{
{
ProductCode: testProduct.Code,
StockUpdate: &update,
},
},
}
resp := tapi.doAdmin("POST", "/inventary", inventary, nil)
if resp.StatusCode != http.StatusCreated {
t.Fatal("Can't create inventary:", resp.Status)
}
var newInventary []db.Inventary
resp = tapi.doAdmin("GET", "/inventary", nil, &newInventary)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get inventary:", resp.Status)
}
if len(newInventary) != 1 {
t.Fatal("Wrong inventary length:", newInventary)
}
if newInventary[0].Comment != inventary.Comment {
t.Error("Wrong comment:", newInventary[0].Comment)
}
if len(newInventary[0].Products) != 1 {
t.Error("Wrong products:", newInventary[0].Products)
}
var entry db.Inventary
resp = tapi.doAdmin("GET", fmt.Sprintf("/inventary/%d", newInventary[0].ID), nil, &entry)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get inventary:", resp.Status)
}
if entry.Comment != inventary.Comment {
t.Error("Wrong comment:", entry.Comment)
}
if len(entry.Products) != 1 {
t.Error("Wrong products:", entry.Products)
}
var product db.Product
resp = tapi.doAdmin("GET", fmt.Sprintf("/product/%d", testProduct.Code), nil, &product)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get product:", resp.Status)
}
if product.Stock != testProduct.Stock+*inventary.Products[0].StockUpdate {
t.Error("Wrong stock:", product.Stock)
}
}
func TestInventaryUpdatePrice(t *testing.T) {
tapi := newTestAPI(t)
defer tapi.close()
supplierID := tapi.addTestSuppliers()
tapi.addTestProducts()
update := 1000
inventary := db.Inventary{
SupplierID: &supplierID,
Comment: "Got aceite",
Products: []db.InventaryProduct{
{
ProductCode: testProduct.Code,
Price: &update,
},
},
}
resp := tapi.doAdmin("POST", "/inventary", inventary, nil)
if resp.StatusCode != http.StatusCreated {
t.Fatal("Can't create inventary:", resp.Status)
}
var product db.Product
resp = tapi.doAdmin("GET", fmt.Sprintf("/product/%d", testProduct.Code), nil, &product)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get product:", resp.Status)
}
if product.Price != *inventary.Products[0].Price {
t.Error("Wrong price:", product.Price)
}
}
func TestInventaryUpdateBoth(t *testing.T) {
tapi := newTestAPI(t)
defer tapi.close()
supplierID := tapi.addTestSuppliers()
tapi.addTestProducts()
updateStock := 5
price := 800
inventary := db.Inventary{
SupplierID: &supplierID,
Comment: "Got aceite",
Products: []db.InventaryProduct{
{
ProductCode: testProduct.Code,
StockUpdate: &updateStock,
Price: &price,
},
},
}
resp := tapi.doAdmin("POST", "/inventary", inventary, nil)
if resp.StatusCode != http.StatusCreated {
t.Fatal("Can't create inventary:", resp.Status)
}
var product db.Product
resp = tapi.doAdmin("GET", fmt.Sprintf("/product/%d", testProduct.Code), nil, &product)
if resp.StatusCode != http.StatusOK {
t.Fatal("Can't get product:", resp.Status)
}
if product.Stock != testProduct.Stock+*inventary.Products[0].StockUpdate {
t.Error("Wrong stock:", product.Stock)
}
if product.Price != *inventary.Products[0].Price {
t.Error("Wrong price:", product.Price)
}
}
func (tapi *testAPI) addTestSuppliers() uint {
var supplier db.Supplier
resp := tapi.doAdmin("POST", "/supplier", testSupplier, &supplier)
if resp.StatusCode != http.StatusCreated {
tapi.t.Fatal("Can't create supplier:", resp.Status)
}
return supplier.ID
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment