Solution
Here's the complete code that solves the two challenges in this module.
Bank core test: bank_test.go
//...
func TestTransfer(t *testing.T) {
accountA := Account{
Customer: Customer{
Name: "John",
Address: "Los Angeles, California",
Phone: "(213) 555 0147",
},
Number: 1001,
Balance: 0,
}
accountB := Account{
Customer: Customer{
Name: "Mark",
Address: "Irvine, California",
Phone: "(949) 555 0198",
},
Number: 1002,
Balance: 0,
}
accountA.Deposit(100)
err := accountA.Transfer(50, &accountB)
if accountA.Balance != 50 && accountB.Balance != 50 {
t.Error("transfer from account A to account B is not working", err)
}
}
Bank Core: bank.go
package bank
import (
"errors"
"fmt"
)
//...
// Transfer function
func (a *Account) Transfer(amount float64, dest *Account) error {
if amount <= 0 {
return errors.New("the amount to transfer should be greater than zero")
}
if a.Balance < amount {
return errors.New("the amount to transfer should be greater than the account's balance")
}
a.Withdraw(amount)
dest.Deposit(amount)
return nil
}
// Bank ...
type Bank interface {
Statement() string
}
// Statement ...
func Statement(b Bank) string {
return b.Statement()
}
Bank API: main.go
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strconv"
"github.com/msft/bank"
)
var accounts = map[float64]*CustomAccount{}
func main() {
accounts[1001] = &CustomAccount{
Account: &bank.Account{
Customer: bank.Customer{
Name: "John",
Address: "Los Angeles, California",
Phone: "(213) 555 0147",
},
Number: 1001,
},
}
accounts[1002] = &CustomAccount{
Account: &bank.Account{
Customer: bank.Customer{
Name: "Mark",
Address: "Irvine, California",
Phone: "(949) 555 0198",
},
Number: 1002,
},
}
http.HandleFunc("/statement", statement)
http.HandleFunc("/deposit", deposit)
http.HandleFunc("/withdraw", withdraw)
http.HandleFunc("/transfer", transfer)
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
//...
func transfer(w http.ResponseWriter, req *http.Request) {
numberqs := req.URL.Query().Get("number")
amountqs := req.URL.Query().Get("amount")
destqs := req.URL.Query().Get("dest")
if numberqs == "" {
fmt.Fprintf(w, "Account number is missing!")
return
}
if number, err := strconv.ParseFloat(numberqs, 64); err != nil {
fmt.Fprintf(w, "Invalid account number!")
} else if amount, err := strconv.ParseFloat(amountqs, 64); err != nil {
fmt.Fprintf(w, "Invalid amount number!")
} else if dest, err := strconv.ParseFloat(destqs, 64); err != nil {
fmt.Fprintf(w, "Invalid account destination number!")
} else {
if accountA, ok := accounts[number]; !ok {
fmt.Fprintf(w, "Account with number %v can't be found!", number)
} else if accountB, ok := accounts[dest]; !ok {
fmt.Fprintf(w, "Account with number %v can't be found!", dest)
} else {
err := accountA.Transfer(amount, accountB.Account)
if err != nil {
fmt.Fprintf(w, "%v", err)
} else {
fmt.Fprintf(w, accountA.Statement())
}
}
}
}
func statement(w http.ResponseWriter, req *http.Request) {
numberqs := req.URL.Query().Get("number")
if numberqs == "" {
fmt.Fprintf(w, "Account number is missing!")
return
}
number, err := strconv.ParseFloat(numberqs, 64)
if err != nil {
fmt.Fprintf(w, "Invalid account number!")
} else {
account, ok := accounts[number]
if !ok {
fmt.Fprintf(w, "Account with number %v can't be found!", number)
} else {
json.NewEncoder(w).Encode(bank.Statement(account))
}
}
}
// CustomAccount ...
type CustomAccount struct {
*bank.Account
}
// Statement ...
func (c *CustomAccount) Statement() string {
json, err := json.Marshal(c)
if err != nil {
return err.Error()
}
return string(json)
}