package test_data

import (
	"gitee.com/golang-module/carbon/v2"
	"github.com/shopspring/decimal"
	"gorm.io/gorm"
	"sort"
	"strconv"
	"strings"
	"testData/global"
	"testData/model"
	"testData/request"
)

func WaferList(r *request.WaferList) []*model.WaferList {
	var sql string
	if r.OrderDate != "" {
		sql += "pmm04 = DATE '" + r.OrderDate + "'"
	}
	if r.PBI != "" {
		if sql != "" {
			sql += " AND pmm01 = '" + r.PBI + "'"
		} else {
			sql += "pmm01 = '" + r.PBI + "'"
		}
	}
	if r.Factory != "" {
		var pmc *model.PmcFile
		global.Oracle.Where("pmc03 LIKE ?", "%"+r.Factory+"%").Find(&pmc)
		if sql != "" {
			sql += " AND pmm09 = '" + pmc.Pmc01 + "'"
		} else {
			sql += "pmm09 = '" + pmc.Pmc01 + "'"
		}
	}

	var pmms []*model.PmmFile
	global.Oracle.Where("pmm02 = ? ", "WB0").Where(sql).
		Preload("PmnFile", func(db *gorm.DB) *gorm.DB {
			return db.Preload("ImaFile")
		}).Preload("PmcFile").Preload("RvbFile", func(db *gorm.DB) *gorm.DB {
		return db.Order("rvb12 desc")
	}).Order("pmm01 desc").Find(&pmms)

	var waferList []*model.WaferList
	for _, pmm := range pmms {
		if r.WaferSize != "" && r.WaferSize != pmm.PmnFile.ImaFile.Ima021 {
			continue
		}
		if r.Quantity != "" {
			quantity, _ := strconv.ParseFloat(r.Quantity, 64)
			if quantity != pmm.PmnFile.Pmn20 {
				continue
			}
		}
		if r.OnlineQuantity != "" {
			quantity, _ := strconv.ParseFloat(r.OnlineQuantity, 64)
			if quantity != pmm.PmnFile.Pmn20-pmm.PmnFile.Pmn53 {
				continue
			}
		}
		if r.ReturnQuantity != "" {
			quantity, _ := strconv.ParseFloat(r.ReturnQuantity, 64)
			if quantity != pmm.PmnFile.Pmn53 {
				continue
			}
		}
		var returnDate, lot string
		if len(pmm.RvbFile) > 0 {
			returnDate = pmm.RvbFile[0].Rvb12.Format("2006-01-02")
			lot = pmm.RvbFile[0].Rvb38
		}
		if r.ReturnDate != "" && r.ReturnDate != returnDate {
			continue
		}
		if r.Lot != "" && r.Lot != lot {
			continue
		}
		waferList = append(waferList, &model.WaferList{
			OrderDate:      pmm.Pmm04.Format("2006-01-02"),
			PBI:            pmm.Pmm01,
			Product:        pmm.PmnFile.Pmn041,
			Factory:        pmm.PmcFile.Pmc03,
			WaferSize:      pmm.PmnFile.ImaFile.Ima021,
			Quantity:       pmm.PmnFile.Pmn20,
			OnlineQuantity: pmm.PmnFile.Pmn20 - pmm.PmnFile.Pmn53,
			ReturnDate:     returnDate,
			Lot:            lot,
			ReturnQuantity: pmm.PmnFile.Pmn53,
		})
	}
	return waferList
}

func ABList(r *request.ABList) []*model.ABList {
	var sql string
	if r.OrderDate != "" {
		sql += "tc_sfc02 = DATE '" + r.OrderDate + "'"
	} else {
		start := carbon.Now().SubYears(2).Format("Y-m-d")
		end := carbon.Now().Format("Y-m-d")
		sql += "tc_sfc02 BETWEEN DATE '" + start + "' AND DATE '" + end + "'"
	}
	if r.PBI != "" {
		if sql != "" {
			sql += " AND tc_sfc01 = '" + r.PBI + "'"
		} else {
			sql += "tc_sfc01 = '" + r.PBI + "'"
		}
	}
	if r.Factory != "" {
		var pmc *model.PmcFile
		global.Oracle.Where("pmc03 LIKE ?", "%"+r.Factory+"%").Find(&pmc)
		if sql != "" {
			sql += " AND tc_sfc04 = '" + pmc.Pmc01 + "'"
		} else {
			sql += "tc_sfc04 = '" + pmc.Pmc01 + "'"
		}
	}
	var tcSfcFile []*model.TcSfcFile
	var tcSfcFilePBIs []string
	_ = global.Oracle.Transaction(func(tx *gorm.DB) error {
		tx.Model(&model.TcSfcFile{}).Where("tc_sfc08 LIKE ? AND tc_sfc10 = ?", "%AB%", "N").Where(sql).
			Order("tc_sfc01").Select("tc_sfc01").Find(&tcSfcFilePBIs)
		page := len(tcSfcFilePBIs)/200 + 1
		for i := 0; i < page; i++ {
			var pageTcSfcFile []*model.TcSfcFile
			var s []string
			if i == page-1 {
				s = tcSfcFilePBIs[i*200:]
			} else {
				s = tcSfcFilePBIs[i*200 : (i+1)*200]
			}
			tx.Where("tc_sfc01 IN ? AND tc_sfc08 LIKE ?", s, "%AB%").
				Preload("TcSfdFile", func(db *gorm.DB) *gorm.DB {
					return db.Preload("SfbFile").Preload("ImaFile").Preload("RvaFile", func(db *gorm.DB) *gorm.DB {
						return db.Preload("IddFile")
					})
				}).Preload("TcSfeFile", func(db *gorm.DB) *gorm.DB {
				return db.Preload("ImaFile")
			}).
				Preload("PmcFile").Find(&pageTcSfcFile)
			tcSfcFile = append(tcSfcFile, pageTcSfcFile...)
		}
		return nil
	})

	var abList []*model.ABList
	for _, tcSfc := range tcSfcFile {
		for _, tcSfd := range tcSfc.TcSfdFile {
			if r.Product != "" && r.Product != tcSfd.ImaFile.Ima02 {
				continue
			}
			if r.Package != "" && r.Package != tcSfd.ImaFile.Ima021 {
				continue
			}
			if r.Lot != "" && r.Lot != tcSfd.TcSfd06 {
				continue
			}
			if r.Seal != "" && r.Seal != tcSfd.TcSfdUd02 {
				continue
			}
			if r.Quantity != "" {
				quantity, _ := strconv.ParseFloat(r.Quantity, 64)
				if quantity != tcSfd.TcSfd05 {
					continue
				}
			}
			if r.StockOutQuantity != "" {
				quantity, _ := strconv.ParseFloat(r.StockOutQuantity, 64)
				if quantity != tcSfd.TcSfd05 {
					continue
				}
			}
			var waferProduct, waferID string
			var abWafer []*model.ABWaferList
			for _, tcSfe := range tcSfc.TcSfeFile {
				if tcSfe.TcSfe01 == tcSfc.TcSfc01 && tcSfe.TcSfe02 == tcSfd.TcSfd02 {
					if tcSfe.TcSfe17 == "Y" {
						waferProduct = tcSfe.ImaFile.Ima02
						waferID = tcSfe.TcSfe15
					}
					abWafer = append(abWafer, &model.ABWaferList{
						Material:      tcSfe.TcSfe04,
						Product:       tcSfe.ImaFile.Ima02,
						Specification: tcSfe.ImaFile.Ima021,
						Lot:           tcSfe.TcSfe10,
						WaferID:       tcSfe.TcSfe15,
					})
				}
			}
			if r.WaferProduct != "" && r.WaferProduct != waferProduct {
				continue
			}
			if r.WaferID != "" && r.WaferID != waferID {
				continue
			}
			var stockInQuantity, failQuantity, passQuantity, onlineQuantity float64
			for _, rva := range tcSfd.RvaFile {
				for _, idd := range rva.IddFile {
					stockInQuantity += idd.Idd13
					if idd.Idd06 == "BIN99" {
						failQuantity += idd.Idd13
					} else {
						passQuantity += idd.Idd13
					}
				}
			}
			if r.StockInQuantity != "" {
				quantity, _ := strconv.ParseFloat(r.StockInQuantity, 64)
				if quantity != stockInQuantity {
					continue
				}
			}
			isFinish := "进行中"
			if tcSfd.SfbFile.Sfb04 == "8" {
				isFinish = "已完成"
			}
			if r.IsFinish != "" && r.IsFinish != isFinish {
				continue
			}
			var passProbability string
			if strings.Contains(tcSfc.TcSfc01, "M596") {
				var reports []*model.Report
				global.PostGreSQL.Where("pbi = ? AND product = ? AND lot = ?", tcSfc.TcSfc01, tcSfd.ImaFile.Ima02,
					tcSfd.TcSfd06).Find(&reports)
				for _, report := range reports {
					testQuantityDecimal, _ := decimal.NewFromString(report.TestQuantity)
					testQuantityFloat, _ := testQuantityDecimal.Float64()
					passQuantity += testQuantityFloat
				}
				if tcSfd.SfbFile.Sfb04 == "8" {
					onlineQuantity = 0
					failQuantity = tcSfd.TcSfd05 - passQuantity
					passProbability = decimal.NewFromFloat(passQuantity).Div(decimal.NewFromFloat(tcSfd.TcSfd05)).
						Round(4).Mul(decimal.NewFromFloat(100)).String()
				}
			} else {
				if tcSfd.SfbFile.Sfb04 == "8" {
					onlineQuantity = 0
					failQuantity = tcSfd.TcSfd05 - passQuantity
					passProbability = decimal.NewFromFloat(passQuantity).Div(decimal.NewFromFloat(tcSfd.TcSfd05)).
						Round(4).Mul(decimal.NewFromFloat(100)).String()
				} else {
					onlineQuantity = tcSfd.TcSfd05 - stockInQuantity
					passProbability = decimal.NewFromFloat(passQuantity).Div(decimal.NewFromFloat(tcSfd.TcSfd05)).
						Round(4).Mul(decimal.NewFromFloat(100)).String()
				}
			}
			if r.FailQuantity != "" {
				quantity, _ := strconv.ParseFloat(r.FailQuantity, 64)
				if quantity != failQuantity {
					continue
				}
			}
			if r.OnlineQuantity != "" {
				quantity, _ := strconv.ParseFloat(r.OnlineQuantity, 64)
				if quantity != onlineQuantity {
					continue
				}
			}
			if r.PassProbability != "" && r.PassProbability != passProbability+"%" {
				continue
			}
			abList = append(abList, &model.ABList{
				OrderDate:        tcSfc.TcSfc02.Format("2006-01-02"),
				PBI:              tcSfc.TcSfc01,
				OutsourcingPBI:   tcSfd.TcSfd13,
				Product:          tcSfd.ImaFile.Ima02,
				WaferProduct:     waferProduct,
				Package:          tcSfd.ImaFile.Ima021,
				Factory:          tcSfc.PmcFile.Pmc03,
				Lot:              tcSfd.TcSfd06,
				Seal:             tcSfd.TcSfdUd02,
				WaferID:          waferID,
				Quantity:         tcSfd.TcSfd05,
				OnlineQuantity:   onlineQuantity,
				IsFinish:         isFinish,
				PassProbability:  passProbability + "%",
				StockOutQuantity: tcSfd.TcSfd05,
				StockInQuantity:  stockInQuantity,
				FailQuantity:     failQuantity,
				ABWaferList:      abWafer,
			})
		}
	}
	return abList
}

func CPList(r *request.CPList) ([]*model.ReportList, int64) {
	var sql string
	if r.WaferProduct != "" {
		sql += "product = '" + r.WaferProduct + "'"
	}
	if r.Lot != "" {
		if sql == "" {
			sql += "lot ='" + r.Lot + "'"
		} else {
			sql += " AND lot = '" + r.Lot + "'"
		}
	}
	if r.Factory != "" {
		if sql == "" {
			sql += "factory ='" + r.Factory + "'"
		} else {
			sql += " AND factory = '" + r.Factory + "'"
		}
	}
	if r.TestMachine != "" {
		if sql == "" {
			sql += "test_machine ='" + r.TestMachine + "'"
		} else {
			sql += " AND test_machine = '" + r.TestMachine + "'"
		}
	}
	if r.PBI != "" {
		if sql == "" {
			sql += "pbi ='" + r.PBI + "'"
		} else {
			sql += " AND pbi = '" + r.PBI + "'"
		}
	}
	if r.OrderDate != "" {
		if sql == "" {
			sql += "order_date ='" + r.OrderDate + "'"
		} else {
			sql += " AND order_date = '" + r.OrderDate + "'"
		}
	}
	if r.Page > 0 {
		r.Page--
	}
	var reportList []*model.ReportList
	var total int64
	if r.QueryType == "List" {
		var reports []*model.Report
		global.PostGreSQL.Where("step = ?", "CP").Order("pbi").Find(&reports).Count(&total).
			Offset(r.Page * r.PageSize).Limit(r.PageSize).Find(&reports)
		for _, report := range reports {
			var finalReport *model.FinalReport
			global.PostGreSQL.Where("pbi = ? AND product = ? AND lot = ? AND step = ?",
				report.PBI, report.Product, report.Lot, "CP").Find(&finalReport)
			isAppend := true
			for _, list := range reportList {
				if list.PBI == report.PBI {
					firstPassQuantity, _ := decimal.NewFromString(report.FirstPassQuantity)
					listFirstPassQuantity, _ := decimal.NewFromString(list.PassQuantity)
					testQuantity, _ := decimal.NewFromString(report.TestQuantity)
					passQuantity, _ := decimal.NewFromString(report.PassQuantity)
					listTestQuantity, _ := decimal.NewFromString(list.TestQuantity)
					listPassQuantity, _ := decimal.NewFromString(list.PassQuantity)
					list.TestQuantity = testQuantity.Add(listTestQuantity).String()
					list.PassQuantity = passQuantity.Add(listPassQuantity).String()
					list.PassProbability = passQuantity.Add(listPassQuantity).Div(testQuantity.Add(listTestQuantity)).
						Round(4).Mul(decimal.NewFromInt(100)).String() + "%"

					list.FirstPassQuantity = firstPassQuantity.Add(listFirstPassQuantity).String()
					list.FirstPassProbability = firstPassQuantity.Add(listFirstPassQuantity).Div(testQuantity.Add(listTestQuantity)).
						Round(4).Mul(decimal.NewFromInt(100)).String() + "%"

					isAppend = false
					break
				}
			}
			if isAppend {
				reportList = append(reportList, &model.ReportList{
					Product:               report.Product,
					Lot:                   report.Lot,
					Factory:               report.Factory,
					TestMachine:           report.TestMachine,
					TestProgram:           report.TestProgram,
					PBI:                   report.PBI,
					OrderDate:             report.OrderDate,
					Seal:                  report.Seal,
					TestQuantity:          report.TestQuantity,
					FirstPassQuantity:     report.FirstPassQuantity,
					FirstPassProbability:  report.FirstPassProbability,
					PassQuantity:          report.PassQuantity,
					PassProbability:       report.PassProbability,
					ReportTestQuantity:    finalReport.ReportTestQuantity,
					ReportPassQuantity:    finalReport.ReportPassQuantity,
					ReportPassProbability: finalReport.ReportPassProbability,
					TestTime:              report.TestTime,
					Step:                  "CP",
					StackingMaterials:     report.StackingMaterials,
				})
			}
		}
		for _, reportlist := range reportList {
			var testQuantityDiffLabel, passQuantityDiffLabel, returnProbabilityLabel bool
			testQuantityDecimal, _ := decimal.NewFromString(reportlist.TestQuantity)
			reportTestQuantityDecimal, _ := decimal.NewFromString(reportlist.ReportTestQuantity)
			firstPassQuantityDecimal, _ := decimal.NewFromString(reportlist.FirstPassQuantity)
			passQuantityDecimal, _ := decimal.NewFromString(reportlist.PassQuantity)
			reportPassQuantityDecimal, _ := decimal.NewFromString(reportlist.ReportPassQuantity)
			if !testQuantityDecimal.IsZero() {
				diff := reportTestQuantityDecimal.Sub(testQuantityDecimal).Div(testQuantityDecimal).Round(4).
					Mul(decimal.NewFromInt(100))
				if reportTestQuantityDecimal.Sub(testQuantityDecimal).LessThan(decimal.NewFromInt(0)) ||
					decimal.NewFromInt(5).LessThanOrEqual(diff) {
					testQuantityDiffLabel = true
				}
				reportlist.TestQuantityDiff = diff.String() + "%"
				reportlist.TestQuantityDiffLabel = testQuantityDiffLabel
				probability := passQuantityDecimal.Sub(firstPassQuantityDecimal).Div(testQuantityDecimal).Round(4).
					Mul(decimal.NewFromInt(100))
				if probability.LessThan(decimal.NewFromInt(0)) ||
					decimal.NewFromInt(5).LessThanOrEqual(probability) {
					returnProbabilityLabel = true
				}
				reportlist.ReturnProbability = probability.String() + "%"
				reportlist.ReturnProbabilityLabel = returnProbabilityLabel
			}
			if !reportPassQuantityDecimal.IsZero() {
				diff := passQuantityDecimal.Sub(reportPassQuantityDecimal).Div(reportPassQuantityDecimal).Round(4).
					Mul(decimal.NewFromInt(100))
				if passQuantityDecimal.Sub(reportPassQuantityDecimal).LessThan(decimal.NewFromInt(0)) ||
					decimal.NewFromInt(5).LessThanOrEqual(diff) {
					passQuantityDiffLabel = true
				}
				reportlist.PassQuantityDiff = diff.String() + "%"
				reportlist.PassQuantityDiffLabel = passQuantityDiffLabel
			}
		}
	} else if r.QueryType == "Bin" {
		var reports []*model.Report
		global.PostGreSQL.Where("step = ?", "CP").Where(sql).
			Preload("BinFail", func(db *gorm.DB) *gorm.DB {
				return db.Where("report_site_id = ?", "0")
			}).Preload("Site", func(db *gorm.DB) *gorm.DB {
			return db.Preload("BinFail")
		}).Order("pbi").Find(&reports)
		for _, report := range reports {
			isAppend := true
			for _, list := range reportList {
				if list.PBI == report.PBI {
					//reportTestQuantity, _ := decimal.NewFromString(report.TestQuantity)
					//reportPassQuantity, _ := decimal.NewFromString(report.PassQuantity)
					//listTestQuantity, _ := decimal.NewFromString(list.TestQuantity)
					//listPassQuantity, _ := decimal.NewFromString(list.PassQuantity)
					//list.TestQuantity = reportTestQuantity.Add(listTestQuantity).String()
					//list.PassQuantity = reportPassQuantity.Add(listPassQuantity).String()
					//list.PassProbability = reportPassQuantity.Add(listPassQuantity).Div(reportTestQuantity.Add(listTestQuantity)).
					//	Round(4).Mul(decimal.NewFromInt(100)).String() + "%"
					isAppend = false

					for _, binFail := range report.BinFail {
						quantityDecimal, _ := decimal.NewFromString(binFail.Quantity)
						quantity, _ := quantityDecimal.Float64()
						list.SoftBinFailMap[binFail.SoftBin] += quantity
						list.HardBinFailMap[binFail.HardBin] += quantity
					}
					for _, site := range report.Site {
						for _, reportSite := range list.Site {
							if reportSite.Site == site.Site {
								siteTestQuantity, _ := decimal.NewFromString(site.TestQuantity)
								sitePassQuantity, _ := decimal.NewFromString(site.PassQuantity)
								reportSiteTestQuantity, _ := decimal.NewFromString(reportSite.TestQuantity)
								reportSitePassQuantity, _ := decimal.NewFromString(reportSite.PassQuantity)
								reportSite.TestQuantity = siteTestQuantity.Add(reportSiteTestQuantity).String()
								reportSite.PassQuantity = sitePassQuantity.Add(reportSitePassQuantity).String()
								reportSite.PassProbability = sitePassQuantity.Add(reportSitePassQuantity).Div(siteTestQuantity.Add(reportSiteTestQuantity)).
									Round(4).Mul(decimal.NewFromInt(100)).String() + "%"
								for _, binFail := range site.BinFail {
									quantityDecimal, _ := decimal.NewFromString(binFail.Quantity)
									quantity, _ := quantityDecimal.Float64()
									reportSite.SoftBinFailMap[binFail.SoftBin] += quantity
									reportSite.HardBinFailMap[binFail.HardBin] += quantity
								}
								break
							}
						}
					}
					break
				}
			}
			if isAppend {
				softBinFail, hardBinFail := make(map[string]float64), make(map[string]float64)
				for _, binFail := range report.BinFail {
					quantityDecimal, _ := decimal.NewFromString(binFail.Quantity)
					quantity, _ := quantityDecimal.Float64()
					softBinFail[binFail.SoftBin] += quantity
					hardBinFail[binFail.HardBin] += quantity
				}
				var reportListSites []*model.ReportListSites
				for _, site := range report.Site {
					siteSoftBinFail, siteHardBinFail := make(map[string]float64), make(map[string]float64)
					for _, binFail := range site.BinFail {
						quantityDecimal, _ := decimal.NewFromString(binFail.Quantity)
						quantity, _ := quantityDecimal.Float64()
						siteSoftBinFail[binFail.SoftBin] += quantity
						siteHardBinFail[binFail.HardBin] += quantity
					}
					reportListSites = append(reportListSites, &model.ReportListSites{
						ID:              site.ID,
						ReportID:        site.ReportID,
						Site:            site.Site,
						TestQuantity:    site.TestQuantity,
						PassQuantity:    site.PassQuantity,
						PassProbability: site.PassProbability,
						SoftBinFailMap:  siteSoftBinFail,
						HardBinFailMap:  siteHardBinFail,
					})
				}
				reportList = append(reportList, &model.ReportList{
					Product:              report.Product,
					Lot:                  report.Lot,
					Factory:              report.Factory,
					TestMachine:          report.TestMachine,
					TestProgram:          report.TestProgram,
					PBI:                  report.PBI,
					OrderDate:            report.OrderDate,
					Seal:                 report.Seal,
					TestQuantity:         report.TestQuantity,
					FirstPassQuantity:    report.FirstPassQuantity,
					FirstPassProbability: report.FirstPassProbability,
					PassQuantity:         report.PassQuantity,
					PassProbability:      report.PassProbability,
					TestTime:             report.TestTime,
					Step:                 report.Step,
					SoftBinFailMap:       softBinFail,
					HardBinFailMap:       hardBinFail,
					Site:                 reportListSites,
				})
			}
		}
		for _, list := range reportList {
			testQuantityDecimal, _ := decimal.NewFromString(list.TestQuantity)
			var softBinFail, hardBinFail []*model.ReportBinFail
			for softBin, softBinQuantity := range list.SoftBinFailMap {
				softBinQuantityDecimal := decimal.NewFromFloat(softBinQuantity)
				softBinFail = append(softBinFail, &model.ReportBinFail{
					Bin:      softBin,
					Quantity: softBinQuantity,
					Proportion: softBinQuantityDecimal.Div(testQuantityDecimal).Round(4).
						Mul(decimal.NewFromInt(100)).String() + "%",
				})
			}
			sort.Slice(softBinFail, func(i, j int) bool {
				return softBinFail[i].Quantity > softBinFail[j].Quantity
			})
			for hardBin, hardBinQuantity := range list.HardBinFailMap {
				hardBinQuantityDecimal := decimal.NewFromFloat(hardBinQuantity)
				hardBinFail = append(hardBinFail, &model.ReportBinFail{
					Bin:      hardBin,
					Quantity: hardBinQuantity,
					Proportion: hardBinQuantityDecimal.Div(testQuantityDecimal).Round(4).
						Mul(decimal.NewFromInt(100)).String() + "%",
				})
			}
			sort.Slice(hardBinFail, func(i, j int) bool {
				return hardBinFail[i].Quantity > hardBinFail[j].Quantity
			})
			for _, site := range list.Site {
				var siteSoftBinFail, siteHardBinFail []*model.ReportBinFail
				for softBin, softBinQuantity := range site.SoftBinFailMap {
					siteSoftBinFail = append(siteSoftBinFail, &model.ReportBinFail{
						Bin:      softBin,
						Quantity: softBinQuantity,
					})
				}
				sort.Slice(siteSoftBinFail, func(i, j int) bool {
					return siteSoftBinFail[i].Quantity > siteSoftBinFail[j].Quantity
				})
				for hardBin, hardBinQuantity := range site.HardBinFailMap {
					siteHardBinFail = append(siteHardBinFail, &model.ReportBinFail{
						Bin:      hardBin,
						Quantity: hardBinQuantity,
					})
				}
				sort.Slice(siteHardBinFail, func(i, j int) bool {
					return siteHardBinFail[i].Quantity > siteHardBinFail[j].Quantity
				})
				site.SoftBinFail = siteSoftBinFail
				site.HardBinFail = siteHardBinFail
			}
			sort.Slice(list.Site, func(i, j int) bool {
				iDecimal, _ := decimal.NewFromString(list.Site[i].PassProbability[:len(list.Site[i].PassProbability)-1])
				jDecimal, _ := decimal.NewFromString(list.Site[j].PassProbability[:len(list.Site[j].PassProbability)-1])
				return jDecimal.LessThan(iDecimal)
			})
			list.SoftBinFail = softBinFail
			list.HardBinFail = hardBinFail
		}
	} else if r.QueryType == "WaferID" {
		var reports []*model.Report
		global.PostGreSQL.Where("step = ?", "CP").Where(sql).
			Preload("BinFail", func(db *gorm.DB) *gorm.DB {
				return db.Where("report_site_id = ?", "0")
			}).Preload("Site", func(db *gorm.DB) *gorm.DB {
			return db.Preload("BinFail")
		}).Order("pbi").Find(&reports)
		for _, report := range reports {
			softBinFailMap, hardBinFailMap := make(map[string]float64), make(map[string]float64)
			for _, binFail := range report.BinFail {
				quantityDecimal, _ := decimal.NewFromString(binFail.Quantity)
				quantity, _ := quantityDecimal.Float64()
				softBinFailMap[binFail.SoftBin] += quantity
				hardBinFailMap[binFail.HardBin] += quantity
			}
			var reportListSites []*model.ReportListSites
			for _, site := range report.Site {
				siteSoftBinFailMap, siteHardBinFailMap := make(map[string]float64), make(map[string]float64)
				for _, binFail := range site.BinFail {
					quantityDecimal, _ := decimal.NewFromString(binFail.Quantity)
					quantity, _ := quantityDecimal.Float64()
					siteSoftBinFailMap[binFail.SoftBin] += quantity
					siteHardBinFailMap[binFail.HardBin] += quantity
				}
				var siteSoftBinFail, siteHardBinFail []*model.ReportBinFail
				for softBin, softBinQuantity := range siteSoftBinFailMap {
					siteSoftBinFail = append(siteSoftBinFail, &model.ReportBinFail{
						Bin:      softBin,
						Quantity: softBinQuantity,
					})
				}
				sort.Slice(siteSoftBinFail, func(i, j int) bool {
					return siteSoftBinFail[i].Quantity > siteSoftBinFail[j].Quantity
				})
				for hardBin, hardBinQuantity := range siteHardBinFailMap {
					siteHardBinFail = append(siteHardBinFail, &model.ReportBinFail{
						Bin:      hardBin,
						Quantity: hardBinQuantity,
					})
				}
				sort.Slice(siteHardBinFail, func(i, j int) bool {
					return siteHardBinFail[i].Quantity > siteHardBinFail[j].Quantity
				})
				reportListSites = append(reportListSites, &model.ReportListSites{
					ID:              site.ID,
					ReportID:        site.ReportID,
					Site:            site.Site,
					TestQuantity:    site.TestQuantity,
					PassQuantity:    site.PassQuantity,
					PassProbability: site.PassProbability,
					SoftBinFailMap:  siteSoftBinFailMap,
					HardBinFailMap:  siteHardBinFailMap,
					SoftBinFail:     siteSoftBinFail,
					HardBinFail:     siteHardBinFail,
				})
			}
			testQuantityDecimal, _ := decimal.NewFromString(report.TestQuantity)
			var softBinFail, hardBinFail []*model.ReportBinFail
			for softBin, softBinQuantity := range softBinFailMap {
				softBinQuantityDecimal := decimal.NewFromFloat(softBinQuantity)
				softBinFail = append(softBinFail, &model.ReportBinFail{
					Bin:      softBin,
					Quantity: softBinQuantity,
					Proportion: softBinQuantityDecimal.Div(testQuantityDecimal).Round(4).
						Mul(decimal.NewFromInt(100)).String() + "%",
				})
			}
			sort.Slice(softBinFail, func(i, j int) bool {
				return softBinFail[i].Quantity > softBinFail[j].Quantity
			})
			for hardBin, hardBinQuantity := range hardBinFailMap {
				hardBinQuantityDecimal := decimal.NewFromFloat(hardBinQuantity)
				hardBinFail = append(hardBinFail, &model.ReportBinFail{
					Bin:      hardBin,
					Quantity: hardBinQuantity,
					Proportion: hardBinQuantityDecimal.Div(testQuantityDecimal).Round(4).
						Mul(decimal.NewFromInt(100)).String() + "%",
				})
			}
			sort.Slice(hardBinFail, func(i, j int) bool {
				return hardBinFail[i].Quantity > hardBinFail[j].Quantity
			})
			reportList = append(reportList, &model.ReportList{
				Product:              report.Product,
				Lot:                  report.Lot,
				SubBatch:             report.SubBatch,
				WaferID:              report.WaferID,
				Factory:              report.Factory,
				TestMachine:          report.TestMachine,
				TestProgram:          report.TestProgram,
				PBI:                  report.PBI,
				OrderDate:            report.OrderDate,
				Seal:                 report.Seal,
				TestQuantity:         report.TestQuantity,
				FirstPassQuantity:    report.FirstPassQuantity,
				FirstPassProbability: report.FirstPassProbability,
				PassQuantity:         report.PassQuantity,
				PassProbability:      report.PassProbability,
				TestTime:             report.TestTime,
				Step:                 report.Step,
				StackingMaterials:    report.StackingMaterials,
				SoftBinFailMap:       softBinFailMap,
				HardBinFailMap:       hardBinFailMap,
				SoftBinFail:          softBinFail,
				HardBinFail:          hardBinFail,
				Site:                 reportListSites,
			})
		}
	}
	sort.Slice(reportList, func(i, j int) bool {
		iDecimal, _ := decimal.NewFromString(reportList[i].PassProbability[:len(reportList[i].PassProbability)-1])
		jDecimal, _ := decimal.NewFromString(reportList[j].PassProbability[:len(reportList[j].PassProbability)-1])
		return jDecimal.LessThan(iDecimal)
	})
	return reportList, total
}

func FTList(r *request.FTList) ([]*model.ReportList, int64) {
	var sql string
	if r.Product != "" {
		sql += "product = '" + r.Product + "'"
	}
	if r.Lot != "" {
		if sql == "" {
			sql += "lot ='" + r.Lot + "'"
		} else {
			sql += " AND lot = '" + r.Lot + "'"
		}
	}
	if r.Factory != "" {
		if sql == "" {
			sql += "factory ='" + r.Factory + "'"
		} else {
			sql += " AND factory = '" + r.Factory + "'"
		}
	}
	if r.TestProgram != "" {
		if sql == "" {
			sql += "test_program ='" + r.TestProgram + "'"
		} else {
			sql += " AND test_program = '" + r.TestProgram + "'"
		}
	}
	if r.PBI != "" {
		if sql == "" {
			sql += "pbi ='" + r.PBI + "'"
		} else {
			sql += " AND pbi = '" + r.PBI + "'"
		}
	}
	if r.OrderDate != "" {
		if sql == "" {
			sql += "order_date ='" + r.OrderDate + "'"
		} else {
			sql += " AND order_date = '" + r.OrderDate + "'"
		}
	}
	if r.Seal != "" {
		if sql == "" {
			sql += "seal ='" + r.Seal + "'"
		} else {
			sql += " AND seal = '" + r.Seal + "'"
		}
	}
	if r.Page > 0 {
		r.Page--
	}
	var reportList []*model.ReportList
	var total int64
	if r.QueryType == "List" {
		var reports []*model.Report
		global.PostGreSQL.Where("step = ?", "FT").Order("pbi").Find(&reports).Count(&total).
			Offset(r.Page * r.PageSize).Limit(r.PageSize).Find(&reports)
		for _, report := range reports {
			var finalReport *model.FinalReport
			global.PostGreSQL.Where("pbi = ? AND product = ? AND lot = ? AND step = ?",
				report.PBI, report.Product, report.Lot, "FT").Find(&finalReport)
			isAppend := true
			for _, list := range reportList {
				if list.PBI == report.PBI {
					firstPassQuantity, _ := decimal.NewFromString(report.FirstPassQuantity)
					listFirstPassQuantity, _ := decimal.NewFromString(list.PassQuantity)
					testQuantity, _ := decimal.NewFromString(report.TestQuantity)
					passQuantity, _ := decimal.NewFromString(report.PassQuantity)
					listTestQuantity, _ := decimal.NewFromString(list.TestQuantity)
					listPassQuantity, _ := decimal.NewFromString(list.PassQuantity)
					list.TestQuantity = testQuantity.Add(listTestQuantity).String()
					list.PassQuantity = passQuantity.Add(listPassQuantity).String()
					list.PassProbability = passQuantity.Add(listPassQuantity).Div(testQuantity.Add(listTestQuantity)).
						Round(4).Mul(decimal.NewFromInt(100)).String() + "%"

					list.FirstPassQuantity = firstPassQuantity.Add(listFirstPassQuantity).String()
					list.PassProbability = firstPassQuantity.Add(listFirstPassQuantity).Div(testQuantity.Add(listTestQuantity)).
						Round(4).Mul(decimal.NewFromInt(100)).String() + "%"

					//reportTestQuantity, _ := decimal.NewFromString(finalReport.ReportTestQuantity)
					//reportPassQuantity, _ := decimal.NewFromString(finalReport.ReportPassQuantity)
					//listReportTestQuantity, _ := decimal.NewFromString(list.ReportTestQuantity)
					//listReportPassQuantity, _ := decimal.NewFromString(list.ReportPassQuantity)
					//if !reportTestQuantity.Add(listReportTestQuantity).IsZero() {
					//	list.ReportTestQuantity = reportTestQuantity.Add(listReportTestQuantity).String()
					//	list.ReportPassQuantity = reportPassQuantity.Add(listReportPassQuantity).String()
					//	list.PassProbability = reportPassQuantity.Add(listReportPassQuantity).Div(reportTestQuantity.Add(listReportTestQuantity)).
					//		Round(4).Mul(decimal.NewFromInt(100)).String() + "%"
					//}
					isAppend = false
					break
				}
			}
			if isAppend {
				reportList = append(reportList, &model.ReportList{
					Product:               report.Product,
					Lot:                   report.Lot,
					Factory:               report.Factory,
					TestMachine:           report.TestMachine,
					TestProgram:           report.TestProgram,
					PBI:                   report.PBI,
					OrderDate:             report.OrderDate,
					Seal:                  report.Seal,
					TestQuantity:          report.TestQuantity,
					FirstPassQuantity:     report.FirstPassQuantity,
					FirstPassProbability:  report.FirstPassProbability,
					PassQuantity:          report.PassQuantity,
					PassProbability:       report.PassProbability,
					ReportTestQuantity:    finalReport.ReportTestQuantity,
					ReportPassQuantity:    finalReport.ReportPassQuantity,
					ReportPassProbability: finalReport.ReportPassProbability,
					TestTime:              report.TestTime,
					Step:                  "FT",
					StackingMaterials:     report.StackingMaterials,
				})
			}
		}
		for _, reportlist := range reportList {
			var testQuantityDiffLabel, passQuantityDiffLabel, returnProbabilityLabel bool
			testQuantityDecimal, _ := decimal.NewFromString(reportlist.TestQuantity)
			reportTestQuantityDecimal, _ := decimal.NewFromString(reportlist.ReportTestQuantity)
			firstPassQuantityDecimal, _ := decimal.NewFromString(reportlist.FirstPassQuantity)
			passQuantityDecimal, _ := decimal.NewFromString(reportlist.PassQuantity)
			reportPassQuantityDecimal, _ := decimal.NewFromString(reportlist.ReportPassQuantity)
			if !testQuantityDecimal.IsZero() {
				diff := reportTestQuantityDecimal.Sub(testQuantityDecimal).Div(testQuantityDecimal).Round(4).
					Mul(decimal.NewFromInt(100))
				if reportTestQuantityDecimal.Sub(testQuantityDecimal).LessThan(decimal.NewFromInt(0)) ||
					decimal.NewFromInt(5).LessThanOrEqual(diff) {
					testQuantityDiffLabel = true
				}
				reportlist.TestQuantityDiff = diff.String() + "%"
				reportlist.TestQuantityDiffLabel = testQuantityDiffLabel
				probability := passQuantityDecimal.Sub(firstPassQuantityDecimal).Div(testQuantityDecimal).Round(4).
					Mul(decimal.NewFromInt(100))
				if probability.LessThan(decimal.NewFromInt(0)) ||
					decimal.NewFromInt(5).LessThanOrEqual(probability) {
					returnProbabilityLabel = true
				}
				reportlist.ReturnProbability = probability.String() + "%"
				reportlist.ReturnProbabilityLabel = returnProbabilityLabel
			}
			if !reportPassQuantityDecimal.IsZero() {
				diff := passQuantityDecimal.Sub(reportPassQuantityDecimal).Div(reportPassQuantityDecimal).Round(4).
					Mul(decimal.NewFromInt(100))
				if passQuantityDecimal.Sub(reportPassQuantityDecimal).LessThan(decimal.NewFromInt(0)) ||
					decimal.NewFromInt(5).LessThanOrEqual(diff) {
					passQuantityDiffLabel = true
				}
				reportlist.PassQuantityDiff = diff.String() + "%"
				reportlist.PassQuantityDiffLabel = passQuantityDiffLabel
			}
		}
	} else if r.QueryType == "Bin" {
		var reports []*model.Report
		global.PostGreSQL.Where("step = ?", "FT").Where(sql).
			Preload("BinFail", func(db *gorm.DB) *gorm.DB {
				return db.Where("report_site_id = ?", "0")
			}).Preload("Site", func(db *gorm.DB) *gorm.DB {
			return db.Preload("BinFail")
		}).Order("pbi").Find(&reports)
		for _, report := range reports {
			isAppend := true
			for _, list := range reportList {
				if list.PBI == report.PBI {
					reportTestQuantity, _ := decimal.NewFromString(report.TestQuantity)
					reportPassQuantity, _ := decimal.NewFromString(report.PassQuantity)
					listTestQuantity, _ := decimal.NewFromString(list.TestQuantity)
					listPassQuantity, _ := decimal.NewFromString(list.PassQuantity)
					list.TestQuantity = reportTestQuantity.Add(listTestQuantity).String()
					list.PassQuantity = reportPassQuantity.Add(listPassQuantity).String()
					list.PassProbability = reportPassQuantity.Add(listPassQuantity).Div(reportTestQuantity.Add(listTestQuantity)).
						Round(4).Mul(decimal.NewFromInt(100)).String() + "%"
					isAppend = false
					for _, binFail := range report.BinFail {
						quantityDecimal, _ := decimal.NewFromString(binFail.Quantity)
						quantity, _ := quantityDecimal.Float64()
						list.SoftBinFailMap[binFail.SoftBin] += quantity
						list.HardBinFailMap[binFail.HardBin] += quantity
					}
					for _, site := range report.Site {
						for _, reportSite := range list.Site {
							if reportSite.Site == site.Site {
								siteTestQuantity, _ := decimal.NewFromString(site.TestQuantity)
								sitePassQuantity, _ := decimal.NewFromString(site.PassQuantity)
								reportSiteTestQuantity, _ := decimal.NewFromString(reportSite.TestQuantity)
								reportSitePassQuantity, _ := decimal.NewFromString(reportSite.PassQuantity)
								reportSite.TestQuantity = siteTestQuantity.Add(reportSiteTestQuantity).String()
								reportSite.PassQuantity = sitePassQuantity.Add(reportSitePassQuantity).String()
								reportSite.PassProbability = sitePassQuantity.Add(reportSitePassQuantity).Div(siteTestQuantity.Add(reportSiteTestQuantity)).
									Round(4).Mul(decimal.NewFromInt(100)).String() + "%"
								for _, binFail := range site.BinFail {
									quantityDecimal, _ := decimal.NewFromString(binFail.Quantity)
									quantity, _ := quantityDecimal.Float64()
									reportSite.SoftBinFailMap[binFail.SoftBin] += quantity
									reportSite.HardBinFailMap[binFail.HardBin] += quantity
								}
								break
							}
						}
					}
					break
				}
			}
			if isAppend {
				softBinFail, hardBinFail := make(map[string]float64), make(map[string]float64)
				for _, binFail := range report.BinFail {
					quantityDecimal, _ := decimal.NewFromString(binFail.Quantity)
					quantity, _ := quantityDecimal.Float64()
					softBinFail[binFail.SoftBin] += quantity
					hardBinFail[binFail.HardBin] += quantity
				}
				var reportListSites []*model.ReportListSites
				for _, site := range report.Site {
					siteSoftBinFail, siteHardBinFail := make(map[string]float64), make(map[string]float64)
					for _, binFail := range site.BinFail {
						quantityDecimal, _ := decimal.NewFromString(binFail.Quantity)
						quantity, _ := quantityDecimal.Float64()
						siteSoftBinFail[binFail.SoftBin] += quantity
						siteHardBinFail[binFail.HardBin] += quantity
					}
					reportListSites = append(reportListSites, &model.ReportListSites{
						ID:              site.ID,
						ReportID:        site.ReportID,
						Site:            site.Site,
						TestQuantity:    site.TestQuantity,
						PassQuantity:    site.PassQuantity,
						PassProbability: site.PassProbability,
						SoftBinFailMap:  siteSoftBinFail,
						HardBinFailMap:  siteHardBinFail,
					})
				}
				//var finalReport *model.FinalReport
				//if errors.Is(global.PostGreSQL.Where("pbi = ? AND product = ? AND lot = ?",
				//	report.PBI, report.Product, report.Lot).Find(&finalReport).Error, gorm.ErrRecordNotFound) {
				//	//finalReport.ReportTestQuantity = ""
				//	//finalReport.ReportPassQuantity = ""
				//	//finalReport.ReportPassProbability = ""
				//}
				reportList = append(reportList, &model.ReportList{
					Product:              report.Product,
					Lot:                  report.Lot,
					Factory:              report.Factory,
					TestMachine:          report.TestMachine,
					TestProgram:          report.TestProgram,
					PBI:                  report.PBI,
					OrderDate:            report.OrderDate,
					Seal:                 report.Seal,
					TestQuantity:         report.TestQuantity,
					FirstPassQuantity:    report.FirstPassQuantity,
					FirstPassProbability: report.FirstPassProbability,
					PassQuantity:         report.PassQuantity,
					PassProbability:      report.PassProbability,
					//ReportTestQuantity:    finalReport.ReportTestQuantity,
					//ReportPassQuantity:    finalReport.ReportPassQuantity,
					//ReportPassProbability: finalReport.ReportPassProbability,
					TestTime:       report.TestTime,
					Step:           report.Step,
					SoftBinFailMap: softBinFail,
					HardBinFailMap: hardBinFail,
					Site:           reportListSites,
				})
			}
		}
		for _, list := range reportList {
			testQuantity, _ := decimal.NewFromString(list.TestQuantity)

			var softBinFail, hardBinFail []*model.ReportBinFail
			for softBin, softBinQuantity := range list.SoftBinFailMap {
				softBinQuantityDecimal := decimal.NewFromFloat(softBinQuantity)
				softBinFail = append(softBinFail, &model.ReportBinFail{
					Bin:        softBin,
					Quantity:   softBinQuantity,
					Proportion: softBinQuantityDecimal.Div(testQuantity).Round(4).Mul(decimal.NewFromInt(100)).String() + "%",
				})
			}
			sort.Slice(softBinFail, func(i, j int) bool {
				return softBinFail[i].Quantity > softBinFail[j].Quantity
			})
			for hardBin, hardBinQuantity := range list.HardBinFailMap {
				hardBinQuantityDecimal := decimal.NewFromFloat(hardBinQuantity)
				hardBinFail = append(hardBinFail, &model.ReportBinFail{
					Bin:        hardBin,
					Quantity:   hardBinQuantity,
					Proportion: hardBinQuantityDecimal.Div(testQuantity).Round(4).Mul(decimal.NewFromInt(100)).String() + "%",
				})
			}
			sort.Slice(hardBinFail, func(i, j int) bool {
				return hardBinFail[i].Quantity > hardBinFail[j].Quantity
			})
			for _, site := range list.Site {
				var siteSoftBinFail, siteHardBinFail []*model.ReportBinFail
				for softBin, softBinQuantity := range site.SoftBinFailMap {
					siteSoftBinFail = append(siteSoftBinFail, &model.ReportBinFail{
						Bin:      softBin,
						Quantity: softBinQuantity,
					})
				}
				sort.Slice(siteSoftBinFail, func(i, j int) bool {
					return siteSoftBinFail[i].Quantity > siteSoftBinFail[j].Quantity
				})
				for hardBin, hardBinQuantity := range site.HardBinFailMap {
					siteHardBinFail = append(siteHardBinFail, &model.ReportBinFail{
						Bin:      hardBin,
						Quantity: hardBinQuantity,
					})
				}
				sort.Slice(siteHardBinFail, func(i, j int) bool {
					return siteHardBinFail[i].Quantity > siteHardBinFail[j].Quantity
				})
				site.SoftBinFail = siteSoftBinFail
				site.HardBinFail = siteHardBinFail
			}
			sort.Slice(list.Site, func(i, j int) bool {
				iDecimal, _ := decimal.NewFromString(list.Site[i].PassProbability[:len(list.Site[i].PassProbability)-1])
				jDecimal, _ := decimal.NewFromString(list.Site[j].PassProbability[:len(list.Site[j].PassProbability)-1])
				return jDecimal.LessThan(iDecimal)
			})
			list.SoftBinFail = softBinFail
			list.HardBinFail = hardBinFail
		}
	} else if r.QueryType == "SubBatch" {
		var reports []*model.Report
		global.PostGreSQL.Where("step = ?", "FT").Where(sql).
			Preload("BinFail", func(db *gorm.DB) *gorm.DB {
				return db.Where("report_site_id = ?", "0")
			}).Preload("Site", func(db *gorm.DB) *gorm.DB {
			return db.Preload("BinFail")
		}).Order("pbi").Find(&reports)
		for _, report := range reports {
			softBinFailMap, hardBinFailMap := make(map[string]float64), make(map[string]float64)
			for _, binFail := range report.BinFail {
				quantityDecimal, _ := decimal.NewFromString(binFail.Quantity)
				quantity, _ := quantityDecimal.Float64()
				softBinFailMap[binFail.SoftBin] += quantity
				hardBinFailMap[binFail.HardBin] += quantity
			}
			var reportListSites []*model.ReportListSites
			for _, site := range report.Site {
				siteSoftBinFailMap, siteHardBinFailMap := make(map[string]float64), make(map[string]float64)
				for _, binFail := range site.BinFail {
					quantityDecimal, _ := decimal.NewFromString(binFail.Quantity)
					quantity, _ := quantityDecimal.Float64()
					siteSoftBinFailMap[binFail.SoftBin] += quantity
					siteHardBinFailMap[binFail.HardBin] += quantity
				}
				var siteSoftBinFail, siteHardBinFail []*model.ReportBinFail
				for softBin, softBinQuantity := range siteSoftBinFailMap {
					siteSoftBinFail = append(siteSoftBinFail, &model.ReportBinFail{
						Bin:      softBin,
						Quantity: softBinQuantity,
					})
				}
				sort.Slice(siteSoftBinFail, func(i, j int) bool {
					return siteSoftBinFail[i].Quantity > siteSoftBinFail[j].Quantity
				})
				for hardBin, hardBinQuantity := range siteHardBinFailMap {
					siteHardBinFail = append(siteHardBinFail, &model.ReportBinFail{
						Bin:      hardBin,
						Quantity: hardBinQuantity,
					})
				}
				sort.Slice(siteHardBinFail, func(i, j int) bool {
					return siteHardBinFail[i].Quantity > siteHardBinFail[j].Quantity
				})
				reportListSites = append(reportListSites, &model.ReportListSites{
					ID:              site.ID,
					ReportID:        site.ReportID,
					Site:            site.Site,
					TestQuantity:    site.TestQuantity,
					PassQuantity:    site.PassQuantity,
					PassProbability: site.PassProbability,
					SoftBinFailMap:  siteSoftBinFailMap,
					HardBinFailMap:  siteHardBinFailMap,
					SoftBinFail:     siteSoftBinFail,
					HardBinFail:     siteHardBinFail,
				})
			}
			sort.Slice(reportListSites, func(i, j int) bool {
				iDecimal, _ := decimal.NewFromString(reportListSites[i].PassProbability[:len(reportListSites[i].PassProbability)-1])
				jDecimal, _ := decimal.NewFromString(reportListSites[j].PassProbability[:len(reportListSites[j].PassProbability)-1])
				return jDecimal.LessThan(iDecimal)
			})
			testQuantityDecimal, _ := decimal.NewFromString(report.TestQuantity)
			var softBinFail, hardBinFail []*model.ReportBinFail
			for softBin, softBinQuantity := range softBinFailMap {
				softBinQuantityDecimal := decimal.NewFromFloat(softBinQuantity)
				softBinFail = append(softBinFail, &model.ReportBinFail{
					Bin:        softBin,
					Quantity:   softBinQuantity,
					Proportion: softBinQuantityDecimal.Div(testQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).String() + "%",
				})
			}
			sort.Slice(softBinFail, func(i, j int) bool {
				return softBinFail[i].Quantity > softBinFail[j].Quantity
			})
			for hardBin, hardBinQuantity := range hardBinFailMap {
				hardBinQuantityDecimal := decimal.NewFromFloat(hardBinQuantity)
				hardBinFail = append(hardBinFail, &model.ReportBinFail{
					Bin:        hardBin,
					Quantity:   hardBinQuantity,
					Proportion: hardBinQuantityDecimal.Div(testQuantityDecimal).Round(4).Mul(decimal.NewFromInt(100)).String() + "%",
				})
			}
			sort.Slice(hardBinFail, func(i, j int) bool {
				return hardBinFail[i].Quantity > hardBinFail[j].Quantity
			})
			reportList = append(reportList, &model.ReportList{
				Product:              report.Product,
				Lot:                  report.Lot,
				SubBatch:             report.SubBatch,
				Factory:              report.Factory,
				TestMachine:          report.TestMachine,
				TestProgram:          report.TestProgram,
				PBI:                  report.PBI,
				OrderDate:            report.OrderDate,
				Seal:                 report.Seal,
				TestQuantity:         report.TestQuantity,
				FirstPassQuantity:    report.FirstPassQuantity,
				FirstPassProbability: report.FirstPassProbability,
				PassQuantity:         report.PassQuantity,
				PassProbability:      report.PassProbability,
				TestTime:             report.TestTime,
				Step:                 report.Step,
				SoftBinFailMap:       softBinFailMap,
				HardBinFailMap:       hardBinFailMap,
				StackingMaterials:    report.StackingMaterials,
				SoftBinFail:          softBinFail,
				HardBinFail:          hardBinFail,
				Site:                 reportListSites,
			})
		}
		sort.Slice(reportList, func(i, j int) bool {
			iDecimal, _ := decimal.NewFromString(reportList[i].PassProbability[:len(reportList[i].PassProbability)-1])
			jDecimal, _ := decimal.NewFromString(reportList[j].PassProbability[:len(reportList[j].PassProbability)-1])
			return jDecimal.LessThan(iDecimal)
		})
	}
	return reportList, total
}
