Browse Source

Represent money as int and percentages as float32

master
Immanuel Onyeka 1 year ago
parent
commit
e9968ae63b
4 changed files with 59 additions and 47 deletions
  1. +6
    -5
      components/new/details.vue
  2. +15
    -15
      components/new/new.vue
  3. +37
    -26
      components/new/summary.vue
  4. +1
    -1
      skouter.go

+ 6
- 5
components/new/details.vue View File

@@ -48,7 +48,7 @@
<section class="form inputs"> <section class="form inputs">
<h3>Property Details</h3> <h3>Property Details</h3>
<label>Price ($)</label> <label>Price ($)</label>
<input :value="estimate.price" @input="(e) => $emit('update:price', strip(e))">
<input :value="estimate.price/100" @input="(e) => $emit('update:price', strip(e))">
<label>Type</label> <label>Type</label>
<select id="" name="" <select id="" name=""
:value="estimate.property" :value="estimate.property"
@@ -113,7 +113,7 @@
<label>Total DTI (%) - Optional</label> <label>Total DTI (%) - Optional</label>
<input :value="loan.dti" @input="(e) => $emit('update:dti', e)"> <input :value="loan.dti" @input="(e) => $emit('update:dti', e)">
<label>Home Owner's Association ($/month)</label> <label>Home Owner's Association ($/month)</label>
<input :value="loan.hoa"
<input :value="loan.hoa / 100"
@input="(e) => { $emit('update:hoa', strip(e)) }"> @input="(e) => { $emit('update:hoa', strip(e)) }">


<label>Interest Rate (%)</label> <label>Interest Rate (%)</label>
@@ -127,14 +127,14 @@
<input :value="loan.hazardEscrow" <input :value="loan.hazardEscrow"
@input="(e) => { $emit('update:hazardEscrow', stripInt(e)) }"> @input="(e) => { $emit('update:hazardEscrow', stripInt(e)) }">
<label>Hazard Insurance ($/month)</label> <label>Hazard Insurance ($/month)</label>
<input :value="loan.hazard"
<input :value="loan.hazard / 100"
@input="(e) => $emit('update:hazard', strip(e))"> @input="(e) => $emit('update:hazard', strip(e))">


<label>Real Estate Tax Escrow (months)</label> <label>Real Estate Tax Escrow (months)</label>
<input :value="loan.taxEscrow" <input :value="loan.taxEscrow"
@input="e => $emit('update:taxEscrow', stripInt(e))"> @input="e => $emit('update:taxEscrow', stripInt(e))">
<label>Real Estate Tax ($/month)</label> <label>Real Estate Tax ($/month)</label>
<input :value="loan.tax"
<input :value="loan.tax/100"
@input="(e) => $emit('update:tax', strip(e))"> @input="(e) => $emit('update:tax', strip(e))">
</section> </section>


@@ -144,7 +144,8 @@
:key="fee.name + indx" class="fee" :key="fee.name + indx" class="fee"
> >
<label> <label>
${{fee.amount}}{{ fee.perc ? ` ${fee.perc}%` : ''}} - {{fee.name}}<br>
${{(fee.amount / 100).toFixed(2)}}
{{ fee.perc ? ` ${fee.perc}%` : ''}} - {{fee.name}}<br>
{{fee.type}} {{fee.type}}
</label> </label>
<img width="21" height="21" src="/assets/image/icon/x-red.svg" <img width="21" height="21" src="/assets/image/icon/x-red.svg"


+ 15
- 15
components/new/new.vue View File

@@ -37,26 +37,26 @@ class="bi bi-plus" viewBox="0 0 16 16"> <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0
@update:property="(p) => estimate.property = p" @update:property="(p) => estimate.property = p"


@update:loanType="(lt) => loan.type.id = lt" @update:loanType="(lt) => loan.type.id = lt"
@update:term="(lt) => loans[sel].term = lt"
@update:term="(lt) => loan.term = lt"
@update:program="(p) => loans[sel].program = p" @update:program="(p) => loans[sel].program = p"
@update:ltv="setLtv" @update:ltv="setLtv"
@update:amount="setAmount" @update:amount="setAmount"
@update:housingDti="setHousingDti" @update:housingDti="setHousingDti"
@update:dti="setDti" @update:dti="setDti"
@update:hoa="(hoa) => loans[sel].hoa = hoa"
@update:interest="(i) => loans[sel].interest = i"
@update:hoa="(hoa) => loan.hoa = hoa*100"
@update:interest="(i) => loan.interest = i"
@update:interestDays="(d) => loans[sel].interestDays = d" @update:interestDays="(d) => loans[sel].interestDays = d"
@update:hazardEscrow="(h) => loans[sel].hazardEscrow = h" @update:hazardEscrow="(h) => loans[sel].hazardEscrow = h"
@update:hazard="(h) => loans[sel].hazard = h"
@update:hazard="(h) => loan.hazard = h * 100"
@update:taxEscrow="(t) => loans[sel].taxEscrow = t" @update:taxEscrow="(t) => loans[sel].taxEscrow = t"
@update:tax="(t) => loans[sel].tax = t"
@update:manualMI="perc => loans[sel].mi.rate = perc"
@update:tax="(t) => loan.tax = t*100"
@update:manualMI="perc => loan.mi.rate = perc"
@toggle:manualMIMonthly= @toggle:manualMIMonthly=
"() => loans[sel].mi.monthly = !loans[sel].mi.monthly" "() => loans[sel].mi.monthly = !loans[sel].mi.monthly"
@continue="generate" @continue="generate"
/> />
<loan-summary v-if="hash == '#new/summary'" <loan-summary v-if="hash == '#new/summary'"
:loan="loan" :downpayment="estimate.price - loan.amount" :token="token" :estimate="estimate"/>
:loan="loan" :downpayment="estimate.price - loan.amount" :token="token" :estimate="estimate"/>


</div> </div>
</template> </template>
@@ -81,7 +81,7 @@ const example = {
hazardEscrow: 0, // Hazard insurance escrow in months (0 is none) hazardEscrow: 0, // Hazard insurance escrow in months (0 is none)
tax: 0, // Real Estate taxes monthly payment tax: 0, // Real Estate taxes monthly payment
taxEscrow: 0, // Months to escrow (0 is none) taxEscrow: 0, // Months to escrow (0 is none)
hoa: 100, // Home owner's association monthly fee
hoa: 10000, // Home owner's association monthly fee
program: "", program: "",
pud: true, // Property under development pud: true, // Property under development
zip: '', zip: '',
@@ -133,7 +133,7 @@ function del() {


// Updates the property price for all loans and their fee amounts. // Updates the property price for all loans and their fee amounts.
function setPrice(value) { function setPrice(value) {
this.estimate.price = value
this.estimate.price = Math.round(value*100)
this.estimate.loans[this.sel].fees.forEach(fee => { this.estimate.loans[this.sel].fees.forEach(fee => {
if (fee.perc) fee.amount = (fee.perc / 100 * value).toFixed(2) if (fee.perc) fee.amount = (fee.perc / 100 * value).toFixed(2)
}) })
@@ -151,21 +151,21 @@ function setLtv(e) {


this.loan.ltv = ltv this.loan.ltv = ltv
let num = ltv / 100 * this.estimate.price let num = ltv / 100 * this.estimate.price
this.loan.amount = Math.round(num*100)
this.loan.amount = Math.round(num)
} }


// Changes loan.amount\'s <input> and data() values, then syncs with data.ltv // Changes loan.amount\'s <input> and data() values, then syncs with data.ltv
// Loan amount is in cents but LTV is in decimals so some rounding needs to be done. // Loan amount is in cents but LTV is in decimals so some rounding needs to be done.
function setAmount(e) { function setAmount(e) {
let amount = strip(e)
let amount = strip(e) * 100
if (!this.estimate.price) return if (!this.estimate.price) return


if (amount > this.loan.price) amount = this.loan.price
if (amount > this.estimate.price) amount = this.estimate.price
if (amount < 0) amount = 0 if (amount < 0) amount = 0


this.loan.amount = Math.round(amount * 100)
let num = amount / this.estimate.price * 100
this.loan.ltv = Math.round(num*100) / 100
this.loan.amount = Math.round(amount)
let num = amount / this.estimate.price
this.loan.ltv = Math.round(num*100)
} }


function setDti(e) { function setDti(e) {


+ 37
- 26
components/new/summary.vue View File

@@ -1,22 +1,23 @@
<template> <template>
<div v-if="downpayment && totalMonthly > 0">
<div v-if="valid">


<section class="form inputs"> <section class="form inputs">
<h3>Monthly Payment - ${{totalMonthly}}</h3>
<label>Loan payment: ${{loanPayment.toFixed(2)}}</label>
<h3>Monthly Payment - ${{format(totalMonthly)}}</h3>
<label>Loan payment: ${{format(loanPayment)}}</label>
<label v-if="loan.mi.monthly"> <label v-if="loan.mi.monthly">
Mortgage insurance: ${{(loan.amount*loan.mi.rate/100/12).toFixed(2)}}
Mortgage insurance: ${{format(loan.amount*loan.mi.rate/100/12)}}
</label> </label>
<label>Property taxes: ${{loan.tax}}</label>
<label>Property taxes: ${{format(loan.tax)}}</label>
<label>Homeowner's Insurance: ${{format(loan.hoa)}}</label>
</section> </section>


<section class="form inputs"> <section class="form inputs">
<h3>Cash to Close - ${{totalMonthly}}</h3>
<label>Closing costs: ${{fees}}</label>
<h3>Cash to Close - ${{format(cashToClose)}}</h3>
<label>Closing costs: ${{format(fees)}}</label>
<label v-if="credits">Credits: ${{credits}}</label> <label v-if="credits">Credits: ${{credits}}</label>
<label>Down payment: ${{downpayment.toFixed(2)}}</label>
<label>Down payment: ${{format(downpayment)}}</label>
<label v-if="!loan.mi.monthly"> <label v-if="!loan.mi.monthly">
Mortgage insurance: ${{(loanPayment*loan.mi.rate/100).toFixed(2)}}
Mortgage insurance: ${{format(loan.amount*loan.mi.rate/100)}}
</label> </label>
</section> </section>


@@ -30,7 +31,8 @@


<script setup> <script setup>
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
const props = defineProps(['downpayment', 'loan', 'valid', 'token', 'estimate'])
let valid = ref(false)
const props = defineProps(['downpayment', 'loan', 'token', 'estimate'])


function amortize(principle, rate, periods) { function amortize(principle, rate, periods) {
return principle * rate*(1+rate)**periods / ((1+rate)**periods - 1) return principle * rate*(1+rate)**periods / ((1+rate)**periods - 1)
@@ -38,43 +40,46 @@ function amortize(principle, rate, periods) {


const loanPayment = computed(() => { const loanPayment = computed(() => {
let amount = props.loan.amount let amount = props.loan.amount
if (!props.loan.mi.monthly) amount =
amount + props.loan.mi.rate/100*(amount+props.downpayment)
return amortize(props.loan.amount, return amortize(props.loan.amount,
props.loan.interest / 100 / 12, props.loan.interest / 100 / 12,
props.loan.term*12) props.loan.term*12)
}) })
const totalMonthly = computed (
() => (loanPayment.value +
const totalMonthly = computed (() => {
let total = loanPayment.value +
props.loan.tax + props.loan.tax +
props.loan.hoa + props.loan.hoa +
props.loan.hazard).toFixed(2)
)

const totalCash = computed (
() => (fees.value +
credits.value +
props.downpayment).toFixed(2)
)
props.loan.hazard
if (props.loan.mi.monthly) {
total = total + props.loan.mi.rate/100*(props.loan.amount)
}
return total
})


// Closing costs // Closing costs
const fees = computed(() => { const fees = computed(() => {
return props.loan.fees.reduce((total, x) => { return props.loan.fees.reduce((total, x) => {
return x.amount > 0 ? total + x.amount : 0 return x.amount > 0 ? total + x.amount : 0
}, 0 }, 0
).toFixed(2)
)
}) })


const credits = computed(() => { const credits = computed(() => {
return props.loan.fees.reduce((total, x) => { return props.loan.fees.reduce((total, x) => {
return x.amount < 0 ? total + x.amount : 0 return x.amount < 0 ? total + x.amount : 0
}, 0 }, 0
).toFixed(2)
)
}) })


const cashToClose = computed(() => { const cashToClose = computed(() => {
return fees + credits + downpayment
let total = fees.value + credits.value + props.downpayment
if (!props.loan.mi.monthly) {
total = total + props.loan.mi.rate/100*(props.loan.amount)
}
return total
}) })


function validate() { function validate() {
@@ -87,15 +92,21 @@ function validate() {
}, },
}).then(resp => { }).then(resp => {
if (resp.ok && resp.status == 200) { if (resp.ok && resp.status == 200) {
valid.value = true
return return
} else { } else {
// resp.text().then(t => this.errors = [t]) // resp.text().then(t => this.errors = [t])
window.location.hash = 'new'
// window.location.hash = 'new'
} }
}) })


} }


// Print number of cents as a nice string of dollars
function format(num) {
return (num/100).toFixed(2)
}

onMounted(() => {validate()}) onMounted(() => {validate()})


</script> </script>

+ 1
- 1
skouter.go View File

@@ -94,7 +94,7 @@ type Loan struct {
Ltv float32 `json:"ltv"` Ltv float32 `json:"ltv"`
Dti float32 `json:"dti"` Dti float32 `json:"dti"`
Hoi int `json:"hoi"` Hoi int `json:"hoi"`
Interest int `json:"interest"`
Interest float32 `json:"interest"`
Mi MI `json:"mi"` Mi MI `json:"mi"`
Fees []Fee `json:"fees"` Fees []Fee `json:"fees"`
Name string `json:"name"` Name string `json:"name"`


Loading…
Cancel
Save