데이터베이스와 파이썬을 이용한 간단한 재고 관리프로그램
테이블 구성
CREATE TABLE COMPANY(
C_CODE VARCHAR(100) PRIMARY KEY,
C_NAME VARCHAR(20) NOT NULL UNIQUE,
NUMB VARCHAR(15)
);
CREATE TABLE PRODUCT(
P_CODE VARCHAR(100) NOT NULL PRIMARY KEY,
P_NAME VARCHAR(100) NOT NULL,
PRICE INT,
C_CODE VARCHAR(100),
C_NAME VARCHAR(100),
FOREIGN KEY(C_CODE) REFERENCES COMPANY(C_CODE)
);
CREATE TABLE USAGE_Data (
usage_code int primary key auto_increment,
P_CODE VARCHAR(100) NOT NULL,
P_NAME VARCHAR(100) NOT NULL,
USE_Data VARCHAR(100) NOT NULL,
USAGE_DATE DATETIME DEFAULT NOW(),
FOREIGN KEY(P_CODE) REFERENCES PRODUCT(P_CODE),
FOREIGN KEY(P_NAME) REFERENCES PRODUCT(P_NAME)
);
CREATE TABLE receiving_goods(
receiving_code int primary key auto_increment,
P_CODE VARCHAR(100) NOT NULL,
P_NAME VARCHAR(100) NOT NULL,
receiving_data VARCHAR(100) NOT NULL,
PRICE INT,
receiving_DATE DATETIME DEFAULT NOW(),
FOREIGN KEY(P_CODE) REFERENCES PRODUCT(P_CODE),
FOREIGN KEY(P_NAME) REFERENCES PRODUCT(P_NAME)
);
CREATE TABLE INVENTORY(
P_CODE VARCHAR(100),
P_NAME VARCHAR(100),
receiving_data VARCHAR(100),
USE_Data VARCHAR(100) ,
prev_inven_total VARCHAR(100),
INVEN_TOTAL VARCHAR(100) ,
DATE DATE DEFAULT (CURRENT_DATE),
FOREIGN KEY(P_CODE) REFERENCES PRODUCT(P_CODE) ON UPDATE CASCADE on delete cascade,
FOREIGN KEY(receiving_data) REFERENCES receiving_goods(receiving_data) ON UPDATE CASCADE on delete cascade,
FOREIGN KEY(USE_Data) REFERENCES USAGE_Data(USE_Data) ON UPDATE CASCADE on delete cascade,
FOREIGN KEY(P_NAME) REFERENCES PRODUCT(P_NAME) ON UPDATE CASCADE on delete cascade
);
테이블 EER다이어그램
거래처 상품 사용량 입고량 재고 테이블이 있고,
상품을 추가하려면 거래처 코드가 필요하고,
입고량이나 사용량을 등록하면 인벤토리 테이블에 반영된다.
외래키 옵션을통해 인벤토리에서 참조하고 있는 입고량, 사용량이 수정,삭제 가 되면
인벤토리 테이블의 데이터도 똑같이 반영이된다.
drop trigger 1_update_inventory_for_USAGE_Data;
# inventory 테이블의 업데이트를 감지해 실시간으로 계산 프로시저 를 실행시켜주는 트리거
DELIMITER //
CREATE TRIGGER 1_update_inventory_for_USAGE_Data
after UPDATE ON USAGE_Data
FOR EACH ROW
BEGIN
CALL update_current_inventory_procedure(new.p_code,old.USAGE_DATE);
END;
//
DELIMITER ;
# usage_data테이블의 delete 를 감지해 inventory 재고계산 프로시저를 호출해주는 트리거
DELIMITER //
CREATE TRIGGER delete_inventory_for_USAGE_Data
after delete ON USAGE_Data
FOR EACH ROW
BEGIN
CALL update_current_inventory_procedure(old.p_code,old.USAGE_DATE);
END;
//
DELIMITER ;
drop trigger 2_insert_inventory_USAGE_Data;
# usage_data테이블의 use_data 의 insert 를 감지해 해당 데이터를 inventory 테이블에 반영해주는 트리거
DELIMITER //
CREATE TRIGGER 2_insert_inventory_USAGE_Data
AFTER INSERT ON USAGE_Data
FOR EACH ROW
BEGIN
DECLARE MATCHING INT;
SELECT COUNT(*) INTO MATCHING
FROM INVENTORY
WHERE P_CODE = NEW.P_CODE AND DATE = now();
IF MATCHING > 0 THEN
UPDATE INVENTORY SET USE_Data = NEW.USE_Data WHERE P_CODE = NEW.P_CODE AND DATE = now();
ELSE
INSERT INTO INVENTORY (P_CODE, P_NAME, USE_Data)
VALUES (NEW.P_CODE, NEW.P_NAME, now());
END IF;
CALL 5_update_previous_inventory(new.p_code,now());
END;
//
DELIMITER ;
drop trigger 3_update_inventory_receiving_goods;
# receving_goods 테이블의 update 를 감지해 재고량계산 프로시저를 실행시켜주는 트리거
DELIMITER //
CREATE TRIGGER 3_update_inventory_receiving_goods
AFTER UPDATE ON receiving_goods
FOR EACH ROW
BEGIN
CALL update_current_inventory_procedure(new.p_code,old.receiving_DATE);
END;
//
DELIMITER ;
# receiving_goods테이블의 delete 를 감지해 inventory 재고계산 프로시저를 호출하는 트리거
DELIMITER //
CREATE TRIGGER delete_inventory_for_receiving_goods
after delete ON receiving_goods
FOR EACH ROW
BEGIN
CALL update_current_inventory_procedure(old.p_code,old.receiving_date);
END;
//
DELIMITER ;
drop trigger 4_insert_inventory_receiving_goods;
# receiving_goods 테이블의 insert를 감지해 inventory테이블에 반영해주는 트리거
DELIMITER //
CREATE TRIGGER 4_insert_inventory_receiving_goods
AFTER INSERT ON receiving_goods
FOR EACH ROW
BEGIN
DECLARE MATCHING INT;
SELECT COUNT(*) INTO MATCHING
FROM INVENTORY
WHERE P_CODE = NEW.P_CODE AND DATE = CURDATE();
IF MATCHING > 0 THEN
UPDATE INVENTORY SET receiving_data = NEW.receiving_data WHERE P_CODE = NEW.P_CODE AND DATE = CURDATE();
ELSE
INSERT INTO INVENTORY (P_CODE, P_NAME, receiving_data)
VALUES (NEW.P_CODE, NEW.P_NAME, CURDATE());
END IF;
CALL 5_update_previous_inventory(new.p_code,CURDATE());
END;
//
DELIMITER ;
# inventory 테이블에 상품 코드와 입력된 시간을 전달받아 해당 상품의 재고량을 계산해서 update 해주는 프로시저
DELIMITER //
CREATE PROCEDURE update_current_inventory_procedure(IN n_code VARCHAR(100), IN p_date DATE)
BEGIN
DECLARE current_inventory DECIMAL(10, 2);
# 현재 재고 계산
SET current_inventory = (
SELECT COALESCE(SUM(receiving_data), 0) - COALESCE(SUM(use_data), 0) + COALESCE(SUM(prev_inven_total), 0)
FROM inventory
WHERE P_CODE = n_code AND DATE = p_date
);
# 재고 업데이트
UPDATE inventory
SET INVEN_TOTAL = current_inventory
WHERE P_CODE = n_code AND DATE = p_date;
END //
DELIMITER ;
DELIMITER //
CREATE PROCEDURE 5_update_previous_inventory (IN n_code VARCHAR(100), IN p_date DATE)
BEGIN
DECLARE prev_total DECIMAL(10,2);
SELECT INVEN_TOTAL INTO prev_total
FROM inventory
WHERE P_CODE = n_code
AND DATE = DATE_SUB(p_date, INTERVAL 1 DAY);
IF prev_total IS NOT NULL THEN
UPDATE inventory
SET prev_inven_total = prev_total
WHERE P_CODE = n_code AND DATE = DATE_SUB(p_date, INTERVAL 1 DAY);
ELSE
UPDATE inventory
SET prev_inven_total = 0
WHERE P_CODE = n_code AND DATE = DATE_SUB(p_date, INTERVAL 1 DAY);
END IF;
CALL update_current_inventory_procedure(n_code,CURDATE());
END;
//
DELIMITER ;
사용한 트리거와 프로시저
사용량, 입고량 데이터의 변화를 감지해 인벤토리 테이블에 반영을 하고,
insert 시 전날의 총재고량을 가져와 현재의 전재고 필드에 값을 입력,
트리거들이 작동이 끝날때 재고량을 계산하는 프로시저를 호출해 실시간으로 반영해준다.
class DbUtil:
# 코드 제작
@staticmethod
def create_code():
rlist = string.ascii_lowercase + string.digits
result = ''.join(random.choices(rlist, k=6))
return result
# 거래처 정보 검색
@staticmethod
def get_c_info(c_name, connection):
try:
cur = connection.cursor()
cur.execute("SELECT * FROM COMPANY WHERE C_NAME = %s", (c_name,))
row = cur.fetchall()
if row:
return row
else:
print('해당 정보가 없습니다.')
connection.close()
cur.close()
except Exception as e:
print("Error:", e)
# 거래처 이름 검색
@staticmethod
def get_c_name(c_code, connection):
try:
cur = connection.cursor()
cur.execute("SELECT C_NAME FROM COMPANY WHERE C_CODE = %s", (c_code,))
row = cur.fetchone()
print(row)
if row:
return row[0]
else:
print('해당 정보가 없습니다')
connection.close()
cur.close()
except Exception as e:
print("Error:", e)
# 상품 정보 검색
@staticmethod
def get_p_info(p_name, connection):
try:
cur = connection.cursor()
cur.execute("SELECT * FROM PRODUCT WHERE P_NAME = %s", (p_name,))
row = cur.fetchall()
if row:
return row
else:
print('해당 정보가 없습니다')
connection.close()
cur.close()
except Exception as e:
print("Error:", e)
# 상품 이름 검색
@staticmethod
def get_p_name(p_code, connection):
try:
cur = connection.cursor()
cur.execute("SELECT P_NAME FROM PRODUCT WHERE P_CODE=%s", (p_code,))
row = cur.fetchone()
if row:
return row[0]
else:
print('해당 정보가 없습니다')
connection.close()
cur.close()
except Exception as e:
print("Error:", e)
클래스 들에서 공통적으로 사용할 기능을 따로 빼서 모듈화 시켰다.
class CompanyDAO:
def __init__(self):
self.db = None
def connect(self):
self.db = MySQLdb.connect('localhost', 'root', '1234', 'kdt')
return self.db
def disconnect(self):
self.db.close()
def printall(self): # 거래처조회
self.connect()
cur = self.db.cursor()
sql = 'select * from COMPANY'
cur.execute(sql)
row = cur.fetchall()
cur.close()
self.disconnect()
return row
def add_company(self, c_name, numb): # 거래처 추가
self.connect()
cur = self.db.cursor()
c_code = DbUtil.create_code()
sql = "insert into company (c_code,c_name,numb) values (%s, %s, %s)"
data = (c_code, c_name, numb)
cur.execute(sql, data)
self.db.commit()
print('등록 되었습니다.')
cur.close()
self.disconnect()
def del_company(self, c_code): # 거래처삭제
self.connect()
cur = self.db.cursor()
result = cur.execute('delete from company where c_code=%s', (c_code,))
self.db.commit()
if result > 0:
print('삭제되었습니다')
else:
print('오류!')
cur.close()
self.disconnect()
def update_company(self, c_name, numb, c_code): # 거래처수정
self.connect()
cur = self.db.cursor()
sql = "update company set c_name=%s, numb=%s where c_code=%s"
data = (c_name, numb, c_code)
result = cur.execute(sql, data)
self.db.commit()
if result > 0:
print('수정되었습니다')
else:
print('에러!')
cur.close()
self.disconnect()
def search_company(self, c_name): # 거래처 검색
self.connect()
cur = self.db.cursor()
cur.execute("select * from company where c_name = %s ", (c_name,))
row = cur.fetchall()
cur.close()
self.disconnect()
return row
# 상품 테이블 DAO 클래스
class ProductDAO:
def __init__(self):
self.db = None
def connect(self):
self.db = MySQLdb.connect('localhost', 'root', '1234', 'kdt')
return self.db
def disconnect(self):
self.db.close()
# 전체 상품 조회
def print_all(self):
self.connect()
cur = self.db.cursor()
cur.execute('select * from PRODUCT')
row = cur.fetchall()
cur.close()
self.disconnect()
return row
# 추가
def add_product(self, p_name, price, c_code):
self.connect()
cur = self.db.cursor()
p_code = DbUtil.create_code()
c_name = DbUtil.get_c_name(c_code, self.db)
sql = "insert into product (p_code, p_name, price, c_code, c_name) values (%s, %s, %s, %s, %s)"
data = (p_code, p_name, price, c_code, c_name)
cur.execute(sql, data)
self.db.commit()
print('등록 되었습니다.')
cur.close()
self.disconnect()
# 삭제
def del_product(self, p_code):
self.connect()
cur = self.db.cursor()
result = cur.execute('delete from product where p_code=%s', (p_code,))
self.db.commit()
if result > 0:
print('삭제되었습니다')
else:
print('오류!')
cur.close()
self.disconnect()
# 수정
def product_update(self, p_code, p_name, price):
self.connect()
cur = self.db.cursor()
sql = "update product set p_name=%s, price = %s where p_code=%s"
data = (p_name, price, p_code)
result = cur.execute(sql, data)
self.db.commit()
if result > 0:
print('수정되었습니다')
else:
print('에러!')
cur.close()
self.disconnect()
# 검색
def product_search(self, p_name):
self.connect()
cur = self.db.cursor()
cur.execute("select * from product where p_name = %s", (p_name,))
row = cur.fetchall()
cur.close()
self.disconnect()
return row
# 재고 테이블 DAO 클래스
class InventoryDAO:
def __init__(self):
self.db = None
def connect(self):
self.db = MySQLdb.connect('localhost', 'root', '1234', 'kdt')
def disconnect(self):
self.db.close()
# 재고 조회
def inven_data(self, time1, time2):
self.connect()
cur = self.db.cursor()
sql = 'SELECT * FROM INVENTORY WHERE DATE >= %s AND DATE <= %s;'
data = (time1, time2)
cur.execute(sql, data)
row = cur.fetchall()
cur.close()
self.disconnect()
return row
# 검색
def inven_search(self, p_name):
self.connect()
cur = self.db.cursor()
cur.execute("select * from inventory where p_name = %s", (p_name,))
row = cur.fetchall()
cur.close()
self.disconnect()
return row
# 사용량 테이블 DAO 클래스
class UsageDataDAO:
def __init__(self):
self.db = None
def connect(self):
self.db = MySQLdb.connect('localhost', 'root', '1234', 'kdt')
return self.db
def disconnect(self):
self.db.close()
# 추가
def insert_usage_data(self, p_code, p_name, use_data):
self.connect()
cur = self.db.cursor()
sql = "insert into usage_data ( P_CODE, P_NAME, USE_Data) values (%s, %s, %s)"
data = (p_code, p_name, use_data)
cur.execute(sql, data)
self.db.commit()
print('등록 되었습니다.')
cur.close()
self.disconnect()
# 사용량 조회
def print_all(self, time1, time2):
self.connect()
cur = self.db.cursor()
sql = 'SELECT * FROM usage_data WHERE USAGE_DATE >= %s AND USAGE_DATE <= %s;'
data = (time1, time2)
cur.execute(sql, data)
row = cur.fetchall()
cur.close()
self.disconnect()
return row
# 검색
def usage_search(self, p_name):
self.connect()
cur = self.db.cursor()
cur.execute("select * from usage_data where p_name = %s", (p_name,))
row = cur.fetchall()
cur.close()
self.disconnect()
return row
# 수정
def usage_update(self, p_name, usage_code, use_data):
self.connect()
cur = self.db.cursor()
sql = "update usage_data set USE_Data=%s where usage_code=%s"
data = (use_data, usage_code)
result = cur.execute(sql, data)
self.db.commit()
if result > 0:
print('수정되었습니다')
else:
print('에러!')
cur.close()
self.disconnect()
# 삭제
def del_usage(self, usage_code):
self.connect()
cur = self.db.cursor()
result = cur.execute('delete from usage_data where usage_code=%s', (usage_code,))
self.db.commit()
if result > 0:
print('삭제되었습니다')
else:
print('오류!')
cur.close()
self.disconnect()
# 입고 테이블 DAO 클래스
class ReceivingGoodsDAO:
def __init__(self):
self.db = None
def connect(self):
self.db = MySQLdb.connect('localhost', 'root', '1234', 'kdt')
return self.db
def disconnect(self):
self.db.close()
# 입고 등록
def insert_receiving_goods(self, p_code, p_name, receiving_data, price): # 추가
self.connect()
cur = self.db.cursor()
sql = "insert into receiving_goods (P_CODE, P_NAME, receiving_data, PRICE) values (%s, %s, %s, %s)"
data = (p_code, p_name, receiving_data, price)
print(data)
cur.execute(sql, data)
self.db.commit()
print('등록 되었습니다.')
cur.close()
self.disconnect()
# 입고량 조회
def print_all(self, time1, time2):
self.connect()
cur = self.db.cursor()
sql = 'SELECT * FROM receiving_goods WHERE DATE(receiving_DATE) >= %s AND DATE(receiving_DATE) <= %s;'
data = (time1, time2)
cur.execute(sql, data)
row = cur.fetchall()
cur.close()
self.disconnect()
return row
# 입고 검색
def receiving_goods_search(self, p_name):
self.connect()
cur = self.db.cursor()
cur.execute("SELECT * FROM receiving_goods WHERE p_name = %s", (p_name,))
row = cur.fetchall()
cur.close()
self.disconnect()
return row
# 입고 수정
def receiving_goods_update(self, receiving_code, receiving_data, price): # 수정
self.connect()
cur = self.db.cursor()
sql = "update receiving_goods set receiving_data = %s, PRICE = %s where receiving_code=%s"
data = (receiving_data, price, receiving_code)
result = cur.execute(sql, data)
self.db.commit()
if result > 0:
print('수정되었습니다')
else:
print('에러!')
cur.close()
self.disconnect()
# 입고 삭제
def del_receiving_goods(self, receiving_code): # 삭제
self.connect()
cur = self.db.cursor()
result = cur.execute('delete from receiving_goods where receiving_code=%s', (receiving_code,))
self.db.commit()
if result > 0:
print('삭제되었습니다')
else:
print('오류!')
cur.close()
self.disconnect()
각 테이블에 상호작용을 위한 DAO 클래스 기능추가나 유지보수의 편의를 위해 모두 분리를 시켜주었다
# 서비스 클래스:
# 거래처 관리 서비스
class CompanyService:
def __init__(self):
self.dao = CompanyDAO()
# 거래처 조회 서비스
def check_service(self):
datas = self.dao.printall()
if datas:
for data in datas:
print(f'거래처코드: {data[0]} | 거래처명: {data[1]} | 전화번호: {data[2]}')
else:
print('현재 거래처가 없습니다.')
# 거래처 추가 서비스
def add_service(self):
c_name = input('거래처명 을 입력하세요: ')
numb = input("거래처 전화번호를 입력하세요 000 - 0000 - 0000: ")
self.dao.add_company(c_name, numb)
# 거래처 삭제 서비스
def del_service(self): # 거래처 삭제
c_name = input('삭제할 거래처를 입력하세요: ')
check = self.dao.search_company(c_name) # 해당 거래처 유무 검사
if not check:
print('삭제할 거래처가 없습니다')
else:
for data in check:
print(f'거래처코드: {data[0]} | 거래처명: {data[1]} | 전화번호: {data[2]}')
c_code = input("삭제할 거래처 코드를 입력하세요: ")
self.dao.del_company(c_code)
# 거래처 수정 서비스
def edit_service(self):
c_name = input('수정할 거래처명 을 입력하세요: ')
company = self.dao.search_company(c_name) # 해당 거래처 유무 검사
if not company:
print('수정할 거래처가 없습니다')
else:
for data in company:
print(f'거래처코드: {data[0]} | 거래처명: {data[1]} | 전화번호: {data[2]}')
c_code = input('데이터를 수정할 거래처의 코드를 입력하세요: ')
c_name = input('새로운 거래처 명을 입력하세요: ')
numb = input('새로운 전화번호를 입력하세요 000 - 0000 - 0000: ')
self.dao.update_company(c_name, numb, c_code)
# 거래처 검색 서비스
def search_service(self):
c_name = input('검색할 거래처명 을 입력하세요')
datas = self.dao.search_company(c_name)
if datas:
for data in datas:
print(f'거래처코드: {data[0]} | 거래처명: {data[1]} | 전화번호: {data[2]}')
else:
print('찾는 단어가 없습니다')
# 거래처 관리 메뉴
def company_menu(self):
while True:
print("1. 거래처 조회")
print("2. 거래처 추가")
print("3. 거래처 삭제")
print("4. 거래처 수정")
print("5. 거래처 검색")
print("6. 이전 메뉴로 돌아가기")
choice = input("거래처 관리 메뉴를 선택하세요: ")
if choice == '1':
self.check_service()
elif choice == '2':
self.add_service()
elif choice == '3':
self.del_service()
elif choice == '4':
self.edit_service()
elif choice == '5':
self.search_service()
elif choice == '6':
print('이전 메뉴로 돌아갑니다')
break
else:
print('입력을 확인하세요')
# 상품 관리 서비스
class ProductService:
def __init__(self):
self.dao = ProductDAO()
# 전체 상품 조회 서비스
def check_service(self): # 상품 조회
datas = self.dao.print_all()
if datas:
for data in datas:
print(f'상품코드: {data[0]} | 상품명: {data[1]} | 상품가격: {data[2]} | 거래처코드: {data[3]} | 거래처명: {data[4]}')
else:
print('등록된 상품이 없습니다.')
# 상품 추가 서비스
def add_service(self):
c_name = input('거래처명을 입력하세요')
connect = self.dao.connect()
c_info = DbUtil.get_c_info(c_name, connect)
if c_info:
for info in c_info:
print(f'거래처코드: {info[0]} | 거래처명: {info[1]} | 전화번호: {info[2]}')
else:
print('해당 거래처 정보가 없습니다.')
c_code = input('거래처 코드를 입력하세요')
p_name = input('상품명을 입력하세요')
price = int(input('상품가격을 입력하세요'))
self.dao.add_product(p_name, price, c_code)
# 상품 삭제 서비스
def del_service(self): # 상품 삭제
p_name = input('삭제할 상품명을 입력하세요: ')
check = self.dao.product_search(p_name) # 해당 상품 유무 검사
if not check:
print('삭제할 상품이 없습니다')
else:
for data in check:
print(f'상품코드: {data[0]} | 상품명: {data[1]} | 상품가격: {data[2]} | 거래처코드: {data[3]} | 거래처명: {data[4]}')
p_code = input("삭제할 상품코드를 입력하세요: ")
self.dao.del_product(p_code)
# 상품 수정 서비스
def edit_service(self): # 상품 수정
p_name = input('수정할 상품명을 입력하세요')
check = self.dao.product_search(p_name) # 해당 상품 유무 검사
if not check:
print('수정할 상품이 없습니다')
else:
for data in check:
print(f'상품코드: {data[0]} | 상품명: {data[1]} | 상품가격: {data[2]} | 거래처코드: {data[3]} | 거래처명: {data[4]}')
p_code = input('데이터를 수정할 상품의 코드를 입력하세요')
p_name = input('새로운 상품명을 입력하세요')
price = int(input('새로운 가격을 입력하세요'))
self.dao.product_update(p_code, p_name, price)
# 상품 검색 서비스
def search_service(self): # 상품 검색
p_name = input('검색할 상품명 을 입력하세요')
datas = self.dao.product_search(p_name)
if datas:
for data in datas:
print(f'상품코드: {data[0]} | 상품명: {data[1]} | 상품가격: {data[2]} | 거래처코드: {data[3]} | 거래처명: {data[4]}')
else:
print('찾는 상품이 없습니다')
# 상품 관리 메뉴
def product_menu(self):
while True:
print("1. 상품 조회")
print("2. 상품 추가")
print("3. 상품 삭제")
print("4. 상품 수정")
print("5. 상품 검색")
print("6. 이전 메뉴로 돌아가기")
choice = input("상품 관리 메뉴를 선택하세요: ")
if choice == '1':
self.check_service()
elif choice == '2':
self.add_service()
elif choice == '3':
self.del_service()
elif choice == '4':
self.edit_service()
elif choice == '5':
self.search_service()
elif choice == '6':
print('이전 메뉴로 돌아갑니다')
break
else:
print('입력을 확인하세요')
# 재고 관리 서비스
class InvenService:
def __init__(self):
self.dao = InventoryDAO()
def check_service(self): # 재고 조회
time1 = input("날짜를 입력하세요 (YYYY-MM-DD): ")
time2 = input("날짜를 입력하세요 (YYYY-MM-DD): ")
datas = self.dao.inven_data(time1, time2)
if datas:
# P_CODE, P_NAME, receiving_data, USE_Data, prev_inven_total, INVEN_TOTAL, DATE
for data in datas:
print(f"상품코드: {data[0]} | 상품명: {data[1]} | 입고량: {data[2]} | 사용량: {data[3]} | 전 재고: {data[4]} | 현재총재고: {data[5]} | 날짜: {data[6]}")
else:
print('정보가 없습니다')
# 재고 정보 검색 서비스
def search_service(self): # 재고 검색
p_name = input('검색할 재고의 상품명을 입력하세요: ')
datas = self.dao.inven_search(p_name)
if datas:
for data in datas:
print(f"상품코드: {data[0]} | 상품명: {data[1]} | 입고량: {data[2]} | 사용량: {data[3]} | 전 재고: {data[4]} | 현재총재고: {data[5]} | 날짜: {data[6]}")
else:
print('검색한 상품의 재고정보가 없습니다.')
# 재고관리 메뉴
def inven_menu(self):
while True:
print('1. 재고 조회')
print('2. 재고 검색')
print('3. 이전 메뉴로 돌아가기')
choice = input('메뉴를 선택하세요: ')
if choice == '1':
self.check_service()
elif choice == '2':
self.search_service()
elif choice == '3':
print('이전 메뉴로 돌아갑니다.')
break
else:
print('입력을 확인하세요.')
# 사용 정보 관리 서비스
class UsageService:
def __init__(self):
self.dao = UsageDataDAO()
# 사용정보 조회 서비스
def check_service(self):
time1 = input("날짜를 입력하세요 (YYYY-MM-DD): ")
time2 = input("날짜를 입력하세요 (YYYY-MM-DD): ")
datas = self.dao.print_all(time1, time2)
# usage_code, P_CODE, P_NAME, USE_Data, USAGE_DATE
if datas:
for data in datas:
print(f"No: {data[0]} | 상품코드: {data[1]} | 상품명: {data[2]} | 사용량: {data[3]} | 사용날짜: {data[4]}")
else:
print('해당 사용정보가 없습니다')
# 사용정보 등록 서비스
def add_service(self):
p_name = input("사용정보를 등록할 상품명을 입력하세요: ")
p_info = DbUtil.get_p_info(p_name, self.dao.connect())
if p_info:
for info in p_info:
print(f'상품코드: {info[0]} | 상품명: {info[1]} | 상품가격: {info[2]} | 거래처코드: {info[3]} | 거래처명: {info[4]}')
else:
print('해당 사용정보가 없습니다.')
p_code = input('사용정보를 등록할 상품코드를 입력하세요: ')
use_data = input('사용정보를 등록하세요: ')
self.dao.insert_usage_data(p_code, p_name, use_data)
# 사용정보 삭제 서비스
def del_service(self):
p_name = input('사용정보를 삭제할 상품명을 입력하세요: ')
u_info = self.dao.usage_search(p_name)
if u_info:
for info in u_info:
print(f"No: {info[0]} | 상품코드: {info[1]} | 상품명: {info[2]} | 사용량: {info[3]} | 사용날짜: {info[4]}")
else:
print('해당 사용정보가 없습니다')
usage_code = int(input('삭제할 사용정보의 코드를 입력하세요: '))
self.dao.del_usage(usage_code)
# 사용정보 수정 서비스
def edit_service(self):
p_name = input('사용정보를 수정할 상품명을 입력하세요: ')
u_info = self.dao.usage_search(p_name)
if u_info:
for info in u_info:
print(f"No: {info[0]} | 상품코드: {info[1]} | 상품명: {info[2]} | 사용량: {info[3]} | 사용날짜: {info[4]}")
else:
print('해당 상품의 사용정보가 없습니다')
usage_code = int(input('수정할 사용정보의 코드를 입력하세요: '))
use_data = input('수정할 사용정보를 입력하세요: ')
self.dao.usage_update(p_name, usage_code, use_data)
# 사용정보 검색 서비스
def search_service(self):
p_name = input('사용량을 검색할 상품을 입력하세요: ')
datas = self.dao.usage_search(p_name)
if datas:
for data in datas:
print(f"No: {data[0]} | 상품코드: {data[1]} | 상품명: {data[2]} | 사용량: {data[3]} | 사용날짜: {data[4]}")
else:
print('입력한 상품의 사용정보가 없습니다.')
# 사용정보 관리 메뉴
def usage_menu(self):
while True:
print("1. 데이터 조회")
print("2. 테이터 추가")
print("3. 데이터 삭제")
print("4. 데이터 수정")
print("5. 데이터 검색")
print("6. 이전 메뉴로 돌아가기")
choice = input("상품 관리 메뉴를 선택하세요: ")
if choice == '1':
self.check_service()
elif choice == '2':
self.add_service()
elif choice == '3':
self.del_service()
elif choice == '4':
self.edit_service()
elif choice == '5':
self.search_service()
elif choice == '6':
print('이전 메뉴로 돌아갑니다')
break
else:
print('입력을 확인하세요')
# 입고 정보 관리 서비스
class ReceivingService:
def __init__(self):
self.dao = ReceivingGoodsDAO()
# 입고 정보 조회
def check_service(self):
time1 = input("날짜를 입력하세요 (YYYY-MM-DD): ")
time2 = input("날짜를 입력하세요 (YYYY-MM-DD): ")
datas = self.dao.print_all(time1, time2)
# receiving_code, P_CODE, P_NAME, receiving_data, PRICE, receiving_DATE
if datas:
for data in datas:
print(f"No: {data[0]} | 상품코드: {data[1]} | 상품명: {data[2]} | 입고량: {data[3]} | 입고가: {data[4]} | 입고날짜: {data[5]}")
else:
print('입고정보가 없습니다.')
# 입고 정보 등록 서비스
def add_service(self):
p_name = input("입고정보를 등록할 상품명을 입력하세요: ")
p_info = DbUtil.get_p_info(p_name, self.dao.connect())
if p_info:
for info in p_info:
print(f'상품코드: {info[0]} | 상품명: {info[1]} | 상품가격: {info[2]} | 거래처코드: {info[3]} | 거래처명: {info[4]}')
else:
print('해당 입고 정보가 없습니다.')
p_code = input('입고된 상품코드를 입력하세요: ')
receiving_data = input('입고정보를 등록하세요: ')
price = int(input('입고가 를 입력하세요: '))
self.dao.insert_receiving_goods(p_code, p_name, receiving_data, price)
# 입고 정보 삭제 서비스
def del_service(self):
p_name = input('입고정보를 삭제할 상품명을 입력하세요: ')
r_info = self.dao.receiving_goods_search(p_name)
if r_info:
for info in r_info:
print(f"No: {info[0]} | 상품코드: {info[1]} | 상품명: {info[2]} | 입고량: {info[3]} | 입고가: {info[4]} | 입고날짜: {info[5]}")
else:
print('해당 입고정보가 없습니다')
receiving_code = int(input('삭제할 입고정보의 코드를 입력하세요: '))
self.dao.del_receiving_goods(receiving_code)
# 입고 정보 수정 서비스
def edit_service(self):
p_name = input('입고정보를 수정할 상품명을 입력하세요: ')
r_info = self.dao.receiving_goods_search(p_name)
if r_info:
for info in r_info:
print(f"No: {info[0]} | 상품코드: {info[1]} | 상품명: {info[2]} | 입고량: {info[3]} | 입고가: {info[4]} | 입고날짜: {info[5]}")
else:
print('해당 상품의 입고정보가 없습니다')
receiving_code = int(input('수정할 입고정보의 코드를 입력하세요: '))
receiving_data_data = input('수정할 입고정보를 입력하세요: ')
price = int(input('수정할 입고가를 입력하세요'))
self.dao.receiving_goods_update(receiving_code, receiving_data_data, price)
# 입고 정보 검색 서비스
def search_service(self):
p_name = input('입고정보를 검색할 상품을 입력하세요: ')
datas = self.dao.receiving_goods_search(p_name)
# receiving_code, P_CODE, P_NAME, receiving_data, PRICE, receiving_DATE
if datas:
for data in datas:
print(f"No: {data[0]} | 상품코드: {data[1]} | 상품명: {data[2]} | 입고량: {data[3]} | 입고가: {data[4]} | 입고날짜: {data[5]}")
else:
print('입력한 상품의 입고정보가 없습니다.')
# 입고 관리 서비스
def receiving_menu(self):
while True:
print("1. 데이터 조회")
print("2. 테이터 추가")
print("3. 데이터 삭제")
print("4. 데이터 수정")
print("5. 데이터 검색")
print("6. 이전 메뉴로 돌아가기")
choice = input("상품 관리 메뉴를 선택하세요: ")
if choice == '1':
self.check_service()
elif choice == '2':
self.add_service()
elif choice == '3':
self.del_service()
elif choice == '4':
self.edit_service()
elif choice == '5':
self.search_service()
elif choice == '6':
print('이전 메뉴로 돌아갑니다')
break
else:
print('입력을 확인하세요')
상품 관리 서비스를 위한 클래스 테이블의DAO 마다 각각 접근해 데이터를 보내기위한 클래스이다.
마찬가지로 모두 분리를 시켜주었고 각 클래스마다 따로 메뉴를 만들어 각각 서비스기능추가,삭제 가 생길시
편하게 반영하기위해 마찬가지로 분리하여 서비스 클래스들에 넣어주었다
# 실행 메뉴 클래스:
class Menu:
def __init__(self, company_service, prod_service, inven_service, usage_service, receiving_service):
self.com_service = company_service
self.prod_service = prod_service
self.inven_service = inven_service
self.usage_service = usage_service
self.receiving_service = receiving_service
def run(self):
while True:
try:
print("1. 거래처 관리")
print("2. 상품 관리")
print("3. 재고 관리")
print("4. 사용량 관리")
print("5. 입고 관리")
print("6. 나가기")
choice = input("관리 메뉴를 선택하세요: ")
if choice == '1':
self.com_service.company_menu()
elif choice == '2':
self.prod_service.product_menu()
elif choice == '3':
self.inven_service.inven_menu()
elif choice == '4':
self.usage_service.usage_menu()
elif choice == '5':
self.receiving_service.receiving_menu()
elif choice == '6':
print('프로그램을 종료합니다')
break
else:
print('입력을 확인하세요')
except Exception as e:
print(e)
print('에러 발생 입력을 확인하세요')
# DbUtil.error_list(e)
# 메인 클래스:
if __name__ == "__main__":
company_service = CompanyService()
prod_service = ProductService()
inven_service = InvenService()
usage_service = UsageService()
receiving_service = ReceivingService()
menu = Menu(company_service, prod_service, inven_service, usage_service, receiving_service)
menu.run()
각각의 서비스에 접근하기 위한 메뉴클래스
선택지에 따라 각 서비스클래스의 메뉴 메서드로 연결해준다.
작동확인
과정:
파이썬 코드는 생각보다 금방 끝났지만,
원하는 기능을 구현하기위해 mysql의 트리거라는 기능을 찾아서 공부한뒤
적용 시켰는데 설계를 잘못해서 여러 트리거들이 같이 실행이 되면서 계속 충돌이나 오류가 났다.
그래서 순서를 지정하는법, 각각따로 실행하는 법 들을 찾아보다 프로시저를 발견해서,
몇개의 트리거를 프로시저로 바꾸고 각 트리거가 실행한뒤에 프로시저가 순서대로 실행할수 있게 설계하였다.
ex) 사용량에 insert 가 감지되면 트리거가 실행되어 데이터를 인벤토리에 insert나 업데이트를 시켜주고 트리거가 끝나는 시점에 전날의 재고량을 가져오는 프로시저를 실행시키고,
해당 프로시저가 끝나면서 재고량을 계산해주는 프로시저를 호출 하는 방식으로 순서 설계를 해주었다.
기능은 구현 되었는데 사용량,입고량 데이터가 업데이트 가 안되어 찾아보니 인벤토리 테이블에서 참조중인 값이라
오류가 생기는걸 발견 해당 문제를 해결하기위해 트리거를 이용해 동시에 값을 바꾸거나,
외래키를 드랍한뒤 바꾸는등 많은 시도를 해봤는데 계속 값을 바꿀수 없다는 오류가 발생해 gpt와 함께 한참을 고민을 하다 구글에 검색해보니 외래키 옵션이라는게 있었다.....
외래키 옵션에는 on update, on delete 등 업데이트와 삭제시 부여한 옵션에 따라
참조하고 있는 값이 삭제되면 null로 바꾸는 기능이나, 값이 같이 변경되거나 삭제,수정이 아예안되는 옵션이 있었다.
(옵션을 부여하지 않을시 수정,삭제 안되는 옵션이 기본값으로 적용된다.) 그래서 값이 함께 수정이 되는 옵션을 부여하여 원하는데로 잘 작동을 하였고 트리거를 수정해 업데이트 감지시 값을 입력을 하는게 아닌 재고계산 프로시저를 호출하는 용도로 바꾸어 insert, update, delete 시 실시간으로 계산에 반영되는 시스템을 구현하였다.
결론:
이번 과제를 하면서 프로그램에 대해 설계를하고 기능을 구현하기위해서
클래스를 계속 나누어보고 합쳐보고 사용하면서 대해 많은 복습과 공부를 하게되었고
쉽다고 생각했던 sql도 어렵고 복잡해 sql에 대해 찾아보며 공부하는 계기가 되어서
(생각과는 다르게 파이썬보다 sql이 더 스트레스) 앞으로 sql을 얼마나 더 쓸지는 모르겠지만
프로그램을 설계하고 구현하는데 많은 도움이 되었다.
'코딩 > 과제' 카테고리의 다른 글
CSS 과제1 (0) | 2024.04.09 |
---|---|
과제 html (0) | 2024.04.05 |
과제 - 파이썬 파일 관련 프로그램 (1) | 2024.03.22 |
과제 4 - 파일 입출력을 이용한 단어장 만들기 (0) | 2024.03.22 |
과제 - 주민등록번호 유효검사 (0) | 2024.03.19 |