Summary component was moved to master.tpl because sub-template calls allow only one argument to be passed. Passing info for both Estimate and Loan structs dynamically would involve looping during template execution, or calling a custom function to restructure the estimate, which are all too complicated.master
@@ -121,6 +121,7 @@ type Loan struct { | |||||
Interest float32 `json:"interest"` | Interest float32 `json:"interest"` | ||||
Mi MI `json:"mi"` | Mi MI `json:"mi"` | ||||
Fees []Fee `json:"fees"` | Fees []Fee `json:"fees"` | ||||
Credits []Fee // Fees with negative amounts for internal use | |||||
Name string `json:"title"` | Name string `json:"title"` | ||||
Result Result `json:"result"` | Result Result `json:"result"` | ||||
} | } | ||||
@@ -231,7 +232,20 @@ func cachePdf(name string) Page { | |||||
return strconv.FormatFloat(float64(b - a)/100, 'f', 2, 32) | return strconv.FormatFloat(float64(b - a)/100, 'f', 2, 32) | ||||
} | } | ||||
fm := template.FuncMap{ "dollars": dollars, "diff": diff } | sortFees := func(ftype string, fees []Fee) []Fee { | ||||
result := make([]Fee, 0) | |||||
for i := range fees { | |||||
if fees[i].Type != ftype { continue } | |||||
result = append(result, fees[i]) | |||||
} | |||||
return result | |||||
} | |||||
fm := template.FuncMap{ | |||||
"dollars": dollars, | |||||
"diff": diff, | |||||
"sortFees": sortFees } | |||||
var p = []string{"views/report/master.tpl", | var p = []string{"views/report/master.tpl", | ||||
"views/report/header.tpl", | "views/report/header.tpl", | ||||
"views/report/summary.tpl", | "views/report/summary.tpl", | ||||
@@ -1871,6 +1885,15 @@ func showPDF(w http.ResponseWriter, r *http.Request) { | |||||
info.Letterhead = | info.Letterhead = | ||||
base64.StdEncoding.EncodeToString(letterhead) | base64.StdEncoding.EncodeToString(letterhead) | ||||
for l := range info.Estimate.Loans { | |||||
loan := info.Estimate.Loans[l] | |||||
for f := range info.Estimate.Loans[l].Fees { | |||||
if info.Estimate.Loans[l].Fees[f].Amount < 0 { | |||||
loan.Credits = append(loan.Credits, loan.Fees[f]) | |||||
} | |||||
} | |||||
} | |||||
err = page.tpl.ExecuteTemplate(w, "master.tpl", info) | err = page.tpl.ExecuteTemplate(w, "master.tpl", info) | ||||
if err != nil {fmt.Println(err)} | if err != nil {fmt.Println(err)} | ||||
@@ -14,10 +14,14 @@ | |||||
{{range .Estimate.Loans}}<td>{{.Amortization}}</td>{{end}}</tr> | {{range .Estimate.Loans}}<td>{{.Amortization}}</td>{{end}}</tr> | ||||
<tr><td>Interest rate</td> | <tr><td>Interest rate</td> | ||||
{{range .Estimate.Loans}}<td>{{.Interest}}%</td>{{end}}</tr> | {{range .Estimate.Loans}}<td>{{.Interest}}%</td>{{end}}</tr> | ||||
<tr><td>Loan payment</td> | |||||
{{range .Estimate.Loans}}<td>${{dollars .Result.LoanPayment}}/month</td>{{end}}</tr> | |||||
<tr><td>Monthly MI</td> | <tr><td>Monthly MI</td> | ||||
{{range .Estimate.Loans}}<td>${{dollars .Mi.Premium}}/month</td>{{end}}</tr> | {{range .Estimate.Loans}}<td>${{dollars .Mi.Premium}}/month</td>{{end}}</tr> | ||||
<tr><td>Real estate taxes</td> | <tr><td>Real estate taxes</td> | ||||
{{range .Estimate.Loans}}<td>${{dollars .Tax}}/month</td>{{end}}</tr> | {{range .Estimate.Loans}}<td>${{dollars .Tax}}/month</td>{{end}}</tr> | ||||
<tr><td>Hazard insurance</td> | |||||
{{range .Estimate.Loans}}<td>${{dollars .Hazard}}/month</td>{{end}}</tr> | |||||
<tr class="total"><td>Total monthly</td> | <tr class="total"><td>Total monthly</td> | ||||
{{range .Estimate.Loans}}<td>${{dollars .Result.TotalMonthly}}</td>{{end}}</tr> | {{range .Estimate.Loans}}<td>${{dollars .Result.TotalMonthly}}</td>{{end}}</tr> | ||||
<tr class="gap"></tr> | <tr class="gap"></tr> | ||||
@@ -14,22 +14,78 @@ Get an official quote before choosing a loan.</p> | |||||
{{template "header" .}} | {{template "header" .}} | ||||
{{template "comparison" .}} | {{template "comparison" .}} | ||||
{{range .Estimate.Loans}} | |||||
<div class="break"></div> | <div class="break"></div> | ||||
<div class="disclaimer"> | <div class="disclaimer"> | ||||
<p>Actual costs may vary from estimates after approval. | <p>Actual costs may vary from estimates after approval. | ||||
Get an official quote before choosing a loan.</p> | Get an official quote before choosing a loan.</p> | ||||
</div> | </div> | ||||
{{template "header" .}} | {{template "header" $}} | ||||
{{template "summary" .}} | <section class="summary"> | ||||
<h1>{{.Name}}</h1> | |||||
<h4>{{.Type.Name}} {{.Term}} Year, {{.Amortization}} rate</h4> | |||||
<div> | |||||
<div class="entries"> | |||||
<h4 class="title">Monthly Payment</h4> | |||||
<p><span>Loan payment</span> <span>${{dollars .Result.LoanPayment}}</span></p> | |||||
<p><span>Mortgage insurance</span> <span>${{dollars .Mi.Premium}}</span></p> | |||||
<p><span>Property taxes</span> <span>${{dollars .Tax}}</span></p> | |||||
<p><span>Homeowner's insurance</span> <span>${{dollars .Hoi}}</span></p> | |||||
<p class="total"><span>Total</span> <span>${{dollars .Result.TotalMonthly}}</span></p> | |||||
</div> | |||||
<div class="entries"> | |||||
<h4 class="title">Transaction Details</h4> | |||||
<p><span>Down payment</span> <span>${{diff .Amount $.Estimate.Price}}</span></p> | |||||
<p><span>Closing costs</span> <span>${{dollars .Result.TotalFees}}</span></p> | |||||
<p><span>Credits</span> <span>${{dollars .Result.TotalCredits}}</span></p> | |||||
<p class="total"><span>Total</span> | |||||
<span>${{dollars .Result.CashToClose}}</span></p> | |||||
</div> | |||||
</div> | |||||
<h2>Closing Costs Breakdown</h2> | |||||
<div> | |||||
<div class="entries"> | |||||
<h4 class="title">Fees Paid to Lender</h4> | |||||
{{range (sortFees "Lender" .Fees)}} | |||||
<p><span>{{.Name}}</span> <span>${{dollars .Amount}}</span></p> | |||||
{{end}} | |||||
</div> | |||||
<div class="entries"> | |||||
<h4 class="title">Items Required by Lender</h4> | |||||
{{range (sortFees "Required" .Fees)}} | |||||
<p><span>{{.Name}}</span> <span>${{dollars .Amount}}</span></p> | |||||
{{end}} | |||||
</div> | |||||
<div class="entries"> | |||||
<h4 class="title">Title Company Fees</h4> | |||||
{{range (sortFees "Title" .Fees)}} | |||||
<p><span>{{.Name}}</span> <span>${{dollars .Amount}}</span></p> | |||||
{{end}} | |||||
</div> | |||||
<div class="entries"> | |||||
<h4 class="title">Goverment and Recording Fees</h4> | |||||
{{range (sortFees "Government" .Fees)}} | |||||
<p><span>{{.Name}}</span> <span>${{dollars .Amount}}</span></p> | |||||
{{end}} | |||||
</div> | |||||
<div class="entries"> | |||||
<h4 class="title">Other Fees</h4> | |||||
{{range (sortFees "Other" .Fees)}} | |||||
<p><span>{{.Name}}</span> <span>${{dollars .Amount}}</span></p> | |||||
{{end}} | |||||
</div> | |||||
</div> | |||||
</section> | |||||
{{end}} | |||||
</body> | </body> | ||||
<style> | <style> | ||||
#pdf-doc { | |||||
margin: 0px 30px; | |||||
} | |||||
.disclaimer { | .disclaimer { | ||||
font-weight: bold; | font-weight: bold; | ||||
border-bottom: 1px solid lightgrey; | border-bottom: 1px solid lightgrey; | ||||
@@ -45,4 +101,45 @@ Get an official quote before choosing a loan.</p> | |||||
div.break { | div.break { | ||||
page-break-after: always; | page-break-after: always; | ||||
} | } | ||||
.summary h1 { | |||||
text-align: center; | |||||
} | |||||
.summary h2 { | |||||
text-align: center; | |||||
font-size: 20px; | |||||
color: #4C555E; | |||||
} | |||||
.summary h4 { | |||||
text-align: center; | |||||
font-weight: normal; | |||||
margin-bottom: 25px; | |||||
} | |||||
.summary > div { | |||||
display: flex; | |||||
flex-flow: wrap; | |||||
justify-content: center; | |||||
} | |||||
.summary .entries { | |||||
width: 300px; | |||||
margin: 0 10px; | |||||
} | |||||
.summary .entries h4 { | |||||
background: #F5F5F3; | |||||
padding: 5px; | |||||
} | |||||
.summary .entries p { | |||||
display: flex; | |||||
justify-content: space-between; | |||||
border-bottom: 1px solid #F5F5F3; | |||||
} | |||||
p.total { | |||||
font-weight: bold; | |||||
} | |||||
</style> | </style> |