adjust mat selection

This commit is contained in:
pakintada@gmail.com 2023-12-29 16:10:57 +07:00
parent 17030c72ce
commit bf693aab2a
15 changed files with 548 additions and 186 deletions

View file

@ -1,6 +1,7 @@
package data
import (
"fmt"
"strings"
"github.com/jmoiron/sqlx"
@ -16,7 +17,8 @@ CREATE TABLE IF NOT EXISTS commit_log (
msg VARCHAR(255),
created_at DATETIME,
editor VARCHAR(255),
change_file VARCHAR(255)
change_file VARCHAR(255),
relation VARCHAR(255)
);
`
@ -26,6 +28,7 @@ type CommitLog struct {
Created_at string `db:"created_at"`
Editor string `db:"editor"`
Change_file string `db:"change_file"`
Relation string `db:"relation"`
}
func HashCommit(n int) (string, error) {
@ -52,7 +55,7 @@ func Insert(c *CommitLog) error {
// init table in db
commit_db.MustExec(schema)
_, err = commit_db.NamedExec("INSERT INTO commit_log (id, msg, created_at, editor, change_file) VALUES (:id, :msg, :created_at, :editor, :change_file)", c)
_, err = commit_db.NamedExec("INSERT INTO commit_log (id, msg, created_at, editor, change_file, relation) VALUES (:id, :msg, :created_at, :editor, :change_file, :relation)", c)
if err != nil {
return err
@ -74,8 +77,10 @@ func GetCommitLogOfFilename(countryId string, filename string) ([]CommitLog, err
}
commitDB, err := sqlx.Connect("sqlite3", "./data/database.db")
// fmt.Println("GetCommitLogOfFilename", err)
if err != nil {
return nil, err
}
var commits []CommitLog
@ -84,6 +89,12 @@ func GetCommitLogOfFilename(countryId string, filename string) ([]CommitLog, err
err = commitDB.Select(&commits, "SELECT * FROM commit_log WHERE change_file LIKE ?", "%"+filename+"%")
// fmt.Println("commits", err)
if err != nil {
return nil, err
}
var commitsByCountryID []CommitLog
for _, v := range commits {
@ -101,6 +112,12 @@ func GetCommitLogOfFilename(countryId string, filename string) ([]CommitLog, err
return nil, err
}
// fmt.Println("commitsByCountryID", len(commitsByCountryID) == 0)
if len(commitsByCountryID) == 0 {
return nil, fmt.Errorf("no commit found for %s", filename)
}
return commitsByCountryID, nil
}

View file

@ -6,6 +6,7 @@ import (
"recipe-manager/helpers"
"recipe-manager/models"
"recipe-manager/services/logger"
"strings"
"time"
"reflect"
@ -28,9 +29,8 @@ type Data struct {
taoLogger *logger.TaoLogger
}
func NewData(taoLogger *logger.TaoLogger) *Data {
countries := []helpers.CountryName{{
var (
countries = []helpers.CountryName{{
CountryID: "tha",
CountryName: "Thailand",
}, {
@ -41,6 +41,9 @@ func NewData(taoLogger *logger.TaoLogger) *Data {
CountryName: "Australia",
},
}
)
func NewData(taoLogger *logger.TaoLogger) *Data {
allRecipeFiles := helpers.ScanRecipeFiles(countries)
@ -129,22 +132,35 @@ func (d *Data) GetCurrentRecipe() *models.Recipe {
func (d *Data) GetRecipe01ByProductCode(filename, countryID, productCode string) (models.Recipe01, error) {
if filename == "" || filename == d.CurrentFile {
for _, v := range d.currentRecipe.Recipe01 {
if v.ProductCode == productCode {
return v, nil
if !strings.Contains(filename, "tmp") {
if filename == "" || filename == d.CurrentFile {
fmt.Println("GetRecipe01ByProductCode.ReadCurrent", filename, d.CurrentFile)
for _, v := range d.currentRecipe.Recipe01 {
if v.ProductCode == productCode {
return v, nil
}
}
}
} else if recipe, ok := d.recipeMap[filename]; ok {
for _, v := range recipe.Recipe.Recipe01 {
if v.ProductCode == productCode {
return v, nil
} else if recipe, ok := d.recipeMap[filename]; ok {
fmt.Println("GetRecipe01ByProductCode.ReadMap", filename, d.CurrentFile)
for _, v := range recipe.Recipe.Recipe01 {
if v.ProductCode == productCode {
return v, nil
}
}
}
}
d.CurrentFile = filename
d.CurrentCountryID = countryID
for _, v := range countries {
if v.CountryName == countryID {
d.CurrentCountryID = v.CountryID
countryID = v.CountryID
break
}
}
recipe, err := helpers.ReadRecipeFile(countryID, filename)
if err != nil {
@ -179,6 +195,7 @@ func (d *Data) GetRecipe01ByProductCode(filename, countryID, productCode string)
for _, v := range d.currentRecipe.Recipe01 {
if v.ProductCode == productCode {
// d.taoLogger.Log.Debug("GetRecipe01ByProductCode", zap.Any("productCode", productCode), zap.Any("result", v))
return v, nil
}
}
@ -186,7 +203,6 @@ func (d *Data) GetRecipe01ByProductCode(filename, countryID, productCode string)
return models.Recipe01{}, fmt.Errorf("product code: %s not found", productCode)
}
// FIXME: saved in log but not actual file
func (d *Data) SetValuesToRecipe(base_recipe []models.Recipe01, recipe models.Recipe01) {
not_found := false
global_idx := 0
@ -203,7 +219,7 @@ func (d *Data) SetValuesToRecipe(base_recipe []models.Recipe01, recipe models.Re
for k, v := range recipe01_Map {
if !reflect.DeepEqual(base_recipe01_Map[k], v) {
d.taoLogger.Log.Debug("SetValuesToRecipe", zap.Any("key", k), zap.Any("value", v), zap.Any("old", base_recipe01_Map[k]), zap.Any("new", recipe01_Map[k]))
d.taoLogger.Log.Debug("SetValuesToRecipe", zap.Any("key", k))
base_recipe01_Map[k] = v
}
}
@ -231,16 +247,19 @@ func (d *Data) GetMaterialSetting(countryID, filename string) []models.MaterialS
return result
}
if filename == "" || filename == d.CurrentFile {
copy(result, d.currentRecipe.MaterialSetting)
return result
}
if !strings.Contains(filename, "tmp") {
if filename == "" || filename == d.CurrentFile {
copy(result, d.currentRecipe.MaterialSetting)
d.taoLogger.Log.Debug("GetMaterialSetting", zap.Any("result", result))
return d.currentRecipe.MaterialSetting
}
if recipe, ok := d.recipeMap[filename]; ok {
copy(result, recipe.Recipe.MaterialSetting)
d.CurrentFile = filename
d.CurrentCountryID = countryID
return result
if recipe, ok := d.recipeMap[filename]; ok {
copy(result, recipe.Recipe.MaterialSetting)
d.CurrentFile = filename
d.CurrentCountryID = countryID
return d.currentRecipe.MaterialSetting
}
}
d.CurrentFile = filename
@ -250,9 +269,11 @@ func (d *Data) GetMaterialSetting(countryID, filename string) []models.MaterialS
if err != nil {
d.taoLogger.Log.Error("Error when read recipe file, Return default recipe", zap.Error(err))
copy(result, d.currentRecipe.MaterialSetting)
return result
return d.currentRecipe.MaterialSetting
}
d.taoLogger.Log.Debug("GetMaterialSetting", zap.Any("recipe", recipe.MaterialSetting))
d.currentRecipe = recipe
// save to map
@ -274,8 +295,8 @@ func (d *Data) GetMaterialSetting(countryID, filename string) []models.MaterialS
TimeStamps: time.Now().Unix(),
}
copy(result, d.currentRecipe.MaterialSetting)
return result
// copy(result, recipe.MaterialSetting)
return recipe.MaterialSetting
}
func (d *Data) GetMaterialCode(ids []uint64, countryID, filename string) []models.MaterialCode {
@ -341,6 +362,39 @@ func (d *Data) GetMaterialCode(ids []uint64, countryID, filename string) []model
return resultFilter
}
func (d *Data) GetToppings(countryID, filename string) models.Topping {
if filename == "" || filename == d.CurrentFile {
return d.currentRecipe.Topping
} else if recipe, ok := d.recipeMap[filename]; ok {
d.CurrentFile = filename
return recipe.Recipe.Topping
}
d.CurrentFile = filename
d.CurrentCountryID = countryID
recipe, err := helpers.ReadRecipeFile(countryID, filename)
if err != nil {
d.taoLogger.Log.Error("Error when read recipe file, Return default recipe", zap.Error(err))
return d.currentRecipe.Topping
}
d.currentRecipe = recipe
return recipe.Topping
}
func (d *Data) GetToppingsOfRecipe(countryID, filename string, productCode string) ([]models.ToppingSet, error) {
recipe, err := d.GetRecipe01ByProductCode(filename, countryID, productCode)
if err != nil {
d.taoLogger.Log.Error("Error when read recipe file, Return default recipe", zap.Error(err))
return []models.ToppingSet{}, err
}
return recipe.ToppingSet, nil
}
func (d *Data) GetCountryNameByID(countryID string) (string, error) {
for _, country := range d.Countries {
if country.CountryID == countryID {

Binary file not shown.

View file

@ -50,6 +50,9 @@ type MaterialSetting struct {
PayRettryMaxCount int `json:"pay_rettry_max_count"`
FeedMode string `json:"feed_mode"`
MaterialParameter string `json:"MaterialParameter"`
MaterialName string `json:"materialName"`
MaterialOtherName string `json:"materialOtherName"`
RawMaterialUnit string `json:"RawMaterialUnit"`
}
type Recipe01 struct {

View file

@ -2,14 +2,15 @@ package routers
import (
"encoding/json"
"github.com/go-chi/chi/v5"
"go.uber.org/zap"
"net/http"
"recipe-manager/data"
"recipe-manager/models"
"recipe-manager/services/logger"
"strconv"
"strings"
"github.com/go-chi/chi/v5"
"go.uber.org/zap"
)
type MaterialRouter struct {
@ -29,9 +30,72 @@ func (mr *MaterialRouter) Route(r chi.Router) {
r.Get("/code", mr.getMaterialCode)
r.Get("/setting/{mat_id}", mr.getMaterialSettingByMatID)
r.Get("/full/{country}/{filename}", mr.GetFullMaterialDetail)
})
}
func (mr *MaterialRouter) GetFullMaterialDetail(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "application/json")
country := chi.URLParam(r, "country")
filename := chi.URLParam(r, "filename")
mr.taoLogger.Log.Debug("GetFullMaterialDetail", zap.Any("country", country), zap.Any("filename", filename))
// get material setting and code
matSettings := mr.data.GetMaterialSetting(country, filename)
matCodes := mr.data.GetRecipe(country, filename).MaterialCode
// combine
materialDetails := []map[string]interface{}{}
for _, matSetting := range matSettings {
// if material name exist
mat_name := ""
if matSetting.MaterialName != "" {
mat_name = matSetting.MaterialName
// mr.taoLogger.Log.Debug("GetFullMaterialDetail", zap.Any("mat_name", mat_name))
} else {
for _, matCode := range matCodes {
if matCode.MaterialID == matSetting.ID {
mat_name = matCode.PackageDescription
break
}
}
}
materialDetails = append(materialDetails, map[string]interface{}{
"materialId": matSetting.ID,
"name": mat_name,
"type": "powder:" + strconv.FormatBool(matSetting.PowderChannel) + ",syrup:" + strconv.FormatBool(matSetting.SyrupChannel) + ",bean:" + strconv.FormatBool(matSetting.BeanChannel) + ",equipment:" + strconv.FormatBool(matSetting.IsEquipment),
})
}
// for _, matCode := range matCodes {
// for index, matDetail := range materialDetails {
// if matCode.MaterialID == matDetail["materialId"] {
// materialDetails[index]["name"] = matCode.PackageDescription
// } else if matDetail["materialId"].(uint64) > 8110 && matDetail["materialId"].(uint64) <= 8130 {
// slotNum := matDetail["materialId"].(uint64) - 8110
// // mr.taoLogger.Log.Debug("GetFullMaterialDetail", zap.Any("slotNum", matDetail["materialId"]), zap.Any("slotNum", slotNum))
// materialDetails[index]["name"] = "Topping" + strconv.Itoa(int(slotNum))
// }
// }
// }
// send result
if err := json.NewEncoder(w).Encode(materialDetails); err != nil {
mr.taoLogger.Log.Error("MaterialRouter.GetFullMaterialDetail", zap.Error(err))
http.Error(w, "Internal Error", http.StatusInternalServerError)
return
}
}
func (mr *MaterialRouter) getMaterialCode(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "application/json")

View file

@ -53,12 +53,12 @@ func (rr *RecipeRouter) Route(r chi.Router) {
r.Get("/{product_code}/mat", rr.getRecipeMatByProductCode)
r.Get("/{country}/{filename}/toppings", rr.getToppings)
r.Get("/{country}/{filename}/json", rr.getRecipeJson)
r.Post("/edit/{country}/{filename}", rr.updateRecipe)
r.Post("/upgrade/{country}/{filename}", rr.ApplyTmpChanges)
r.Get("/saved/{country}/{filename_version_only}", rr.getSavedRecipes)
r.Get("/countries", func(w http.ResponseWriter, r *http.Request) {
@ -336,7 +336,7 @@ func (rr *RecipeRouter) updateRecipe(w http.ResponseWriter, r *http.Request) {
rr.taoLogger.Log.Debug("Changes: ", zap.Any("changes", changes))
// TODO: find the matched pd
targetMenu, err := rr.data.GetRecipe01ByProductCode(filename, countryID, changes.ProductCode)
_, err = rr.data.GetRecipe01ByProductCode(filename, countryID, changes.ProductCode)
if err != nil {
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(errors.WithMessage(err, "Error when get recipe by product code")))
@ -344,28 +344,28 @@ func (rr *RecipeRouter) updateRecipe(w http.ResponseWriter, r *http.Request) {
return
}
menuMap := targetMenu.ToMap()
// menuMap := targetMenu.ToMap()
changeMap := changes.ToMap()
// Find changes
for key, val := range menuMap {
// rr.taoLogger.Log.Debug("..DynamicCompare.key", zap.Any("key", key))
testBool, err := helpers.DynamicCompare(val, changeMap[key])
// for key, val := range menuMap {
// // rr.taoLogger.Log.Debug("..DynamicCompare.key", zap.Any("key", key))
// testBool, err := helpers.DynamicCompare(val, changeMap[key])
// if err != nil {
// rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(errors.WithMessage(err, "DynamicCompare in request failed")))
// http.Error(w, "Internal Error", http.StatusInternalServerError)
// return
// }
// // if err != nil {
// // rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(errors.WithMessage(err, "DynamicCompare in request failed")))
// // http.Error(w, "Internal Error", http.StatusInternalServerError)
// // return
// // }
if !testBool && err == nil {
menuMap[key] = changeMap[key]
}
}
// if !testBool && err == nil {
// menuMap[key] = changeMap[key]
// }
// }
// Apply changes
tempRecipe := models.Recipe01{}
tempRecipe = tempRecipe.FromMap(menuMap)
tempRecipe = tempRecipe.FromMap(changeMap)
rr.data.SetValuesToRecipe(targetRecipe.Recipe01, tempRecipe)
rr.taoLogger.Log.Debug("ApplyChange", zap.Any("status", "passed"))
@ -390,6 +390,7 @@ func (rr *RecipeRouter) updateRecipe(w http.ResponseWriter, r *http.Request) {
Created_at: time.Now().Local().Format("2006-01-02 15:04:05"),
Editor: editor,
Change_file: temp_file_name,
Relation: filename,
}
err = data.Insert(&commit)
@ -434,10 +435,10 @@ func (rr *RecipeRouter) getSavedRecipes(w http.ResponseWriter, r *http.Request)
}
commits, err := data.GetCommitLogOfFilename(countryID, file_version)
// fmt.Println("commits", commits)
rr.taoLogger.Log.Debug("RecipeRouter.getSavedRecipes", zap.Any("commits", commits))
if err != nil {
if err != nil || len(commits) == 0 {
return
}
@ -448,92 +449,46 @@ func (rr *RecipeRouter) getSavedRecipes(w http.ResponseWriter, r *http.Request)
json.NewEncoder(w).Encode(map[string]interface{}{"files": commits})
}
func (rr *RecipeRouter) ApplyTmpChanges(w http.ResponseWriter, r *http.Request) {
func (rr *RecipeRouter) getToppings(w http.ResponseWriter, r *http.Request) {
countryID := chi.URLParam(r, "country")
filename := chi.URLParam(r, "filename")
country := chi.URLParam(r, "country")
countryID, err := rr.data.GetCountryIDByName(country)
if err != nil {
rr.taoLogger.Log.Error("RecipeRouter.UpdateRecipe", zap.Error(err))
http.Error(w, fmt.Sprintf("Country Name: %s not found!!!", country), http.StatusNotFound)
return
}
var legit_changes map[string]interface{}
target_recipe := rr.data.GetRecipe(countryID, filename)
new_file_version := target_recipe.MachineSetting.ConfigNumber + 1
show_to_current := legit_changes["no_upgrade"].(bool)
if show_to_current {
new_file_version = target_recipe.MachineSetting.ConfigNumber
}
err = json.NewDecoder(r.Body).Decode(&legit_changes)
if err != nil {
rr.taoLogger.Log.Error("ApplyErr", zap.Any("err", err))
return
}
user_selected_tmp := legit_changes["selected_files"].([]string)
for select_tmp := range user_selected_tmp {
// open selected
current_temp_file, err := os.ReadFile(user_selected_tmp[select_tmp])
if err != nil {
rr.taoLogger.Log.Error("TmpFile", zap.Any("Open", "tried to open but failed => "+user_selected_tmp[select_tmp]))
continue
}
// load to model
temp_recipe := models.Recipe01{}
json.Unmarshal(current_temp_file, &temp_recipe)
// apply set value
rr.data.SetValuesToRecipe(target_recipe.Recipe01, temp_recipe)
rr.taoLogger.Log.Debug("ApplyTmpChanges", zap.Any("Update|Push", string(rune(temp_recipe.ID))+":"+temp_recipe.ProductCode))
}
// export
exported_filename := "coffeethai02_" + string(rune(new_file_version))
if countryID != "tha" {
exported_filename += "_" + countryID
}
exported_filename += ".json"
full_exported_path := "cofffeemachineConfig/" + countryID + "/" + exported_filename
outfile, _ := os.Create(full_exported_path)
target_recipe.MachineSetting.ConfigNumber = new_file_version
encoder := json.NewEncoder(outfile)
encoder.SetIndent("", " ")
err = encoder.Encode(target_recipe)
if err != nil {
rr.taoLogger.Log.Error("UpgradeToFullRecipeFailed", zap.Any("File", err))
http.Error(w, "Internal Error", http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"status": "OK",
"version": new_file_version,
"path": full_exported_path,
})
json.NewEncoder(w).Encode(rr.data.GetToppings(countryID, filename))
delete_files := legit_changes["del_after_upgrade"].(bool)
}
if delete_files && !show_to_current {
for seleted_file := range user_selected_tmp {
os.Remove(user_selected_tmp[seleted_file])
}
}
func (rr *RecipeRouter) getToppingsOfRecipe(w http.ResponseWriter, r *http.Request) {
// countryID := chi.URLParam(r, "country")
// filename := chi.URLParam(r, "filename")
// productCode := chi.URLParam(r, "product_code")
w.Header().Add("Content-Type", "application/json")
// all toppings
// allToppings := rr.data.GetToppings(countryID, filename)
// topps, err := rr.data.GetToppingsOfRecipe(countryID, filename, productCode)
// expandedToppings := map[string]interface{}{}
// for _, v := range allToppings.ToppingGroup {
// for _, t := range topps {
// if v.GroupID == t.ListGroupID[0] {
// expandedToppings[v.GroupID] = v
// break
// }
// }
// }
// if err != nil {
// http.Error(w, err.Error(), http.StatusNotFound)
// return
// }
// json.NewEncoder(w).Encode()
}
func (rr *RecipeRouter) doMergeJson(w http.ResponseWriter, r *http.Request) {

View file

@ -40,13 +40,20 @@ func (rs *recipeService) GetRecipeDetail(request *contracts.RecipeDetailRequest)
// DEBUG: picture
rs.taoLogger.Log.Debug("GetRecipeDetail", zap.String("picture", recipe.UriData))
uri_img := recipe.UriData
uri_img = strings.TrimPrefix(uri_img, "img=")
// if strings.HasPrefix(uri_img, "img=") {
// uri_img = uri_img[len("img="):]
// }
result := contracts.RecipeDetailResponse{
Name: recipe.Name,
OtherName: recipe.OtherName,
Description: recipe.Description,
OtherDescription: recipe.OtherDescription,
LastUpdated: recipe.LastChange,
Picture: recipe.UriData[len("img="):], // remove "img=" prefix
Picture: uri_img, // remove "img=" prefix
}
return result, nil
@ -60,6 +67,8 @@ func (rs *recipeService) GetRecipeDetailMat(request *contracts.RecipeDetailReque
return contracts.RecipeDetailMatListResponse{}, fmt.Errorf("country name: %s not found", request.Country)
}
// rs.taoLogger.Log.Debug("GetRecipeDetailMat", zap.Any("request", request))
recipe, err := rs.db.GetRecipe01ByProductCode(request.Filename, request.Country, request.ProductCode)
if err != nil {
@ -73,19 +82,46 @@ func (rs *recipeService) GetRecipeDetailMat(request *contracts.RecipeDetailReque
}
}
// rs.taoLogger.Log.Debug("GetRecipeDetailMat", zap.Any("matIds", matIds))
matsCode := rs.db.GetMaterialCode(matIds, countryID, request.Filename)
materials := []models.MaterialSetting{}
matsSetting := rs.db.GetMaterialSetting(countryID, request.Filename)
// rs.taoLogger.Log.Debug("GetRecipeDetailMat", zap.Any("matsSetting", matsSetting))
for _, v := range matsSetting {
// rs.taoLogger.Log.Debug("GetRecipeDetailMat,Iterate", zap.Any("mats", v.ID))
for _, mat := range matIds {
if v.ID == mat {
materials = append(materials, v)
break
}
}
}
// rs.taoLogger.Log.Debug("GetRecipeDetailMat", zap.Any("matsCode", materials))
result := contracts.RecipeDetailMatListResponse{
Result: []contracts.RecipeDetailMat{},
}
for _, v := range recipe.Recipes {
for _, mat := range matsCode {
if v.MaterialPathId == int(mat.MaterialID) {
for _, mat := range materials {
if v.MaterialPathId == int(mat.ID) {
mat_name := ""
for _, m := range matsCode {
if m.MaterialID == mat.ID {
mat_name = m.PackageDescription
break
}
}
result.Result = append(result.Result, contracts.RecipeDetailMat{
IsUse: v.IsUse,
MaterialID: mat.MaterialID,
Name: mat.PackageDescription,
MaterialID: mat.ID,
Name: mat_name,
MixOrder: v.MixOrder,
FeedParameter: v.FeedParameter,
FeedPattern: v.FeedPattern,
@ -103,6 +139,30 @@ func (rs *recipeService) GetRecipeDetailMat(request *contracts.RecipeDetailReque
}
}
// add padding until full 30
if len(result.Result) < 30 {
for i := len(result.Result); i < 30; i++ {
result.Result = append(result.Result, contracts.RecipeDetailMat{
IsUse: false,
MaterialID: 0,
Name: "",
MixOrder: 0,
FeedParameter: 0,
FeedPattern: 0,
MaterialPathId: 0,
PowderGram: 0,
PowderTime: 0,
StirTime: 0,
SyrupGram: 0,
SyrupTime: 0,
WaterCold: 0,
WaterYield: 0,
})
}
}
// rs.taoLogger.Log.Debug("GetRecipeDetailMat", zap.Any("result", result))
// sort by id
// sort.Slice(result.Result, func(i, j int) bool {
// return result.Result[i].MaterialID < result.Result[j].MaterialID