eStore Database/Application

Transcription

eStore Database/Application
eStore Database/Application
Final Project Report
By: David Sampson and Steve Kazmierczak
December 13, 2007
WPI CS542 – Professor Rundensteiner
INTRODUCTION AND OVERVIEW ......................................................................................................................1
ABSTRACT .................................................................................................................................................................1
KEYWORDS................................................................................................................................................................1
HIGH LEVEL OBJECTIVES ACCOMPLISHED ..................................................................................................................1
ANALYSIS – DOMAIN REQUIREMENTS OF MODELED DATA ....................................................................1
APPLICATION REQUIREMENTS ...................................................................................................................................2
DATA MODEL TO SUPPORT BUSINESS LOGIC.............................................................................................................2
ER DIAGRAMS AND SYSTEM DESIGN: .......................................................................................................................2
Overview ..............................................................................................................................................................2
Customer Data Exploded View ............................................................................................................................3
Question: Why model street# and street_name separately? .............................................................................................. 3
Order and Product Data Exploded View .............................................................................................................4
Question: Why separate ORDER_ITEM from ORDER ? ................................................................................................ 4
Question: Why capture INVENTORY_EVENTS (stock received)? ................................................................................ 5
Revisions Since Proposal .....................................................................................................................................5
Revisions Since Proposal .....................................................................................................................................7
ARCHITECTURE AND TOOLS ..............................................................................................................................7
TOOLS USED ..............................................................................................................................................................7
Database ..............................................................................................................................................................7
Why we chose Oracle and not MySQL post proposal ..........................................................................................7
FRONT-END ...............................................................................................................................................................8
Additional Java, Swing, SQL references used: ....................................................................................................9
JDBC ........................................................................................................................................................................9
Resources on How To Connect using JDBC:.....................................................................................................10
IMPLEMENTATION DETAILS.............................................................................................................................10
ER DIAGRAMS TO SQL TABLES ..............................................................................................................................10
STORED PROCEDURES, TRIGGERS AND/OR ALGORITHMS (PSEUDOCODE) ...............................................................17
Prototype Procedure for Order Fulfillment:......................................................................................................17
Prototype Procedure for Customer Order Process: ..........................................................................................18
Prototype Procedure for Customer Order History: ...........................................................................................18
Prototype Procedure for Inventory Event:.........................................................................................................18
APPLICATION DETAILS ............................................................................................................................................18
Original Prototype Employee Application .........................................................................................................19
Original Prototype Employee Application Screen Shots (deprecated)............................................................................ 19
Customer Application as of Progress Report time: ......................................................................................................... 22
THE CUSTOMER ESTORE APPLICATION TODAY (WITH TRIGGER/PROCEDURE DISCUSSION) .24
1) SHOP FOR PRODUCTS:..........................................................................................................................................24
2) VIEW CART MODE ...............................................................................................................................................25
3) CHECKOUT (3 STEPS)...........................................................................................................................................25
3.1) Select Shipping Address or Cancel Checkout .............................................................................................25
3.2) Select Billing Address or Cancel Checkout ................................................................................................26
3.3) Confirm Order and Submit .........................................................................................................................26
4) ACCOUNT MANAGEMENT ....................................................................................................................................27
ESTORE ORDER FULFILLMENT THEORY...................................................................................................................28
EXAMPLE ORDER @ SUBMIT ORDER TIME ..............................................................................................................28
What Happens In Oracle When Order Is Submitted ..........................................................................................29
Case 2 (order_item could not ship, send notification):......................................................................................31
Additional profit costing example (multiple inventory_events per order_item): ...............................................36
QUERIES ..................................................................................................................................................................37
EMPLOYEE APPLICATION AND ESTORE STATISTICS .................................................................................................37
EMPLOYEE APP STATISTICS VIEW ...........................................................................................................................40
Product Stats
.......................................................................................................................40
Inventory Stats
......................................................................................................................41
Order Fulfillment Stats
Profit Stats
..................................................................................................43
................................................................................................................................44
Unfulfilled Order Stats
...................................................................................................46
TESTING ..................................................................................................................................................................46
ACCOMPLISHMENTS & COMMENTS ..............................................................................................................46
SCHEDULE ...............................................................................................................................................................47
Goals Completed Since Project Progress Report: ........................................................................................................... 47
Table Of Contents 2 of 2
Introduction and Overview
Abstract
Our project simulates eStore, an on-line merchant via a database with respective front-end
applications. We model the process of customers purchasing products via a shopping cart model,
tracking transactions yielding product and sales metrics. The process of conducting a transaction
and stocking inventory are areas for extension of the project focus. Our target user group
includes anyone familiar with eCommerce and buying products via the Internet, people
interested in databases and database applications, and anyone attracted to portable applications
utilized via the Internet. The exercise of constructing a database architecture involved planning
and revision of an Entity Relationship model to support desired functionality and have
reasonable future extensibility if desired.
Keywords
•
Database, eCommerce, Java, JDBC, SQL, Oracle, Swing, ER Diagrams
High level objectives accomplished
This presents some of the following challenges accomplished:
• Represent the data in terms of entities and relationships.
• Translate ER model into a physical schema in Oracle using SQL, and enforcing integrity
constraints using sequences, triggers, and client application data checks.
• Represent business logic partially using triggers and stored procedures
• Implement Java front-end for interaction with the Oracle DB.
• Use JDBC so the Java application can talk to and write to the DB.
• Design a prototype user interface to facilitate corporate data entry.
• Implemented cart flow and order events in the GUI/DB.
• Implemented existing plan for shopping cart and order fulfillment in DB.
• Construct procedures for updating and ordering inventory in DB and GUI, shipping
products, running queries, and deriving calculated attribute values in DB.
• Implementing sample data and queries to illustrate value from using our DB business
model.
• query output via graphical charts, additional useful features in shopping cart, checkout
process, and further utilize vendor information in the DB schema.
• For future work: storing pictures (BLOBs) in Oracle DB
Analysis – Domain Requirements of Modeled Data
Analysis of the domain required for the data began with a discussion about what type of entities
we wanted to model for eStore. eStore sells merchandise in different categories (ex books,
electronics, and music). Customers buy these products via shopping cart style order process, and
the business tracks who bought what, when and for what price, as well as the wholesale costs for
stocking inventory. These entities required meaningful attributes that would help in associating
them with respective relationships to form the basis for business logic.
A brain storming session via whiteboard took place on October 2, 2007 where we constructed a
mock Entity Relationship (ER) diagram of entities, attributes of those entities, participating
PAGE 1 OF 48
relationships and associated integrity constraints. The goal here was to construct a model that
would allow for useful and interesting data to be derived via queries, and be manageable when
constructing triggers and procedures to operate the eStore business logic.
Background material for the eStore concept was modeled after online retails such as
Amazon.com, iTunes Store, buy.com, which utilize a shopping cart and business transaction
processing system. Due to the limited time for planning and implementation we tried to focus
the scope on what we find to be the most interesting areas of the business infrastructure from a
DB and GUI front-end perspective.
Application Requirements
•
•
•
•
•
•
•
Oracle Database with SQL, PL/SQL
JRE 1.5.1 or higher
JDBC connectivity to DB
Java Swing (portable) front-end GUI prototype application for interacting with DB
Sample product data for use by testers who conduct sample orders
SMTP access via Oracle modules (recently added)
Java graphing package (recently added)
Data Model to Support Business Logic
The database is robust enough to capture commonly used retail data, much of which is
implemented in the schema, and some left for future extension:
•
•
•
•
•
•
•
•
Which customers order what products, when, and for how much?
How was a customer order billed and with what form of payment?
How much product inventory exists at any one time for customers to purchase?
What the current profit margin is for a particular product given actual costs to carry
product (wholesale unit cost vs. sale price)?
When, where and to whom we ship an order?
Which products are selling the best in a given time period?
Who manages product departments?
Extensible schema/architecture for future requirements.
ER Diagrams and System Design:
Overview
Figure 3 (pg 7) is our ER diagram for eStore illustrating entities, their relationships, and integrity
constraints between these relationships, as well as areas for extension. The two primary
relationship sets are 1) customer data and 2) order and product data. Attributes have been
excluded from this high level overview.
PAGE 2 OF 48
Customer Data Exploded View
Attributes for customer related data is captured below in Figure 1:
passwd
f_Name
l_Name
email
customer_id
phone
CUSTOMER
card#
exp.date
type
has
cid
has
ISA
SHIP_addr
registered
BILL_addr
CCARD
ADDRESS
name
street #
street_name
country
addr_2
city
state
zip
Figure 1: exploded view showing attributes
•
•
•
•
•
•
CUSTOMERs have a customer_id, First Name, Last Name, Email address, phone
number and passwd.
Constraint: Email will be unique to the entity and serve as the login name.
Constraint: Passwords must be more than 6 characters.
SHIP_address and BILL_address are both (ISA) an ADDRESS.
An address has a Name, Street#, Street Name, Address Line 2, City, State, Zip Code, and
Country.
Schema will implement this with primary key / foreign key relationships.
Question: Why model street# and street_name separately?
If population density is high within a given large city, this would allow us to track how many
customers per section of street#s, or by street. For example, 1st Ave in Manhattan, NYC runs
through many sections of town that cross socio-economic boundaries, business districts, income
levels, etc.
•
•
•
BILL_addresses are registered to CreditCard/PaymentTypes
CreditCard has a type, card#, expiration date, and cardid
Constraint: Exactly one credit card is associated with a BILL_address
PAGE 3 OF 48
Order and Product Data Exploded View
Attributes for order and product related data is captured below in Figure 2:
date_recvd
picture_blob
pictid
product_cost
qty_avail
ship_cost
stock_num
PICTURE
qty_recvd
active
profit
INVENTORY EVENTS
calc_ship_cost
notified
oitem_num
stocked_by
qty
has
date_shipped
unit_price
ORDER_ITEM
name
of_type
description
PRODUCT
weight
has
markup%
curr_profit
ship_cost
ORDER
calc_total
qty_items
order_num
status
qty
product_id
curr_price
date placed
Figure 2: exploded view showing attributes
ORDERs consist of an order_number, date_placed, status, qty_items, and calculated_total cost of
order including shipping.
• Each ORDER is billed_to exactly 1..1 BILL_addr, paid_with exactly 1..1 CCARD of a
given CUSTOMER and shipped_to exactly 1..1 SHIP_addr. By enforcing these 1..1
constraints, we simplify the business logic for billing.
• Each ORDER has 1..n ORDER_ITEMs, and each ORDER_ITEM is associated with
exactly 1..1 ORDER. Each ORDER_ITEM is of_type PRODUCT, of qty.
• Each ORDER_ITEM is made up of an ORDER_ITEM_number, a date_shipped, qty of
product, unit_price, a derived calculated_shipping_cost based on qty x ,
PRODUCT.ship_cost, profit and notified (to track status of notification to customer).
Question: Why separate ORDER_ITEM from ORDER ?
One goal of this model is to track actual purchased PRODUCTs at sale time cost. An order is
made up of various quantities of a particular PRODUCT, and each PRODUCT may or may not
PAGE 4 OF 48
be in stock, and may ship from different locations. Separately, each ORDER_ITEM has derived
values for calc_shipping_cost based on the qty_items of_type PRODUCT x a
PRODUCT.ship_cost.
• ORDER_ITEMs are exactly 1..1 of_type PRODUCTs.
• Each PRODUCT contains a name, customer facing description, weight, derived
current_profit, current_price, derived qty in inventory, ship_cost per unit, markup%,
picture_blob (binary object) and product_id.
• PRODUCTs are supplied_by VENDORs which is used for reordering a PRODUCT in
eStore's inventory.
• VENDORs have a venderid, contact_name, phone#, address, and preferred vendor status.
• PRODUCTs are stocked_by INVENTORY_EVENTs.
• INVENTORY_EVENTS consists of a stock_num, date_received, qty_received of a
PRODUCT, total product_cost in a given shipment, active, qty_avail, and ship_cost of
the PRODUCT qty_received.
Question: Why capture INVENTORY_EVENTS (stock received)?
The WAREHOUSE captures wholesale costs of inventory that is stocked, as it is shipped to
eStore. When capturing a product_cost (or subtotal of costs of the products portion of the
shipment), an INVENTORY_EVENTS.ship_cost for the entire delivery, and the qty_received of
a product, we can derive the wholesale unit cost of each PRODUCT in the shipment, as well as
the unit cost of all remaining PRODUCT quantities of all recently received
INVENTORY_EVENTS for the same PRODUCT.
An aggregate of INVENTORY_EVENTS for a particular PRODUCT can be used to derive a
curr_price based on a desired markup% (according to a procedural formula) and the calculated
wholesale unit cost including INVENTORY_EVENTS.ship_cost to arrive at a
PRODUCT.curr_price and unit PRODUCT.curr_profit, as well as a PRODUCT.qty which is
incremented by new INVENTORY_EVENTS, and decremented by ORDER_ITEMs being
shipped. (This inventory increment and decrement over time is seen in a chart in our GUI).
Revisions Since Proposal
•
•
•
•
•
•
•
EMPLOYEE section was solidified as depicted in Figure 3.
EMPLOYEE entity was revised to include the attributes: eid, fname, lname, addr_id,
username, passwd, phone#, emp_role.
emp_role stores the role: admin or mgr of an employee.
Employees have exactly one address.
Removed relationship paid_with between ORDER and CCARD since an ORDER is
billed_to exactly one BILL_addr and exactly one CCARD is registered to a BILL_addr.
Added area for future addition if time permits: PICTURE table to store binary large
objects (BLOBs) of pictures, exactly at most 1 per product.
This was kept in a separate table so queries would not have to handle this special binary
type when doing a select *. This is an issue for the GUI and sqlplus.
PAGE 5 OF 48
Fig 1
INVENTORY_EVENT
PICTURE
Note:
Dashed line for PICTURE and VENDOR is an
area for future extension.
has
stocked_by
VENDOR
supplied_by
ORDER_ITEM
PRODUCT
of_type
DEPT
catalogued
has
manages
EMPLOYEE
ORDER
eid
phone
fname
addr_id
place
lname
emp_role
ship_to
username
billed_to
CUSTOMER
password
has
has
has
Fig 2
SHIP_addr
ISA
BILL_addr
registered
CCARD
ADDRESS
Figure 3: Overall System Logical View (Represented as ER - Diagram)
PAGE 6 OF 48
Revisions Since Proposal
•
•
•
•
•
•
•
Added active (Boolean functionality) and qty_avail (qty of inventory events remaining in
stock as a result of this inventory_event) to inventory_events to help in profit calculation
for order_items that span multiple inventory_events (range of input costs vs. sale price).
Order_items has profit instead of unit_profit, to illustrate profit over multiple
inventory_events for a particular product. Logic was also changed so that an entire
order_item must ship at once (all qty of a particular ordered product within a given
order).
Enhancement of multiple triggers for inventory_events pre and post insert, and
order_items pre-insert.
Procedure to calculate profit-per-order_item
SMTP functionality implemented in Oracle and utilized by stored procedure to send
email notification about dynamic events specifically when an order_item cannot be
fulfilled until a specific qty is re-stocked for administrative use.
Chart making package added to plot data returned by inventory-over-time queries.
Scores of GUI enhancments, such as the full implementation of a shopping cart, store
browser, account management (including shipped vs. unshipped orders) for customers,
and the ability to add inventory_events (stock the store), and get statistics (run queries)
within the employee application.
Architecture and Tools
Tools Used
•
•
•
•
•
•
•
Oracle 10g
NetBeans 5.5.1 IDE
Java 1.5 JDK/JRE development platform and runtime environment
JDBC Oracle classes12.zip drivers for database connectivity
CVS Source Control, via sourceforge.wpi.edu
Putty SSH and Cygwin X-Server for connectivity to sqlplus
Scientific Graphics Toolkit (SGT) graphing package developed by the US NOAA
available here: http://www.epic.noaa.gov/java/sgt/
Database
•
We chose Oracle 10g Enterprise Edition Release 10.2.0.3.0 - 64bit Production running on
Linux with 2.6.9-55.0.9.ELsmp kernel.
Why we chose Oracle and not MySQL post proposal
•
•
•
•
Oracle is an enterprise level DB server platform that we can expect to get potentially
better performance from.
Oracle is already being administered by WPI, this permits for us to not have to perform
maintenance but also limits our control.
It's not free for commercial use, but for the purposes of this course a free license can be
obtained if we wished to install it locally as a single user (not at WPI).
Oracle is more robust for at least these reasons:
PAGE 7 OF 48
1. Can enforce CHECK integrity constraints within a table to be applied during INSERT
o http://techonthenet.com/oracle/check.php
2. MySQL does not have a CHECK constraint at the table level, to model integrity
constraints one has to create an updateable view and use "WITH CHECK CONTRAINT"
which is not the same, and is less reliable to accomplish the goal. This would also
require mimicking CHECK constraints with triggers and stored procedures.
o Emulating check: http://db4free.blogspot.com/2006/01/emulating-checkconstraints-with-views.html
o WITH CHECK OPTION part of CREATE VIEW http://dev.mysql.com/doc/refman/5.1/en/create-view.html
o Why not to use: http://forums.mysql.com/read.php?61,17513,20375#msg-20375
o http://forums.mysql.com/read.php?61,17513,18905#msg-18905
3. Additional differences between Oracle and standard SQL:
http://infolab.stanford.edu/~ullman/fcdb/oracle/or-nonstandard.html#transactions
•
•
•
Challenge: There was initially a difficulty in connecting to Oracle at WPI for what was
later found to be a lack of appropriate connection string. This was the single hurdle
keeping us from using Oracle.
Oracle @WPI can be accessed off campus without a VPN.
SMTP package was easy to get privileges to use for sending emails within procedures.
Front-end
Due to time constraints, ease of use for prototyping GUIs, and some limited experience in GUI
design, we chose to use Java as a programming language and deployment platform. We are
using Java Swing for GUI interface elements, and like the write once run many nature of Java
byte code for portable reuse on any platform. Java Swing also has many predefined interface
widgets that ease the GUI prototyping.
We chose the free NetBeans
(http://www.netbeans.org) as our IDE.
NetBeans makes GUI design with Java
Swing extremely quick as depicted in Figure
4. NetBeans also has built-in support for
working with a CVS source code repository
server. A set of sourceforge.wpi.edu
accounts and a CVS repository for the project
eStore were set up and configured for use
with NetBeans to checkout and commit code.
Originally we had planned on using Eclipse
IDE with IBM Rational ClearCase version
control, but the Visual Editor plug-in is not
Figure 4: NetBeans JSwing widgets palette
compatible with the most recent version of
Eclipse. Even if using a beta version of the Visual Editor plug-in, working with the Visual
Editor proved to be cumbersome compared to NetBeans. NetBeans proved to be very easy to
learn and use, and we had a basic working Java Swing application written in minutes. The
PAGE 8 OF 48
NetBeans design mode also set up action event listeners and associated methods by dragging and
dropping the widgets allowing us to focus on DB access and application logic. The combination
of ease of use for visual GUI design and integrated CVS support were the deciding factors vs.
Eclipse.
eStore is compiled to run on Java JRE's 1.5 and higher for the front-end with DB connectivity,
though initially we had considered a web-browser based JSP/Servlet front-end. Time constraints
and lack of experience with JSP and Servlets led us to use a Java Application for the prototype
model. We're hoping to spend increasing time on the DB as the GUI design for the shopping cart
and inventory stocking is implemented. Time permitting there may be some GUI surprises
Additional Java, Swing, SQL references used:
Java Swing:
• http://java.sun.com/docs/books/tutorial/ui/features/components.html
• Regarding beta Visual Editor for the latest Eclipse: http://wiki.eclipse.org/VE/Installing
• http://download.eclipse.org/tools/ve/downloads/drops/R-1.2.3_jem200701301117/index.html
• http://www.eclipse.org/vep/WebContent/faq.html
• Graphing package—Scientific Graphics Toolkit (SGT) developed by and available from:
http://www.epic.noaa.gov/java/sgt/
SQL:
• For altering table: http://www.adp-gmbh.ch/ora/sql/alter_table.html
• For integrity constraints: http://www.adp-gmbh.ch/ora/misc/integrity_constraints.html
• For Oracle/PLSQL Topics: http://www.techonthenet.com/oracle/index.php
• http://www.psoug.org/library.html
• Attempt at dynamic cursors never implemented: http://www.oraclebase.com/articles/8i/NativeDynamicSQL.php
• For insert: http://www.psoug.org/reference/insert.html
• For cursors: http://infolab.stanford.edu/~ullman/fcdb/oracle/or-plsql.html#cursors
• BLOB storage and access: http://www.go4expert.com/forums/showthread.php?t=866
• Oracle 8i The Complete Reference, Loney and Koch, Osborne McGraw Hill publishers.
SMTP within Oracle:
• For SMTP email access within Oracle: access granted to the UTL_SMTP package with
the assistance of the WPI Oracle administrator: Mark Taylor
• Sample code used to enable email sending within procedures from:
http://www.databasejournal.com/features/oracle/article.php/3423431
• How to guide with overview: http://www.quest-pipelines.com/newsletter-v2/smtp.htm
JDBC
To connect the Java front-end application to Oracle we have chosen JDBC drivers supplied by
Oracle.
• Oracle - ojdbc14.jar
o http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/index.html
PAGE 9 OF 48
If using MySQL we had planned:
• MySQL – Connector/J
o http://dev.mysql.com/downloads/connector/j/5.1.html
Resources on How To Connect using JDBC:
Sun JDBC tutorials:
• http://java.sun.com/docs/books/tutorial/jdbc/basics/index.html
• http://java.sun.com/developer/onlineTraining/Database/JDBCShortCourse/index.html
• http://www.stardeveloper.com/articles/display.html?article=2003090401&page=1
• http://www.cs.unc.edu/Courses/comp118/docs/lessons/java/java_jdbc/
• http://web.njit.edu/all_topics/Servers/MySQL/Docs/mySample.java.html
• http://dev.mysql.com/doc/refman/5.1/en/connector-j-examples.html
• Our cs542 textbook provides some examples in Chapter 6
• Our cs542 course website has some resources:
o http://web.cs.wpi.edu/~cs542/f07/links.html
Guidance on reading and writing a BLOB using JDBC:
• http://www.go4expert.com/forums/showthread.php?t=866
• http://www.oracle.com/technology/sample_code/tech/java/codesnippet/jdbc/clob10g/han
dlingclobsinoraclejdbc10g.html#how1
• http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:23281415900
6#6891533553691
•
Implementation Details
ER Diagrams to SQL Tables
We have converted almost all of our ER Diagrams to SQL Tables, and added Sequences and
Triggers to aid in tracking unique IDs for many of the tables. Below is a listing of the tables,
some with comments to describe design decisions.
• Sequences in Oracle permit us to have auto-generated id numbers that are enforced by
triggers upon initial insert.
CREATE TABLE CUSTOMERS (
id INT PRIMARY KEY,
fname VARCHAR(100) NOT NULL,
lname VARCHAR(100) NOT NULL,
phone VARCHAR(20) NOT NULL,
email VARCHAR(100) NOT NULL,
passwd VARCHAR(100) NOT NULL,
CONSTRAINT unique_cust_email UNIQUE (email),
CONSTRAINT ck_cust_password CHECK (LENGTH(passwd) > 6));
•
•
Email is unique as it will be used as the logon identity for customers.
Passwords must be greater than 6 characters.
CREATE SEQUENCE customers_id_seq
MINVALUE 1
PAGE 10 OF 48
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER customers_trg
BEFORE INSERT ON CUSTOMERS
FOR EACH ROW
BEGIN
SELECT customers_id_seq.nextval INTO :new.id FROM dual;
END;
/
The Sequence/Trigger combination shown here is located throughout the table schemas, one for
each table that contains an ID field. MySQL has the concept of an “auto-update” field, which is
automatically set whenever a new item is inserted into the table. The value automatically
increases, so each insert is one higher than the previous. Oracle does not contain an auto-update
type, but by using a sequence and a pre-operation insert trigger we can simulate the type quite
nicely.
CREATE TABLE ADDRESSES (
id INT PRIMARY KEY,
street_num INT NOT NULL,
street_name VARCHAR(100) NOT NULL,
street_name_2 VARCHAR(100),
city VARCHAR(100) NOT NULL,
state_abbr CHAR(2),
zip VARCHAR(10),
country VARCHAR(100) NOT NULL);
•
Design note: Both state_abbr and zip are not set to NOT NULL because an address that
does not reside in the US may not have a state and zip code.
CREATE SEQUENCE addresses_id_seq
MINVALUE 1
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER addresses_trg
BEFORE INSERT ON ADDRESSES
FOR EACH ROW
BEGIN
SELECT addresses_id_seq.nextval INTO :new.id FROM dual;
END;
/
CREATE TABLE BILLING_INFOS (
id INT PRIMARY KEY,
addr_id INT,
ccard_type VARCHAR(30) NOT NULL,
ccard_num CHAR(16) NOT NULL,
ccard_exp CHAR(4) NOT NULL,
CONSTRAINT unique_bi_addr UNIQUE (addr_id),
CONSTRAINT fk_bi_addr FOREIGN KEY (addr_id) REFERENCES ADDRESSES(id) ON
DELETE CASCADE);
PAGE 11 OF 48
•
Constraint: The billing_infos address must be unique, as an address can contain at most
one billing information associated with it.
CREATE SEQUENCE billing_infos_id_seq
MINVALUE 1
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER billing_infos_trg
BEFORE INSERT ON BILLING_INFOS
FOR EACH ROW
BEGIN
SELECT billing_infos_id_seq.nextval INTO :new.id FROM dual;
END;
/
CREATE TABLE CUSTOMER_ADDRESSES (
cust_id INT,
addr_id INT,
CONSTRAINT CA_PK PRIMARY KEY (cust_id, addr_id),
CONSTRAINT fk_ca_cust FOREIGN KEY (cust_id) REFERENCES CUSTOMERS(id) ON
DELETE CASCADE,
CONSTRAINT fk_ca_addr FOREIGN KEY (addr_id) REFERENCES ADDRESSES(id) ON
DELETE CASCADE);
•
A customer can store many addresses in their account (customer address and shipping
addresses), hence the reason the primary key is a combination of customer ID and
address ID.
CREATE TABLE CUSTOMER_BILLING_INFOS (
cust_id INT,
billing_id INT,
CONSTRAINT cbi_pk PRIMARY KEY (cust_id, billing_id),
CONSTRAINT fk_cbi_cust FOREIGN KEY (cust_id) REFERENCES CUSTOMERS(id) ON
DELETE CASCADE,
CONSTRAINT fk_cbi_billing FOREIGN KEY (billing_id) REFERENCES
BILLING_INFOS(id) ON DELETE CASCADE);
•
Likewise, a customer can store many billing_infos in their account; again, hence the
reason the primary key is a combination of customer ID and billing ID.
CREATE TABLE ORDERS (
id INT PRIMARY KEY,
cust_id INT NOT NULL,
addr_id INT NOT NULL,
billing_id INT NOT NULL,
status VARCHAR(30) NOT NULL,
date_placed DATE NOT NULL,
qty_items INT NOT NULL,
calc_total_cost INT NOT NULL,
shipping_cost INT NOT NULL,
CONSTRAINT fk_ord_cust FOREIGN KEY (cust_id) REFERENCES CUSTOMERS(id) ON
DELETE SET NULL,
PAGE 12 OF 48
CONSTRAINT fk_ord_addr FOREIGN KEY (addr_id) REFERENCES ADDRESSES(id) ON
DELETE SET NULL,
CONSTRAINT fk_ord_billing FOREIGN KEY (billing_id) REFERENCES
BILLING_INFOS(id) ON DELETE SET NULL,
CONSTRAINT ck_status CHECK (status IN ('In Progress', 'Complete')));
•
•
•
•
•
The cust_id is the customer who placed the order. The addr_id is the shipping address.
The billing_id is the billing address (and its associated credit card information) for the
order.
The constraint ck_status having only two allowed values acts as a boolean operation,
either the status is "In Progress" or "Complete".
The ck_status constraint and associated column were removed from the DB and replaced
with date_completed. Now an order ‘In Progress’ is a date_completed of value Null, and
a ‘Complete’ order is a date_completed with a non-null value.
Modifying the schema in place sometimes presented a challenge.
Schema change since Project Progress Report:
CREATE TABLE ORDERS (
id INT PRIMARY KEY,
cust_id INT NOT NULL,
addr_id INT NOT NULL,
billing_id INT NOT NULL,
status VARCHAR(30) NOT NULL,
date_placed DATE NOT NULL,
qty_items INT NOT NULL,
calc_total_cost INT NOT NULL,
shipping_cost INT NOT NULL,
date_completed DATE,
CREATE SEQUENCE orders_id_seq
MINVALUE 1
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER orders_trg
BEFORE INSERT ON ORDERS
FOR EACH ROW
BEGIN
SELECT orders_id_seq.nextval INTO :new.id FROM dual;
END;
/
CREATE TABLE EMPLOYEES (
id INT PRIMARY KEY,
fname VARCHAR(100) NOT NULL,
lname VARCHAR(100) NOT NULL,
addr_id INT NOT NULL,
phone VARCHAR(20) NOT NULL,
email VARCHAR(100) NOT NULL,
username VARCHAR(100) NOT NULL,
passwd VARCHAR(100) NOT NULL,
emp_role VARCHAR(10) NOT NULL,
CONSTRAINT fk_emp_addr FOREIGN KEY (addr_id) REFERENCES ADDRESSES (id) ON
DELETE CASCADE,
CONSTRAINT unique_emp_email UNIQUE (email),
PAGE 13 OF 48
CONSTRAINT ck_emp_password CHECK (LENGTH(passwd) > 6),
CONSTRAINT ck_role CHECK (emp_role IN ('EMP', 'ADMIN')));
CREATE SEQUENCE employees_id_seq
MINVALUE 1
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER employees_trg
BEFORE INSERT ON EMPLOYEES
FOR EACH ROW
BEGIN
SELECT employees_id_seq.nextval INTO :new.id FROM dual;
END;
/
CREATE TABLE DEPARTMENTS (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
manager_id INT NOT NULL,
dept_desc VARCHAR(300) NOT NULL,
CONSTRAINT fk_manager FOREIGN KEY (manager_id) REFERENCES EMPLOYEES (id)
ON DELETE SET NULL);
CREATE SEQUENCE departments_id_seq
MINVALUE 1
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER departments_trg
BEFORE INSERT ON DEPARTMENTS
FOR EACH ROW
BEGIN
SELECT departments_id_seq.nextval INTO :new.id FROM dual;
END;
/
CREATE TABLE PICTURES (
id INT PRIMARY KEY,
pic_blob BLOB NOT NULL);
CREATE SEQUENCE pic_id_seq
MINVALUE 1
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER pictures_trg
BEFORE INSERT ON PICTURES
FOR EACH ROW
BEGIN
SELECT pic_id_seq.nextval INTO :new.id FROM dual;
END;
/
•
The use of BLOB data (binary large objects) to store pictures is an area for future
enhancement, but left in place to make the architecture extensible.
PAGE 14 OF 48
CREATE TABLE PRODUCTS (
id INT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
description VARCHAR(100) NOT NULL,
dept_id INT NOT NULL,
weight INT NOT NULL,
qty_in_stock INT NOT NULL,
current_price INT NOT NULL,
current_profit INT NOT NULL,
markup_percent INT NOT NULL,
shipping_cost INT NOT NULL,
pic_id INT NOT NULL,
CONSTRAINT fk_dept FOREIGN KEY (dept_id) REFERENCES DEPARTMENTS(id) ON
DELETE CASCADE ,
CONSTRAINT fk_pic FOREIGN KEY (pic_id) REFERENCES PICTURES(id) ON DELETE
SET NULL ,
CONSTRAINT unique_pict_id unique (picture_id) ,
CONSTRAINT unique_prod_name unique (name) );
Note: the current_price attribute is an integer, not a float. All instances of money are stored in
cents, not in dollars. There are two main reasons for this. First, integer math is significantly less
expensive to perform than floating point operations (server side). With all of the algorithms we
plan on running on all things money, speed may become an issue (especially if the sample space
were to grow). Second, floating point is an imprecise value, and although we would only care
about the first two decimal to three decimal places for precision, the database would store many
more than that. This has the potential of introducing round-off errors if things lined up just right
(or just wrong, depending on your point of view). So we decided to avoid the hassle of floating
point and stuck with integers for monetary values.
Originally we had the picture of the product within the PRODUCTS table as a Binary Large
Object (BLOB). Unfortunately a “select *” query would be unable to complete, as the
requesting entity would have to be able to handle the BLOB (SQLPlus would fail on the query,
for instance). So we moved the picture out to its own table and reference it with a foreign key.
We may not implement this, depending on time, but have kept the option there with the pictid
attribute and pic_id_seq sequence.
CREATE SEQUENCE prod_id_seq
MINVALUE 1
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER products_trg
BEFORE INSERT ON PRODUCTS
FOR EACH ROW
BEGIN
SELECT prod_id_seq.nextval INTO :new.id FROM dual;
SELECT prod_pictid_seq.nextval INTO :new.pictid FROM dual;
END;
/
CREATE TABLE ORDER_ITEMS (
id INT PRIMARY KEY,
PAGE 15 OF 48
order_id INT NOT NULL,
prod_id INT NOT NULL,
quantity INT NOT NULL,
unit_price INT NOT NULL,
shipping_cost INT NOT NULL,
date_shipped DATE NOT NULL,
notified SMALLINT NOT NULL,
CONSTRAINT fk_order FOREIGN KEY (order_id) REFERENCES ORDERS(id) ON
DELETE SET NULL,
CONSTRAINT fk_oi_prod FOREIGN KEY (prod_id) REFERENCES PRODUCTS(id) ON
DELETE SET NULL,
CONSTRAINT ck_oi_quantity CHECK (quantity > 0),
CONSTRAINT ck_notified CHECK (notified BETWEEN 0 AND 1));
•
•
•
The notified attribute is a SMALLINT to save space. We also verified the check
constraint on a test table, and the constraint “Between 0 and 1” means the value may be
set to 0 and 1 but nothing else.
Notified was intended to indicate that email notification was sent to a customer that this
part of the order had shipped, though it will remain an area for future work.
Here is the test for "boolean like functionality" we tested:
SQL> create table booltest
2 (
3 notified smallint,
4 constraint ck_bool check (notified between 0 and 1));
Table created.
SQL> insert into booltest (notified) values (1);
1 row created.
SQL> insert into booltest (notified) values (2);
insert into booltest (notified) values (2)
*
ERROR at line 1:
ORA-02290: check constraint (DSAMPSON.CK_BOOL) violated
SQL> insert into booltest (notified) values (0);
1 row created.
SQL> insert into booltest (notified) values (-1);
insert into booltest (notified) values (-1)
*
ERROR at line 1:
ORA-02290: check constraint (DSAMPSON.CK_BOOL) violated
CREATE SEQUENCE order_items_id_seq
MINVALUE 1
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER order_items_trg
BEFORE INSERT ON ORDER_ITEMS
FOR EACH ROW
BEGIN
SELECT order_items_id_seq.nextval INTO :new.id FROM dual;
END;
/
PAGE 16 OF 48
CREATE TABLE INVENTORY_EVENTS (
id INT PRIMARY KEY,
prod_id INT NOT NULL,
date_recv DATE NOT NULL,
product_cost INT NOT NULL,
shipping_cost INT NOT NULL,
quantity INT NOT NULL,
active INT NOT NULL,
qty_avail INT NOT NULL,
CONSTRAINT fk_ie_prod FOREIGN KEY (prod_id) REFERENCES PRODUCTS(id) ON
DELETE SET NULL,
CONSTRAINT ck_active_boolean CHECK (active = 1 OR active =0),
CONSTRAINT ck_ie_quantity CHECK (quantity > 0));
•
•
All inventory_events represent an addition of warehouse stock. Thus, an inventory event
can never have a quantity of 0 or less.
Added active and qty_avail to assist in profit calculation where an order_item spanned
multiple inventory_events. Thus, we could keep track of when an inventory_event was
no long represented by product.qty_in_stock, and how much qty_avail could be used in
profit calculations. Quantity represents the actual amount of inventory provided by this
inventory_event, and qty_avail is what remains over time until none of this
inventory_event’s quantity remains.
CREATE SEQUENCE inventory_event_id_seq
MINVALUE 1
START WITH 1
INCREMENT BY 1;
CREATE OR REPLACE TRIGGER inventory_event_trg
BEFORE INSERT ON INVENTORY_EVENTS
FOR EACH ROW
BEGIN
SELECT inventory_event_id_seq.nextval INTO :new.id FROM dual;
END;
/
Triggers and stored procedures in PL/SQL are in the application demo section with discussion.
Stored Procedures, Triggers and/or Algorithms (Pseudocode)
•
•
Implemented in PL/SQL procedures and/or Java client side application.
Additional procedures not listed here for example: calculate product.current_price based
on recently added inventory_events that were purchased wholesale at a particular price,
as well as calculating current_profit based on markup and wholesale price.
Prototype Procedure for Order Fulfillment:
•
•
•
To be run once per day or manually by employees
Can be run for a single ORDER or on all incomplete (IN_PROGRESS) ORDERS
Can be run for a particular PRODUCT or on all PRODUCTS
PAGE 17 OF 48
1. Check through order_item list to see if unsatisfied (date_shipped == NULL) orders can
be fulfilled.
2. If order_item can be fulfilled (i.e. there is sufficient PRODUCT.qty for the item)
a. Send email to employee and to customer
b. Set date_shipped
c. Decrement PRODUCT.qty
Prototype Procedure for Customer Order Process:
1.
2.
3.
4.
5.
6.
Customer browses departments and locates products
When product found, ADD product to cart with desired QTY
Go to step 1 as needed (while loop)
SUBMIT order, notify user that order summary offered before commitment
Select shipping address from existing, OR create new
Select existing billing address (includes exactly 1 registered CCARD, offer to modify
CCARD), or create new billing address (create new registered CCARD)
7. Display order summary
8. COMMIT or CANCEL
9. if CANCEL then go to step 1
10. if COMMIT
a. BILL (returns ACCEPT or REJECT)
b. if REJECT
i. alert user and bring to step 6 again to re-select billing address/CCARD
(option to modify)
c. if ACCEPT
i. Send email to confirm BILL and order summary with ship expectations
ii. Set ORDER.status=IN_PROGRESS
iii. Create exactly 1 ORDER_ITEM per PRODUCT in shopping cart@qty for
this order_num
iv. Clear shopping cart
v. Trigger fulfillment procedure on this order_num
vi. Goto step 1
Prototype Procedure for Customer Order History:
1. Display all orders currently IN_PROGRESS
2. Display all COMPLETE orders
Prototype Procedure for Inventory Event:
1. Employee enters an INVENTORY_EVENT into the system
2. Activate Inventory Update Trigger
a. Update PRODUCT.qty
b. Calculate price/unit
c. Update PRODUCT.cur_profit
d. Run Order Fulfillment procedure for PRODUCT
Application Details
•
Separate user interfaces for Employees and Customers.
PAGE 18 OF 48
Original Prototype Employee Application
•
•
DB Administrator can:
o Create Employees and assign role.
o Create Departments
ƒ Set name, description, and manager, etc.
o Create Products
ƒ Set name, description, price, etc.
ƒ CANNOT set quantity or current profit (derived by Inventory_Events)
o Assign Product to a Departments.
To do:
o Initiate an Inventory Event when product is received.
ƒ (See Inventory Event Procedure)
o Run reports/queries/intiate daily tasks (stored procedures)
o Refine/add functionality.
Original Prototype Employee Application Screen Shots (deprecated)
DBA must login to gain access to Oracle DB from Employees application.
Upon logging in DBA can choose to see existing employees and update their records. Employee
List is populated with a minial column query. Whereas, upon clicking an employee in the
Employee List, their data is populated into the fields for easy editing and DB updates.
PAGE 19 OF 48
Here we see Employees ID: 3, fname: V, last name: R, and ID: 2, fname: D, lname: S. Clicking
an employee will populate the update fields in real time. This is to minimize DB reads (don't
collect information about all employees, unless a specific employee record is needed at a
particular time for update).
To add a new employee, click "New
Employee":
Fill in fields, as well as role from drop down.
Fields are validated prior to insert. The new
employee will appear in the Employee List
immediately.
The Departments tab shows each department and deptid in the Department List. Similarly you
can update the name or manager of the department and this will update in Oracle.
PAGE 20 OF 48
Click to add New Department:
Products tab has more to be implemented:
This products list shows product ID, name,
and department.
Click to enter a New Product.
PAGE 21 OF 48
Here we enter weight in ounces, markup > 4% (constraint in schema), cost to ship in cents,
JFileChooser for the image, and the department (which normally shows with a department list).
To assist with schema and SQL query testing this “Raw SQL” tab allows for sql syntax input and
result output in the box. This is very convenient instead of having to switch to sqlplus during
debugging.
Customer Application as of Progress Report time:
At this time, the majority of the customer application including shopping cart, checkout, billing,
etc has not yet been implemented. At this time a customer can only create an account and login:
Current screen shots are listed below are active and function:
PAGE 22 OF 48
Shop, Cart, Account Management are minimally implemented at this time:
From prototype drawing then later to implementation:
•
As of project progress report customers could only:
o Create an account
o Login
PAGE 23 OF 48
The Customer eStore Application Today (with trigger/procedure discussion)
Login:
Includes password recovery, and account
creation.
Upon successful login customer is now
presented with 3 modes of operation
(below):
1) Shop for Products
2) View Cart (shopping cart with items
added)
3) Account Management (to view
shipping/billing addresses, credit cards
used, order status
1) Shop for Products:
A tree view of all products, and then more details about the selected product along with the
ability to add it to the cart: Select items, select quantity, add to cart, repeat:
A second view mode for finding products and adding to cart, Most Popular Items:
Click Most Popular Items from the shop mode to see most popular items by
common time frames.
PAGE 24 OF 48
Again, pick a quantity, and add these popular items to your shopping cart.
2) View Cart mode
Now let’s view our cart: We can make choices about what items we want to
keep out of the selection made, return to Shop for more Products, or Proceed to Checkout.
3) Checkout (3 steps)
3.1) Select Shipping Address or Cancel Checkout
Choose an existing address or make a new one, then proceed to billing or cancel:
PAGE 25 OF 48
Æ
or
or
. Then, click proceed to billing:
3.2) Select Billing Address or Cancel Checkout
Choose an existing billing address with associated credit card or make a address/associated credit
card, then proceed to checkout summary:
Æ
, or
or
. Then, click Proceed to Order Confirmation:
.
3.3) Confirm Order and Submit
Review the final checkout summary including shipping information, billing information, items
ordered, and shipping costs.
When ready submit order
or cancel
(see below):
PAGE 26 OF 48
Once the order has been submitted the customer application can view your order status.
4) Account Management
has the following option tabs:
4.1) User Info: Change customer information (first name, last name, phone#, password).
4.2) Shipping Addresses: add new addresses, or view existing.
4.3) Billing Info: view existing billing addresses and associated credit cards or add new.
4.4) Past Orders: Check on A) Orders In Progress and B) Completed Orders
PAGE 27 OF 48
Orders in Progress will always show as Completed: In Progress. To get more details and check
on the status of order_items (individual products) that make up this order, and whether or not
they have shipped click View,
.
We can see the Items Ordered:
The Shipping & Handling is calculated by sum of: (shipping_cost of each product)*(qty ordered)
eStore Order Fulfillment Theory
eStore does not allow customers to see whether or not a product is in stock at the time of order.
Our goal is to fulfill orders as quickly and fairly as possible, but ensure:
1) All quantity of an order_item (1 product) must ship together at once.
2) If an order_item is not in stock, only when an inventory event that increments the
product.qty_in_stock to at minimum the order_item.quantity will attempt to ship the item.
Caveats:
3) If a large order_item comes in, we will not hold up smaller order_items (from other orders).
4) It is the responsibility of the eStore admin to provide enough inventory to ship all order_items.
Email notification and a query is used to facilitate this. Re-notification will take place if still not
enough inventory is available to ship order_items.
Example Order @ Submit Order Time
Two items were added to our cart: “Guitar Hero” and “Legend of Zelda”, (products #6 and #7)
respectively, then we submitted the order. Here’s what was in stock at the time of order
submission:
PAGE 28 OF 48
SQL> select id, qty_in_stock from products where id=6 OR id=7;
ID QTY_IN_STOCK
---------- -----------6
0
7
3
We currently have qty_in_stock 3 of Guitar Hero and qty_in_stock 0 of Legend of Zelda.
Because inventory was available to ship the entire order_item for Guitar Hero, but no inventory
to ship Legend of Zelda the following should occur:
1) Guitar Hero (product#7) has 3 in stock, and should ship immediately
2) Legend of Zelda (product#6) will have to wait for an inventory_event so that it can ship. The
customer is guaranteed the product.current_price at order time. In theory we could loose profit
on this but we anticipate most inventory costs will stay fairly stable.
From the detailed Orders In Progress (Account Management) view, we see that as expected
, and Legend of Zelda
Guitar Hero shipped with a ship date of 2007-12-13
(which is out of stock) has not shipped
.
What Happens In Oracle When Order Is Submitted
The GUI app does an insert on order. The trigger: orders_trg (before insert) sets the
order.date_placed, and sets the order.date_completed to null, as well as assigns the order.id from
the sequence: orders_id_seq with a unique value as primary key.
Then each order_item that makes up this order is submitted with the new order id, recall it’s one
order_item per product with multiple quantity. Here’s what happens:
Constraint: ck_oi_quantity ensures that there are more than 0 being ordered, constraint:
ck_notified ensures notified is 0 or 1 (but this is for future extension to send email to customers
to notify them of ship status), and sequence: order_items_id_seq generates an order_item.id.
Before insert on order_items trigger: ship_order_items_inv_evt tries to ship the order_item.
CREATE OR REPLACE TRIGGER SHIP_ORDER_ITEMS_INV_EVT
BEFORE INSERT ON ORDER_ITEMS
FOR EACH ROW
DECLARE
qtyInStock NUMBER(38);
profit INT;
p_name VARCHAR2(100);
BEGIN
/* Get the product quantity available in the database */
SELECT p.QTY_IN_STOCK, p.name INTO qtyInStock, p_name
FROM PRODUCTS p
WHERE p.id=:new.prod_id;
/*If we have enough in stock to ship this order_item ship it!*/
IF (qtyInStock>=:new.quantity) THEN
/*call procedure to calculate profit*/
CALC_ORDER_ITEM_PROFIT(:new.id, :new.prod_id, :new.quantity,
:new.unit_price, :new.shipping_cost, profit);
:new.profit:=profit;
/* Flag order_item as shipped */
SELECT sysdate INTO :new.date_shipped FROM dual;
/* Update the new product.qty_in_stock */
PAGE 29 OF 48
UPDATE PRODUCTS p
SET p.qty_in_stock = p.qty_in_stock - :new.quantity
WHERE p.id=:new.prod_id;
ELSE /*not enough in stock to ship this item, send notification to admin*/
send_oi_stock_qty_notify (:new.id, :new.quantity, qtyInStock,
p_name);
END IF;
RETURN;
END;
/
Essentially: if we have enough in stock for this product, ship the order_item right away, calculate
the profit for this order_item that we made using calc_order_item_profit() procedure, flag the
order_item as shipped by setting the order_item.date_shipped with the current date/time, update
the product.qty_in_stock (decrement by qty shipped).
Thus Guitar Hero shipped (qty_in_stock has decreased by 1) see here:
SQL> select id, qty_in_stock from products where id=6 OR id=7;
ID QTY_IN_STOCK
---------- -----------6
0
7
2
In the case of Zelda which was not in stock, an email was received by the admin in their email
server’s mailbox per send_oi_stock_qty_notify():
Date: Thu, 13 Dec 2007 00:35:26 -0500
From: [email protected]
Message-Id: <[email protected]>
Subject: Product requires more inventory qty to ship!
From:
[email protected]
Date:
12/13/2007 00:35:26
To:
[email protected]
CC:
[email protected]
Order Item# 84 requires the following quantity in stock to ship the
order_item: 1
However, only 0 of product are in stock at this time. Please add inventory
for the product: "Legend of Zelda: Twilight Princess."
Product "Legend of Zelda: Twilight Princess" requires 1 more inventory qty to
ship!
**ATTN: service machine, please do not reply.**
This informs the admin of the store which order_item is being held up by how much quantity of
a product that is not in stock. The action the admin must take is to add an inventory event which
we’ll see later.
For the Guitar Hero which did ship let’s see how the profit was calculated:
CREATE OR REPLACE PROCEDURE CALC_ORDER_ITEM_PROFIT (
OI_ID IN NUMBER, OI_PID IN NUMBER, OI_QTY_REQD IN NUMBER, OI_UPRICE IN
NUMBER, OI_SHPPRC IN NUMBER, OI_PROFIT IN OUT NUMBER)
IS
/* IN OUT parameters allow for a value to be passed in and a value to be
modified by reference upon completion */
ie_id NUMBER;
ie_price NUMBER;
ie_shpcost NUMBER;
ie_qty NUMBER;
PAGE 30 OF 48
QTY_REQD INT;
/* this cursor shows us inventory_events which still represent active
qty_in_stock ordered by date_recv for the product of this order_item */
CURSOR active_inv_evts IS
SELECT id, product_cost, shipping_cost, qty_avail
FROM inventory_events
WHERE active=1 AND prod_id=OI_PID
ORDER BY date_recv ASC;
BEGIN
QTY_REQD := oi_qty_reqd;
oi_profit :=0;
OPEN active_inv_evts;
LOOP
FETCH active_inv_evts INTO ie_id, ie_price, ie_shpcost, ie_qty;
/* If there are no more rows to fetch, exit the loop: */
EXIT WHEN active_inv_evts%NOTFOUND;
IF (QTY_REQD > 0)
THEN
/*if order_item can be fulfilled by the first inventory_event entirely*/
IF (QTY_REQD <=ie_qty)
THEN
/*what we made on the item less the costs to stock the item and ship it*/
oi_profit:=oi_profit+((OI_UPRICE+OI_SHPPRC-ie_priceie_shpcost)*QTY_REQD);
/*If this inventory_event will be exactly consumed by this order_item*/
IF (QTY_REQD=ie_qty)
THEN
/*set this inventory_event to inactive*/
UPDATE inventory_events set active=0, qty_avail =0 where
id=ie_id;
ELSE
/*we must update what we used of this inventory_event and continue with loop*/
UPDATE inventory_events set qty_avail = qty_avail QTY_REQD where id=ie_id;
END IF;
/*if QTY_REQD<ie_qty (not a full inventory event) don't set to inactive*/
QTY_REQD :=0;
ELSE /*QTY_REQD>this inventory_event_qty*/
oi_profit:=oi_profit+((OI_UPRICE+OI_SHPPRC-ie_priceie_shpcost)*ie_qty);
/*what we made on the item less the costs to stock the item and
ship it for this inventory event*/
QTY_REQD:=QTY_REQD-ie_qty;
UPDATE inventory_events set active=0, qty_avail = 0 where
id=ie_id;
END IF;
END IF; /*we had some qty*/
END LOOP; /*all inventory_events processed for this order_item*/
END;
/
Case 2 (order_item could not ship, send notification):
For the Zelda order_item which did not ship here’s how we sent the email to admin:
CREATE or REPLACE PROCEDURE send_oi_stock_qty_notify (OI_ID IN NUMBER, OI_QTY
IN NUMBER, P_QTY IN NUMBER, P_NAME IN VARCHAR2)
IS
/*REF: code adapted from
http://www.databasejournal.com/features/oracle/article.php/3423431 */
/*October 21, 2004 "Sending e-mail from within Oracle" By James
Koopmann*/
PAGE 31 OF 48
mailHOST
mailFROM
mailTO
mailCC
mailSBJ
mailCONN
mailDATE
vreply
vreplies
i
VARCHAR2(64):= 'smtp.wpi.edu';
VARCHAR2(64):= '[email protected]';
VARCHAR2(64):= '[email protected]';
VARCHAR2(64):= '[email protected]';
VARCHAR2(64):= 'Product requires more inventory qty to ship!';
utl_smtp.connection;
VARCHAR2(20);
utl_smtp.reply;
utl_smtp.replies;
number;
BEGIN
SELECT TO_CHAR(SYSDATE,'MM/DD/YYYY HH24:MI:SS') INTO mailDATE FROM dual;
vreply := utl_smtp.open_connection(mailHOST, 25, mailCONN);
vreplies := utl_smtp.help(mailCONN, 'HELP');
for i in 1..vreplies.count loop
dbms_output.put_line( 'code = ' || vreplies(i).code );
dbms_output.put_line( 'text = ' || vreplies(i).text );
end loop;
vreplies := utl_smtp.ehlo(mailCONN, mailHOST);
for i in 1..vreplies.count loop
dbms_output.put_line( 'code = ' || vreplies(i).code );
dbms_output.put_line( 'text = ' || vreplies(i).text );
end loop;
vreply := utl_smtp.mail(mailCONN, mailFROM);
vreply := utl_smtp.rcpt(mailCONN, mailTO);
vreply := utl_smtp.open_data(mailCONN);
/*construct email message and write to SMTP connection stream*/
utl_smtp.write_data(mailCONN, 'Subject: '||mailSBJ
|| chr(13));
utl_smtp.write_data(mailCONN, 'From:
'||mailFROM
|| chr(13));
utl_smtp.write_data(mailCONN, 'Date:
'||mailDATE
|| chr(13));
utl_smtp.write_data(mailCONN, 'To:
'||mailTO
|| chr(13));
utl_smtp.write_data(mailCONN, 'CC:
'||mailCC
|| chr(13));
--utl_smtp.write_data(mailCONN, 'BCC:
'||mailFROM
|| chr(13));
utl_smtp.write_data(mailCONN,
chr(13));
utl_smtp.write_data(mailCONN, 'Order Item# '||OI_ID||' requires the
following quantity in stock to ship the order_item: '|| OI_QTY || chr(13));
utl_smtp.write_data(mailCONN, 'However, only '||P_QTY||' of product are
in stock at this time. Please add inventory for the product: "'|| P_NAME
||'."'||chr(13));
utl_smtp.write_data(mailCONN,
chr(13));
utl_smtp.write_data(mailCONN, 'Product "'||p_name||'" requires
'||(OI_QTY-P_QTY)||' more inventory qty to ship!' );
utl_smtp.write_data(mailCONN,
chr(13));
utl_smtp.write_data(mailCONN, '**ATTN: service machine, please do not
reply.**'
|| chr(13));
vreply := utl_smtp.close_data(mailCONN);
vreply := utl_smtp.quit(mailCONN);
END;
/
This required package permission was granted by WPI’s Oracle admin as indicated earlier and
access to the WPI SMTP server, many thanks.
Next, the GUI app executes the procedure: check_order_complete(order.id). This takes in the
order.id and will set it’s order.date_completed to today only if the nested query (return the count
of all order_items for this order whose date_shipped is NULL (unshipped)) is 0.
CREATE OR REPLACE PROCEDURE CHECK_ORDER_COMPLETE (
ORD_ID IN NUMBER)
PAGE 32 OF 48
AS
oi_count INT := 0;
BEGIN
UPDATE ORDERS
SET date_completed=sysdate
WHERE id=ord_id AND 0=(
SELECT COUNT(order_id)
FROM ORDER_ITEMS
WHERE order_id=ord_id AND date_shipped IS NULL);
RETURN;
END;
/
As an admin, we’ll add an inventory_event to stock the Zelda product:
Note that the new inventory_event has been added, but the stock level remains at 0:
This is because the 1 item in stock allowed the one order_item to ship:
SQL> select * from order_items where order_id=61;
ID
ORDER_ID
PROD_ID
QUANTITY UNIT_PRICE SHIPPING_COST DATE_SHIP
---------- ---------- ---------- ---------- ---------- ------------- --------NOTIFIED
PROFIT
---------- ---------83
61
7
1
4290
500 13-DEC-07
0
390
84
0
61
378
6
1
4158
500 13-DEC-07
What happened behind the scenes? Before insert on inventory_events trigger:
inventory_event_trg fires:
CREATE OR REPLACE TRIGGER INVENTORY_EVENT_TRG
PAGE 33 OF 48
BEFORE INSERT ON INVENTORY_EVENTS
FOR EACH ROW
DECLARE
old_qtyInStock NUMBER(38);
old_price NUMBER(38);
old_shipcost NUMBER(38);
percent NUMBER(38);
new_qtyInStock NUMBER(38);
new_price NUMBER(38);
new_shipcost NUMBER(38);
new_profit NUMBER(38);
old_profit NUMBER(38);
BEGIN
SELECT inventory_event_id_seq.nextval INTO :new.id FROM dual;
/*date of inventory event is now*/
SELECT sysdate INTO :new.date_recv FROM dual;
/*get prior information about this product so we can update to reflect new*/
SELECT qty_in_stock, current_price, shipping_cost, markup_percent,
current_profit INTO old_qtyInStock, old_price, old_shipcost, percent,
old_profit
FROM PRODUCTS
where id = :new.prod_id;
new_qtyInStock := (old_qtyInStock+:new.quantity);
/*new price takes into account existing price for remaining quantity and price
of new quantity being added as well as the markup percent for this product*/
new_price :=
((old_qtyInStock*old_price)+(:new.quantity*(:new.product_cost*(percent+100)/10
0)))/new_qtyInStock;
/*new shipping cost takes into account existing shipping cost for remaining
qty and new quantity at new rate*/
new_shipcost := (((old_qtyInStock*old_shipcost) +
(:new.quantity*:new.shipping_cost))/(new_qtyInStock));
/*estimate of profit for this product incorporating new and old*/
new_profit:=old_profit+(:new.quantity*(new_price-old_price));
UPDATE products
SET current_price= new_price, shipping_cost = new_shipcost,
qty_in_stock= new_qtyInStock, current_profit=new_profit
WHERE id=:new.prod_id;
END;
/
Now the trigger: invevt_scan_orders_trg fires (after insert) on inventory_events:
CREATE OR REPLACE TRIGGER INVEVT_SCAN_ORDERS_TRG
AFTER INSERT ON INVENTORY_EVENTS
FOR EACH ROW
DECLARE
qtyInStock NUMBER(38);
oi_id NUMBER(38);
oi_qty NUMBER(38);
p_name VARCHAR2(100);
/* cursor gets order_items that process the same product and have not been
shipped ordered by the order date */
CURSOR unshipped_oi IS
SELECT oi.id, oi.quantity
FROM ORDERS o, ORDER_ITEMS oi
WHERE oi.prod_id=:new.prod_id AND oi.date_shipped IS NULL AND
oi.order_id=o.ID
ORDER BY o.date_placed ASC;
BEGIN
/* get qty_in_stock for the product*/
SELECT p.QTY_IN_STOCK, p.name INTO qtyInStock, p_name
PAGE 34 OF 48
FROM PRODUCTS p
WHERE p.id=:new.prod_id;
OPEN unshipped_oi;
LOOP
FETCH unshipped_oi INTO oi_id, oi_qty;
/* If there are no more rows to fetch, exit the loop:
EXIT WHEN unshipped_oi%NOTFOUND;
/*inventory was available to ship the item*/
IF (qtyInStock>=oi_qty) THEN
/* Flag to be shipped with the date*/
UPDATE ORDER_ITEMS oi2
SET oi2.date_shipped=sysdate
WHERE oi2.id=oi_id;
/* Update the new product.qty_in_stock */
UPDATE PRODUCTS p
SET p.qty_in_stock = p.qty_in_stock - oi_qty
WHERE p.id=:new.prod_id;
*/
/*decrement qtyInStock that we originally queried for its value
since we’re in a loop and may need to ship another order_item for this
product*/
qtyInStock:=qtyInStock-oi_qty;
ELSE /*not enough in stock to ship this order_item, send notification
to admin to stock more of this product*/
send_oi_stock_qty_notify (oi_id, oi_qty, qtyInStock, p_name);
END IF;
END LOOP;
/*close cursor */
CLOSE unshipped_oi;
END;
/
Now this order should be complete, let’s check in the customer’s account management:
We can see that order#61 with both order_items has shipped.
PAGE 35 OF 48
Click view to confirm shipment has shipped by finding Ship Dates:
Let’s check our profit for these order_items:
SQL> select id, order_id, prod_id, quantity, unit_price, shipping_cost, profit
from order_items where order_id=61;
ID
ORDER_ID
PROD_ID
QUANTITY UNIT_PRICE SHIPPING_COST
PROFIT
---------- ---------- ---------- ---------- ---------- ------------- --------83
61
7
1
4290
500
390
84
61
6
1
4158
500
378
It appears including the markup, we made around 4 dollars of profit per order_item. Good job!
Additional profit costing example (multiple inventory_events per order_item):
Added 10 MacBooks to the inventory as follows:
Date
---------2007-12-09
2007-12-09
2007-12-09
| Qty |
Price
| Shipping
| --- | --------- | ---------|
3 |
1300.00 |
50.00
|
4 |
990.00 |
60.00
|
3 |
1000.00 |
50.00
PROD_ID
QUANTITY QTY_AVAIL SHIPPING_COST PRODUCT_COST
ID
---------- ---------- ---------- ------------- ------------ ---------12
3
3
5000
100000
105
12
4
4
6000
99000
106
12
3
3
5000
130000
107
Customer buys 5 MacBooks at 1172.88 each (current_price) at shipping_cost of 270 for the 5,
thus an order total is 6134.40.
Our actual cost was 5250 (3@(1000+50)+2@(990+60))
difference is 884.4 profit on this order
see below that trigger+procedure worked in calculating profit:
SQL> select * from order_items where order_id=48;
ID
ORDER_ID
PROD_ID
QUANTITY UNIT_PRICE SHIPPING_COST
---------- ---------- ---------- ---------- ---------- ------------DATE_SHIPPED
NOTIFIED
PROFIT
-------------------- ---------- ---------67
48
12
5
117288
5400
09-Dec-2007 22:26:28
0
88440
PAGE 36 OF 48
OK, so we have 5 in stock remaining (2 from inventory_event.id#106 + 3 from event#107):
PROD_ID
QUANTITY QTY_AVAIL SHIPPING_COST PRODUCT_COST
ID
---------- ---------- ---------- ------------- ------------ ---------12
4
2
6000
99000
106
12
3
3
5000
130000
107
inventory_event 106 shows prod_id 12 (macbook) was stocked with quantity: 4, but only 2 are
now qty_available.
Queries
The following table illustrates queries directly accessed in GUI, many other queries are used to
collect data and construct GUI elements behind the scenes (such as products within
departments).
Description
Customer order history (customer account management)
Shipping status for each part of a specific order (customer account mgmt)
Top 10 best selling items (Employee can see top 10, customer can see top 5).
• By week/month/all time
Timeline: Profit
• By Product
• By Customer
• Overall
Timeline: Inventory Level
• By Product (within inventory_events and stats)
• All Products Combined (Overall) (stats)
Average time to fulfill an order
Highest ship-to locations
• By country/state/city
Unfulfilled orders due to order_items without inventory in stock to ship.
Daily Reports
• Highest selling products
o By Quantity
o By Profit
• Highest buying customers
o By Quantity
o By Amount Spent
Where to run?
Customer
Customer
Both
Employee (stats)
Employee
Employee (stats)
Employee (stats)
Employee (stats)
Employee (stats)
Employee Application and eStore Statistics
Screen shot below of basic functionality of Employee application:
We can add or modify: Employees, Departments, Products, Inventory_Events, or execute SQL
commands.
Login as admin (password is admin1234):
PAGE 37 OF 48
now we see the Welcome screen:
.
Inventory Update allows us to add inventory_events for products:
Edit Departments allows us to modify or add a new department:
Æ
PAGE 38 OF 48
Edit Products allows us to modify existing products or add new ones:
We can see that a markup can be changed. This value will be applied to actual costs in
calculating current_price (the price the customer pays) and allows eStore to make a profit.
Markup is only applied upon new inventory_event insertions. If the admin were to change the
markup now, it would apply to the next inventory_events, not existing.
Note: pictures stored as Binary Large Objects (BLOBs) have not been implemented at this time,
but the table that stores them, and the primary key/foreign key relationship exists with the
products table should we choose to insert them at a later time in the GUI.
Add New Product is below:
Note: all forms in the GUI have data validation as well as Oracle schema constraints that will be
caught and passed as errors via GUI exceptions.
,
.
PAGE 39 OF 48
Employees can be modified or added (see below):
Note: if Role: specifies EMP (employee) instead of ADMIN (administrator) this store worker
will not be able to login to the Employee application. This is solely permitted for the ADMINs.
New Employees can be added as follows:
Note that the password did not meet the Oracle schema
constraint:
Making the password the required length allows the insert
to complete.
Employee App Statistics View
Via the Statistics and Reports button in the Management
window of the Employee application, an eStore employee
is able to view a number of interesting statistics and usage
patterns.
Product Stats
Here the employee can see the top selling products of the past 24 hours, the past week, the past
month, the past year, or of all time. The results can be sorted by quantity sold or profit made.
The query to the database is across the Order_Items table, of Order_Items that have shipped
within the given timeframe. Since the Date is an SQL object it cannot be used directly in the
query string when using JDBC and a java.sql.PreparedStatement must be used. The
PreparedStatement object is created using the basic query string with a ‘?’ substituting the date.
Then the setDate method of the PreparedStatement is called, passing it the Date required for the
query. In this case, it is a date based on the value of the time drop-down box – the current
PAGE 40 OF 48
date/time minus 24 hours, the current date/time minus 7 days, etc. Then getting the name of the
product is a simple join with the Products table based on the product ID stored in the
Order_Item. The result of this can then be displayed sorted by quantity or sorted by profit made.
Changing the sorting criteria does not reissue the query; it simply changes how the data is
displayed.
Also included in the Product Stats is a list of the top buying customers of the past 24 hours, the
past week, the past month, the past year, or of all time. This is a select from the Orders table of
all orders that are complete and are within the specified time frame. The data includes how
much the customer spent and how many unique items the customer bought, and the name of the
customer is obtained via a join with the Customers table using the customer ID. The results of
this can be sorted by the amount spent or by the number of unique items purchased, and again
changing the sorting criteria does not reissue the query.
Continued from above:
Inventory Stats
The window shows a line graph of the inventory level of a product (or all products together) over
time. Submitted Inventory_Events cause inventory levels to rise, and shipped Order_Items cause
inventory levels to fall. If a single product is selected the time span shown is only for that
particular product; it begins with the first arrival into inventory and ends with the last time an
Order_Item was shipped. If all products are selected the time span is over the life of all products,
beginning with the arrival of the first product and ending with the shipping of the most recent
Order_Item.
PAGE 41 OF 48
The line graphs were made possible thanks to the Scientific Graphics Toolkit (SGT) from the
National Oceanic and Atmospheric Administration (NOAA). The SGT graphics package is
available free for use at http://www.epic.noaa.gov/java/sgt/ The SGT facilitates graph creation
and handles much of the 2D graphics involved; the user simply must supply properly formatted
data in the form of an SGTData model. Multiple sets of SGTData objects can be added to a
single graph, and this is how the inventory levels of all products is built; the application loops
through all products and builds an SGTData object for each one. If only a single product is
select only one SGTData object is built. The building of the data object for the graph is as
follows. First the date and quantity for each Inventory_Event for the product are retrieved. Then
the date and quantity for each shipped Order_Item for the product are retrieved. All instances of
the two event types are stored together in a single list and are sorted by date. A running total of
the inventory level is initialized, and as each event is processed the inventory level goes either up
(in the case of an Inventory_Event) or down (in the case of an Order_Item). At each event the
date/time is stored, as is the inventory level at that particular point in time. These two data lists
are then fed to the SGT package and an SGTData object is created to model the data. This object
is fed to the 2D plot object and a graph is created. In the case the employee wishes to view the
inventory levels of all products simultaneously, the previous process is done once for each
product, and all SGTData objects are collected and fed into the same 2D plot object to create the
complete graph.
PAGE 42 OF 48
Order Fulfillment Stats
The Order Fulfillment window shows the highest ship-to locations and the average time required
to fulfill an order. The highest ship-to locations can be sorted by country, state, or city.
The retrieval and then display of this data is a multi-step
process. First a select is done across all completed orders in
the Orders table. For each result it retrieves the shipping
address ID and the order ID. The shipping address ID is then
used to look into the Addresses table to get the address information. At the same time the order
ID is used over the Order_Items table to get all items in the order, and quantity for each
Order_Item is retrieved. If the address is unique a new Order Address object is created with the
given address and quantity. If this address has been seen before the current quantity is added to
the existing Order Address. Once the data is completely retrieved it can be displayed to the
employee. Depending on whether the employee wants to group by country, state, or city, the
data list is traversed looking for each unique entry (country, state, or city). The quantity for each
unique entry is tallied up and the data is displayed to the user.
PAGE 43 OF 48
The Average Time to Fulfill an Order calculation simply queries all completed orders from the
Orders table, totals the difference of data completed minus date placed, and takes an average.
The time is displayed by number of days, hours, minutes, and seconds.
Profit Stats
The final statistics window allows the viewing of profit over time, on a per-product basis or for
all products, and on a per-customer basis or for all customers. The building of the graph is done
the same way as the graph of the Inventory Level statistics; the data used to create the SGTData
objects is different, of course. But like the Inventory Level graph the Profit graph is created with
either a single line (a single product) or with multiple lines (all products). For each product line
a select is done over the Order_Items table looking for shipped items of the particular product.
The order ID, data shipped, and profit calculated are all retrieved. The order ID is only used if
the line is being built in reference to a specific customer; if it is the order ID must be checked
against the customer ID in the Orders table, and the data is used only if there is a match. If the
data is going to be used, either because the customer ID matches or all customer data is being
used, the date shipped and the profit are stored in an Order Item Event object. A list of these
objects is created and sorted by date. The SGTData object is then created using the time span as
a base and the profit as data points. Once created each SGTData object is added to the 2D plot,
and once all objects have been created the plot is displayed to the user.
Profit for All Products over all time based on David Sampson’s purchases:
PAGE 44 OF 48
Profit for Guitar Hero over all time based on All Customers purchases:
Profit for All Products over all time based on All Customers purchases:
Earlier discrepancies in the data were caused by updates of how profit was calculated (or not at
all) from earlier in the testing. The timeline indicates the end of November through December
PAGE 45 OF 48
12th. Also, because some big ticket items have hundreds of dollars of profit, the items with
smaller profit margins (of less than 10 dollars) are difficult to see on this scale. Additional
charting can be extended in future work, as this was intended as a proof of concept, and was not
in the original scope. It was an exciting addition, allowing some visualization of the data.
Unfulfilled Order Stats
This can be useful to an admin who has not checked their email in some time or wants an up-todate summary of which orders are being held up for which order_items, and which products and
quantities are needed to fulfill them, sorted by date placed.
Here is the query:
SELECT o.id AS ORDER_ID, oi.id AS ORDER_ITEMID, oi.prod_id AS PROD_ID,
oi.quantity AS QTY_ORDERED, p.qty_in_stock AS QTY_IN_STOCK, o.date_placed AS
DATE_PLACED
FROM order_items oi, products p, orders o
WHERE oi.date_shipped IS NULL AND oi.order_id=o.id AND oi.prod_id=p.id
ORDER BY o.date_placed
Example output:
Order Item #45 of Order #38 (placed at 2007-12-08 22:33:14.0) requires 7 more
of product ID 9 (LEGO Harry Potter Hogwarts Castle) to ship.
Testing
Utilizing ourselves and friends, perform white box testing (testing via the GUI), we tested:
1. Create Employees, Departments, Products
2. Generate inventory_events
3. Generate Customer Data (orders)
4. For each of the above verify that the following are honored:
1. Schema integrity contraints honored as well as Primary/Foreign Key relationships.
2. Triggers before and after perform as expected (pre and post condition met)
3. Procedures perform as expected when called individually or from within a trigger.
4. Business logic is honored: calculation of profits, qty_in_stock, markup% upon
current_price, relationship between customer data with their respective orders and
order_items.
5. Business process flow working as expected (add products, view cart, cancel checkout,
all of checkout process, submit of order, check of order status, etc.
5. Run queries, verify they work.
6. Verify email procedure and Oracle SMTP functionality works.
7. Repeat for different use cases.
• A working system will allow for creation of all necessary entities, and produce customer
order history that is queryable.
Def: white box testing—“The tester chooses test case inputs to exercise paths through the code
and determines the appropriate outputs.” Source: http://en.wikipedia.org/wiki/White_box_testing
Accomplishments & Comments
•
Learning Swing UI design has been a challenge, getting JDBC to work, picking an IDE
and DB system, setting up the source code repository, debugging SQL and schema syntax
errors, and planning the original ER diagram were a lot of effort, but quite enjoyable.
PAGE 46 OF 48
Emphasizing a strong initial project proposal, and identifying preliminary details allowed
us to begin prototyping rapidly.
• A simple missing “space” in an SQL statement formed in the GUI front end took nearly 2
hours to debug. The most mundane things can at times be perplexing!
• We agree that we would work in a similar manner if we were to do this again, it has thus
far been a good learning experience, however schema design is very challenging, and
making changes after the fact can be tricky!
9 We both worked hard to collaborate and have equal contribution to the project.
Schedule
™ Goals Completed as of Project Progress Report: 11/8 (Week 10 of cs542):
• DB:
o Finalized ER diagram and entity attributes
o Construct relational model (table design)
o Built SQL tables translating ER model
o DB transaction management tutorials/reference materials
o Finalized using Oracle vs. MySQL
• Java Application front-end:
o Set up source code control repository using SourceForge CVS
o Java Swing refresher/practice
o Confirmed database access using JDBC
• Basic Data Entry Application
o Create a Java Swing application to configure the database for our application and
being creating data
ƒ Create all tables, sequences, and basic triggers
ƒ Allow employee creation complete with address
ƒ Allow department creation
ƒ Allow product creation
ƒ “Raw” mode to do manual SQL queries and commands
o Designed to be converted into the Employee Application with minor
modifications
o Employee, Department, and Product data input has begun
• Customer Application
o Designed from scratch using lessons learned creating the Basic Data Entry
Application
o Database access is hidden from the customer, making it look like a true app.
o Customers can create an account for themselves and log in
o Mockups (sketches) are complete for shopping user interface
o Application currently logs most SQL commands to a file, to ease data replication
across databases
Goals Completed Since Project Progress Report:
™ Completion goal by 11/15 (Week 11):
• Continue work on Customer Application, add product browsing, shopping cart, and order
placement.
• Finish Data-Entry Application.
PAGE 47 OF 48
•
•
•
•
•
•
•
•
•
•
• Start converting Data-Entry Application into Employee Application.
• Begin working out more complex queries.
• Continue adding data, mostly products, and begin making customer orders.
• Plan to implement stored procedures to handle orders once inserted.
™ Completion goal by 11/22 (Week 12):
• Finalize the more complex queries and procedures.
• Complete Employee Application.
• Complete Customer Application, adding account management and configuration.
• Start running through use cases/debugging.
• Continue to add customer order data and increase sample set.
• Start building query output reports.
• Invite friends to participate in usability studies and assist in data creation.
™ Completion goal by 11/29 (Week 13):
• Continue to generate data and evaluate effectiveness of queries/output/reporting.
• Additional use cases (data points).
• Incorporate input from family and friends.
• Begin Final Project report.
• Begin demonstration slides / demo planning.
™ Completion goal by 12/6 (Week 14):
• Final debugging.
• Take UI work flow screen shots and construct sample work flow.
• Finalize written report and Submit Final Project Report.
• Other Deliverables:
o Environmental setup/DB setup.
o Schema.
o Sample data loading/bulk loader.
o Java Application with directions.
o Source code
o UI screen shots/run demo
¾ Extras:
o SMTP email generation within stored PL/SQL procedures on Oracle
o Graphic charting of queries
¾ Database concepts utilized:
Entity and Relationship models
• PL/SQL Language Usage
Schema Design
• Oracle sys_date from dual table
Primary Key / Foreign Key Relationships,
• Nested Queries
Table Level Integrity Constraints
• SQL concepts GROUP BY (aggregation),
ORDER BY, Ascending vs. Descending
Sequences
• alter of schema after data loaded
Triggers (before and after)
• Concurrency With Commit (JDBC by default
Procedures with IN, and IN OUT (used to pass
commits transacations)
values and references)
• error resolution when defining triggers and
JDBC Connectivity for queries and procedure
procedures using show <type> errors
execution
• Binding new: variables on before insert triggers
Static Cursors to traverse tables
for each row
SMTP Package of Oracle
PAGE 48 OF 48