spread

https://git.tonybtw.com/spread.git git://git.tonybtw.com/spread.git
2,054 bytes raw
1
package spread
2
3
import "math"
4
5
func round(x float64, places int) float64 {
6
	p := math.Pow(10, float64(places))
7
	return math.Round(x*p) / p
8
}
9
10
// spreadPrice returns our unit price for a line and whether it was an exact
11
// catalog match. It never returns a price above the customer's current price.
12
func spreadPrice(li LineItem, cat Catalog) (price float64, matched bool) {
13
	if p, ok := cat.Lookup(li.PartNumber); ok {
14
		matched = true
15
		price = p
16
	} else {
17
		price = li.UnitPrice * (1 - modelDiscount(li))
18
	}
19
	price = round(price, 4)
20
	if price > li.UnitPrice || li.UnitPrice <= 0 {
21
		price = li.UnitPrice
22
	}
23
	return price, matched
24
}
25
26
// Analyze re-quotes every line against the built-in catalog (public demo).
27
func Analyze(ref string, items []LineItem) Report {
28
	return AnalyzeWith(ref, items, BuiltinCatalog{})
29
}
30
31
// AnalyzeWith re-quotes every line against the given catalog and rolls up the
32
// totals. Parts not found in the catalog are priced by the category model.
33
func AnalyzeWith(ref string, items []LineItem, cat Catalog) Report {
34
	rep := Report{BOMRef: ref}
35
	rep.Totals.CutRate = CutRate
36
37
	for _, li := range items {
38
		price, matched := spreadPrice(li, cat)
39
		unitSave := round(li.UnitPrice-price, 4)
40
		if unitSave < 0 {
41
			unitSave = 0
42
		}
43
		al := AnalyzedLine{
44
			LineItem:    li,
45
			SpreadPrice: price,
46
			UnitSaving:  unitSave,
47
			LineMarket:  round(li.UnitPrice*li.Quantity, 2),
48
			LineSpread:  round(price*li.Quantity, 2),
49
			Matched:     matched,
50
		}
51
		al.LineSaving = round(al.LineMarket-al.LineSpread, 2)
52
		if al.LineSaving < 0 {
53
			al.LineSaving = 0
54
		}
55
56
		rep.Lines = append(rep.Lines, al)
57
		rep.Totals.Market += al.LineMarket
58
		rep.Totals.Spread += al.LineSpread
59
		rep.Totals.Savings += al.LineSaving
60
	}
61
62
	rep.Totals.Lines = len(rep.Lines)
63
	rep.Totals.Market = round(rep.Totals.Market, 2)
64
	rep.Totals.Spread = round(rep.Totals.Spread, 2)
65
	rep.Totals.Savings = round(rep.Totals.Savings, 2)
66
	rep.Totals.OurCut = round(rep.Totals.Savings*CutRate, 2)
67
	rep.Totals.NetSavings = round(rep.Totals.Savings-rep.Totals.OurCut, 2)
68
	return rep
69
}