ISC Practicals and Theory - Stock to Purchase/Sale (OOP)
Updated 21 Oct 2026
A shop keeps an item in stock: a purchase raises the stock and costs money, a sale lowers the stock and earns money. This version uses parameterised constructors that call the base class constructor with super(...), and the derived classes override the methods transact() and display(). In main, one reference of the base class type Stock first points to a Purchase object and then to a Sale object, so the call that runs depends on the object (dynamic binding). The classic version with default constructors is under the Classic button.
Definition
Inheritance lets a derived class acquire the members of a base class using extends. Method overriding means the derived class redefines a base class method with the same name and parameters. Polymorphism (dynamic binding) means that when a base class reference holds a derived class object, a call to an overridden method runs the derived class version, decided at run time. super(...) calls the base class constructor and super.display() calls the base class method.
For example, with Stock st = new Purchase("Pen", 50, 12.5, 30); the call st.transact() runs Purchase's version and the stock becomes $50 + 30 = 80$.
The rules used in this program are stated below, as the question gives no exact rules.
- Opening stock must be 0 or more, the rate above 0 and the purchase and sale quantities at least 1; otherwise the input is invalid.
- A sale is rejected if the quantity sold is more than the stock in hand, and the stock stays unchanged.
- The sale rate is the purchase rate plus a 10% margin, so the sale amount is $\text{quantity sold} \times \text{rate} \times 1.10$.
- The sale is made from the stock left after the purchase.
Algorithm
main(in the driver classTest) reads the item, the opening stock, the rate and the purchased quantity with its ownScanner. After each value that has a limit it checks it, and if it is invalid it prints the invalid input message and stops.maincreatesStock st = new Purchase(item, qty, rate, pq). The constructor ofPurchasepassesitem,qtyandratetoStockwithsuper(i, q, r)and storespqty.st.transact()runs the overridden method ofPurchase: it addspqtytoqty, findscost = pqty * rateand returnstrue.st.display()runsPurchase'sdisplay(), which prints the quantity purchased and the cost and then callssuper.display()to print the item, the stock in hand and the rate.mainreads the quantity soldsq(at least 1, else invalid input) and makesstpoint to a new objectnew Sale(st.item, st.qty, st.rate, sq).st.transact()now runsSale's method:- if
sqty > qtyit returnsfalseand the stock is unchanged; - otherwise it reduces
qtybysqty, findsamount = sqty * rate * (1 + margin / 100)and returnstrue.
- if
- If
transact()returnedtrue,st.display()runsSale'sdisplay(); otherwisemainprints that the sale is rejected, with the stock in hand.
Program
Stock holds the common data and the base versions of transact() and display(); Purchase and Sale override both; Test holds main and uses a base class reference throughout.
import java.util.Scanner;
/* Class Stock: the base class. It holds the item, the quantity in stock and the rate. */
class Stock
{
String item; // name of the item (one word)
int qty; // quantity of the item in stock
double rate; // rate (price) of one unit in rupees
/* Parameterised constructor: sets the item, the stock and the rate. */
Stock(String i, int q, double r)
{
item = i;
qty = q;
rate = r;
}
/* Does the transaction. The base class has none, so it only returns true.
Purchase and Sale override this method. */
boolean transact()
{
return true;
}
/* Prints the item, the stock in hand and the rate. */
void display()
{
System.out.println("Item: " + item);
System.out.println("Stock in hand: " + qty);
System.out.printf("Rate per unit: %.2f%n", rate);
}
}
/* Class Purchase: derived class. It adds the purchased quantity and the cost. */
class Purchase extends Stock
{
int pqty; // quantity purchased
double cost; // cost of the purchase = pqty * rate
/* Parameterised constructor: passes item, stock and rate to the base class with super(...). */
Purchase(String i, int q, double r, int p)
{
super(i, q, r);
pqty = p;
cost = 0;
}
/* Overrides transact(): adds the purchased quantity to the stock and finds the cost.
Always returns true, as a purchase is never rejected. */
boolean transact()
{
qty = qty + pqty;
cost = pqty * rate;
return true;
}
/* Overrides display(): prints the purchase details and then the stock (super.display()). */
void display()
{
System.out.println("Quantity purchased: " + pqty);
System.out.printf("Purchase cost: %.2f%n", cost);
super.display();
}
}
/* Class Sale: derived class. It adds the quantity sold and the sale amount. */
class Sale extends Stock
{
int sqty; // quantity sold
double margin; // profit margin in percent added to the rate
double amount; // sale amount = sqty * rate * (1 + margin / 100)
/* Parameterised constructor: passes item, stock and rate to the base class with super(...). */
Sale(String i, int q, double r, int s)
{
super(i, q, r);
sqty = s;
margin = 10;
amount = 0;
}
/* Overrides transact(): returns false (stock unchanged) if sqty is more than the stock;
otherwise reduces the stock, finds the sale amount and returns true. */
boolean transact()
{
if (sqty > qty)
return false;
qty = qty - sqty;
amount = sqty * rate * (1 + margin / 100);
return true;
}
/* Overrides display(): prints the sale details and then the stock (super.display()). */
void display()
{
System.out.println("Quantity sold: " + sqty);
System.out.printf("Sale amount (rate + %.0f%% margin): %.2f%n", margin, amount);
super.display();
}
}
/* Class Test: the driver class that holds main. */
public class Test
{
/* Reads the data, makes a purchase and then a sale using one Stock reference,
printing the stock after each. */
public static void main(String args[])
{
Scanner sc = new Scanner(System.in); // reads the typed values
String msg = "Invalid input. Stock must be 0 or more, rate above 0 and quantities at least 1.";
System.out.print("Enter the item name: ");
String item = sc.next(); // name of the item
System.out.print("Enter the opening stock: ");
int qty = sc.nextInt(); // opening stock
if (qty < 0)
{
System.out.println(msg);
return;
}
System.out.print("Enter the rate per unit: ");
double rate = sc.nextDouble(); // rate per unit
if (rate <= 0)
{
System.out.println(msg);
return;
}
System.out.print("Enter the quantity purchased: ");
int pq = sc.nextInt(); // quantity purchased
if (pq < 1)
{
System.out.println(msg);
return;
}
Stock st = new Purchase(item, qty, rate, pq); // base class reference to a Purchase object
st.transact(); // calls Purchase's transact()
System.out.println("After the purchase:");
st.display(); // calls Purchase's display()
System.out.print("Enter the quantity sold: ");
int sq = sc.nextInt(); // quantity sold
if (sq < 1)
{
System.out.println(msg);
return;
}
st = new Sale(st.item, st.qty, st.rate, sq); // the same reference now points to a Sale object
if (st.transact()) // calls Sale's transact()
{
System.out.println("After the sale:");
st.display(); // calls Sale's display()
}
else
{
System.out.println("Sale rejected. Quantity sold is more than the stock in hand (" + st.qty + ").");
}
}
}Variable description table
| Variable | Data Type | Purpose |
|---|---|---|
item | String | Data member of Stock: name of the item; also the local in main that holds the typed name |
qty | int | Data member of Stock: quantity in stock; also the local in main that holds the opening stock |
rate | double | Data member of Stock: rate of one unit in rupees; also the local in main that holds the typed rate |
i | String | Parameter of the constructors: the item name |
q | int | Parameter of the constructors: the stock |
r | double | Parameter of the constructors: the rate |
pqty | int | Data member of Purchase: quantity purchased |
cost | double | Data member of Purchase: cost of the purchase, pqty * rate |
p | int | Parameter of the Purchase constructor: the quantity purchased |
sqty | int | Data member of Sale: quantity sold |
margin | double | Data member of Sale: profit margin in percent (10) added to the rate |
amount | double | Data member of Sale: sale amount, sqty * rate * (1 + margin / 100) |
s | int | Parameter of the Sale constructor: the quantity sold |
sc | Scanner | Local in main: reads everything typed by the user |
msg | String | Local in main: the invalid input message |
pq | int | Local in main: the quantity purchased typed by the user |
sq | int | Local in main: the quantity sold typed by the user |
st | Stock | Base class reference in main, pointing first to a Purchase and then to a Sale object |
args | String[] | Command-line arguments of main (not used) |
Sample input and output
Sample 1
Enter the item name: Pen
Enter the opening stock: 50
Enter the rate per unit: 12.50
Enter the quantity purchased: 30
After the purchase:
Quantity purchased: 30
Purchase cost: 375.00
Item: Pen
Stock in hand: 80
Rate per unit: 12.50
Enter the quantity sold: 20
After the sale:
Quantity sold: 20
Sale amount (rate + 10% margin): 275.00
Item: Pen
Stock in hand: 60
Rate per unit: 12.50Sample 2
Enter the item name: Pen
Enter the opening stock: 50
Enter the rate per unit: 12.50
Enter the quantity purchased: 30
After the purchase:
Quantity purchased: 30
Purchase cost: 375.00
Item: Pen
Stock in hand: 80
Rate per unit: 12.50
Enter the quantity sold: 90
Sale rejected. Quantity sold is more than the stock in hand (80).Sample 3
Enter the item name: Book
Enter the opening stock: 0
Enter the rate per unit: 99.99
Enter the quantity purchased: 10
After the purchase:
Quantity purchased: 10
Purchase cost: 999.90
Item: Book
Stock in hand: 10
Rate per unit: 99.99
Enter the quantity sold: 10
After the sale:
Quantity sold: 10
Sale amount (rate + 10% margin): 1099.89
Item: Book
Stock in hand: 0
Rate per unit: 99.99Sample 4
Enter the item name: Pen
Enter the opening stock: -5
Invalid input. Stock must be 0 or more, rate above 0 and quantities at least 1.Dry run
Take the first sample: item Pen, opening stock 50, rate 12.50, purchased 30, sold 20.
| Step | Statement | Object st points to | qty | pqty or sqty | cost or amount |
|---|---|---|---|---|---|
| 1 | new Purchase("Pen", 50, 12.5, 30) | Purchase | 50 | pqty = 30 | cost = 0 |
| 2 | st.transact(): qty = 50 + 30, cost = 30 * 12.5 | Purchase | 80 | pqty = 30 | cost = 375.00 |
| 3 | new Sale("Pen", 80, 12.5, 20) | Sale | 80 | sqty = 20 | amount = 0 |
| 4 | st.transact(): 20 > 80 is false, qty = 80 - 20, amount = 20 * 12.5 * 1.1 | Sale | 60 | sqty = 20 | amount = 275.00 |
st.display() then runs Sale's display() and prints the quantity sold, the sale amount 275.00 and the stock in hand 60, as in the first sample run. In the second sample sqty = 90, 90 > 80 is true, so Sale's transact() returns false and the sale is rejected.
Variations
- Discount "Add a derived class that reduces the rate by a given percentage and overrides
display()to print the new rate." - Margin from the user "Read the profit margin as input instead of fixing it at 10%."
- Another hierarchy "Write a base class
Accountand derived classesDepositandWithdraw, each overriding a methodtransact(); reject a withdrawal larger than the balance."