From 59de2e648e89a9a9285750ff601e368d23833fb6 Mon Sep 17 00:00:00 2001 From: Gowtham M Date: Fri, 14 Feb 2025 08:58:38 +0530 Subject: [PATCH] GWM : CARD calculation sum,avg,min,max,diff --- main.go | 100 ++++++++++++++++--- utils/card_calculation.go | 200 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 286 insertions(+), 14 deletions(-) create mode 100644 utils/card_calculation.go diff --git a/main.go b/main.go index d4bab9f..3216532 100644 --- a/main.go +++ b/main.go @@ -593,11 +593,9 @@ func main() { chartData = filterDynamicChartData(chartData, keyToFilter, valueToExclude) } - cRes := utils.ProcessChartData(chartData, languageSourceConverted, langKey) - + //logo url generating var logoURL string cardLogo := record.GetString("card_logo") - if cardLogo == "" { logoURL = "" } else { @@ -608,24 +606,75 @@ func main() { ) } + cResRaw := utils.ProcessChartData(chartData, languageSourceConverted, langKey) + + // Convert cResRaw ([]map[string]interface{}) to []utils.Observation + var cRes []utils.Observation + cResJSON, err := json.Marshal(cResRaw) + if err != nil { + fmt.Println("Error encoding chart data:", err) + } + err = json.Unmarshal(cResJSON, &cRes) + if err != nil { + fmt.Println("Error decoding chart data:", err) + } + + // card data calculation + var cardResults []map[string]string + if record.GetString("is_chart") == "false" { + + // Extract `card_type` JSON from `record.Get("card_type")` + requestData := record.Get("card_type") + requestJSON, err := json.Marshal(requestData) // Convert interface{} to JSON string + if err != nil { + fmt.Println("Error encoding request data:", err) + os.Exit(1) + } + + // Decode JSON into an array of `utils.Request` + var requests []utils.Request + err = json.Unmarshal(requestJSON, &requests) + if err != nil { + fmt.Println("Error decoding request data:", err) + os.Exit(1) + } + + // Process each request and store results + for _, req := range requests { + result, err := utils.Calculate(cRes, req) + if err != nil { + fmt.Println("Error processing data:", err) + continue // Skip this request and move to the next + } + cardResults = append(cardResults, result) + } + + } + chartHeadingKey := "chart_heading_" + language tabHeadingKey := "tab_heading_" + language - // Prepare the structure with URL and its response + // Correct conditional assignment for "response" recordResult := map[string]interface{}{ - "url": apiURL, - "dataset": record.GetString("dataset"), - "main_id": record.GetString("main_id"), - "sub_id": record.GetString("sub_id"), - "kpi": record.GetString("kpi"), - "is_chart": record.GetString("is_chart"), - "chart_type": record.GetString("chart_type"), - "response": cRes, + "url": apiURL, + "dataset": record.GetString("dataset"), + "main_id": record.GetString("main_id"), + "sub_id": record.GetString("sub_id"), + "kpi": record.GetString("kpi"), + "is_chart": record.GetString("is_chart"), + "chart_type": record.GetString("chart_type"), + // "response": record.GetString("is_chart") = true cRes : cardResults, "group_by": record.GetString("group_by"), "chart_heading": record.GetString(chartHeadingKey), "tab_heading": record.GetString(tabHeadingKey), "unset_value": record.Get("unset_value"), "card_logo": logoURL, "order_id": record.Get("order_id"), + "card_type": record.Get("card_type"), + } + if record.GetString("is_chart") == "true" { + recordResult["response"] = cRes + } else { + recordResult["response"] = cardResults } // Add the result to the aggregated response @@ -660,10 +709,32 @@ func main() { } //-------------------- + //mainTopic kpi heading and screen color + headingAndColor := struct { + DataSet string `db:"data_set" json:"data_set"` + MainTopic string `db:"main_topic" json:"main_topic"` + SubTopic string `db:"sub_topic" json:"sub_topic"` + DataSetTileHeading string `db:"data_set_tile_heading" json:"data_set_tile_heading"` + HeaderColor string `db:"header_color" json:"header_color"` + BodyColor string `db:"body_color" json:"body_color"` + BorderColor string `db:"border_color" json:"border_color"` + }{} + + data_set_tile_heading := "data_set_tile_heading_" + language + main_topic := "main_topic_" + language + sub_topic := "sub_topic_" + language + query := ` SELECT id,data_set,` + data_set_tile_heading + ` AS data_set_tile_heading,` + main_topic + ` AS main_topic,` + sub_topic + ` AS sub_topic,header_color,body_color,border_color FROM uae_numbers_screen WHERE data_set = {:data_set} ` + err = app.DB().NewQuery(query).Bind(dbx.Params{"data_set": dataset}).One(&headingAndColor) + if err != nil { + log.Printf("Failed to fetch data-set for sub topic %s: %v", dataset, err) + } + //--------------------- + // Create the response structure response := map[string]interface{}{ - "new_filter_data": aggregatedFilterResponse, - "data": aggregatedResponse, + "new_filter_data": aggregatedFilterResponse, + "data": aggregatedResponse, + "screen_heading_and_color": headingAndColor, } if len(aggregatedResponse) == 0 { @@ -932,6 +1003,7 @@ func main() { "bookmark": bookmark.Dataset, }). One(&dataSets) + log.Printf("query %s: %v", bookmark.Dataset, query) if err != nil { log.Printf("Failed to fetch data-set for sub topic %s: %v", bookmark.Dataset, err) diff --git a/utils/card_calculation.go b/utils/card_calculation.go new file mode 100644 index 0000000..c2c45ff --- /dev/null +++ b/utils/card_calculation.go @@ -0,0 +1,200 @@ +// utils/calculations.go +package utils + +import ( + "encoding/json" + "errors" + "fmt" + "sort" + "strconv" +) + +// Observation struct with json.Number for flexible value handling +type Observation struct { + ObsKey map[string]string `json:"ObsKey"` + ObsValue struct { + Value json.Number `json:"Value"` + } `json:"ObsValue"` +} + +type Request struct { + Formula string `json:"formula"` + RecordCount string `json:"record_count"` + RecodeIndex string `json:"record_index"` + RecordKey string `json:"record_key"` + NumberFormat string `json:"number_format"` + Conversion string `json:"conversion"` +} + +func Calculate(data []Observation, req Request) (map[string]string, error) { + // Sort the data in descending order based on TimePeriod + sort.Slice(data, func(i, j int) bool { + return data[i].ObsKey["TIME_PERIOD"] > data[j].ObsKey["TIME_PERIOD"] + }) + + var selectedData []Observation + if req.RecodeIndex != "" { + // Convert RecodeIndex to an integer + index, err := strconv.Atoi(req.RecodeIndex) + if err != nil || index < 0 || index >= len(data) { + return nil, errors.New("invalid record index") + } + // Select only the requested index record + selectedData = []Observation{data[index]} + + } else { + // Determine the number of records to use + n := len(data) // array leangth + if req.RecordCount != "all" { + var err error + n, err = strconv.Atoi(req.RecordCount) + if err != nil || n > len(data) { + return nil, errors.New("invalid record count") + } + } + selectedData = data[:n] + } + + var result float64 + switch req.Formula { + case "none": + result = none(selectedData) + case "total": + result = sum(selectedData) + case "average": + result = average(selectedData) + case "highest": + result = highest(selectedData) + case "lowest": + result = lowest(selectedData) + case "different": + result = difference(selectedData) + default: + return nil, errors.New("invalid formula") + } + + convertedValue := applyConversion(result, req.Conversion, req.NumberFormat) + displayValue := extractRecordKeyValue(selectedData, req.RecordKey, req.Formula, result) + + return map[string]string{ + "value": convertedValue, + "display_value": displayValue, + }, nil +} + +// Helper function to convert json.Number to float64 safely +func getFloatValue(num json.Number) float64 { + val, err := num.Float64() + if err != nil { + fmt.Println("Error converting value:", err) + return 0 + } + return val +} + +func none(data []Observation) float64 { + total := 0.0 + for _, obs := range data { + total += getFloatValue(obs.ObsValue.Value) + } + return total +} + +func sum(data []Observation) float64 { + total := 0.0 + for _, obs := range data { + total += getFloatValue(obs.ObsValue.Value) + } + return total +} + +func average(data []Observation) float64 { + if len(data) == 0 { + return 0 + } + return sum(data) / float64(len(data)) +} + +func highest(data []Observation) float64 { + max := getFloatValue(data[0].ObsValue.Value) + for _, obs := range data { + val := getFloatValue(obs.ObsValue.Value) + if val > max { + max = val + } + } + return max +} + +func lowest(data []Observation) float64 { + min := getFloatValue(data[0].ObsValue.Value) + for _, obs := range data { + val := getFloatValue(obs.ObsValue.Value) + if val < min { + min = val + } + } + return min +} + +func difference(data []Observation) float64 { + if len(data) < 2 { + return 0 + } + latest := getFloatValue(data[0].ObsValue.Value) + previous := getFloatValue(data[1].ObsValue.Value) + if previous == 0 { + return 0 + } + return ((latest - previous) / previous) * 100 +} + +func applyConversion(value float64, conversion string, numberFormat string) string { + + if numberFormat == "M" { + value *= 1000000 + } else if numberFormat == "T" { + value *= 1000000000000 + } else if numberFormat == "K" { + value *= 1000 + } + + switch conversion { + case "M": + return fmt.Sprintf("%.2fM", value/1000000) + case "T": + return fmt.Sprintf("%.2fT", value/1000000000000) + case "K": + return fmt.Sprintf("%.2fK", value/1000) + case "%": + return fmt.Sprintf("%.2f%%", value) + default: + return fmt.Sprintf("%.2f", value) + } +} + +func extractRecordKeyValue(data []Observation, key string, formula string, targetValue float64) string { + if len(data) == 0 { + return "" + } + + switch formula { + case "highest", "lowest", "none": + for _, obs := range data { + value, err := obs.ObsValue.Value.Float64() + if err == nil && value == targetValue { + if val, exists := obs.ObsKey[key]; exists { + return val + } + } + } + case "total", "average", "different": + if val1, exists1 := data[0].ObsKey[key]; exists1 { + if val2, exists2 := data[len(data)-1].ObsKey[key]; exists2 { + return val1 + " - " + val2 + } + return val1 + } + } + return "" +}