Enter stdin input for the program and click Run.
#!/usr/bin/env python3
"""ACCT-STMT — deposit-account monthly statement calculator.
Idiomatic Python 3 rebuild of a free-format COBOL program.
Reads three whole-number values from stdin (one per line):
1) account type 1=Checking 2=Savings 3=Money Market
2) opening balance (whole dollars, unsigned)
3) transaction count this cycle
Writes a formatted statement to stdout.
Decimal is used for currency arithmetic to mirror COBOL fixed-point
rounding (ROUND_HALF_UP) and PIC-style edited output formatting.
"""
import sys
from decimal import Decimal, ROUND_HALF_UP
def read_int(stream):
"""ACCEPT a numeric line. COBOL ACCEPT into an unsigned PIC 9 field
interprets the digits; we read one line and parse as int."""
line = stream.readline()
return int(line.strip())
def fmt_pic_bal(value):
"""PIC Z,ZZZ,ZZ9 — 7 digits, comma grouping, leading-zero suppression
(one mandatory final 9 so zero prints as '0'). Field width 9."""
# Truncate to PIC 9(7): keep low 7 digits.
n = int(value) % 10_000_000
s = format(n, ",d")
return s.rjust(9)
def fmt_pic_int(value):
"""PIC ZZ,ZZ9.99 — 5 integer digits w/ grouping (one mandatory 9),
2 decimal places. Field width 9."""
q = value.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
int_part = int(q)
frac = (q - int_part).copy_abs().quantize(Decimal("0.01"))
int_str = format(int_part, ",d")
frac_str = format(frac, ".2f")[2:] # two digits after the point
return (int_str + "." + frac_str).rjust(9)
def fmt_pic_fee(value):
"""PIC ZZ9.99 — 3 integer digits (one mandatory 9), 2 decimals.
Field width 6."""
q = value.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
int_part = int(q)
frac = (q - int_part).copy_abs().quantize(Decimal("0.01"))
frac_str = format(frac, ".2f")[2:]
return (str(int_part) + "." + frac_str).rjust(6)
def fmt_pic_end(value):
"""PIC -Z,ZZZ,ZZ9.99 — leading floating minus sign, 7 integer digits
with grouping (one mandatory 9), 2 decimals. Field width 13.
COBOL edits the sign into the suppressed-zero area: a single '-' floats
immediately left of the most significant printed digit, with the rest
of the suppression zone blank-filled to the left.
"""
q = value.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
negative = q < 0
mag = q.copy_abs()
int_part = int(mag)
frac = (mag - int_part).quantize(Decimal("0.01"))
int_str = format(int_part, ",d")
frac_str = format(frac, ".2f")[2:]
body = int_str + "." + frac_str
# Width 13: optional sign char then the edited number, right-justified.
if negative:
# Sign floats just left of the number; pad the rest with spaces.
out = "-" + body
return out.rjust(13)
return body.rjust(13)
def checking_rules(balance, txns):
rate = Decimal("0")
if balance >= 1500 or txns >= 15:
fee = Decimal("0")
else:
fee = Decimal("12.00")
return rate, fee
def savings_rules(balance, txns):
if balance >= 10000:
rate = Decimal("0.0100")
else:
rate = Decimal("0.0050")
if balance >= 300:
fee = Decimal("0")
else:
fee = Decimal("5.00")
return rate, fee
def mm_rules(balance, txns):
if balance >= 25000:
rate = Decimal("0.0225")
else:
rate = Decimal("0.0150")
if balance >= 10000:
fee = Decimal("0")
else:
fee = Decimal("15.00")
return rate, fee
def main():
acct_type = read_int(sys.stdin)
balance = read_int(sys.stdin)
txn_count = read_int(sys.stdin)
# COBOL fixed-field truncation on ACCEPT:
# WS-ACCT-TYPE PIC 9 -> 1 digit
# WS-BALANCE PIC 9(7)
# WS-TXN-COUNT PIC 9(3)
acct_type %= 10
balance %= 10_000_000
txn_count %= 1000
if acct_type == 1:
type_name = "CHECKING"
rate, fee = checking_rules(balance, txn_count)
elif acct_type == 2:
type_name = "SAVINGS"
rate, fee = savings_rules(balance, txn_count)
elif acct_type == 3:
type_name = "MONEY MARKET"
rate, fee = mm_rules(balance, txn_count)
else:
type_name = "UNKNOWN"
rate = Decimal("0")
fee = Decimal("0")
# COMPUTE WS-INTEREST ROUNDED = WS-BALANCE * WS-ANNUAL-RATE / 12
# WS-INTEREST is PIC 9(7)V99 -> 2 decimal places, ROUNDED = half-up.
interest = (Decimal(balance) * rate / Decimal(12)).quantize(
Decimal("0.01"), rounding=ROUND_HALF_UP
)
# COMPUTE WS-ENDING = WS-BALANCE + WS-INTEREST - WS-FEE (no ROUNDED)
ending = Decimal(balance) + interest - fee
if ending < 0:
od_fee = Decimal("35.00")
ending = ending - od_fee
else:
od_fee = Decimal("0")
# WS-TYPE-NAME is PIC X(12): left-justified, space-padded to 12.
type_field = type_name.ljust(12)
out = sys.stdout
out.write("ACCOUNT TYPE : " + type_field + "\n")
out.write("OPENING BAL : " + fmt_pic_bal(balance) + "\n")
out.write("INTEREST : " + fmt_pic_int(interest) + "\n")
out.write("MAINT FEE : " + fmt_pic_fee(fee) + "\n")
out.write("OVERDRAFT FEE: " + fmt_pic_fee(od_fee) + "\n")
out.write("ENDING BAL : " + fmt_pic_end(ending) + "\n")
if __name__ == "__main__":
main()