Build a COBOL Banking Batch Processor
Build a COBOL batch processor with validation and an audit report.
Introduction
30 Second Summary
A single unchecked withdrawal can turn an ordinary day of account activity into a balance that should never exist. Finding the record behind that result is the kind of puzzle support developers solve.
In this project, you will build a banking batch processor in COBOL. It uses business-rule validation to turn a daily transaction file into a $155.00 balance with an audit trail you can publish on GitHub.
What You'll Build
You run the processor and watch each deposit or withdrawal receive a clear decision before the final balance settles at $155.00.
By the end of this project, you'll have:
- A working processor that reads all five records before showing a final balance of $155.00.
- A root-cause demo that reproduces -$245.00 before proving overdraft protection plus invalid-type rejection.
- A reproducible GitHub portfolio that documents the path from transactions.dat through main.cob to audit-report.txt.
- Secret Mission: Add a $100.00 withdrawal review rule that rejects the affordable $150.00 transaction while preserving overdraft protection.
Do I need anything before starting?
You need a Mac with Visual Studio Code plus Homebrew already installed. You'll set up GnuCOBOL 3.2 plus a free GitHub personal account during the walkthrough.
Before We Start
Before the hands-on work begins, lock in what your banking batch processor needs to accomplish. This commitment gives every compiler command and business rule a clear purpose.
Set Up the Compiler and Portfolio Workspace
Your banking processor needs a reproducible compiler before its first COBOL source file can become a runnable program. The finished files also need a public destination where someone else can review them.
In this step, you will install GnuCOBOL 3.2 through Homebrew. You will also prepare a public GitHub repository plus a matching workspace in Visual Studio Code.
In this step, get ready to:
- Create a verified GitHub personal account plus a public repository.
- Install GnuCOBOL 3.2 through Homebrew.
- Open the matching local workspace in Visual Studio Code.
Create your GitHub repository
GitHub requires a verified email address before a personal account can create repositories. GitHub Free costs $0 USD per month.
- Use the official GitHub account guide to create your personal account.
- Complete the account prompts with your own details.
- Open the verification message in your email inbox.
- Select the verification link in that message.
Your account is now verified. That verification unlocks the repository where your portfolio project will live.
- Select New repository in GitHub.
You should see a form for configuring a new repository.
- Enter cobol-banking-transactions as the repository name.
- Select Public as the repository visibility.
- Select Create repository.
Good progress. Your empty cobol-banking-transactions repository is now the public destination for the project files you create later.
Install GnuCOBOL 3.2
A compiler translates your COBOL source into an executable your Mac can run. Start by checking whether the required compiler version is already available.
- Check the installed compiler version by running this command in Terminal:
cobc --version
What does this command check?
The --version flag asks the cobc compiler to display its version information. The result determines which setup path you need.
✔️ I see version 3.2 or higher
That check passed. Your Mac already has the compiler version used throughout this project.
ⓧ I see an older version
The compiler is installed with an older version. Upgrade the named Homebrew formula to bring it up to date.
- Upgrade the GnuCOBOL formula by running this command:
brew upgrade gnucobol
What does this command do?
Homebrew upgrades the installed GnuCOBOL formula. Naming the formula limits the upgrade to this compiler package.
- Check the upgraded compiler version by running this command:
cobc --version
What should you see?
You should see compiler information that includes version 3.2. Your upgraded compiler is ready for the project.
Upgrade not completing?
- Confirm that your Mac has an active internet connection.
- Review the final lines of the Homebrew output for the package that needs attention.
Share only non-sensitive output when you ask for help. Help me troubleshoot my GnuCOBOL upgrade.
ⓧ The command is unavailable
The unavailable command means GnuCOBOL still needs to be installed. Homebrew can install the stable formula used by this project.
- Install the GnuCOBOL formula by running this command:
brew install gnucobol
What does this command do?
Homebrew downloads the stable GnuCOBOL formula. The installation provides the cobc compiler used throughout this project.
- Check the installed compiler version by running this command:
cobc --version
What should you see?
You should see compiler information that includes version 3.2. Your Mac can now compile the COBOL program you build next.
Installation not completing?
- Confirm that your Mac has an active internet connection.
- Review the final lines of the Homebrew output for a dependency that needs attention.
Share only non-sensitive output when you ask for help. Help me troubleshoot my GnuCOBOL installation.
Open your local workspace
A Visual Studio Code workspace is a folder that the editor treats as one project. Using the repository name for this folder keeps the local project easy to match with its public destination.
- Click a blank area on your Mac desktop to make Finder active.
- Press Shift+Command+N to create a folder.
You should see a new untitled folder selected on your desktop.
- Enter cobol-banking-transactions as the folder name.
- Press Return to save the name.
You should see the empty cobol-banking-transactions folder on your desktop.
- Press Cmd+Space to open Spotlight.
You should see the Spotlight search field.
- Type Visual Studio Code into Spotlight.
- Press Return to open the editor.
You should see the Visual Studio Code window.
- Select File in the top menu bar.
- Select Open Folder....
You should see the macOS folder picker.
- Select the cobol-banking-transactions folder on your desktop.
Visual Studio Code may ask whether you trust the folder after it opens. This empty local folder contains only files you create.
- Select Open.
- Confirm that you trust the folder if prompted.
You should see cobol-banking-transactions at the top of the Explorer sidebar. This confirms that Visual Studio Code is using the correct workspace.
- Select View in the top menu bar.
- Select Terminal.
You should see the integrated terminal at the bottom of the editor. It starts inside the folder shown in the Explorer sidebar.
Before you run the final check, do you expect the integrated terminal to find the same compiler you verified earlier?
- Verify the compiler from inside your workspace by running this command:
cobc --version
What does this final check prove?
The integrated terminal uses the command-line tools available on your Mac. Finding version 3.2 proves that the editor can access the required compiler from this workspace.
You should see GnuCOBOL compiler information that includes version 3.2.
- Return to the browser tab showing the cobol-banking-transactions repository from earlier.
- Confirm that Public appears beside the repository name.
That is the foundation in place. Your compiler works inside the local workspace while your public repository waits for the finished project.
Your workspace is ready. Next, you will process your first transaction feed and expose an impossible negative balance.
Run a Naive Batch Processor
Your GnuCOBOL compiler is ready in the Visual Studio Code workspace from earlier. Now you can turn the empty folder into a running banking batch.
Banking arithmetic needs business rules before it can protect an account balance. In this step, you will build an arithmetic-only version and let its output expose the missing safeguard.
In this step, get ready to:
- Create a fixed-width transaction feed with five banking records.
- Build a COBOL processor that reads every record in sequence.
- Compile the processor to expose its balance result.
Create the transaction feed
In batch processing, a program reads a prepared set of records from start to finish. Each line in this feed represents one deposit or withdrawal.
- In the VS Code sidebar, click Explorer.
- Click New File beside the cobol-banking-transactions folder.
- Enter transactions.dat as the file name.
- Fill transactions.dat by pasting the five records below:
D000020000
W000040000
W000015000
X000001000
D000000500
What does this data represent?
The first character stores the transaction type. The remaining nine digits store an amount with two implied decimal places.
- D000020000 deposits $200.00.
- W000040000 withdraws $400.00.
- W000015000 withdraws $150.00.
- X000001000 uses an unsupported transaction type for $10.00.
- D000000500 deposits $5.00.
- Save transactions.dat.
- Confirm the editor shows exactly five records on five lines.
Does the transaction file look different?
- Check that each record contains one letter followed by nine digits.
- Remove any spaces between the transaction type and its amount.
- Confirm the file name is exactly transactions.dat.
Help me check my transaction records.
Build the arithmetic-only processor
A COBOL program uses divisions to separate its identity, data, and instructions. Start with a runnable slice that stores the opening balance.
- Click New File beside the cobol-banking-transactions folder.
- Enter main.cob as the file name.
- Create the runnable starting point by pasting this code:
IDENTIFICATION DIVISION.
PROGRAM-ID. TRANSACTION-PROCESSOR.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-BALANCE PIC S9(7)V99 VALUE 100.00.
PROCEDURE DIVISION.
MAIN.
DISPLAY "FINAL BALANCE: " WS-BALANCE
STOP RUN.
How is this program organized?
- IDENTIFICATION DIVISION names the program TRANSACTION-PROCESSOR.
- WORKING-STORAGE SECTION defines WS-BALANCE with a starting value of $100.00.
- PROCEDURE DIVISION contains the instructions that display the balance before the program stops.
- Save main.cob.
- Compile this first runnable slice in the integrated Terminal by running:
cobc -x -o main main.cob
What does this command do?
The cobc command compiles the COBOL source. The -x option builds an executable.
The -o main option names that executable main. The final argument identifies main.cob as the source file.
- Run the new executable by running:
./main
What should I see?
You should see FINAL BALANCE: followed by the starting value of $100.00. That first run is working because GnuCOBOL compiled your source into a local executable.
Did the first program fail to run?
- Confirm the integrated Terminal is still inside the cobol-banking-transactions folder.
- Check that main.cob is saved before compiling it.
- Compare the indentation with the code block because this source uses fixed-format COBOL.
Help me diagnose my first COBOL compile or run problem.
A sequential file gives the processor one record at a time. The record definition splits each line into a transaction type and an amount.
- In main.cob, locate the section from DATA DIVISION. through the WS-BALANCE definition.
- Replace that section with the file definition below:
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT TRANSACTION-FILE
ASSIGN TO "transactions.dat"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD TRANSACTION-FILE.
01 TRANSACTION-RECORD.
05 TXN-TYPE PIC X.
05 TXN-AMOUNT PIC 9(7)V99.
WORKING-STORAGE SECTION.
01 WS-BALANCE PIC S9(7)V99 VALUE 100.00.
01 WS-EOF PIC X VALUE "N".
88 END-OF-FILE VALUE "Y".
How does COBOL read each record?
- TRANSACTION-FILE connects the program to transactions.dat.
- LINE SEQUENTIAL treats each line as one record.
- TXN-TYPE stores the first character.
- TXN-AMOUNT stores seven whole-number digits followed by two implied decimal digits.
- END-OF-FILE becomes true after the final record has been read.
- Save main.cob.
A processing paragraph groups the instructions for one transaction. This version has separate arithmetic paths for deposits and withdrawals.
- Add the transaction paragraph below STOP RUN. by pasting this code:
PROCESS-TRANSACTION.
IF TXN-TYPE EQUAL TO "D"
ADD TXN-AMOUNT TO WS-BALANCE
END-IF
IF TXN-TYPE EQUAL TO "W"
SUBTRACT TXN-AMOUNT FROM WS-BALANCE
END-IF.
What does this paragraph do?
PROCESS-TRANSACTION checks the type stored in the current record. A D adds its amount to the balance.
A W subtracts its amount from the balance. Other transaction types do not match either condition.
- Save main.cob.
- Check the expanded source for syntax errors by compiling it again:
cobc -x -o main main.cob
What does this check prove?
A successful compilation confirms that the file definition and transaction paragraph use valid COBOL syntax. The next edit connects those pieces through the main read loop.
Does the expanded source fail to compile?
- Confirm ENVIRONMENT DIVISION. appears before DATA DIVISION..
- Check that PROCESS-TRANSACTION. appears after STOP RUN..
- Compare every period with the code blocks because periods close COBOL structures.
Help me find the syntax problem in my expanded COBOL source.
The main read loop opens the transaction feed and repeats until it reaches the end. Every successful read passes the current record to PROCESS-TRANSACTION.
- In main.cob, locate the block from MAIN. through STOP RUN..
- Replace that block with the complete read loop below:
MAIN.
OPEN INPUT TRANSACTION-FILE
PERFORM UNTIL END-OF-FILE
READ TRANSACTION-FILE
AT END
SET END-OF-FILE TO TRUE
NOT AT END
PERFORM PROCESS-TRANSACTION
END-READ
END-PERFORM
CLOSE TRANSACTION-FILE
DISPLAY "FINAL BALANCE: " WS-BALANCE
STOP RUN.
How does the read loop work?
- OPEN INPUT TRANSACTION-FILE makes the transaction feed available for reading.
- PERFORM UNTIL END-OF-FILE repeats the read operation while records remain.
- NOT AT END sends each record to PROCESS-TRANSACTION.
- AT END changes the end-of-file condition so the loop can stop.
- CLOSE TRANSACTION-FILE releases the input file before the final balance is displayed.
- Save main.cob.
✔️ Awesome, I've got everything!
Great. Confirm that main.cob is saved before you compile the complete processor.
ⓧ I'd like to double check the full code
IDENTIFICATION DIVISION.
PROGRAM-ID. TRANSACTION-PROCESSOR.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT TRANSACTION-FILE
ASSIGN TO "transactions.dat"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD TRANSACTION-FILE.
01 TRANSACTION-RECORD.
05 TXN-TYPE PIC X.
05 TXN-AMOUNT PIC 9(7)V99.
WORKING-STORAGE SECTION.
01 WS-BALANCE PIC S9(7)V99 VALUE 100.00.
01 WS-EOF PIC X VALUE "N".
88 END-OF-FILE VALUE "Y".
PROCEDURE DIVISION.
MAIN.
OPEN INPUT TRANSACTION-FILE
PERFORM UNTIL END-OF-FILE
READ TRANSACTION-FILE
AT END
SET END-OF-FILE TO TRUE
NOT AT END
PERFORM PROCESS-TRANSACTION
END-READ
END-PERFORM
CLOSE TRANSACTION-FILE
DISPLAY "FINAL BALANCE: " WS-BALANCE
STOP RUN.
PROCESS-TRANSACTION.
IF TXN-TYPE EQUAL TO "D"
ADD TXN-AMOUNT TO WS-BALANCE
END-IF
IF TXN-TYPE EQUAL TO "W"
SUBTRACT TXN-AMOUNT FROM WS-BALANCE
END-IF.
How to compare this file
This reference combines the program identity, sequential input definition, balance storage, read loop, and transaction arithmetic. Compare it with your saved main.cob from top to bottom.
Run the batch and trace the defect
Root-cause analysis follows the balance through each record until the first incorrect decision appears. The final number gives you evidence that the processor needs investigation.
- Compile the complete processor in the integrated Terminal by running:
cobc -x -o main main.cob
What does this compilation create?
The command rebuilds the local main executable from your completed main.cob source. A successful compilation returns control to the Terminal without reporting a source error.
Before you run the batch, what balance do you expect from a processor that makes decisions using only the transaction type? Hold your prediction in mind.
- Process all five records by running:
./main
What does the run reveal?
The final line shows a negative value representing -$245.00. The program processed the complete feed without stopping, but the account balance is impossible.
- Switch back to transactions.dat from earlier.
- Locate the W000040000 record.
- Compare its $400.00 amount with the $300.00 balance available at that point.
Trace the balance
- The processor starts with $100.00.
- The $200.00 deposit raises the balance to $300.00.
- The $400.00 withdrawal lowers the balance to -$100.00.
- The $150.00 withdrawal lowers the balance to -$250.00.
- The unsupported record changes nothing before the $5.00 deposit produces -$245.00.
You found the intended defect: the processor trusts the $400.00 withdrawal even though only $300.00 is available.
Do you see a different final balance?
- Confirm transactions.dat contains the five records in the original order.
- Save main.cob before compiling the executable again.
- Check that the withdrawal branch uses SUBTRACT TXN-AMOUNT FROM WS-BALANCE.
Help me trace why my final balance differs from the expected negative result.
Your batch program now reproduces a real business-rule defect and points to the transaction that caused it. Next, you will add explicit approval and rejection paths so invalid records cannot change the balance.
Enforce Banking Rules
Your first COBOL run exposed the core risk in the naive batch processor. The unchecked $400.00 withdrawal drove the balance below zero.
Arithmetic alone cannot protect a bank balance. Explicit business-rule validation gives every record an approval or rejection path before its amount can affect the balance.
In this step, get ready to:
- Store one result for every transaction.
- Route each record through an EVALUATE decision.
- Verify that rejected records preserve the available balance.
Store each transaction decision
Every record needs a result that describes its outcome. The WS-RESULT field keeps that decision separate from the numeric balance.
- In main.cob, find the line 88 END-OF-FILE VALUE "Y"..
- Add the result field directly below that line so the storage section ends like this:
88 END-OF-FILE VALUE "Y".
01 WS-RESULT PIC X(24).
What does this field do?
- The END-OF-FILE condition continues to control the read loop.
- The new WS-RESULT field stores up to 24 characters for one transaction decision.
- Keeping the decision in a field gives every branch a consistent value to display.
- Save main.cob.
- Check the new storage field by running this compile command:
cobc -x -o main main.cob
What does this compile check?
The compiler checks the fixed-format placement of WS-RESULT. A successful build returns control to the terminal without a compiler message.
Did the storage field fail to compile?
- Check that WS-RESULT begins in the same fixed-format area as WS-BALANCE.
- Confirm that PIC X(24) ends with a full stop.
- Confirm that the integrated Terminal remains inside the cobol-banking-transactions folder.
Help me fix the storage field compile problem.
Route records through banking rules
An EVALUATE statement selects one path from the transaction type. The withdrawal path can test available funds before subtraction.
- In main.cob, select both existing IF blocks beneath PROCESS-TRANSACTION..
- Replace the selection so the full paragraph matches this code:
PROCESS-TRANSACTION.
EVALUATE TXN-TYPE
WHEN "D"
ADD TXN-AMOUNT TO WS-BALANCE
MOVE "APPROVED DEPOSIT" TO WS-RESULT
WHEN "W"
IF TXN-AMOUNT GREATER THAN WS-BALANCE
MOVE "REJECTED: FUNDS" TO WS-RESULT
ELSE
SUBTRACT TXN-AMOUNT FROM WS-BALANCE
MOVE "APPROVED WITHDRAWAL" TO WS-RESULT
END-IF
WHEN OTHER
MOVE "REJECTED: TYPE" TO WS-RESULT
END-EVALUATE
DISPLAY WS-RESULT.
How do these rules protect the balance?
- The EVALUATE statement routes each record according to TXN-TYPE.
- The deposit branch adds TXN-AMOUNT to WS-BALANCE.
- The withdrawal branch compares the requested amount with the available balance.
- An unaffordable withdrawal changes only WS-RESULT.
- An approved withdrawal subtracts its amount from WS-BALANCE.
- The WHEN OTHER branch rejects every unsupported transaction type.
- The final DISPLAY statement makes every decision visible in the terminal.
- Save main.cob.
Verify the protected balance
Rejected records should leave WS-BALANCE unchanged. The final run tests that rule against the same five transaction records.
- Recompile the saved processor by running this command:
cobc -x -o main main.cob
What does this compile prove?
A successful compile confirms that the EVALUATE structure is complete. It also confirms that the withdrawal check has a matching END-IF.
- Run the validated processor by running this command:
Before you run the processor, which two records do you expect to leave WS-BALANCE unchanged?
./main
What should I see?
You should see five decisions in transaction order. The $400.00 withdrawal shows REJECTED: FUNDS.
The X record shows REJECTED: TYPE. The final numeric balance represents $155.00.
You have closed the defect that pushed the account below zero. Rejected records now preserve the available balance.
Missing a rejection result?
- Confirm that the withdrawal comparison uses TXN-AMOUNT GREATER THAN WS-BALANCE.
- Check that WHEN OTHER appears before END-EVALUATE.
- Confirm that transactions.dat still contains all five records from the previous step.
Help me troubleshoot the banking-rule output.
✔️ Awesome, I've got everything!
Your saved main.cob now contains the validated banking rules for this step.
ⓧ I'd like to double check the full code
IDENTIFICATION DIVISION.
PROGRAM-ID. TRANSACTION-PROCESSOR.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT TRANSACTION-FILE
ASSIGN TO "transactions.dat"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD TRANSACTION-FILE.
01 TRANSACTION-RECORD.
05 TXN-TYPE PIC X.
05 TXN-AMOUNT PIC 9(7)V99.
WORKING-STORAGE SECTION.
01 WS-BALANCE PIC S9(7)V99 VALUE 100.00.
01 WS-EOF PIC X VALUE "N".
88 END-OF-FILE VALUE "Y".
01 WS-RESULT PIC X(24).
PROCEDURE DIVISION.
MAIN.
OPEN INPUT TRANSACTION-FILE
PERFORM UNTIL END-OF-FILE
READ TRANSACTION-FILE
AT END
SET END-OF-FILE TO TRUE
NOT AT END
PERFORM PROCESS-TRANSACTION
END-READ
END-PERFORM
CLOSE TRANSACTION-FILE
DISPLAY "FINAL BALANCE: " WS-BALANCE
STOP RUN.
PROCESS-TRANSACTION.
EVALUATE TXN-TYPE
WHEN "D"
ADD TXN-AMOUNT TO WS-BALANCE
MOVE "APPROVED DEPOSIT" TO WS-RESULT
WHEN "W"
IF TXN-AMOUNT GREATER THAN WS-BALANCE
MOVE "REJECTED: FUNDS" TO WS-RESULT
ELSE
SUBTRACT TXN-AMOUNT FROM WS-BALANCE
MOVE "APPROVED WITHDRAWAL" TO WS-RESULT
END-IF
WHEN OTHER
MOVE "REJECTED: TYPE" TO WS-RESULT
END-EVALUATE
DISPLAY WS-RESULT.
What should I compare?
Check the placement of WS-RESULT in the storage section. Compare the complete PROCESS-TRANSACTION paragraph with your saved file.
Your processor now has explicit approval paths and rejection paths. Next, you will preserve every transaction decision in a durable audit report.
Generate an Audit Report
Your COBOL processor now protects balances through explicit transaction rules. Its decisions still live only in Terminal scrollback.
Support work depends on a durable record that remains available after a run. This step writes each transaction result to audit-report.txt.
You will also check whether both files opened successfully. A failed file open now produces a visible status instead of allowing the batch run to continue silently.
In this step, get ready to:
- Define the audit output file plus its readable report layout.
- Check the input file status plus the audit file status.
- Write every transaction decision to Terminal plus audit-report.txt.
Define the audit report structure
The report needs fields that format raw numeric values as readable currency. It also needs a header that labels each column.
- In main.cob, find 01 WS-RESULT PIC X(24)..
- Replace that line with this report workspace:
01 WS-INPUT-STATUS PIC XX.
01 WS-AUDIT-STATUS PIC XX.
01 WS-RESULT PIC X(24).
01 WS-DISPLAY-AMOUNT PIC Z,ZZZ,ZZ9.99.
01 WS-DISPLAY-BALANCE PIC -Z,ZZZ,ZZ9.99.
01 WS-HEADER PIC X(80) VALUE
"TYPE AMOUNT RESULT BALANCE".
What Does This Workspace Hold?
- WS-INPUT-STATUS holds the result of opening the transaction file.
- WS-AUDIT-STATUS holds the result of opening the audit file.
- WS-DISPLAY-AMOUNT formats each transaction amount with separators plus two decimal places.
- WS-DISPLAY-BALANCE formats the current balance with a possible negative sign.
- WS-HEADER stores the labels that appear at the top of the report.
- Save main.cob.
- Confirm the report workspace compiles by running this command:
cobc -x -o main main.cob
What Should You See?
The compiler should return you to the Terminal prompt without reporting an error. That confirms the new report fields use valid COBOL declarations.
A line-sequential file stores one report record per line. The audit file needs both a file-control entry and an 80-character output record.
- In main.cob, select the block from FILE-CONTROL. through 05 TXN-AMOUNT PIC 9(7)V99..
- Replace the selected block with this file definition:
FILE-CONTROL.
SELECT TRANSACTION-FILE
ASSIGN TO "transactions.dat"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-INPUT-STATUS.
SELECT AUDIT-FILE
ASSIGN TO "audit-report.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-AUDIT-STATUS.
DATA DIVISION.
FILE SECTION.
FD TRANSACTION-FILE.
01 TRANSACTION-RECORD.
05 TXN-TYPE PIC X.
05 TXN-AMOUNT PIC 9(7)V99.
FD AUDIT-FILE.
01 AUDIT-LINE PIC X(80).
How Is the Audit File Defined?
- AUDIT-FILE connects the COBOL program to audit-report.txt.
- ORGANIZATION IS LINE SEQUENTIAL makes each written record a separate line.
- AUDIT-LINE provides 80 characters for a formatted report row.
- FILE STATUS IS WS-AUDIT-STATUS captures the audit file open result.
- Save main.cob.
- Confirm both file definitions compile by running this command:
cobc -x -o main main.cob
What Did the Compiler Confirm?
The Terminal should return to its prompt without a compiler error. Your source now has valid input and output file definitions.
Seeing a File Definition Error?
- Check that FD AUDIT-FILE. sits inside the FILE SECTION..
- Check that 01 AUDIT-LINE PIC X(80). appears directly below the audit file descriptor.
- Check that the final period remains after FILE STATUS IS WS-AUDIT-STATUS..
Help me diagnose my COBOL audit file definition.
Open both files and check their status
A file status is a two-character result produced by a file operation. A value of 00 confirms a successful open.
The program should stop immediately when either file cannot open. This gives support teams a concrete failure status instead of incomplete processing.
- In the MAIN paragraph of main.cob, find OPEN INPUT TRANSACTION-FILE.
- Replace that line with this startup block:
OPEN INPUT TRANSACTION-FILE
OUTPUT AUDIT-FILE
IF WS-INPUT-STATUS NOT EQUAL TO "00"
DISPLAY "INPUT OPEN FAILED: " WS-INPUT-STATUS
STOP RUN
END-IF
IF WS-AUDIT-STATUS NOT EQUAL TO "00"
DISPLAY "AUDIT OPEN FAILED: " WS-AUDIT-STATUS
STOP RUN
END-IF
MOVE WS-HEADER TO AUDIT-LINE
WRITE AUDIT-LINE
How Does Startup Work?
- OPEN INPUT TRANSACTION-FILE prepares the transaction records for reading.
- OUTPUT AUDIT-FILE creates a fresh audit report for the run.
- The first IF stops processing when the transaction file does not open successfully.
- The second IF stops processing when the audit file does not open successfully.
- WRITE AUDIT-LINE places the readable header into the report.
- Save main.cob.
- Check the startup block by compiling the program:
cobc -x -o main main.cob
What Did This Check Prove?
The compiler should return to the Terminal prompt without an error. The program can now open the audit file before processing transactions.
- In MAIN, find the closing block that starts with CLOSE TRANSACTION-FILE.
- Replace that block through STOP RUN. with this shutdown block:
CLOSE TRANSACTION-FILE AUDIT-FILE
MOVE WS-BALANCE TO WS-DISPLAY-BALANCE
DISPLAY "FINAL BALANCE: $" WS-DISPLAY-BALANCE
DISPLAY "AUDIT REPORT: audit-report.txt"
STOP RUN.
How Does Shutdown Work?
- CLOSE TRANSACTION-FILE AUDIT-FILE finishes both file operations cleanly.
- WS-DISPLAY-BALANCE converts the stored balance into readable currency formatting.
- The final display tells you which report file contains the audit trail.
- Save main.cob.
- Build the updated executable by running this command:
cobc -x -o main main.cob
What Should Compilation Confirm?
The Terminal should return to its prompt without reporting a compiler error. The updated executable now manages both files during startup and shutdown.
Before you run the program, how many lines do you expect the audit report to contain before transaction writing is connected?
- Run the processor by using this command:
./main
What Should You See?
The Terminal shows the existing transaction decisions. It finishes with a formatted final balance of $155.00.
The final message names audit-report.txt. At this stage, that file contains the report header.
- Select audit-report.txt from the VS Code file list.
You should see TYPE AMOUNT RESULT BALANCE on the first line. This proves the output file opened successfully and accepted its first record.
Missing the Report Header?
- Confirm that you ran the newly compiled main executable from the cobol-banking-transactions folder.
- Check that WRITE AUDIT-LINE appears after MOVE WS-HEADER TO AUDIT-LINE.
- Check the Terminal for a file-open status message from the input file or audit file.
Help me troubleshoot why my COBOL program does not write the audit report header.
Write every decision to the audit report
Each transaction needs one audit line containing its type, amount, decision, and resulting balance. The STRING statement assembles those values into the 80-character output record.
- In main.cob, select the PROCESS-TRANSACTION. paragraph through END-EVALUATE.
- Replace the selected code with this decision block:
PROCESS-TRANSACTION.
MOVE SPACES TO WS-RESULT
EVALUATE TXN-TYPE
WHEN "D"
ADD TXN-AMOUNT TO WS-BALANCE
MOVE "APPROVED DEPOSIT" TO WS-RESULT
WHEN "W"
IF TXN-AMOUNT GREATER THAN WS-BALANCE
MOVE "REJECTED: FUNDS" TO WS-RESULT
ELSE
SUBTRACT TXN-AMOUNT FROM WS-BALANCE
MOVE "APPROVED WITHDRAWAL" TO WS-RESULT
END-IF
WHEN OTHER
MOVE "REJECTED: TYPE" TO WS-RESULT
END-EVALUATE
Why Clear the Result First?
MOVE SPACES TO WS-RESULT clears the previous transaction decision. Every audit row therefore starts with an empty result field before the current rule assigns its outcome.
- Save main.cob.
- Confirm the updated decision block compiles by running this command:
cobc -x -o main main.cob
What Did the Compiler Check?
The Terminal should return to its prompt without an error. Each transaction now begins with a clean result field.
- Find the final DISPLAY WS-RESULT. line in PROCESS-TRANSACTION.
- Replace that line with this audit formatting block:
MOVE TXN-AMOUNT TO WS-DISPLAY-AMOUNT
MOVE WS-BALANCE TO WS-DISPLAY-BALANCE
MOVE SPACES TO AUDIT-LINE
STRING
TXN-TYPE DELIMITED BY SIZE
" $" DELIMITED BY SIZE
WS-DISPLAY-AMOUNT DELIMITED BY SIZE
" " DELIMITED BY SIZE
WS-RESULT DELIMITED BY SIZE
" $" DELIMITED BY SIZE
WS-DISPLAY-BALANCE DELIMITED BY SIZE
INTO AUDIT-LINE
END-STRING
DISPLAY AUDIT-LINE
WRITE AUDIT-LINE.
How Is Each Audit Line Built?
- The first two MOVE statements format the transaction amount plus the updated balance.
- MOVE SPACES TO AUDIT-LINE removes content left by the previous record.
- STRING joins the transaction fields into one readable record.
- DISPLAY AUDIT-LINE sends the decision to Terminal.
- WRITE AUDIT-LINE preserves the same decision in the report.
- Save main.cob.
- Build the finished audit-enabled executable by running this command:
cobc -x -o main main.cob
What Should Compilation Prove?
The compiler should return you to the Terminal prompt without an error. The finished program can now format each transaction as a complete audit record.
Before you run the finished processor, do you expect either rejected transaction to change the balance shown on its audit line?
- Run the finished processor by using this command:
./main
What Should the Finished Run Show?
You should see five formatted transaction decisions in Terminal. The $400.00 withdrawal shows REJECTED: FUNDS.
The X record shows REJECTED: TYPE. The final balance remains $155.00.
- Select audit-report.txt from the VS Code file list.
You should see one header plus five transaction decisions. The final deposit row ends with a balance of $155.00.
That is the audit trail working. You now have a durable record that preserves every approval, every rejection, and every resulting balance.
Missing Decisions From the Report?
- Check that WRITE AUDIT-LINE. remains inside PROCESS-TRANSACTION.
- Check that the period remains after the final WRITE AUDIT-LINE. statement.
- Confirm that transactions.dat still contains all five fixed-width records.
Help me troubleshoot missing or malformed COBOL audit rows.
✔️ Awesome, I've got everything!
Great work. Save main.cob once more so your audit-enabled processor is ready for publishing.
ⓧ I'd like to double check the full code
IDENTIFICATION DIVISION.
PROGRAM-ID. TRANSACTION-PROCESSOR.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT TRANSACTION-FILE
ASSIGN TO "transactions.dat"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-INPUT-STATUS.
SELECT AUDIT-FILE
ASSIGN TO "audit-report.txt"
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-AUDIT-STATUS.
DATA DIVISION.
FILE SECTION.
FD TRANSACTION-FILE.
01 TRANSACTION-RECORD.
05 TXN-TYPE PIC X.
05 TXN-AMOUNT PIC 9(7)V99.
FD AUDIT-FILE.
01 AUDIT-LINE PIC X(80).
WORKING-STORAGE SECTION.
01 WS-BALANCE PIC S9(7)V99 VALUE 100.00.
01 WS-EOF PIC X VALUE "N".
88 END-OF-FILE VALUE "Y".
01 WS-INPUT-STATUS PIC XX.
01 WS-AUDIT-STATUS PIC XX.
01 WS-RESULT PIC X(24).
01 WS-DISPLAY-AMOUNT PIC Z,ZZZ,ZZ9.99.
01 WS-DISPLAY-BALANCE PIC -Z,ZZZ,ZZ9.99.
01 WS-HEADER PIC X(80) VALUE
"TYPE AMOUNT RESULT BALANCE".
PROCEDURE DIVISION.
MAIN.
OPEN INPUT TRANSACTION-FILE
OUTPUT AUDIT-FILE
IF WS-INPUT-STATUS NOT EQUAL TO "00"
DISPLAY "INPUT OPEN FAILED: " WS-INPUT-STATUS
STOP RUN
END-IF
IF WS-AUDIT-STATUS NOT EQUAL TO "00"
DISPLAY "AUDIT OPEN FAILED: " WS-AUDIT-STATUS
STOP RUN
END-IF
MOVE WS-HEADER TO AUDIT-LINE
WRITE AUDIT-LINE
PERFORM UNTIL END-OF-FILE
READ TRANSACTION-FILE
AT END
SET END-OF-FILE TO TRUE
NOT AT END
PERFORM PROCESS-TRANSACTION
END-READ
END-PERFORM
CLOSE TRANSACTION-FILE AUDIT-FILE
MOVE WS-BALANCE TO WS-DISPLAY-BALANCE
DISPLAY "FINAL BALANCE: $" WS-DISPLAY-BALANCE
DISPLAY "AUDIT REPORT: audit-report.txt"
STOP RUN.
PROCESS-TRANSACTION.
MOVE SPACES TO WS-RESULT
EVALUATE TXN-TYPE
WHEN "D"
ADD TXN-AMOUNT TO WS-BALANCE
MOVE "APPROVED DEPOSIT" TO WS-RESULT
WHEN "W"
IF TXN-AMOUNT GREATER THAN WS-BALANCE
MOVE "REJECTED: FUNDS" TO WS-RESULT
ELSE
SUBTRACT TXN-AMOUNT FROM WS-BALANCE
MOVE "APPROVED WITHDRAWAL" TO WS-RESULT
END-IF
WHEN OTHER
MOVE "REJECTED: TYPE" TO WS-RESULT
END-EVALUATE
MOVE TXN-AMOUNT TO WS-DISPLAY-AMOUNT
MOVE WS-BALANCE TO WS-DISPLAY-BALANCE
MOVE SPACES TO AUDIT-LINE
STRING
TXN-TYPE DELIMITED BY SIZE
" $" DELIMITED BY SIZE
WS-DISPLAY-AMOUNT DELIMITED BY SIZE
" " DELIMITED BY SIZE
WS-RESULT DELIMITED BY SIZE
" $" DELIMITED BY SIZE
WS-DISPLAY-BALANCE DELIMITED BY SIZE
INTO AUDIT-LINE
END-STRING
DISPLAY AUDIT-LINE
WRITE AUDIT-LINE.
Your processor now leaves behind evidence that support teams can inspect after the run. Next up, you will document the workflow and publish the source as a reproducible portfolio project.
Publish the Portfolio Project
Your COBOL processor now validates each transaction. It preserves every decision in an audit report.
Working code on one laptop is difficult for an employer to assess. A public GitHub repository gives another person the documentation and source files needed to reproduce your result.
In this step, get ready to:
- Create a README.md that documents the business scenario.
- Publish the documentation plus the existing source files in GitHub.
- Verify that a signed-out visitor can inspect the project.
Document the project workflow
A README.md file uses Markdown to explain what a project does. Your README also gives a reader a reproducible path from the transaction layout to the final balance.
- In the VS Code Explorer sidebar from earlier, use the file icon at the top to create README.md inside the cobol-banking-transactions folder.
- Paste the project summary plus the transaction layout into README.md using the content below:
# COBOL Banking Batch Processor
A beginner portfolio project that simulates a banking batch feed. The program starts with a $100.00 balance, reads fixed-width transaction records, applies valid deposits and withdrawals, rejects invalid records, and writes an audit report.
## Transaction layout
Each line contains:
- Column 1: `D` for deposit or `W` for withdrawal
- Columns 2-10: a nine-digit amount with two implied decimal places
Example: `D000020000` means a $200.00 deposit.
What Does This Documentation Cover?
- The opening paragraph describes the banking batch scenario.
- The transaction layout maps each fixed-width position to its meaning.
- The example shows how the implied decimal places turn one record into a deposit amount.
- Save README.md.
- Confirm that README.md appears beside main.cob in the Explorer sidebar.
You should see the project title followed by the transaction layout in the editor.
README File Missing?
- Check that the filename is exactly README.md.
- Confirm that the file sits directly inside the cobol-banking-transactions folder.
Ask for help with a missing README file.
- Place your cursor after the deposit example in README.md.
- Add the reproducible build workflow by pasting the content below:
## Build and run
Install GnuCOBOL 3.2 on macOS:
```bash
brew install gnucobol
```
Compile the fixed-format source:
```bash
cobc -x -o main main.cob
```
Run the batch processor:
```bash
./main
```
The final balance should be $155.00. The run also creates `audit-report.txt`.
Why Include the Run Workflow?
- The install section names the GnuCOBOL compiler used by the project.
- The compile section turns the fixed-format source into the local executable.
- The run section gives the reader two concrete success signals.
- Save README.md.
- Use the preview icon in the top-right corner of the VS Code editor to inspect the rendered Markdown.
You should see a Build and run section with three command blocks. The expected final balance should appear beneath them.
Markdown Preview Look Wrong?
- Check that every command fence begins with three backticks.
- Confirm that each command fence ends with three backticks.
- Remove any spaces before the section headings if they render as code.
Ask for help with the README formatting.
- Place your cursor after the audit report sentence in README.md.
- Finish the documentation by pasting the rules plus the scope below:
## Rules demonstrated
- Deposits increase the balance.
- Withdrawals are approved only when enough funds are available.
- Unsupported transaction types are rejected.
- Every transaction decision is written to an audit report.
## Scope
This project runs locally with GnuCOBOL. It demonstrates COBOL and batch-processing fundamentals, but it does not claim to reproduce JCL, CICS, Db2, or a complete z/OS production environment.
Why State the Project Scope?
- The rules section connects the source code to observable banking decisions.
- The scope section defines the skills this local project demonstrates.
- The final sentence keeps the portfolio claim accurate.
- Save README.md.
- Return to the Markdown preview using the preview icon in the top-right corner of the editor.
You should see sections for the transaction layout, build workflow, demonstrated rules, and project scope.
Missing the Final Sections?
- Confirm that the rules section appears after the audit report sentence.
- Check that ## Rules demonstrated starts on its own line.
- Check that ## Scope starts on its own line.
Ask for help finding a missing README section.
Use the tabs below to confirm that your finished README.md matches the portfolio documentation.
✔️ Awesome, I've got everything!
Your README now documents the scenario, transaction format, run workflow, banking rules, and project scope.
ⓧ I'd like to double check the full code
# COBOL Banking Batch Processor
A beginner portfolio project that simulates a banking batch feed. The program starts with a $100.00 balance, reads fixed-width transaction records, applies valid deposits and withdrawals, rejects invalid records, and writes an audit report.
## Transaction layout
Each line contains:
- Column 1: `D` for deposit or `W` for withdrawal
- Columns 2-10: a nine-digit amount with two implied decimal places
Example: `D000020000` means a $200.00 deposit.
## Build and run
Install GnuCOBOL 3.2 on macOS:
```bash
brew install gnucobol
```
Compile the fixed-format source:
```bash
cobc -x -o main main.cob
```
Run the batch processor:
```bash
./main
```
The final balance should be $155.00. The run also creates `audit-report.txt`.
## Rules demonstrated
- Deposits increase the balance.
- Withdrawals are approved only when enough funds are available.
- Unsupported transaction types are rejected.
- Every transaction decision is written to an audit report.
## Scope
This project runs locally with GnuCOBOL. It demonstrates COBOL and batch-processing fundamentals, but it does not claim to reproduce JCL, CICS, Db2, or a complete z/OS production environment.
Upload the portfolio files
A browser upload adds the three portfolio files in one commit. The commit message records why that snapshot exists.
- Return to the public cobol-banking-transactions repository in your browser.
- Click Add file above the repository file list.
- Click Upload files.
- Click choose your files in the upload area.
- Select README.md, main.cob, and transactions.dat from the local cobol-banking-transactions folder.
- Confirm the file selection in the macOS file picker.
You should see all three filenames listed in the upload area.
- Enter Publish COBOL banking batch processor in the Commit message field.
- Click Commit changes beneath the commit options.
Strong work. Your repository should now list README.md, main.cob, and transactions.dat on its main page.
Upload Missing a File?
- Return to Add file if one filename is missing.
- Choose Upload files to add only the missing file.
- Confirm that the filename matches the local file exactly before committing.
Ask for help with the GitHub upload.
Verify public access
Public visibility proves that another person can inspect the project without using your account. This final check tests the same view a recruiter receives.
- Select the browser address bar while viewing your signed-in repository.
- Copy the repository URL.
- Record the repository URL here: your public repository URL.
- Open a private browser window from your browser's application menu.
Before you load the page, predict whether a signed-out visitor can see all three project files.
- Paste your public repository URL into the private window's address bar.
- Press Enter to load the repository.
You should see README.md, main.cob, and transactions.dat without a sign-in prompt. The README should render beneath the file list.
- Select main.cob from the public file list.
You should see the full source for TRANSACTION-PROCESSOR without running the generated main executable.
- Return to the repository page using the browser's back button.
You have turned a local batch processor into public evidence that another person can inspect and reproduce.
Repository Asking You to Sign In?
- Return to the signed-in repository window.
- Confirm that the repository visibility is public.
- Reload the repository URL in the private window after correcting the visibility.
Ask for help with public repository access.
Secret mission
Add a Withdrawal Review Rule
Your processor protects the balance from overdrafts, yet it still approves every affordable withdrawal. Add a $100.00 review threshold that rejects the $150.00 withdrawal while preserving the insufficient-funds result for the $400.00 withdrawal.
Clean Up Your Resources
Clean Up Your Resources
Choose whether to keep your local project and public repository, pause your work, or remove both. These resources cost $0 because the project uses GitHub Free without paid add-ons or cloud compute.
Resources you used:
- The local cobol-banking-transactions folder containing README.md, main.cob, and transactions.dat.
- The compiled main executable plus the generated audit-report.txt inside the local folder.
- The public cobol-banking-transactions repository on GitHub.
Keep everything running
No action needed. Choose this if you want the portfolio project ready for demonstrations or further rule changes.
- Keep the local cobol-banking-transactions folder for future runs.
- Keep audit-report.txt for comparing transaction decisions.
- Keep the public repository available as portfolio evidence.
- Leave GnuCOBOL installed for future COBOL projects.
Pause - I'll come back to this later
Close your active tools while preserving every local file and repository file. Nothing continues processing after the batch program finishes.
- Close Visual Studio Code to end the integrated Terminal session.
- Leave the local cobol-banking-transactions folder on your Mac.
- Leave the public repository unchanged for future demonstrations.
Delete - I don't want to use this again
Deleting the local folder and public repository is permanent. This option gives you a clean slate without affecting other files on your Mac.
- Save a separate copy first if you want to preserve any part of your work.
- Switch back to the integrated Terminal in Visual Studio Code.
- Remove the local cobol-banking-transactions folder by running these commands:
cd ..
rm -rf cobol-banking-transactions
ls
What Do These Commands Remove?
The first line moves the Terminal to the folder that contains cobol-banking-transactions. The second line permanently removes the local workspace.
The final line lists the remaining items. The project folder should be absent.
You should no longer see cobol-banking-transactions in the command output. That confirms the source files, executable, and audit report are removed from your Mac.
Still See the Local Folder?
- Check that the Terminal was inside cobol-banking-transactions before you moved to its parent folder.
- Use Finder to locate the folder if the Terminal started somewhere else.
- Help me safely remove my local COBOL project folder.
- Return to the public cobol-banking-transactions repository on GitHub.
- Open the repository settings.
- Use the repository deletion settings to delete cobol-banking-transactions.
- Complete the confirmation shown by GitHub.
- Open the former public repository page in a private browser window.
You should see that the repository is no longer available. That confirms the hosted portfolio copy has been removed.
Nice Work!
Nice Work!
You did it! Your published COBOL banking batch processor now turns transaction records into an auditable account balance.
What you learned:
- Compiled a working batch processor with GnuCOBOL. Its line-sequential workflow transforms each transactions.dat record into a decision in audit-report.txt.
- Used root-cause analysis on the -$245.00 result to identify the unchecked $400.00 withdrawal. Added ordered rejection paths for insufficient funds plus unsupported transaction types.
- Published a reproducible GitHub portfolio repository containing README.md, main.cob, plus transactions.dat for signed-out visitors to review.
- Secret Mission: Extended the withdrawal path with a $100.00 review rule while preserving overdraft protection. Verified REJECTED: LIMIT with a final balance of $305.00.
Ready to quiz yourself?