@@ -0,0 +1,929 @@
package routes
import (
"bssapp-backend/models"
"bssapp-backend/queries"
"bssapp-backend/utils"
"context"
"database/sql"
"encoding/json"
"fmt"
"math"
"net/http"
"sort"
"strings"
"time"
"github.com/xuri/excelize/v2"
)
type productPerformanceExcelExportRequest struct {
Filters map [ string ] [ ] string ` json:"filters" `
SortBy string ` json:"sort_by" `
Descending * bool ` json:"descending" `
}
type productPerformanceExcelColumn struct {
Header string
Kind string
Value func ( models . ProductPerformanceRow , models . ProductPerformanceGeneralRow , productPerformanceExcelStats ) any
}
type productPerformanceExcelStats struct {
AvgSalesUSD90 float64
AvgSalesUSD180 float64
AvgSalesUSD365 float64
AvgSalesUSDTotal float64
}
func ExportProductPerformanceExcelHandler ( pg * sql . DB ) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
traceID := utils . TraceIDFromRequest ( r )
ctx , cancel := context . WithTimeout ( utils . ContextWithTraceID ( r . Context ( ) , traceID ) , 180 * time . Second )
defer cancel ( )
var req productPerformanceExcelExportRequest
if r . Method == http . MethodPost {
if err := json . NewDecoder ( r . Body ) . Decode ( & req ) ; err != nil {
http . Error ( w , "gecersiz excel istegi: " + err . Error ( ) , http . StatusBadRequest )
return
}
}
rows , _ , err := queries . ListProductPerformance ( ctx , pg , queries . ProductPerformanceFilters {
Limit : 50000 ,
Page : 1 ,
SortBy : "product_code" ,
Descending : false ,
} )
if err != nil {
http . Error ( w , "urun performans excel listesi alinamadi: " + err . Error ( ) , http . StatusInternalServerError )
return
}
generalRows , err := queries . ListProductPerformanceGeneral ( ctx , pg , 50000 )
if err != nil {
http . Error ( w , "urun performans genel excel listesi alinamadi: " + err . Error ( ) , http . StatusInternalServerError )
return
}
generalByKey := productPerformanceExcelGeneralMap ( generalRows )
rows = filterProductPerformanceExcelRows ( rows , generalByKey , req . Filters )
sortProductPerformanceExcelRows ( rows , generalByKey , req . SortBy , req . Descending == nil || * req . Descending )
stats := productPerformanceExcelStatsFor ( rows , generalByKey )
file , err := buildProductPerformanceExcelFile ( rows , generalByKey , stats )
if err != nil {
http . Error ( w , "urun performans excel dosyasi hazirlanamadi: " + err . Error ( ) , http . StatusInternalServerError )
return
}
defer func ( ) { _ = file . Close ( ) } ( )
buf , err := file . WriteToBuffer ( )
if err != nil {
http . Error ( w , err . Error ( ) , http . StatusInternalServerError )
return
}
filename := fmt . Sprintf ( "product_performance_color_yaka_%s.xlsx" , time . Now ( ) . Format ( "20060102_150405" ) )
w . Header ( ) . Set ( "Content-Type" , "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" )
w . Header ( ) . Set ( "Content-Disposition" , "attachment; filename=\"" + filename + "\"" )
w . Header ( ) . Set ( "Content-Length" , fmt . Sprint ( len ( buf . Bytes ( ) ) ) )
w . WriteHeader ( http . StatusOK )
_ , _ = w . Write ( buf . Bytes ( ) )
}
}
func buildProductPerformanceExcelFile ( rows [ ] models . ProductPerformanceRow , generalByKey map [ string ] models . ProductPerformanceGeneralRow , stats productPerformanceExcelStats ) ( * excelize . File , error ) {
f := excelize . NewFile ( )
sheet := "RenkYaka"
f . SetSheetName ( "Sheet1" , sheet )
columns := productPerformanceExcelColumns ( )
headerStyle , _ := f . NewStyle ( & excelize . Style {
Font : & excelize . Font { Bold : true , Color : "FFFFFF" } ,
Fill : excelize . Fill { Type : "pattern" , Pattern : 1 , Color : [ ] string { "1F4E78" } } ,
Alignment : & excelize . Alignment { Horizontal : "center" , Vertical : "center" , WrapText : true } ,
} )
textStyle , _ := f . NewStyle ( & excelize . Style { NumFmt : 49 } )
intStyle , _ := f . NewStyle ( & excelize . Style { NumFmt : 3 } )
decimalStyle , _ := f . NewStyle ( & excelize . Style { NumFmt : 4 } )
percentStyle , _ := f . NewStyle ( & excelize . Style { NumFmt : 10 } )
for i , col := range columns {
cell , _ := excelize . CoordinatesToCellName ( i + 1 , 1 )
_ = f . SetCellStr ( sheet , cell , col . Header )
}
if len ( columns ) > 0 {
lastHeader , _ := excelize . CoordinatesToCellName ( len ( columns ) , 1 )
_ = f . SetCellStyle ( sheet , "A1" , lastHeader , headerStyle )
}
for rowIndex , row := range rows {
excelRow := rowIndex + 2
general := generalByKey [ productPerformanceExcelVariantKey ( row . ProductCode , row . ColorCode , row . YakaKodu ) ]
for colIndex , col := range columns {
cell , _ := excelize . CoordinatesToCellName ( colIndex + 1 , excelRow )
value := col . Value ( row , general , stats )
switch col . Kind {
case "text" :
_ = f . SetCellStr ( sheet , cell , strings . TrimSpace ( fmt . Sprint ( value ) ) )
default :
_ = f . SetCellValue ( sheet , cell , productPerformanceExcelFloat ( value ) )
}
}
}
lastRow := len ( rows ) + 1
if len ( columns ) > 0 {
filterLastRow := lastRow
if filterLastRow < 2 {
filterLastRow = 2
}
lastFilterCell , _ := excelize . CoordinatesToCellName ( len ( columns ) , filterLastRow )
_ = f . AutoFilter ( sheet , "A1:" + lastFilterCell , [ ] excelize . AutoFilterOptions { } )
}
for i , col := range columns {
colName , _ := excelize . ColumnNumberToName ( i + 1 )
width := productPerformanceExcelColumnWidth ( col . Header , col . Kind )
_ = f . SetColWidth ( sheet , colName , colName , width )
if lastRow >= 2 {
style := decimalStyle
switch col . Kind {
case "text" :
style = textStyle
case "int" :
style = intStyle
case "percent" :
style = percentStyle
}
_ = f . SetCellStyle ( sheet , fmt . Sprintf ( "%s2" , colName ) , fmt . Sprintf ( "%s%d" , colName , lastRow ) , style )
}
}
_ = f . SetPanes ( sheet , & excelize . Panes {
Freeze : true ,
Split : false ,
XSplit : 0 ,
YSplit : 1 ,
TopLeftCell : "A2" ,
ActivePane : "bottomLeft" ,
} )
return f , nil
}
func productPerformanceExcelColumns ( ) [ ] productPerformanceExcelColumn {
return [ ] productPerformanceExcelColumn {
{ Header : "KPI Tarihi" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . KpiDate
} } ,
{ Header : "Ürün İlk Grubu" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelCleanOptional ( r . UrunIlkGrubu )
} } ,
{ Header : "Askı lı /Yan" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelCleanOptional ( r . AskiliYan )
} } ,
{ Header : "Kategori" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . Kategori
} } ,
{ Header : "Ürün Ana Grubu" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . UrunAnaGrubu
} } ,
{ Header : "Ürün Alt Grubu" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . UrunAltGrubu
} } ,
{ Header : "Ürün" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . ProductCode
} } ,
{ Header : "Açıklama" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . ItemDescription
} } ,
{ Header : "Renk" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . ColorCode
} } ,
{ Header : "Renk Açıklama" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . ColorDescription
} } ,
{ Header : "Yaka" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . YakaKodu
} } ,
{ Header : "Renk/Yaka" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelColorYaka ( r )
} } ,
{ Header : "Toplam Stok" , Kind : "int" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . StockQty
} } ,
{ Header : "90G Toplam Adet" , Kind : "int" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . SalesQty90
} } ,
{ Header : "90G Toplam Ciro USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . SalesUSD90
} } ,
{ Header : "90G Ağ. Ort. Fiyat USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelAvgPrice ( r . SalesUSD90 , r . SalesQty90 )
} } ,
{ Header : "90G Ağ. Ort. Stok Gün" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . StockDays90
} } ,
{ Header : "90G Stok Devir" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelFirstNonZero ( r . StockTurnover90 , productPerformanceExcelStockTurnover ( r . SalesQty90 , r . StockQty ) )
} } ,
{ Header : "90G Ort. Taban Maliyet USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . BasePriceUSD
} } ,
{ Header : "90G Ort. Çıplak Maliyet USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . CostPriceUSD
} } ,
{ Header : "90G Ağ. Ort. Birim Taban K/Z USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelUnitProfit ( r . SalesUSD90 , r . SalesQty90 , r . BasePriceUSD )
} } ,
{ Header : "90G Ağ. Ort. Birim Çıplak K/Z USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelUnitProfit ( r . SalesUSD90 , r . SalesQty90 , r . CostPriceUSD )
} } ,
{ Header : "90G Taban Toplam K/Z USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelGrossProfit ( r . SalesUSD90 , r . SalesQty90 , r . BasePriceUSD )
} } ,
{ Header : "90G Çıplak Toplam K/Z USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelGrossProfit ( r . SalesUSD90 , r . SalesQty90 , r . CostPriceUSD )
} } ,
{ Header : "90G Taban Marj" , Kind : "percent" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelMargin ( r . SalesUSD90 , r . SalesQty90 , r . BasePriceUSD )
} } ,
{ Header : "90G Çıplak Marj" , Kind : "percent" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelMargin ( r . SalesUSD90 , r . SalesQty90 , r . CostPriceUSD )
} } ,
{ Header : "90G Tekil Piyasa" , Kind : "int" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . MarketCount90
} } ,
{ Header : "90G Tekil Müşteri" , Kind : "int" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . CustomerCount90
} } ,
{ Header : "90G Endeks" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , stats productPerformanceExcelStats ) any {
return productPerformanceExcelFirstNonZero ( r . SalesIndex90 , productPerformanceExcelRelativeIndex ( r . SalesUSD90 , stats . AvgSalesUSD90 ) )
} } ,
{ Header : "90G Ürün Skor" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , stats productPerformanceExcelStats ) any {
if strings . TrimSpace ( r . PerformanceBucket ) != "" {
return r . PerformanceScore
}
return productPerformanceExcelProductScore ( "90d" , r . SalesUSD90 , productPerformanceExcelRelativeIndex ( r . SalesUSD90 , stats . AvgSalesUSD90 ) , productPerformanceExcelMargin ( r . SalesUSD90 , r . SalesQty90 , r . CostPriceUSD ) , productPerformanceExcelStockTurnover ( r . SalesQty90 , r . StockQty ) , float64 ( r . MarketCount90 ) , float64 ( r . CustomerCount90 ) )
} } ,
{ Header : "180G Toplam Adet" , Kind : "int" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . SalesQty180
} } ,
{ Header : "180G Toplam Ciro USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . SalesUSD180
} } ,
{ Header : "180G Ağ. Ort. Fiyat USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelAvgPrice ( r . SalesUSD180 , r . SalesQty180 )
} } ,
{ Header : "180G Ağ. Ort. Stok Gün" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . StockDays180
} } ,
{ Header : "180G Stok Devir" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelFirstNonZero ( r . StockTurnover180 , productPerformanceExcelStockTurnover ( r . SalesQty180 , r . StockQty ) )
} } ,
{ Header : "180G Ort. Taban Maliyet USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . BasePriceUSD
} } ,
{ Header : "180G Ort. Çıplak Maliyet USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . CostPriceUSD
} } ,
{ Header : "180G Taban Toplam K/Z USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelGrossProfit ( r . SalesUSD180 , r . SalesQty180 , r . BasePriceUSD )
} } ,
{ Header : "180G Çıplak Toplam K/Z USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelGrossProfit ( r . SalesUSD180 , r . SalesQty180 , r . CostPriceUSD )
} } ,
{ Header : "180G Taban Marj" , Kind : "percent" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelMargin ( r . SalesUSD180 , r . SalesQty180 , r . BasePriceUSD )
} } ,
{ Header : "180G Çıplak Marj" , Kind : "percent" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelMargin ( r . SalesUSD180 , r . SalesQty180 , r . CostPriceUSD )
} } ,
{ Header : "180G Ürün Skor" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , stats productPerformanceExcelStats ) any {
return productPerformanceExcelProductScore ( "180d" , r . SalesUSD180 , productPerformanceExcelRelativeIndex ( r . SalesUSD180 , stats . AvgSalesUSD180 ) , productPerformanceExcelMargin ( r . SalesUSD180 , r . SalesQty180 , r . CostPriceUSD ) , productPerformanceExcelStockTurnover ( r . SalesQty180 , r . StockQty ) , productPerformanceExcelFirstNonZero ( float64 ( g . MarketCountTotal ) , float64 ( r . MarketCount90 ) ) , productPerformanceExcelFirstNonZero ( float64 ( g . CustomerCountTotal ) , float64 ( r . CustomerCount90 ) ) )
} } ,
{ Header : "360G Toplam Adet" , Kind : "int" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . SalesQty365
} } ,
{ Header : "360G Toplam Ciro USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . SalesUSD365
} } ,
{ Header : "360G Ağ. Ort. Fiyat USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelAvgPrice ( r . SalesUSD365 , r . SalesQty365 )
} } ,
{ Header : "360G Ağ. Ort. Stok Gün" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . StockDays365
} } ,
{ Header : "360G Stok Devir" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelFirstNonZero ( r . StockTurnover365 , productPerformanceExcelStockTurnover ( r . SalesQty365 , r . StockQty ) )
} } ,
{ Header : "360G Ort. Taban Maliyet USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . BasePriceUSD
} } ,
{ Header : "360G Ort. Çıplak Maliyet USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . CostPriceUSD
} } ,
{ Header : "360G Taban Toplam K/Z USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelGrossProfit ( r . SalesUSD365 , r . SalesQty365 , r . BasePriceUSD )
} } ,
{ Header : "360G Çıplak Toplam K/Z USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelGrossProfit ( r . SalesUSD365 , r . SalesQty365 , r . CostPriceUSD )
} } ,
{ Header : "360G Taban Marj" , Kind : "percent" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelMargin ( r . SalesUSD365 , r . SalesQty365 , r . BasePriceUSD )
} } ,
{ Header : "360G Çıplak Marj" , Kind : "percent" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelMargin ( r . SalesUSD365 , r . SalesQty365 , r . CostPriceUSD )
} } ,
{ Header : "360G Ürün Skor" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , stats productPerformanceExcelStats ) any {
return productPerformanceExcelProductScore ( "365d" , r . SalesUSD365 , productPerformanceExcelRelativeIndex ( r . SalesUSD365 , stats . AvgSalesUSD365 ) , productPerformanceExcelMargin ( r . SalesUSD365 , r . SalesQty365 , r . CostPriceUSD ) , productPerformanceExcelStockTurnover ( r . SalesQty365 , r . StockQty ) , productPerformanceExcelFirstNonZero ( float64 ( g . MarketCountTotal ) , float64 ( r . MarketCount90 ) ) , productPerformanceExcelFirstNonZero ( float64 ( g . CustomerCountTotal ) , float64 ( r . CustomerCount90 ) ) )
} } ,
{ Header : "Genel Toplam Adet" , Kind : "int" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelTotalSalesQty ( r , g )
} } ,
{ Header : "Genel Toplam Ciro USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelTotalSalesUSD ( r , g )
} } ,
{ Header : "Genel Ağ. Ort. Fiyat USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelFirstNonZero ( g . AvgPriceUSDTotal , productPerformanceExcelAvgPrice ( productPerformanceExcelTotalSalesUSD ( r , g ) , productPerformanceExcelTotalSalesQty ( r , g ) ) )
} } ,
{ Header : "Genel Ağ. Ort. Stok Gün" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelFirstNonZero ( g . StockDaysTotal , r . StockDaysTotal )
} } ,
{ Header : "Genel Stok Devir" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelFirstNonZero ( r . StockTurnoverTotal , productPerformanceExcelStockTurnover ( productPerformanceExcelTotalSalesQty ( r , g ) , r . StockQty ) )
} } ,
{ Header : "Genel Ort. Taban Maliyet USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelFirstNonZero ( g . BasePriceUSD , r . BasePriceUSD )
} } ,
{ Header : "Genel Ort. Çıplak Maliyet USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelFirstNonZero ( g . CostPriceUSD , r . CostPriceUSD )
} } ,
{ Header : "Genel Taban Toplam K/Z USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelGrossProfit ( productPerformanceExcelTotalSalesUSD ( r , g ) , productPerformanceExcelTotalSalesQty ( r , g ) , productPerformanceExcelFirstNonZero ( g . BasePriceUSD , r . BasePriceUSD ) )
} } ,
{ Header : "Genel Çıplak Toplam K/Z USD" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelGrossProfit ( productPerformanceExcelTotalSalesUSD ( r , g ) , productPerformanceExcelTotalSalesQty ( r , g ) , productPerformanceExcelFirstNonZero ( g . CostPriceUSD , r . CostPriceUSD ) )
} } ,
{ Header : "Genel Taban Marj" , Kind : "percent" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelMargin ( productPerformanceExcelTotalSalesUSD ( r , g ) , productPerformanceExcelTotalSalesQty ( r , g ) , productPerformanceExcelFirstNonZero ( g . BasePriceUSD , r . BasePriceUSD ) )
} } ,
{ Header : "Genel Çıplak Marj" , Kind : "percent" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelMargin ( productPerformanceExcelTotalSalesUSD ( r , g ) , productPerformanceExcelTotalSalesQty ( r , g ) , productPerformanceExcelFirstNonZero ( g . CostPriceUSD , r . CostPriceUSD ) )
} } ,
{ Header : "Genel Tekil Piyasa" , Kind : "int" , Value : func ( _ models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return g . MarketCountTotal
} } ,
{ Header : "Genel Tekil Müşteri" , Kind : "int" , Value : func ( _ models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return g . CustomerCountTotal
} } ,
{ Header : "Genel Fatura" , Kind : "int" , Value : func ( _ models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return g . InvoiceCountTotal
} } ,
{ Header : "Genel Endeks" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , stats productPerformanceExcelStats ) any {
return productPerformanceExcelFirstNonZero ( g . SalesIndexTotal , productPerformanceExcelRelativeIndex ( productPerformanceExcelTotalSalesUSD ( r , g ) , stats . AvgSalesUSDTotal ) )
} } ,
{ Header : "Genel Ürün Skor" , Kind : "number" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , stats productPerformanceExcelStats ) any {
if strings . TrimSpace ( g . PerformanceBucket ) != "" {
return g . PerformanceScore
}
return productPerformanceExcelProductScore ( "total" , productPerformanceExcelTotalSalesUSD ( r , g ) , productPerformanceExcelRelativeIndex ( productPerformanceExcelTotalSalesUSD ( r , g ) , stats . AvgSalesUSDTotal ) , productPerformanceExcelMargin ( productPerformanceExcelTotalSalesUSD ( r , g ) , productPerformanceExcelTotalSalesQty ( r , g ) , productPerformanceExcelFirstNonZero ( g . CostPriceUSD , r . CostPriceUSD ) ) , productPerformanceExcelStockTurnover ( productPerformanceExcelTotalSalesQty ( r , g ) , r . StockQty ) , float64 ( g . MarketCountTotal ) , float64 ( g . CustomerCountTotal ) )
} } ,
{ Header : "Durum" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelBucketLabel ( productPerformanceExcelFirstNonEmpty ( g . PerformanceBucket , r . PerformanceBucket ) )
} } ,
{ Header : "Öneri" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelFirstNonEmpty ( g . Recommendation , r . Recommendation )
} } ,
{ Header : "Son Satış" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelFirstNonEmpty ( g . LastSaleDate , r . LastSaleDate )
} } ,
{ Header : "Son Ref" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , g models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return productPerformanceExcelFirstNonEmpty ( g . LastRefNumber , r . LastRefNumber )
} } ,
{ Header : "Güncelleme" , Kind : "text" , Value : func ( r models . ProductPerformanceRow , _ models . ProductPerformanceGeneralRow , _ productPerformanceExcelStats ) any {
return r . UpdatedAt
} } ,
}
}
func productPerformanceExcelGeneralMap ( rows [ ] models . ProductPerformanceGeneralRow ) map [ string ] models . ProductPerformanceGeneralRow {
out := make ( map [ string ] models . ProductPerformanceGeneralRow , len ( rows ) )
for _ , row := range rows {
out [ productPerformanceExcelVariantKey ( row . ProductCode , row . ColorCode , row . YakaKodu ) ] = row
}
return out
}
func filterProductPerformanceExcelRows ( rows [ ] models . ProductPerformanceRow , generalByKey map [ string ] models . ProductPerformanceGeneralRow , filters map [ string ] [ ] string ) [ ] models . ProductPerformanceRow {
if len ( filters ) == 0 {
return rows
}
out := make ( [ ] models . ProductPerformanceRow , 0 , len ( rows ) )
for _ , row := range rows {
general := generalByKey [ productPerformanceExcelVariantKey ( row . ProductCode , row . ColorCode , row . YakaKodu ) ]
if productPerformanceExcelRowMatchesFilters ( row , general , filters ) {
out = append ( out , row )
}
}
return out
}
func productPerformanceExcelRowMatchesFilters ( row models . ProductPerformanceRow , general models . ProductPerformanceGeneralRow , filters map [ string ] [ ] string ) bool {
for field , values := range filters {
selected := productPerformanceExcelSelectedSet ( values )
if len ( selected ) == 0 {
continue
}
matched := false
for _ , candidate := range productPerformanceExcelFilterCandidates ( row , general , field ) {
if selected [ productPerformanceExcelNormalize ( candidate ) ] {
matched = true
break
}
}
if ! matched {
return false
}
}
return true
}
func productPerformanceExcelSelectedSet ( values [ ] string ) map [ string ] bool {
out := make ( map [ string ] bool , len ( values ) )
for _ , value := range values {
value = productPerformanceExcelNormalize ( value )
if value != "" {
out [ value ] = true
}
}
return out
}
func productPerformanceExcelFilterCandidates ( row models . ProductPerformanceRow , general models . ProductPerformanceGeneralRow , field string ) [ ] string {
switch strings . TrimSpace ( field ) {
case "product_code" :
return [ ] string { row . ProductCode }
case "item_description" :
return [ ] string { row . ItemDescription }
case "color_code" :
return [ ] string { row . ColorCode }
case "yaka_kodu" :
return [ ] string { row . YakaKodu }
case "color_yaka" :
return [ ] string { productPerformanceExcelColorYaka ( row ) , row . ColorCode + "/" + row . YakaKodu }
case "kategori" :
return [ ] string { row . Kategori }
case "askili_yan" :
return [ ] string { productPerformanceExcelCleanOptional ( row . AskiliYan ) }
case "urun_ilk_grubu" :
return [ ] string { productPerformanceExcelCleanOptional ( row . UrunIlkGrubu ) }
case "urun_ana_grubu" :
return [ ] string { productPerformanceExcelFirstNonEmpty ( general . UrunAnaGrubu , row . UrunAnaGrubu ) }
case "urun_alt_grubu" :
return [ ] string { row . UrunAltGrubu }
case "market_key" :
return [ ] string { row . MarketKey , productPerformanceExcelMarketName ( row . MarketKey ) }
case "performance_bucket" :
bucket := productPerformanceExcelFirstNonEmpty ( general . PerformanceBucket , row . PerformanceBucket )
return [ ] string { bucket , productPerformanceExcelBucketLabel ( bucket ) }
default :
return nil
}
}
func sortProductPerformanceExcelRows ( rows [ ] models . ProductPerformanceRow , generalByKey map [ string ] models . ProductPerformanceGeneralRow , sortBy string , desc bool ) {
sortBy = strings . TrimSpace ( sortBy )
if sortBy == "" || sortBy == "image" {
sortBy = "product_code"
desc = false
}
sort . SliceStable ( rows , func ( i , j int ) bool {
left := rows [ i ]
right := rows [ j ]
leftGen := generalByKey [ productPerformanceExcelVariantKey ( left . ProductCode , left . ColorCode , left . YakaKodu ) ]
rightGen := generalByKey [ productPerformanceExcelVariantKey ( right . ProductCode , right . ColorCode , right . YakaKodu ) ]
cmp := productPerformanceExcelCompareSort ( left , leftGen , right , rightGen , sortBy )
if cmp == 0 {
cmp = strings . Compare ( productPerformanceExcelHierarchySortKey ( left ) , productPerformanceExcelHierarchySortKey ( right ) )
}
if desc {
return cmp > 0
}
return cmp < 0
} )
}
func productPerformanceExcelCompareSort ( left models . ProductPerformanceRow , leftGen models . ProductPerformanceGeneralRow , right models . ProductPerformanceRow , rightGen models . ProductPerformanceGeneralRow , sortBy string ) int {
leftNum , rightNum , numeric := productPerformanceExcelSortNumeric ( left , leftGen , sortBy ) , productPerformanceExcelSortNumeric ( right , rightGen , sortBy ) , productPerformanceExcelIsNumericSort ( sortBy )
if numeric {
if leftNum < rightNum {
return - 1
}
if leftNum > rightNum {
return 1
}
return 0
}
leftText := productPerformanceExcelSortText ( left , leftGen , sortBy )
rightText := productPerformanceExcelSortText ( right , rightGen , sortBy )
return strings . Compare ( productPerformanceExcelNormalize ( leftText ) , productPerformanceExcelNormalize ( rightText ) )
}
func productPerformanceExcelIsNumericSort ( sortBy string ) bool {
switch sortBy {
case "stock_qty" , "sales_qty_90d" , "sales_qty_180d" , "sales_qty_365d" , "sales_qty_total" ,
"sales_usd_90d" , "sales_usd_180d" , "sales_usd_365d" , "sales_usd_total" ,
"avg_price_usd_90d" , "avg_price_usd_180d" , "avg_price_usd_365d" , "avg_price_usd_total" ,
"stock_days_90d" , "stock_days_180d" , "stock_days_365d" , "stock_days_total" ,
"stock_turnover_90d" , "stock_turnover_180d" , "stock_turnover_365d" , "stock_turnover_total" ,
"base_price_usd" , "cost_price_usd" , "market_count_90d" , "customer_count_90d" , "market_count_total" , "customer_count_total" ,
"sales_index_90d" , "sales_index_total" , "performance_score" , "performance_score_90d" , "performance_score_total" :
return true
default :
return false
}
}
func productPerformanceExcelSortNumeric ( row models . ProductPerformanceRow , general models . ProductPerformanceGeneralRow , sortBy string ) float64 {
switch sortBy {
case "stock_qty" :
return row . StockQty
case "sales_qty_90d" :
return row . SalesQty90
case "sales_qty_180d" :
return row . SalesQty180
case "sales_qty_365d" :
return row . SalesQty365
case "sales_qty_total" :
return productPerformanceExcelTotalSalesQty ( row , general )
case "sales_usd_90d" :
return row . SalesUSD90
case "sales_usd_180d" :
return row . SalesUSD180
case "sales_usd_365d" :
return row . SalesUSD365
case "sales_usd_total" :
return productPerformanceExcelTotalSalesUSD ( row , general )
case "avg_price_usd_90d" :
return productPerformanceExcelAvgPrice ( row . SalesUSD90 , row . SalesQty90 )
case "avg_price_usd_180d" :
return productPerformanceExcelAvgPrice ( row . SalesUSD180 , row . SalesQty180 )
case "avg_price_usd_365d" :
return productPerformanceExcelAvgPrice ( row . SalesUSD365 , row . SalesQty365 )
case "avg_price_usd_total" :
return productPerformanceExcelFirstNonZero ( general . AvgPriceUSDTotal , productPerformanceExcelAvgPrice ( productPerformanceExcelTotalSalesUSD ( row , general ) , productPerformanceExcelTotalSalesQty ( row , general ) ) )
case "stock_days_90d" :
return row . StockDays90
case "stock_days_180d" :
return row . StockDays180
case "stock_days_365d" :
return row . StockDays365
case "stock_days_total" :
return productPerformanceExcelFirstNonZero ( general . StockDaysTotal , row . StockDaysTotal )
case "stock_turnover_90d" :
return row . StockTurnover90
case "stock_turnover_180d" :
return row . StockTurnover180
case "stock_turnover_365d" :
return row . StockTurnover365
case "stock_turnover_total" :
return row . StockTurnoverTotal
case "base_price_usd" :
return productPerformanceExcelFirstNonZero ( general . BasePriceUSD , row . BasePriceUSD )
case "cost_price_usd" :
return productPerformanceExcelFirstNonZero ( general . CostPriceUSD , row . CostPriceUSD )
case "market_count_90d" :
return float64 ( row . MarketCount90 )
case "customer_count_90d" :
return float64 ( row . CustomerCount90 )
case "market_count_total" :
return float64 ( general . MarketCountTotal )
case "customer_count_total" :
return float64 ( general . CustomerCountTotal )
case "sales_index_90d" :
return row . SalesIndex90
case "sales_index_total" :
return general . SalesIndexTotal
case "performance_score" , "performance_score_90d" :
return row . PerformanceScore
case "performance_score_total" :
return general . PerformanceScore
default :
return 0
}
}
func productPerformanceExcelSortText ( row models . ProductPerformanceRow , general models . ProductPerformanceGeneralRow , sortBy string ) string {
switch sortBy {
case "product_code" :
return row . ProductCode
case "color_yaka" :
return productPerformanceExcelColorYaka ( row )
case "color_code" :
return row . ColorCode
case "yaka_kodu" :
return row . YakaKodu
case "item_description" :
return row . ItemDescription
case "kategori" :
return row . Kategori
case "askili_yan" :
return productPerformanceExcelCleanOptional ( row . AskiliYan )
case "urun_ilk_grubu" :
return productPerformanceExcelCleanOptional ( row . UrunIlkGrubu )
case "urun_ana_grubu" :
return productPerformanceExcelFirstNonEmpty ( general . UrunAnaGrubu , row . UrunAnaGrubu )
case "urun_alt_grubu" :
return row . UrunAltGrubu
case "market_key" :
return productPerformanceExcelMarketName ( row . MarketKey )
case "performance_bucket" :
return productPerformanceExcelBucketLabel ( productPerformanceExcelFirstNonEmpty ( general . PerformanceBucket , row . PerformanceBucket ) )
default :
return productPerformanceExcelHierarchySortKey ( row )
}
}
func productPerformanceExcelHierarchySortKey ( row models . ProductPerformanceRow ) string {
return strings . Join ( [ ] string {
productPerformanceExcelCleanOptional ( row . UrunIlkGrubu ) ,
productPerformanceExcelCleanOptional ( row . AskiliYan ) ,
row . Kategori ,
row . UrunAnaGrubu ,
row . UrunAltGrubu ,
row . ProductCode ,
row . ColorCode ,
row . YakaKodu ,
} , "|" )
}
func productPerformanceExcelStatsFor ( rows [ ] models . ProductPerformanceRow , generalByKey map [ string ] models . ProductPerformanceGeneralRow ) productPerformanceExcelStats {
var stats productPerformanceExcelStats
var c90 , c180 , c365 , cTotal float64
for _ , row := range rows {
general := generalByKey [ productPerformanceExcelVariantKey ( row . ProductCode , row . ColorCode , row . YakaKodu ) ]
if row . SalesUSD90 > 0 {
stats . AvgSalesUSD90 += row . SalesUSD90
c90 ++
}
if row . SalesUSD180 > 0 {
stats . AvgSalesUSD180 += row . SalesUSD180
c180 ++
}
if row . SalesUSD365 > 0 {
stats . AvgSalesUSD365 += row . SalesUSD365
c365 ++
}
if total := productPerformanceExcelTotalSalesUSD ( row , general ) ; total > 0 {
stats . AvgSalesUSDTotal += total
cTotal ++
}
}
if c90 > 0 {
stats . AvgSalesUSD90 /= c90
}
if c180 > 0 {
stats . AvgSalesUSD180 /= c180
}
if c365 > 0 {
stats . AvgSalesUSD365 /= c365
}
if cTotal > 0 {
stats . AvgSalesUSDTotal /= cTotal
}
return stats
}
func productPerformanceExcelVariantKey ( productCode , colorCode , yakaKodu string ) string {
return strings . ToUpper ( strings . TrimSpace ( productCode ) ) + "|" + strings . ToUpper ( strings . TrimSpace ( colorCode ) ) + "|" + strings . ToUpper ( strings . TrimSpace ( yakaKodu ) )
}
func productPerformanceExcelColorYaka ( row models . ProductPerformanceRow ) string {
color := strings . TrimSpace ( row . ColorCode )
if desc := strings . TrimSpace ( row . ColorDescription ) ; color != "" && desc != "" {
color = color + "-" + strings . ToUpper ( desc )
}
yaka := strings . TrimSpace ( row . YakaKodu )
parts := make ( [ ] string , 0 , 2 )
if color != "" && color != "-" {
parts = append ( parts , color )
}
if yaka != "" && yaka != "-" {
parts = append ( parts , yaka )
}
return strings . Join ( parts , "/" )
}
func productPerformanceExcelMarketName ( value string ) string {
parts := strings . Split ( value , "|" )
for i := len ( parts ) - 1 ; i >= 0 ; i -- {
part := strings . TrimSpace ( parts [ i ] )
if part != "" {
return part
}
}
return ""
}
func productPerformanceExcelBucketLabel ( value string ) string {
switch strings . TrimSpace ( value ) {
case "YILDIZ_URUN" :
return "Yı ldı z Ürün"
case "STOKSUZ_TALEP" :
return "Stoksuz Talep"
case "STOK_RISKI" :
return "Stok Riski"
case "FIYAT_BASKISI" :
return "Fiyat Baskı sı "
case "FIYAT_FIRSATI" :
return "Fiyat Fı rsatı "
case "MALIYET_YOK" :
return "Maliyet Yok"
case "TAKIP" :
return "Takip"
default :
return strings . TrimSpace ( value )
}
}
func productPerformanceExcelCleanOptional ( value string ) string {
value = strings . TrimSpace ( value )
if value == "-" {
return ""
}
return value
}
func productPerformanceExcelNormalize ( value string ) string {
return strings . ToUpper ( strings . TrimSpace ( value ) )
}
func productPerformanceExcelFirstNonEmpty ( values ... string ) string {
for _ , value := range values {
value = strings . TrimSpace ( value )
if value != "" {
return value
}
}
return ""
}
func productPerformanceExcelFirstNonZero ( values ... float64 ) float64 {
for _ , value := range values {
if value != 0 && ! math . IsNaN ( value ) && ! math . IsInf ( value , 0 ) {
return value
}
}
return 0
}
func productPerformanceExcelTotalSalesQty ( row models . ProductPerformanceRow , general models . ProductPerformanceGeneralRow ) float64 {
return productPerformanceExcelFirstNonZero ( general . SalesQtyTotal , row . SalesQtyTotal )
}
func productPerformanceExcelTotalSalesUSD ( row models . ProductPerformanceRow , general models . ProductPerformanceGeneralRow ) float64 {
return productPerformanceExcelFirstNonZero ( general . SalesUSDTotal , row . SalesUSDTotal )
}
func productPerformanceExcelAvgPrice ( salesUSD , qty float64 ) float64 {
if qty == 0 {
return 0
}
return salesUSD / qty
}
func productPerformanceExcelStockTurnover ( salesQty , stockQty float64 ) float64 {
if stockQty <= 0 {
return 0
}
return salesQty / stockQty
}
func productPerformanceExcelUnitProfit ( salesUSD , qty , unitCost float64 ) float64 {
if qty <= 0 {
return 0
}
return ( salesUSD / qty ) - unitCost
}
func productPerformanceExcelGrossProfit ( salesUSD , qty , unitCost float64 ) float64 {
if qty <= 0 {
return 0
}
return salesUSD - qty * unitCost
}
func productPerformanceExcelMargin ( salesUSD , qty , unitCost float64 ) float64 {
if salesUSD == 0 {
return 0
}
return productPerformanceExcelGrossProfit ( salesUSD , qty , unitCost ) / salesUSD
}
func productPerformanceExcelRelativeIndex ( value , average float64 ) float64 {
if value <= 0 || average <= 0 {
return 0
}
return value / average
}
func productPerformanceExcelProductScore ( suffix string , salesUSD , salesIndex , margin , stockTurnover , marketCount , customerCount float64 ) float64 {
revenue := productPerformanceExcelRatioScore ( salesIndex , 2 )
if revenue == 0 {
revenue = productPerformanceExcelRatioScore ( salesUSD , productPerformanceExcelProductRevenueTarget ( suffix ) )
}
score := 0.30 * productPerformanceExcelMarginScore ( margin ) +
0.20 * productPerformanceExcelRatioScore ( stockTurnover , 1.50 ) +
0.20 * revenue +
0.15 * productPerformanceExcelRatioScore ( marketCount , 8 ) +
0.15 * productPerformanceExcelRatioScore ( customerCount , 25 )
return productPerformanceExcelRoundScore ( score )
}
func productPerformanceExcelProductRevenueTarget ( suffix string ) float64 {
switch suffix {
case "180d" :
return 20000
case "365d" :
return 40000
case "total" :
return 120000
default :
return 10000
}
}
func productPerformanceExcelMarginScore ( margin float64 ) float64 {
if margin < 0 {
margin = 0
}
return productPerformanceExcelRatioScore ( margin , 0.40 )
}
func productPerformanceExcelRatioScore ( value , target float64 ) float64 {
if target <= 0 || value <= 0 {
return 0
}
score := value * 100 / target
if score > 100 {
return 100
}
if score < 0 {
return 0
}
return score
}
func productPerformanceExcelRoundScore ( score float64 ) float64 {
if score < 0 {
score = 0
}
if score > 100 {
score = 100
}
return math . Round ( score * 10000 ) / 10000
}
func productPerformanceExcelFloat ( value any ) float64 {
switch v := value . ( type ) {
case float64 :
if math . IsNaN ( v ) || math . IsInf ( v , 0 ) {
return 0
}
return v
case float32 :
return productPerformanceExcelFloat ( float64 ( v ) )
case int :
return float64 ( v )
case int64 :
return float64 ( v )
case int32 :
return float64 ( v )
case uint :
return float64 ( v )
case uint64 :
return float64 ( v )
case uint32 :
return float64 ( v )
default :
return 0
}
}
func productPerformanceExcelColumnWidth ( header , kind string ) float64 {
if kind == "text" {
if len ( [ ] rune ( header ) ) > 14 {
return 24
}
return 16
}
if strings . Contains ( header , "Marj" ) || strings . Contains ( header , "Skor" ) || strings . Contains ( header , "Endeks" ) {
return 14
}
return 16
}