#!/bin/bash # carpymnt.sh Friday 3rd December 2004 # A script created by Ross Drummond of West Finance Ltd to calculate payments in a hire purchase contract # Adapted from script in Advanced Bash Guide # To run, this script requires; # bash, a linux/unix/apple OSX shell # bc, a floating point maths program. The bash shell cannot do floating point arithmetic. # perl, a scripting language required by showtable. # showtable, a perl module to display output in a neat text based table. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, you can either send email to this # program's maintainer or write to: The Free Software Foundation, # Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA. function ShowPeriods { echo -e "\t Years \t Months \t Fortnights \t Weeks \n \t ½ \t 6 \t 13 \t 26 \n \t 1 \t 12 \t 26 \t 52 \n \t 1 ½ \t 18 \t 39 \t 78 \n \t 2 \t 24 \t 52 \t 104 \n \t 2 ½ \t 30 \t 65 \t 130 \n \t 3 \t 36 \t 78 \t 156 \n Payments per year \t 1 \t 12 \t 26 \t 52"|showtable -t=1 ; } function isdigit { # Test if number is digit & not null. if [ -z "$1" ] ; then echo "You didn't enter anything. Enter 0 (zero) at least." return 1 fi # Strip digits with sed. If the nodigits variable is filled then non digits have been passed, thus an error. local nodigits="$(echo $1 | sed 's/[[:digit:]]//g')" if [ ! -z "$nodigits" ] ; then echo "Invalid number format! Only whole numbers, no commas, spaces, decimal points, etc." return 1 fi return 0 } # Lets test to see if either bc or showtable is installed. # Test code borrowed from Volker Kuhlmann. http://cantua.canterbury.ac.nz/~vku10/ Thanks Volker. type bc >/dev/null 2>&1 || { echo "Oops - Can't find bc. Install it first!"; exit; } type showtable >/dev/null 2>&1 || { echo "Oops - Can't find showtable. Install it first!"; exit; } echo -e "Welcome to this bash script that calculates payments for a hire purchase contract. \nPlease follow the prompts. \nIt will return the figures required to write up the contract. \n******Important; Enter whole dollars only and zero for empty fields.******\n" echo -e "Do you wish to view a table of payment periods? (y/n)" read ViewTable if [[ "$ViewTable" = [yY] ]]; then ShowPeriods fi echo -e "Enter the purchase price." read PurchasePrice isdigit $PurchasePrice # If isdigit function returns anything other than zero we have an error. if [ $? -ne 0 ];then exit fi echo "Enter the PPI premium." read PPI isdigit $PPI if [ $? -ne 0 ];then exit fi echo "Enter other charges." read OtherCharges isdigit $OtherCharges if [ $? -ne 0 ];then exit fi echo "Enter deposit." read Deposit isdigit $Deposit if [ $? -ne 0 ];then exit fi (( $Deposit >= $PurchasePrice )) && { echo "deposit greater than or equal to Purchase price" >&2 exit } echo "Enter trade in allowance." read TradeIn isdigit $TradeIn if [ $? -ne 0 ];then exit fi (( $TradeIn >= $PurchasePrice )) && { echo "Trade in greater than or equal to Purchase price" >&2 exit } echo "Enter the number of payments over the term of the loan" read NumPayments isdigit $NumPayments if [ $? -ne 0 ];then exit fi echo "Enter the number of payments in a year" read AnnualPayments isdigit $AnnualPayments if [ $? -ne 0 ];then exit fi echo -e "Enter interest rate. If 12.5%, enter \"12.5\", not \".125\"." read InterestRate echo "Enter documentation fee." read DocumentationFee isdigit $DocumentationFee if [ $? -ne 0 ];then exit fi echo "Enter other fixed charges." read OtherFixedCharges isdigit $OtherFixedCharges if [ $? -ne 0 ];then exit fi # date is really annal about the format of any dates. echo -e "Enter the date of first payment. \nPlease use the following format yyyymmdd ie 20041231 for 31/12/2004." read FirstPaymentDate TotalGrossCost=$(($PurchasePrice + $PPI + $OtherCharges)) TotalDeposit=$(($TradeIn + $Deposit)) AmountFinanced=$(($TotalGrossCost - $TotalDeposit)) TotalFixedCharges=$(($DocumentationFee + $OtherFixedCharges)) interest_r=$(echo "scale=9; $InterestRate/100.0" |bc) interest_rat=$(echo "scale=9; $interest_r/$AnnualPayments + 1.0" | bc) top=$(echo "scale=9; $AmountFinanced*$interest_rat^$NumPayments" | bc) months=$(($NumPayments - 1)) # bad choice of variable name #This is the part that calculates the payments. #for ((x=$months; x > 0; x--)) # do # bot=$(echo "scale=9; $interest_rat^$x" | bc) # bottom=$(echo "scale=9; $bottom+$bot" | bc) # done # This line below replaces the commented out for loop above. Executes the for loop in bc rather than bash. Is more efficient. bottom=$(echo -e "r=$interest_rat; b=1.0; for(x=$months; x > 0; x--){c=r ^ x; b=b + c}; b " |bc -w) payment=$(echo "scale=2; $top/$bottom" | bc) FixedCostsPerInstallment=$(echo "scale=2; $TotalFixedCharges/$NumPayments" | bc) InstallmentAmount=$(echo "scale=2; $FixedCostsPerInstallment + $payment" | bc) BalancePayable=$(echo "scale=2; $InstallmentAmount * $NumPayments" | bc) CostofCredit=$(echo "scale=2; $BalancePayable - $AmountFinanced" | bc) InterestCharged=$(echo "scale=2; $CostofCredit - $TotalFixedCharges" | bc) # This block of code extracts payment interval from number of payments in year. Required for date arithmetic in date command. unset Dateunits case "$AnnualPayments" in 1 ) Dateunits=years;; 12 ) Dateunits=months;; 26 ) Dateunits=fortnights;; 52 ) Dateunits=weeks;; *) Dateunits="Not calculated";; # Difficult to calculate final payment date for unusual payment intervals. esac if [ "$Dateunits" = "Not calculated" ] then LastPaymentDate=$Dateunits # We are not going to calculate the final payment date else # Adjust the number of payments by minus one as we are calculating the last payment from the first payment # date, not the start of the loan. NumPaymentsAdj=$(($NumPayments - 1)) globbb=`echo -e "$FirstPaymentDate $NumPaymentsAdj $Dateunits\c"` #date seems unable to digest arguments unless in this form. LastPaymentDate=`date --date="$globbb" +'%A %d %B %Y'` fi Formatted1stPaymentDate=`date -d $FirstPaymentDate +'%A %d %B %Y'` # Pretty it up for the table # printf "%'i" formats numbers with comma seperators for thousands etc. echo -e "What \t Amount\nTotal gross cost (A) \t \$`printf "%'i" $TotalGrossCost` \nTotal deposit (B) \t \$`printf "%'i" $TotalDeposit` \nAmount financed (C) \t \$`printf "%'i" $AmountFinanced` \nNumber of Installments \t $NumPayments \nInterest rate \t $InterestRate% \nInstalment amount \t \$`printf "%'1.2f" $InstallmentAmount`\nInterest charged \t \$`printf "%'1.2f" $InterestCharged` \nCost of credit \t \$`printf "%'1.2f" $CostofCredit` \nBalance payable \t \$`printf "%'1.2f" $BalancePayable` \nFirst payment date \t $Formatted1stPaymentDate \nLast payment date \t $LastPaymentDate"|showtable -t=1