//ATM Simulation Implementation - Individual Transactions

ATM Simulation Implementation - Individual Transactions

/*
 * Example ATM simulation - file transaction.cc
 *
 * This file implements the classes that represent the various kinds of
 * transactions that the ATM can perform, declared in transaction.h
 *
 * Copyright (c) 1996,1997 - Russell C. Bjork
 *
 */

#include 
#include "sysdep.h"
#include "status.h"
#include "money.h"
#include "bank.h"
#include "session.h"
#include "transaction.h"
#include "atmparts.h"
#include "atm.h"

//


Transaction::Transaction(Session & session, ATM & atm, Bank & bank)
  : _session(session), _atm(atm), _bank(bank),
    _serialNumber(++ _lastSerialNumberAssigned)
  { }

//


int Transaction::_lastSerialNumberAssigned = 0;

//


Transaction * Transaction::chooseTransaction(Session & session,
                                             ATM & atm,
                                             Bank & bank)
  { const char * transactionMenu[] =
      { "Cash Withdrawl",
        "Deposit",
        "Transfer Funds Between Accounts",
        "Balance Inquiry"
      };
     switch (atm.getMenuChoice("Please choose a transaction type:",
                               4, transactionMenu))
      {
        case 1: return new WithdrawlTransaction(session, atm, bank);
        case 2: return new DepositTransaction(session, atm, bank);
        case 3: return new TransferTransaction(session, atm, bank);
        case 4: return new InquiryTransaction(session, atm, bank);
      }
  }

//


Status::Code Transaction::doTransactionUseCase()
  {
    Status::Code code;
    code = getTransactionSpecificsFromCustomer();
    if (code != Status::SUCCESS)
        return code;
    code = sendToBank();
    if (code == Status::INVALID_PIN)
      {
        code = _session.doInvalidPINExtension();
        if (code == Status::INVALID_PIN)
            return code;
      }
    if (code == Status::SUCCESS)
        code = finishApprovedTransaction();
    return code;
  }

//


// getTransactionSpecificsFromCustomer() is abstract for class Transaction::

Status::Code WithdrawlTransaction::getTransactionSpecificsFromCustomer()
  {
    _fromAccount = _bank.chooseAccountType("withdraw from", _atm);
    const char * menu[] =
      { "$ 20", "$ 40", "$ 60", "$ 80", "$ 100", "$ 200", "$ 300" };
    switch (_atm.getMenuChoice("Please choose an amount:", 7, menu))
      {
        case 1: _amount = Money(20); break;
        case 2: _amount = Money(40); break;
        case 3: _amount = Money(60); break;
        case 4: _amount = Money(80); break;
        case 5: _amount = Money(100); break;
        case 6: _amount = Money(200); break;
        case 7: _amount = Money(300); break;
      }
    if (_atm.checkIfCashAvailable(_amount))
       return Status::SUCCESS;
    else
       return Status::TOO_LITTLE_CASH;
  }


Status::Code DepositTransaction::getTransactionSpecificsFromCustomer()
  {
    _toAccount = _bank.chooseAccountType("deposit to", _atm);
    _amount = _atm.getAmountEntry();
    return Status::SUCCESS;
  }

Status::Code TransferTransaction::getTransactionSpecificsFromCustomer()
  {
    _fromAccount = _bank.chooseAccountType("transfer from", _atm);
    _toAccount = _bank.chooseAccountType("transfer to", _atm);
    _amount = _atm.getAmountEntry();
    return Status::SUCCESS;
  }

Status::Code InquiryTransaction::getTransactionSpecificsFromCustomer()
  {
    _fromAccount = _bank.chooseAccountType("balance for", _atm);
    return Status::SUCCESS;
  }

//


// sendToBank() is abstract for class Transaction::

Status::Code WithdrawlTransaction::sendToBank()
  {
    return _bank.initiateWithdrawl(_session.cardNumber(),
                                   _session.PIN(),
                                   _atm.number(),
                                   _serialNumber,
                                   _fromAccount,
                                   _amount,
                                   _newBalance,
                                   _availableBalance);
  }


Status::Code DepositTransaction::sendToBank()
  {
    return _bank.initiateDeposit(_session.cardNumber(),
                                 _session.PIN(),
                                 _atm.number(),
                                 _serialNumber,
                                 _toAccount,
                                 _amount,
                                 _newBalance,
                                 _availableBalance);
  }


Status::Code TransferTransaction::sendToBank()
  {
    return _bank.doTransfer(_session.cardNumber(),
                            _session.PIN(),
                            _atm.number(),
                            _serialNumber,
                            _fromAccount,
                            _toAccount,
                            _amount,
                            _newBalance,
                            _availableBalance);
  }


Status::Code InquiryTransaction::sendToBank()
  {
    return _bank.doInquiry(_session.cardNumber(),
                           _session.PIN(),
                           _atm.number(),
                           _serialNumber,
                           _fromAccount,
                           _newBalance,
                           _availableBalance);
  }

//


// finishApprovedTransaction() is abstract in class Transaction::

Status::Code WithdrawlTransaction::finishApprovedTransaction()
  {
    _atm.dispenseCash(_amount);
    _bank.finishWithdrawl(_atm.number(), _serialNumber, true);
    char description[26];
    sprintf(description, "WITHDRAWL FROM %s",
            _bank.accountName(_fromAccount));
    _atm.issueReceipt(_session.cardNumber(),
                      _serialNumber, 
                      description,
                      _amount,
                      _newBalance,
                      _availableBalance);
    return Status::SUCCESS;
  }

Status::Code DepositTransaction::finishApprovedTransaction()
  {
    bool envelopeAccepted = _atm.acceptEnvelope();
    _bank.finishDeposit(_atm.number(), _serialNumber, envelopeAccepted);
    if (envelopeAccepted)
      {
        char description[26];
        sprintf(description, "DEPOSIT TO %s", 
                _bank.accountName(_toAccount));
        _atm.issueReceipt(_session.cardNumber(),
                          _serialNumber,
                          description,                  
                          _amount,
                          _newBalance,
                          _availableBalance);
        return Status::SUCCESS;
      }
    else
        return Status::ENVELOPE_DEPOSIT_TIMED_OUT;
  }


Status::Code TransferTransaction::finishApprovedTransaction()
  {
    char description[26];
    sprintf(description, "TRANSFER %s TO %s",
            _bank.accountName(_fromAccount),
            _bank.accountName(_toAccount));
    _atm.issueReceipt(_session.cardNumber(),
                      _serialNumber,
                      description,
                      _amount,
                      _newBalance,
                      _availableBalance);
    return Status::SUCCESS;
  }

Status::Code InquiryTransaction::finishApprovedTransaction()
  {
    char description[26];
    sprintf(description, "INQUIRY FROM %s", 
            _bank.accountName(_fromAccount));
    _atm.issueReceipt(_session.cardNumber(),
                      _serialNumber,
                      description,
                      Money(0), // will cause this line to be omitted
                      _newBalance,
                      _availableBalance);
    return Status::SUCCESS;
  }

//


WithdrawlTransaction::WithdrawlTransaction(Session & session,
                                           ATM & atm, Bank & bank)
  : Transaction(session, atm, bank)
  { } 

//


DepositTransaction::DepositTransaction(Session & session,
                                       ATM & atm, Bank & bank)
  : Transaction(session, atm, bank)
  { }

//


TransferTransaction::TransferTransaction(Session & session,
                                         ATM & atm, Bank & bank)
  : Transaction(session, atm, bank)

  { }

//


InquiryTransaction::InquiryTransaction(Session & session,
                                       ATM & atm, Bank & bank)
  : Transaction(session, atm, bank)

  { }

//