Python Cash Register System: Challenge With Modules

Alex Johnson
-
Python Cash Register System: Challenge With Modules

This challenge integrates fundamental programming concepts, including data structure management, modularization, and command-line input processing. The primary goal is to implement functions across different files, utilize lists for effective data organization, and generate a consolidated report for a kiosk's sales system. Let's dive into the details of how to build this robust system.

General Requirements

The core requirement is to develop a console program in Python that processes commands entered via stdin, one command per line, until the FIN command is received. The system must maintain the following information in memory:

  • Inventory of Products: A comprehensive list of all items available for sale.
  • Record of Transactions: Sales and returns, represented using lists to track each transaction.
  • Discount Rules: A set of predefined discount rules, stored as lists of simple structures.
  • External Discount Module: A separate module dedicated to calculating discounts.

Why This Matters

This setup allows for a clean separation of concerns, making the system more modular, maintainable, and scalable. By using an external module for discount calculations, the main program remains focused on handling inventory and transactions, while the promos.py module can be updated independently without affecting other parts of the system. This is crucial for real-world applications where business logic may change frequently.

Key Concepts

  • Data Structures: Utilizing lists and dictionaries to efficiently store and manage data.
  • Modularization: Breaking down the system into manageable modules for better organization.
  • Input Processing: Reading and interpreting commands from the console.
  • Algorithm Design: Implementing logic for sales, returns, and discount calculations.

Commands to Implement

The system should recognize and process the following commands:

  1. ALTA <codigo> <descripcion...> <precio>

    This command is used to register a new product in the inventory or update an existing one. The <codigo> is a unique identifier for the product, <descripcion...> provides a description (which may consist of multiple words), and <precio> is the price of the product. When implementing this command, it’s essential to check if the product already exists. If it does, update its details; if not, add it as a new entry in the inventory. This ensures that your inventory remains current and accurate. Proper error handling should also be considered, such as validating the price to ensure it’s a positive number.

  2. STOCK <codigo> <cantidad>

    The STOCK command adjusts the stock level of a product. The <codigo> identifies the product, and <cantidad> specifies the adjustment to the stock level. This command is vital for tracking inventory levels and preventing overselling. You need to handle cases where the stock might become negative (e.g., due to an incorrect adjustment), which could indicate an issue that needs to be addressed. Consider adding checks to ensure the stock level does not fall below a certain threshold or implementing alerts for low stock levels.

  3. VENDE <codigo> <cantidad>

    This is the core command for processing sales. It first verifies if the product exists, then checks if there is sufficient stock. If both conditions are met, it decrements the stock and records the sale. The <codigo> identifies the product being sold, and <cantidad> is the number of units sold. When implementing this command, you should also consider applying any relevant discounts. This might involve calling the discount calculation function from the external module. Error handling is crucial here, especially for cases where the product is not found or the stock is insufficient. Informative messages to the user about the status of the sale (success, insufficient stock, etc.) are essential.

  4. DEVUELVE <codigo> <cantidad>

    The DEVUELVE command handles returns. It adjusts the stock level upwards and records the return. The <codigo> identifies the product being returned, and <cantidad> is the number of units returned. This command is essentially the reverse of the VENDE command. Proper tracking of returns is important for accurate inventory management and financial reporting. As with sales, ensure that the product exists before processing the return. Consider logging return reasons, as this can provide valuable insights into product issues or customer satisfaction.

  5. PROMOS

    This command displays the active discount rules. It provides a quick overview of the promotions currently in effect. The output should be formatted in a user-friendly way, clearly listing each promotion. For example, you might display the promotion type, the products involved, and the discount amount or percentage. This command is essential for staff to understand what discounts are applicable during sales and for customers to be informed about available deals.

  6. REPORTE

    The REPORTE command generates a consolidated report of the system's state. This includes the inventory status, sales totals, discounts applied, and returns processed. The report should provide a comprehensive overview of the kiosk's operations. Key components of the report include:

    • Inventory Table: Displays each product’s code, description, price, and stock level. This provides a snapshot of the current inventory.
    • Gross Sales Totals: The total value of all sales before discounts.
    • Total Discounts Applied: The total value of all discounts given.
    • Total Returns: The total value of all returned items.
    • Net Amount: The final sales amount after deducting discounts and returns.
    • Top Three Best-Selling Products: A list of the three products with the highest units sold, ordered by quantity. This helps identify popular items and inform inventory decisions.

    The report should be well-formatted and easy to understand, as it is a critical tool for business analysis and decision-making.

  7. FIN

    The FIN command terminates the program. This command ensures a clean exit from the system and allows for any necessary cleanup operations, such as saving data to a file or closing connections.

Discount Calculation Rules

Discounts are a crucial aspect of any sales system, and this challenge requires implementing several types of promotions. These promotions are defined as a list in memory, with each promotion describing its type and the products involved. Let's explore the discount rules in detail:

  • "3 for 2" Discount for chicle: This promotion applies whenever 3 units of chicle (chewing gum) are sold. For every three units, the customer only pays for two. This type of discount encourages bulk purchases and is common in retail environments. When implementing this, you need to check if the quantity of chicle sold is a multiple of 3 and apply the discount accordingly.
  • 10% Discount for agua500: When 5 or more units of agua500 (500ml water bottles) are sold, a 10% discount is applied to those units. This promotion encourages customers to buy more by offering a price reduction for larger quantities. The implementation should check the quantity of agua500 sold and apply the discount if it meets or exceeds the threshold.
  • Fixed Discount for galleta and cafe: A fixed discount of 1000 Gs (Guaraníes) is applied when both galleta (biscuits) and cafe (coffee) are included in the same sale. This type of promotion encourages the sale of complementary items and can increase the average transaction value. The implementation needs to check if both products are present in the sale and apply the discount if they are.

Implementing Discount Logic

To implement these rules effectively, consider the following:

  • Data Structure for Promotions: Use a list or dictionary to store promotions. Each entry should specify the type of discount, the products involved, and any thresholds or discount amounts.
  • Discount Calculation Function: Create a function that takes the items in the sale and the list of promotions as input and returns the total discount amount. This function should iterate through the promotions and apply the relevant discounts based on the items sold.
  • Order of Application: Be mindful of the order in which discounts are applied, as this can affect the final price. Ensure that the discount logic is consistent and fair.

External Module

To promote modularity, the discount calculation logic should reside in an external module named promos.py. This module will contain a function named calcular_descuento, which is responsible for calculating the discount amount based on the items sold and the active promotions.

Function Signature

def calcular_descuento(items_de_venta, productos, promociones):
    '''
    items_de_venta: list that describes the sale performed, e.g., [(code, quantity)].
    productos: dictionary with product information.
    promociones: list of discount rules.
    Returns the total discount amount calculated in Gs.
    '''
    ...

Parameters Explained

  • items_de_venta: This parameter is a list that describes the items sold in a transaction. Each item is represented as a tuple containing the product code and the quantity sold. For example, [('chicle', 3), ('agua500', 5)] indicates that 3 units of chicle and 5 units of agua500 were sold.

  • productos: This parameter is a dictionary containing the information about each product. The keys of the dictionary are the product codes, and the values are dictionaries containing the product details (e.g., description, price). For example:

    {
        'chicle': {'descripcion': 'Chicle menta', 'precio': 1500},
        'agua500': {'descripcion': 'Agua mineral 500', 'precio': 3000},
        ...
    }
    
  • promociones: This parameter is a list of discount rules. Each rule should specify the type of discount, the products involved, and any relevant conditions (e.g., quantity thresholds). For example:

    [
        {'tipo': '3x2', 'producto': 'chicle'},
        {'tipo': 'porcentaje', 'producto': 'agua500', 'cantidad_minima': 5, 'descuento': 0.10},
        {'tipo': 'fijo', 'productos': ['galleta', 'cafe'], 'descuento': 1000}
    ]
    

Return Value

The calcular_descuento function should return the total discount amount calculated in Guaraníes (Gs). This value will be subtracted from the total sales amount to determine the net amount.

Implementation Steps

  1. Iterate Through Items: Loop through the items_de_venta list to identify the products and quantities sold.
  2. Apply Promotions: For each item, check if there are any applicable promotions in the promociones list.
  3. Calculate Discounts: Based on the promotion type and conditions, calculate the discount amount.
  4. Accumulate Discounts: Add up the discounts for each item to get the total discount amount.
  5. Return Total Discount: Return the total discount amount.

Main Program Integration

The main program (caja.py) should import the calcular_descuento function from promos.py and apply it when processing the VENDE command. This ensures that discounts are correctly calculated and applied to sales transactions.

Suggested Program Structure

To keep the codebase organized and maintainable, it is recommended to structure the program into two main files:

  • desafio-02/caja.py

    This file will serve as the main program and handle the following responsibilities:

    • Command Reading: Implement the logic to read commands from the console (stdin).
    • Function Dispatch: Direct each command to its corresponding handler function.
    • Product Management: Implement functions for adding products (ALTA), updating stock (STOCK), processing sales (VENDE), and handling returns (DEVUELVE).
    • Report Generation: Implement the logic to generate reports (REPORTE).
    • Data Storage: Use lists and dictionaries to store data, including inventory, sales, returns, and promotions.
  • desafio-02/promos.py

    This file will contain the discount calculation logic and should include:

    • calcular_descuento Function: Implement the function to calculate discounts based on the sales items and promotion rules. This function should not have any side effects, meaning it should not modify any global variables or data structures. It should only return the calculated discount amount.

Benefits of This Structure

  • Modularity: Each file has a specific set of responsibilities, making the code easier to understand and maintain.
  • Separation of Concerns: The discount calculation logic is isolated in promos.py, allowing it to be updated independently without affecting the main program.
  • Testability: The calcular_descuento function can be tested independently, ensuring that the discount calculations are accurate.

Output Format

PROMOS

When the PROMOS command is entered, the system should display the active discount rules in a user-friendly format. For example:

PROMOCIONES ACTIVAS
1) 3x2 en chicle
2) 10% en agua500 desde 5 unidades
3) Descuento de 1000 Gs en venta conjunta de galleta y cafe

This output clearly lists each promotion, making it easy for staff to understand and communicate to customers.

REPORTE

The REPORTE command should generate a comprehensive report including:

  • Product Table: A table displaying each product's code, description, price, and stock level.
  • Gross Sales: The total value of all sales before discounts.
  • Total Discounts Applied: The total value of all discounts given.
  • Total Returns: The total value of all returned items.
  • Net Amount: The final sales amount after deducting discounts and returns.
  • Top Three Best-Selling Products: A list of the three products with the highest units sold, ordered by quantity.

The report should be well-formatted and easy to read, providing a clear overview of the kiosk's operations.

Example Flow

Input

ALTA chicle Chicle_menta 1500
ALTA agua500 Agua_mineral_500 3000
ALTA galleta Galleta_vainilla 2500
ALTA cafe Cafe_chico 5000
STOCK chicle 10
STOCK agua500 30
STOCK galleta 12
STOCK cafe 10
PROMOS
VENDE chicle 3
VENDE agua500 5
VENDE galleta 1
VENDE cafe 1
DEVUELVE galleta 1
REPORTE
FIN

This input demonstrates a sequence of commands that add products, adjust stock levels, display promotions, process sales and returns, and generate a report.

Expected Deliverables

To successfully complete this challenge, you should deliver the following files:

README.md
desafio-02/caja.py
desafio-02/promos.py

README.md

The README.md file is a crucial part of the delivery. It should explain:

  • Execution Method: How to run the program.
  • Assumptions Made: Any assumptions made during the implementation process.
  • Data Structures Used and Justification: The data structures used (e.g., lists, dictionaries) and why they were chosen.
  • Input and Output Examples: Examples of input commands and the corresponding output.

Code Files

  • desafio-02/caja.py: The main program file containing the command processing and business logic.
  • desafio-02/promos.py: The external module containing the discount calculation function.

Estimated Time

This exercise is designed to be completed in approximately two hours. The focus should be on clarity, modularization, and correct handling of data structures.

In conclusion, building a Python cash register system with external modules, arrays, and functions is a fantastic way to hone your programming skills. It touches on vital concepts like data management, modular design, and algorithm implementation. By following the guidelines and examples provided, you can create a robust and efficient system that meets the challenge's requirements. Remember to focus on clear, maintainable code and thorough documentation. Good luck!

For further reading on best practices in Python programming and design, you might find valuable information on Python.org's documentation.

You may also like