Sunday, July 23, 2017

Programming Challenge 12.13 - Inventory Program

Example Files: EvalDate.h
                         UtilityCls.h
                         PR_Item.dat


/* Inventory Program - This program uses a structure to store the following
    inventory data in a file:
  
        * Item Description
        * Quantity on Hand
        * Wholesale Cost
        * Retail Cost
        * Date Added to Inventory

    The program has a menu that allows the user to perform the following tasks:

        * Add new records to the file
        * Display any record in the file
        * Change any record in the file
  
    Input Validation: The program does not accept quantities, or wholesale or
    retail costs, less than 0. The program does not accept dates determined to
    be unreasonable. */

#include "UtilityCls.h"
#include "EvalDate.h"

const int     DESCR_SIZE = 25;
const int     DATE_SIZE = 12;
const string ADMIN_NAME = "Administrator Rhodan";

struct Inventory
{
    int    numRecord;                        /* Holds the record number                */
    char   itemDescr[DESCR_SIZE];        /* Holds the item name                    */
    int    atHand;                            /* Quantity of items available        */
    double wholesaleCost;                /* Holds the wholesale cost            */  
    double retailCost;                    /* Holds the retail cost                */
    char   dateAdded[DATE_SIZE];        /* Holds the date an item was added */

    /* Inventory Constructor */
    Inventory()
    {
        numRecord = 0;
        itemDescr[DESCR_SIZE] = ' ';
        atHand = 0;
        wholesaleCost = 0.0;
        retailCost = 0.0;
        dateAdded[DATE_SIZE] = ' ';
    }

    /* Inventory Destructor */
    ~Inventory()
    {
    }
};      

struct Date
{
    int addDay;        /* Holds day   [1-31] */
    int addMonth;    /* Holds month [1-12] */
    int addYear;    /* Holds year             */

    Date()
    {
        addDay = 0;
        addMonth = 0;
        addYear = 0;
    }

    ~Date()
    {
    }
};

enum class MenuItems
{
    ADD_RECORD = 'A', DISPLAY_RECORD = 'D', EDIT_RECORD = 'E', QUIT = 'Q'
};

enum class Choice
{
    YES = 'Y', NO = 'N'
};

void     menu(Inventory &);
string getFileName();
void   getItemInfo(Inventory &);
void   getDate(Inventory &);
string dateToString(int, int, int);
void     processRecord(Inventory &, const string);
int    writeRecord(Inventory &, const string);
int    readRecord(Inventory &, const string);
int    editRecord(Inventory &, const string);
void   displayRecord(const Inventory &, const int);

int main()
{
    Inventory itemInfo;

    cout << "\nCOSMIC WAREHOUSE COMPANY - TERRA HQ.\n\n"
          << "Welcome " << ADMIN_NAME << "!\n";

    menu(itemInfo);
  
   pauseSystem();
   return 0;
}

/* **********************************************************
    Definition: menu

    This function accepts a structure variable passed to it by
    reference as its argument. It provides a menu structure
    that allows the user to select from the following items:

        * Add a record
        * Display a record
        * Edit a record
        * Quit
    ********************************************************** */

void menu(Inventory &itemRec)
{
    const char addRec     = static_cast<char>(MenuItems::ADD_RECORD);
    const char dispRec = static_cast<char>(MenuItems::DISPLAY_RECORD);
    const char editRec = static_cast<char>(MenuItems::EDIT_RECORD);
    const char quit     = static_cast<char>(MenuItems::QUIT);
  
    string fileName = "";
    char     choice     = ' ';

    fileName = getFileName();

    do
    {
        cout << "\nCOSMIC WAREHOUSE COMPANY - ADMINISTRATIVE MENU\n\n"
              << "[A] - ADD RECORD\n"
              << "[D] - DISPLAY RECORD\n"
              << "[E] - EDIT RECORD\n"
              << "[Q] - QUIT\n\n";
        cout << "Please make your choice, " << ADMIN_NAME << ": ";
        cin >> choice;
        cout << "\n";

        choice = toupper(choice);

        switch (choice)
        {
            case addRec :
            {
                clearScreen();
                processRecord(itemRec, fileName);
            }
            break;

            case dispRec :
            {
                clearScreen();
                readRecord(itemRec, fileName);  
            }
            break;

            case editRec :
            {
                clearScreen();
                editRecord(itemRec, fileName);
            }
            break;

            case quit :
            {
                cout << "I will now shut this program down, " << ADMIN_NAME << ".\n"
                      << "The Cosmic Warehouse Company Item Record System "
                      << "wishes you a successful day!";
            }
        }
    } while (choice != quit);  
}

/* **********************************************************
    The user is asked for a filename, which is returned from
    this function.
    ********************************************************** */

string getFileName()
{
    string fileName = "";

    cout << "\nPlease enter the name of the file you wish me to store\n"
          << "or retrieve item information from, " << ADMIN_NAME << ": ";
    cin >> fileName;

    return fileName;
}

/* **********************************************************
   Definition: getItemInfo

    This function accepts a structure variable passed to this
    function as its argument. It stores information about an
    item in the member variables of the Inventory structure.
   ********************************************************** */

void getItemInfo(Inventory &itemRec)
{
    Date addDate;

    cout << "Please provide information about the item you wish me\n"
          << "to process " << ADMIN_NAME <<"\n\n";

    /* Get item information */
    cout << "Item Description: ";
    cin.ignore();
    cin.getline(itemRec.itemDescr, DESCR_SIZE);

    cout << "Quantity Available: ";
    cin >> itemRec.atHand;

    while (itemRec.atHand <= 0)
    {
        cout << "Quantity Available: ";
        cin >> itemRec.atHand;
    }

    cout << "Wholesale Cost: $ ";
    cin >> itemRec.wholesaleCost;

    while (itemRec.wholesaleCost <= 0.0)
    {
        cout << "Wholesale Cost: $ ";
        cin >> itemRec.wholesaleCost;
    }

    cout << "Retail Cost: $ ";
    cin >> itemRec.retailCost;

    while (itemRec.retailCost <= 0.0)
    {
        cout << "Retail Cost: $ ";
        cin >> itemRec.retailCost;
    }

    getDate(itemRec);
}

/* **********************************************************
   Definition: getDate

    This function accepts a structure variable passed to it by
    reference as its argument. It asks and evaluates the date
    entered. This information is stored in a member variable
    of the Inventory structure.
   ********************************************************** */

void getDate(Inventory &itemRec)
{
    Date addDate;

    cout << "\nDate added:\n";
    cout << "Day: ";
    cin >> addDate.addDay;

    cout << "Month: ";
    cin >> addDate.addMonth;

    cout << "Year: ";
    cin >> addDate.addYear;

    while (validateDate(addDate.addDay, addDate.addMonth, addDate.addYear) == false)
    {
        cout << "\nI am sorry but this date is invalid, "
              << ADMIN_NAME << ". Please repeat your input ...\n";
        cin.clear();

        cout << "\nDate added:\n";
        cout << "Day: ";
        cin >> addDate.addDay;

        cout << "Month: ";
        cin >> addDate.addMonth;

        cout << "Year: ";
        cin >> addDate.addYear;
    }

    string vDate = dateToString(addDate.addDay, addDate.addMonth,
                                         addDate.addYear);

    strcpy_s(itemRec.dateAdded, DATE_SIZE, vDate.c_str());
}

/* **********************************************************
   Definition: dateToString

    This function accepts three integer values as arguments.
    A stringstream object is used to store the date in a
    specific format, which is returned from the function.
   ********************************************************** */

string dateToString(const int dd, const int mm, const int yy)
{
    stringstream dateStream;

    if (dd < 10 && mm < 10)
    {
        dateStream << "0" << dd << "/0" << mm << "/" << yy;
    }
    else if (dd >= 10 && mm < 10)
    {
        dateStream << dd << "/0" << mm << "/" << yy;
    }
    else
    {
        dateStream << dd << "/" << mm << "/" << yy;
    }

    return dateStream.str();
}

/* **********************************************************
   Definition: processRecord

    This function accepts a structure variable passed to it by
    reference, and a filename as its arguments. It calls two
    functions:

        * getItemInfo()
        * writeRecord()

    As long as the user decides that he or she wishes to add
    a record, these functions are called. If the user, when
    asked, answers with 'n', the function will exit and the
    program returns to the menu function.
   ********************************************************** */

void processRecord(Inventory &itemRec, const string fileName)
{
    const char positive = static_cast<char>(Choice::YES);
    const char negative = static_cast<char>(Choice::NO);

    char choice = ' ';

    do
    {
        getItemInfo(itemRec);
        writeRecord(itemRec, fileName);

        cout << "\nDo you wish to add another item record " << ADMIN_NAME << "?\n"
              << "[Y]es | [N]o: ";
        cin.ignore();
        cin.get(choice);
        cout << "\n";

        choice = toupper(choice);

        while (toupper(choice) != positive && toupper(choice) != negative)
        {
            cout << "\nDo you wish to add another item record " << ADMIN_NAME << "\n";
            cout << "[Y]es | [N]o: ";
            cin.ignore();
            cin.get(choice);
            cout << "\n";

        }
    } while (choice != negative);
}

/* **********************************************************
   Definition: writeRecord

    This function accepts a structure variable passed to it
    by reference and a filename as its arguments. It tries to
    open a file in binary write mode. Upon success, data is
    written in append mode to the file. If an error occurs, a
    message is displayed and the function exits to the menu.
   ********************************************************** */

int writeRecord(Inventory &itemRec, const string fileName)
{
    fstream writeRec(fileName.c_str(), ios::out | ios::binary | ios::app);

    if (!writeRec.fail())
    {
        ++itemRec.numRecord;
       writeRec.write(reinterpret_cast<char *>(&itemRec), sizeof(itemRec));

        cout << "\nI have successfully written the item information to\n"
              << fileName << " " << ADMIN_NAME << ".\n";
    }
    else
    {
        cout << "I could not write the item information to " << fileName
              << ", " << ADMIN_NAME << ".\n"
              << "I will now return to the main menu ...\n";
    }
    writeRec.close();

    return 0;
}

/* **********************************************************
   Definition: readRecord

    This function accepts a structure variable passed to it by
    reference and a filename as its arguments. It tries to
    open a file to read data back in. Upon success, the user
    is first asked to enter a record number. The position of
    this record is retrieved, and the record displayed. In
    case of an error, a message is displayed, and the function
    will exit to the menu.
   ********************************************************** */

int readRecord(Inventory &itemRec, const string fileName)
{
    long recNum = 0;

    fstream readRec(fileName.c_str(), ios::in | ios::binary);

    /* Upon success, the item record conforming to the input made
       by the user is retrieved, and the item information is
        displayed. */
    if (!readRec.fail())
    {
        cout << "\nPlease enter the number of the record I should display, "
              << ADMIN_NAME << ": ";
        cin >> recNum;

        readRec.seekg((recNum -1) * sizeof(itemRec), ios::beg);
        readRec.read(reinterpret_cast<char *>(&itemRec), sizeof(itemRec));

        displayRecord(itemRec, recNum);
    }
    else
    {
        cout << "\nI could not retrieve item information from" << fileName
              << ", " << ADMIN_NAME << "...\n"
              << "I will now return to the main menu ...\n";
        return -1;
    }
    readRec.close();

    return 0;
}

/* **********************************************************
   Definition: editRecord

    This function accepts a structure variable passed to it
    by reference and a filename as its arguments. It tries to
    open a file in read and write mode. Upon succes, the user
    is asked to enter the record number he or she wishes to
    change. This position is retrieved, the record is read in
    from the file, and the item record displayed.
  
    The user is then asked if this is the record he or she
    wishes to edit. If the answer is positive, a function that
    allows the user to enter data is called. Once finished,
    the user is asked if the information is correct. If the
    answer is positive, the item record is written to file
    and the function will exit.

    In case the user decides that he or she does not wish to
    either change a particular record, or finds the item info
    is incorrect, the function exits and the program returns
    to the main menu.
   ********************************************************** */

int editRecord(Inventory &itemRec, const string fileName)
{
    const char positive = static_cast<char>(Choice::YES);
    const char negative = static_cast<char>(Choice::NO);

    long recNum = 0;
    char choice = ' ';

    fstream alterRec(fileName.c_str(), ios::in | ios::out | ios::binary);

    if (!alterRec.fail())
    {
        cout << "\nWhich item record do you wish me to change, "
              << ADMIN_NAME << ": ";
        cin >> recNum;

        alterRec.seekg((recNum -1) * sizeof(itemRec), ios::beg);
        alterRec.read(reinterpret_cast<char *>(&itemRec), sizeof(itemRec));

        /* Display the item information */
        displayRecord(itemRec, recNum);

        /* The user is asked to confirm his or her choice before changing
           any information. */
        cout << "Do you wish me to change this record, " << ADMIN_NAME << "?\n"
                << "[Y]es, [N]o: ";
        cin >> choice;
        cout << "\n";

        choice = toupper(choice);

        if (toupper(choice) == positive)
        {
            /* Get new item information */
            getItemInfo(itemRec);

            /* Moves to the position the item record is stored at. */
            alterRec.seekp((recNum - 1) * sizeof(itemRec), ios::beg);

            /* The user is asked to confirm his or her choice before the changed
                record is written to the file. */
            cout << "\nIs this information correct, " << ADMIN_NAME << "?\n"
                  << "[Y]es, [N]o: ";
            cin >> choice;
            cout << "\n";

            choice = toupper(choice);

            while (toupper(choice) != positive && toupper(choice) != negative)
            {
                cout << "\nIs this information correct, " << ADMIN_NAME << "?\n"
                    << "[Y]es, [N]o: ";
                cin >> choice;
                cout << "\n";
            }

            if (toupper(choice) == positive)
            {
                alterRec.write(reinterpret_cast<char *>(&itemRec), sizeof(itemRec));
            }
        }
        else
        {
            cout << "\nAs you wish, " << ADMIN_NAME << ".\n"
                  << "I will now return to the main menu ...\n";
        }
    }
    else
    {
        cout << "\nI could not read from or write item records to " << fileName
              << ", " << ADMIN_NAME << ".\n"
              << "I will now return to main menu ...\n";
        return -1;
    }
    alterRec.close();

    return 0;
}

/* **********************************************************
    Definition: displayRecord

    This function accepts a nested structure variable passed
    to it by reference and a record number as its arguments.
    It displays information stored in the file under that
    record number.
    ********************************************************** */

void displayRecord(const Inventory &itemRec, const int recNum)
{
    cout << "\nHere is the item with record number: " << recNum << " " << ADMIN_NAME << "\n\n";

    cout << setw(19) << left  << "Item Description:\t\t" << itemRec.itemDescr << "\n";
    cout << setw(17) << left  << "Quantity Available:\t\t" << itemRec.atHand << "\n";
    cout << setprecision(2)    << showpoint << fixed;
    cout << setw(16) << left  << "Wholesale Cost: "
          << setw(15) << right << "$ "
          << setw(4) << right  << itemRec.wholesaleCost << "\n";
    cout << setw(16) << left  << "Retail    Cost: "
          << setw(15) << right << "$ "
          << setw(4) << right  << itemRec.retailCost << "\n";
    cout << "Date Added: "    << setw(30) << right << itemRec.dateAdded << "\n\n";
}

Example Output:







No comments:

Post a Comment