Skip to content

Commit 12e3488

Browse files
Add solution for Challenge 7
1 parent 061108a commit 12e3488

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
// Package challenge7 contains the solution for Challenge 7: Bank Account with Error Handling.
2+
package challenge7
3+
4+
import (
5+
"fmt"
6+
"strings"
7+
"sync"
8+
)
9+
10+
// BankAccount represents a bank account with balance management and minimum balance requirements.
11+
type BankAccount struct {
12+
ID string
13+
Owner string
14+
Balance float64
15+
MinBalance float64
16+
mu sync.Mutex // For thread safety
17+
}
18+
19+
// Constants for account operations
20+
const (
21+
MaxTransactionAmount = 10000.0 // Example limit for deposits/withdrawals
22+
)
23+
24+
// Custom error types
25+
26+
// AccountError is a general error type for bank account operations.
27+
type AccountError struct {
28+
message string
29+
}
30+
31+
func (e *AccountError) Error() string {
32+
return e.message
33+
}
34+
35+
// InsufficientFundsError occurs when a withdrawal or transfer would bring the balance below minimum.
36+
type InsufficientFundsError struct {
37+
id string
38+
owner string
39+
amtName string
40+
amount float64
41+
min float64
42+
}
43+
44+
func (e *InsufficientFundsError) Error() string {
45+
return fmt.Sprintf("Acc Id: %s, owner: %s - %s value $%.2f is below minimum $%.2f", e.id, e.owner, e.amtName, e.amount, e.min)
46+
}
47+
48+
// NegativeAmountError occurs when an amount for deposit, withdrawal, or transfer is negative.
49+
type NegativeAmountError struct {
50+
id string
51+
owner string
52+
amtName string
53+
amount float64
54+
}
55+
56+
func (e *NegativeAmountError) Error() string {
57+
return fmt.Sprintf("Acc Id: %s, owner: %s - %s value $%.2f is negative", e.id, e.owner, e.amtName, e.amount)
58+
}
59+
60+
// ExceedsLimitError occurs when a deposit or withdrawal amount exceeds the defined limit.
61+
type ExceedsLimitError struct {
62+
id string
63+
owner string
64+
amtName string
65+
amount float64
66+
}
67+
68+
func (e *ExceedsLimitError) Error() string {
69+
return fmt.Sprintf("Acc Id: %s, owner: %s - %s value $%.2f exceeds max transaction limit $%.2f",
70+
e.id, e.owner, e.amtName, e.amount, MaxTransactionAmount)
71+
}
72+
73+
// NewBankAccount creates a new bank account with the given parameters.
74+
// It returns an error if any of the parameters are invalid.
75+
func NewBankAccount(id, owner string, initialBalance, minBalance float64) (*BankAccount, error) {
76+
if len(strings.TrimSpace(id)) == 0 {
77+
return nil, &AccountError{"invalid id"}
78+
}
79+
if len(strings.TrimSpace(owner)) == 0 {
80+
return nil, &AccountError{"invalid owner"}
81+
}
82+
if initialBalance < 0 {
83+
return nil, &NegativeAmountError{
84+
id: id,
85+
owner: owner,
86+
amtName: "new account initial balance",
87+
amount: initialBalance,
88+
}
89+
}
90+
if minBalance < 0 {
91+
return nil, &NegativeAmountError{
92+
id: id,
93+
owner: owner,
94+
amtName: "new account minimum balance",
95+
amount: minBalance,
96+
}
97+
} // "initial balance less than minimum"
98+
if initialBalance < minBalance {
99+
return nil, &InsufficientFundsError{
100+
id: id,
101+
owner: owner,
102+
amtName: "new account initial balance",
103+
amount: initialBalance,
104+
min: minBalance,
105+
}
106+
}
107+
108+
acc := BankAccount{
109+
ID: id,
110+
Owner: owner,
111+
Balance: initialBalance,
112+
MinBalance: minBalance,
113+
}
114+
return &acc, nil
115+
}
116+
117+
// Deposit adds the specified amount to the account balance.
118+
// It returns an error if the amount is invalid or exceeds the transaction limit.
119+
func (a *BankAccount) Deposit(amount float64) error {
120+
// lock mutex
121+
a.mu.Lock()
122+
defer a.mu.Unlock()
123+
124+
// validate amount
125+
if amount < 0 {
126+
return &NegativeAmountError{
127+
id: a.ID,
128+
owner: a.Owner,
129+
amtName: "deposit amount",
130+
amount: amount,
131+
}
132+
}
133+
if amount > MaxTransactionAmount {
134+
return &ExceedsLimitError{
135+
id: a.ID,
136+
owner: a.Owner,
137+
amtName: "deposit amount",
138+
amount: amount,
139+
}
140+
}
141+
142+
// increment balance
143+
a.Balance += amount
144+
145+
return nil
146+
}
147+
148+
// Withdraw removes the specified amount from the account balance.
149+
// It returns an error if the amount is invalid, exceeds the transaction limit,
150+
// or would bring the balance below the minimum required balance.
151+
func (a *BankAccount) Withdraw(amount float64) error {
152+
// lock mutex
153+
a.mu.Lock()
154+
defer a.mu.Unlock()
155+
156+
// validate amount
157+
if amount < 0 {
158+
return &NegativeAmountError{
159+
id: a.ID,
160+
owner: a.Owner,
161+
amtName: "withdrawal amount",
162+
amount: amount,
163+
}
164+
}
165+
if amount > MaxTransactionAmount {
166+
return &ExceedsLimitError{
167+
id: a.ID,
168+
owner: a.Owner,
169+
amtName: "withdrawal amount",
170+
amount: amount,
171+
}
172+
}
173+
if a.Balance-amount < a.MinBalance {
174+
return &InsufficientFundsError{
175+
id: a.ID,
176+
owner: a.Owner,
177+
amtName: "remaining balance",
178+
amount: a.Balance - amount,
179+
min: a.MinBalance,
180+
}
181+
}
182+
183+
// decrement balance
184+
a.Balance -= amount
185+
186+
return nil
187+
}
188+
189+
// Transfer moves the specified amount from this account to the target account.
190+
// It returns an error if the amount is invalid, exceeds the transaction limit,
191+
// or would bring the balance below the minimum required balance.
192+
func (a *BankAccount) Transfer(amount float64, target *BankAccount) error {
193+
// capture initial balances
194+
initSrcBal := a.Balance
195+
initTgtBal := target.Balance
196+
197+
if err := a.Withdraw(amount); err != nil {
198+
// revert initial balances
199+
a.Balance = initSrcBal
200+
target.Balance = initTgtBal
201+
return err
202+
}
203+
if err := target.Deposit(amount); err != nil {
204+
// revert initial balances
205+
a.Balance = initSrcBal
206+
target.Balance = initTgtBal
207+
return err
208+
}
209+
return nil
210+
}

0 commit comments

Comments
 (0)