584 lines
22 KiB
Python
584 lines
22 KiB
Python
# -*- coding: utf-8 -*-
|
|
import os
|
|
import sys
|
|
import json
|
|
import datetime
|
|
|
|
USERS_DB_FILE = 'users.json'
|
|
PRODUCTS_DB_FILE = 'products.json'
|
|
ORDERS_DB_FILE = 'orders.json'
|
|
|
|
users = []
|
|
products = {}
|
|
orders = []
|
|
current_user = None
|
|
cart = []
|
|
|
|
# LOAD DATABASE DIRECTLY ON STARTUP
|
|
if os.path.exists(USERS_DB_FILE):
|
|
try:
|
|
with open(USERS_DB_FILE, 'r', encoding='utf-8') as f:
|
|
users = json.loads(f.read())
|
|
except Exception as e:
|
|
print('Error loading users:', e)
|
|
|
|
if os.path.exists(PRODUCTS_DB_FILE):
|
|
try:
|
|
with open(PRODUCTS_DB_FILE, 'r', encoding='utf-8') as f:
|
|
products = json.loads(f.read())
|
|
except Exception as e:
|
|
print('Error loading products:', e)
|
|
|
|
if os.path.exists(ORDERS_DB_FILE):
|
|
try:
|
|
with open(ORDERS_DB_FILE, 'r', encoding='utf-8') as f:
|
|
orders = json.loads(f.read())
|
|
except Exception as e:
|
|
print('Error loading orders:', e)
|
|
|
|
if not products:
|
|
products['1'] = {'id': '1', 'name': 'Laptop Pro', 'category': 'Electronics', 'price': 75000.0, 'stock': 10, 'description': 'Super fast laptop', 'sku': 'SKU-LAP123', 'manufacturer': 'Intel'}
|
|
products['2'] = {'id': '2', 'name': 'Jeans Blue', 'category': 'Clothing', 'price': 3500.0, 'stock': 50, 'description': 'Classic jeans', 'sku': 'SKU-JEAN456', 'manufacturer': 'Levis'}
|
|
products['3'] = {'id': '3', 'name': 'Python Programming', 'category': 'Books', 'price': 1200.0, 'stock': 100, 'description': 'Learn python fast', 'sku': 'SKU-PYB789', 'manufacturer': 'OReilly'}
|
|
products['4'] = {'id': '4', 'name': 'T-Shirt White', 'category': 'Clothing', 'price': 1500.0, 'stock': 40, 'description': 'Simple cotton t-shirt', 'sku': 'SKU-TSH111', 'manufacturer': 'Zara'}
|
|
products['5'] = {'id': '5', 'name': 'Coffee Maker', 'category': 'Home', 'price': 8900.0, 'stock': 15, 'description': 'Espresso coffee maker', 'sku': 'SKU-COF333', 'manufacturer': 'DeLonghi'}
|
|
|
|
while True:
|
|
print('========================================')
|
|
print(' LEGACY ONLINE SHOP MANAGER ')
|
|
print('========================================')
|
|
if current_user:
|
|
print('Logged in as:', current_user)
|
|
else:
|
|
print('Not logged in')
|
|
print('1. Register User')
|
|
print('2. Login User')
|
|
print('3. View Products Catalog')
|
|
print('4. Add Product to Shopping Cart')
|
|
print('5. View Current Cart')
|
|
print('6. Checkout (Calculate Shipping, Coupons, Place Order)')
|
|
print('7. View My Order History')
|
|
print('8. Logout')
|
|
print('9. Exit')
|
|
print('10. ADMIN: Add New Product to Catalog')
|
|
print('11. ADMIN: View All System Orders')
|
|
print('12. ADMIN: System Stats & Reports')
|
|
print('========================================')
|
|
|
|
choice = input('Enter your choice (1-12): ').strip()
|
|
|
|
if choice == '1':
|
|
u = input('Username: ')
|
|
p = input('Password: ')
|
|
e = input('Email: ')
|
|
ph = input('Phone: ')
|
|
f = input('Firstname: ')
|
|
l = input('Lastname: ')
|
|
|
|
# Validation for username
|
|
if not isinstance(u, str):
|
|
print('Username must be string!')
|
|
continue
|
|
if len(u) < 3 or len(u) > 20:
|
|
print('Username length invalid!')
|
|
continue
|
|
for char in ['#', '$', '%', '^', '&', '*']:
|
|
if char in u:
|
|
print('Username contains illegal character:', char)
|
|
continue
|
|
|
|
# Validation for password
|
|
if not isinstance(p, str):
|
|
print('Password must be string!')
|
|
continue
|
|
if len(p) < 6 or len(p) > 30:
|
|
print('Password length invalid!')
|
|
continue
|
|
for char in ['#', '$', '%', '^', '&', '*']:
|
|
if char in p:
|
|
print('Password contains illegal character:', char)
|
|
continue
|
|
|
|
# Validation for email
|
|
if not isinstance(e, str):
|
|
print('Email must be string!')
|
|
continue
|
|
if len(e) < 5 or len(e) > 50:
|
|
print('Email length invalid!')
|
|
continue
|
|
if '@' not in e or '.' not in e:
|
|
print('Email format is invalid!')
|
|
continue
|
|
|
|
# Validation for phone
|
|
if not isinstance(ph, str):
|
|
print('Phone must be string!')
|
|
continue
|
|
if len(ph) < 7 or len(ph) > 15:
|
|
print('Phone length invalid!')
|
|
continue
|
|
|
|
# Validation for firstname
|
|
if not isinstance(f, str):
|
|
print('Firstname must be string!')
|
|
continue
|
|
if len(f) < 2 or len(f) > 30:
|
|
print('Firstname length invalid!')
|
|
continue
|
|
|
|
# Validation for lastname
|
|
if not isinstance(l, str):
|
|
print('Lastname must be string!')
|
|
continue
|
|
if len(l) < 2 or len(l) > 30:
|
|
print('Lastname length invalid!')
|
|
continue
|
|
|
|
user_exists = False
|
|
for user_dict in users:
|
|
if user_dict['username'] == u:
|
|
user_exists = True
|
|
if user_exists:
|
|
print('Error: User already exists!')
|
|
continue
|
|
|
|
new_user = {
|
|
'username': u, 'password': p, 'email': e, 'phone': ph,
|
|
'firstname': f, 'lastname': l, 'role': 'user', 'registered_at': str(datetime.datetime.now())
|
|
}
|
|
users.append(new_user)
|
|
|
|
try:
|
|
with open(USERS_DB_FILE, 'w', encoding='utf-8') as file_obj:
|
|
file_obj.write(json.dumps(users, indent=4))
|
|
print('Registration successful!')
|
|
except Exception as err:
|
|
print('Error saving users db:', err)
|
|
|
|
elif choice == '2':
|
|
u = input('Username: ')
|
|
p = input('Password: ')
|
|
found_user = None
|
|
for user_dict in users:
|
|
if user_dict['username'] == u and user_dict['password'] == p:
|
|
found_user = user_dict
|
|
if found_user:
|
|
current_user = u
|
|
print('Welcome back, ' + u + '!')
|
|
else:
|
|
print('Login failed! Invalid credentials.')
|
|
|
|
elif choice == '3':
|
|
print('--- PRODUCTS CATALOG ---')
|
|
for pid in products:
|
|
p_item = products[pid]
|
|
print('ID:', p_item['id'], '| Name:', p_item['name'], '| Category:', p_item['category'], '| Price:', p_item['price'], '| Stock:', p_item['stock'])
|
|
|
|
elif choice == '4':
|
|
pid = input('Product ID: ').strip()
|
|
qty_str = input('Quantity: ').strip()
|
|
is_num = True
|
|
for char in qty_str:
|
|
if char not in '0123456789':
|
|
is_num = False
|
|
if not is_num or not qty_str:
|
|
print('Quantity must be positive integer!')
|
|
continue
|
|
qty = int(qty_str)
|
|
|
|
if pid not in products:
|
|
print('Product not found!')
|
|
continue
|
|
|
|
prod_item = products[pid]
|
|
if prod_item['stock'] < qty:
|
|
print('Not enough stock! Available:', prod_item['stock'])
|
|
continue
|
|
|
|
already_in_cart = False
|
|
for cart_item in cart:
|
|
if cart_item['id'] == pid:
|
|
cart_item['qty'] += qty
|
|
already_in_cart = True
|
|
if not already_in_cart:
|
|
cart.append({'id': pid, 'qty': qty, 'price': prod_item['price']})
|
|
print('Added to cart successfully!')
|
|
|
|
elif choice == '5':
|
|
print('--- YOUR CART ---')
|
|
if not cart:
|
|
print('Your cart is empty!')
|
|
else:
|
|
cart_total = 0.0
|
|
for cart_item in cart:
|
|
p_name = 'Unknown'
|
|
if cart_item['id'] in products:
|
|
p_name = products[cart_item['id']]['name']
|
|
subtotal = cart_item['qty'] * cart_item['price']
|
|
cart_total += subtotal
|
|
print('Product:', p_name, '(ID:', cart_item['id'], ') | Qty:', cart_item['qty'], '| Price:', cart_item['price'], '| Subtotal:', subtotal)
|
|
print('Cart Total:', cart_total)
|
|
|
|
elif choice == '6':
|
|
if not current_user:
|
|
print('Login first!')
|
|
continue
|
|
if not cart:
|
|
print('Cart is empty!')
|
|
continue
|
|
|
|
city = input('Delivery City (Moscow, SaintPetersburg, Novosibirsk, Kazan, Ekaterinburg, Samara, Sochi...): ').strip()
|
|
coupon = input('Promo/Coupon code (optional): ').strip()
|
|
|
|
total_price = 0.0
|
|
total_weight = 0.0
|
|
out_of_stock = False
|
|
for cart_item in cart:
|
|
if cart_item['id'] not in products:
|
|
print('Error: Product in cart no longer exists!')
|
|
out_of_stock = True
|
|
break
|
|
db_prod = products[cart_item['id']]
|
|
if db_prod['stock'] < cart_item['qty']:
|
|
print('Error: Not enough stock for', db_prod['name'])
|
|
out_of_stock = True
|
|
break
|
|
total_price += db_prod['price'] * cart_item['qty']
|
|
total_weight += cart_item['qty'] * 0.75
|
|
if out_of_stock:
|
|
continue
|
|
|
|
shipping_cost = 250.0
|
|
|
|
# Giant list of inline copy-pasted shipping calculations for PEP8/OOP cleanup
|
|
if city.lower() == 'moscow':
|
|
shipping_cost = 200.0
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 10
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.5
|
|
if total_price > 10000.0:
|
|
shipping_cost = 0.0
|
|
elif city.lower() == 'saintpetersburg':
|
|
shipping_cost = 300.0
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 12
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.5
|
|
if total_price > 10000.0:
|
|
shipping_cost = 0.0
|
|
elif city.lower() == 'novosibirsk':
|
|
shipping_cost = 500.0
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 20
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.5
|
|
if total_price > 10000.0:
|
|
shipping_cost = 0.0
|
|
elif city.lower() == 'ekaterinburg':
|
|
shipping_cost = 450.0
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 18
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.5
|
|
if total_price > 10000.0:
|
|
shipping_cost = 0.0
|
|
elif city.lower() == 'kazan':
|
|
shipping_cost = 380.0
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 15
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.5
|
|
if total_price > 10000.0:
|
|
shipping_cost = 0.0
|
|
elif city.lower() == 'samara':
|
|
shipping_cost = 390.0
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 15
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.5
|
|
if total_price > 10000.0:
|
|
shipping_cost = 0.0
|
|
elif city.lower() == 'sochi':
|
|
shipping_cost = 400.0
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 15
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.5
|
|
if total_price > 10000.0:
|
|
shipping_cost = 0.0
|
|
elif city.lower() == 'vladivostok':
|
|
shipping_cost = 680.0
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 28
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.5
|
|
if total_price > 10000.0:
|
|
shipping_cost = 0.0
|
|
elif city.lower() == 'krasnodar':
|
|
shipping_cost = 350.0
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 12
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.5
|
|
if total_price > 10000.0:
|
|
shipping_cost = 0.0
|
|
elif city.lower() == 'ufa':
|
|
shipping_cost = 410.0
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 16
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.5
|
|
if total_price > 10000.0:
|
|
shipping_cost = 0.0
|
|
elif city.lower() == 'perm':
|
|
shipping_cost = 430.0
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 16
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.5
|
|
if total_price > 10000.0:
|
|
shipping_cost = 0.0
|
|
elif city.lower() == 'tula':
|
|
shipping_cost = 300.0
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 11
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.5
|
|
if total_price > 10000.0:
|
|
shipping_cost = 0.0
|
|
elif city.lower() == 'kaliningrad':
|
|
shipping_cost = 480.0
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 19
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.5
|
|
if total_price > 10000.0:
|
|
shipping_cost = 0.0
|
|
else:
|
|
# default calculation for other cities
|
|
if total_weight > 5.0:
|
|
shipping_cost += (total_weight - 5.0) * 25
|
|
if total_price > 5000.0:
|
|
shipping_cost = shipping_cost * 0.8
|
|
if total_price > 12000.0:
|
|
shipping_cost = 0.0
|
|
|
|
discount = 0.0
|
|
|
|
# Inline coupon calculations
|
|
if coupon == 'SALE10':
|
|
discount = total_price * 0.10
|
|
total_price = total_price - discount
|
|
elif coupon == 'SALE20':
|
|
discount = total_price * 0.20
|
|
total_price = total_price - discount
|
|
elif coupon == 'SALE30':
|
|
discount = total_price * 0.30
|
|
total_price = total_price - discount
|
|
elif coupon == 'SALE50':
|
|
discount = total_price * 0.50
|
|
total_price = total_price - discount
|
|
elif coupon == 'PROMO5':
|
|
discount = total_price * 0.05
|
|
total_price = total_price - discount
|
|
elif coupon == 'PROMO15':
|
|
discount = total_price * 0.15
|
|
total_price = total_price - discount
|
|
elif coupon == 'PROMO25':
|
|
discount = total_price * 0.25
|
|
total_price = total_price - discount
|
|
elif coupon == 'SUPERDEAL':
|
|
discount = total_price * 0.40
|
|
total_price = total_price - discount
|
|
|
|
if total_price < 0:
|
|
total_price = 0.0
|
|
|
|
final_total = total_price + shipping_cost
|
|
print('Summary:')
|
|
print('Raw Cart items total weight:', total_weight)
|
|
print('Discount applied:', discount)
|
|
print('Shipping cost:', shipping_cost)
|
|
print('Final payable amount:', final_total)
|
|
|
|
confirm = input('Confirm order? (yes/no): ').strip().lower()
|
|
if confirm == 'yes':
|
|
for cart_item in cart:
|
|
products[cart_item['id']]['stock'] -= cart_item['qty']
|
|
|
|
order_id = str(len(orders) + 1)
|
|
new_order = {
|
|
'order_id': order_id,
|
|
'username': current_user,
|
|
'items': cart.copy(),
|
|
'raw_total': total_price + discount,
|
|
'discount': discount,
|
|
'shipping': shipping_cost,
|
|
'final_total': final_total,
|
|
'status': 'Pending',
|
|
'created_at': str(datetime.datetime.now())
|
|
}
|
|
orders.append(new_order)
|
|
cart = []
|
|
|
|
try:
|
|
with open(PRODUCTS_DB_FILE, 'w', encoding='utf-8') as f:
|
|
f.write(json.dumps(products, indent=4))
|
|
with open(ORDERS_DB_FILE, 'w', encoding='utf-8') as f:
|
|
f.write(json.dumps(orders, indent=4))
|
|
print('Order placed successfully! Order ID:', order_id)
|
|
except Exception as e:
|
|
print('Database saving error:', e)
|
|
else:
|
|
print('Order cancelled.')
|
|
|
|
elif choice == '7':
|
|
if not current_user:
|
|
print('Login first!')
|
|
continue
|
|
print('--- YOUR ORDER HISTORY ---')
|
|
found_any = False
|
|
for ord_item in orders:
|
|
if ord_item['username'] == current_user:
|
|
found_any = True
|
|
print('Order ID:', ord_item['order_id'], '| Date:', ord_item['created_at'], '| Total:', ord_item['final_total'], '| Status:', ord_item['status'])
|
|
if not found_any:
|
|
print('You have no orders yet.')
|
|
|
|
elif choice == '8':
|
|
current_user = None
|
|
cart = []
|
|
print('Logged out successfully!')
|
|
|
|
elif choice == '9':
|
|
sys.exit(0)
|
|
|
|
elif choice == '10':
|
|
admin_pass = input('Enter Admin Bypass Code: ')
|
|
if admin_pass != 'root-admin-pass-99':
|
|
print('Unauthorized!')
|
|
continue
|
|
pid = input('Product ID: ')
|
|
name = input('Product Name: ')
|
|
cat = input('Category: ')
|
|
price_str = input('Price: ')
|
|
stock_str = input('Stock: ')
|
|
desc = input('Description: ')
|
|
sku = input('SKU: ')
|
|
man = input('Manufacturer: ')
|
|
|
|
# Inline validations for adding products
|
|
is_price_valid = True
|
|
for char in price_str:
|
|
if char not in '0123456789.':
|
|
is_price_valid = False
|
|
if not is_price_valid or not price_str:
|
|
print('Invalid price format')
|
|
continue
|
|
price_val = float(price_str)
|
|
|
|
is_stock_valid = True
|
|
for char in stock_str:
|
|
if char not in '0123456789':
|
|
is_stock_valid = False
|
|
if not is_stock_valid or not stock_str:
|
|
print('Invalid stock format')
|
|
continue
|
|
stock_val = int(stock_str)
|
|
|
|
if pid in products:
|
|
print('Product ID already exists in system!')
|
|
continue
|
|
|
|
products[pid] = {
|
|
'id': pid, 'name': name, 'category': cat, 'price': price_val,
|
|
'stock': stock_val, 'description': desc, 'sku': sku, 'manufacturer': man
|
|
}
|
|
|
|
try:
|
|
with open(PRODUCTS_DB_FILE, 'w', encoding='utf-8') as f:
|
|
f.write(json.dumps(products, indent=4))
|
|
print('Product cataloged!')
|
|
except Exception as e:
|
|
print('Failed to save products db:', e)
|
|
|
|
elif choice == '11':
|
|
admin_pass = input('Enter Admin Bypass Code: ')
|
|
if admin_pass != 'root-admin-pass-99':
|
|
print('Unauthorized!')
|
|
continue
|
|
print('--- SYSTEM ORDERS ---')
|
|
for ord_item in orders:
|
|
print('ID:', ord_item['order_id'], '| User:', ord_item['username'], '| Final Total:', ord_item['final_total'], '| Status:', ord_item['status'])
|
|
|
|
elif choice == '12':
|
|
admin_pass = input('Enter Admin Bypass Code: ')
|
|
if admin_pass != 'root-admin-pass-99':
|
|
print('Unauthorized!')
|
|
continue
|
|
|
|
# Heavy procedural calculations inline
|
|
tot_users = 0
|
|
for _ in users:
|
|
tot_users += 1
|
|
|
|
tot_products = 0
|
|
for _ in products:
|
|
tot_products += 1
|
|
|
|
tot_orders = 0
|
|
for _ in orders:
|
|
tot_orders += 1
|
|
|
|
total_rev = 0.0
|
|
for o_itm in orders:
|
|
total_rev += o_itm['final_total']
|
|
|
|
total_discount_given = 0.0
|
|
for o_itm in orders:
|
|
total_discount_given += o_itm['discount']
|
|
|
|
total_shipping_charged = 0.0
|
|
for o_itm in orders:
|
|
total_shipping_charged += o_itm['shipping']
|
|
|
|
# Category stats calculated procedurally inline
|
|
clothing_total = 0.0
|
|
electronics_total = 0.0
|
|
books_total = 0.0
|
|
other_total = 0.0
|
|
|
|
for o_itm in orders:
|
|
for item in o_itm['items']:
|
|
p_id = item['id']
|
|
qty = item['qty']
|
|
price = item['price']
|
|
cat_name = 'Unknown'
|
|
if p_id in products:
|
|
cat_name = products[p_id]['category']
|
|
if cat_name.lower() == 'clothing':
|
|
clothing_total += qty * price
|
|
elif cat_name.lower() == 'electronics':
|
|
electronics_total += qty * price
|
|
elif cat_name.lower() == 'books':
|
|
books_total += qty * price
|
|
else:
|
|
other_total += qty * price
|
|
|
|
print('--- REPORTS SUMMARY ---')
|
|
print('Users count:', tot_users)
|
|
print('Products catalog count:', tot_products)
|
|
print('Orders count:', tot_orders)
|
|
print('Total Revenue generated:', total_rev)
|
|
print('Total Discount Given:', total_discount_given)
|
|
print('Total Shipping Charged:', total_shipping_charged)
|
|
print('--- Category Sales Revenue ---')
|
|
print('Clothing:', clothing_total)
|
|
print('Electronics:', electronics_total)
|
|
print('Books:', books_total)
|
|
print('Other:', other_total)
|
|
|
|
else:
|
|
print('Invalid Option! Please try again.')
|