230 lines
9.3 KiB
Python
230 lines
9.3 KiB
Python
import unittest
|
||
import sqlite3
|
||
import os
|
||
import sys
|
||
import tempfile
|
||
import time
|
||
from datetime import datetime
|
||
|
||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||
|
||
from database import get_db_connection, calculate_order_total
|
||
from app import app
|
||
|
||
|
||
class TestOrders(unittest.TestCase):
|
||
"""Тестирование функционала заказов"""
|
||
|
||
@classmethod
|
||
def setUpClass(cls):
|
||
"""Создаем тестовую базу данных"""
|
||
cls.db_fd, cls.db_path = tempfile.mkstemp()
|
||
|
||
import database
|
||
database.DATABASE = cls.db_path
|
||
|
||
from database import create_tables
|
||
create_tables()
|
||
|
||
cls.conn = sqlite3.connect(cls.db_path)
|
||
cls.conn.row_factory = sqlite3.Row
|
||
cursor = cls.conn.cursor()
|
||
|
||
# Добавляем типы товаров
|
||
cursor.execute("INSERT INTO product_types (type_name) VALUES ('Ручки')")
|
||
cursor.execute("INSERT INTO product_types (type_name) VALUES ('Тетради')")
|
||
|
||
# Добавляем партнеров (БЕЗ rating)
|
||
cursor.execute('''
|
||
INSERT INTO partners (name, email, inn) VALUES
|
||
('ООО Тест', 'test@test.ru', '1234567890')
|
||
''')
|
||
cursor.execute('''
|
||
INSERT INTO partners (name, email, inn) VALUES
|
||
('ИП Тест', 'test2@test.ru', '0987654321')
|
||
''')
|
||
|
||
# Добавляем товары (БЕЗ quantity_in_stock)
|
||
cursor.execute('''
|
||
INSERT INTO products (product_type_id, product_name, article, min_partner_price)
|
||
VALUES (1, 'Ручка синяя', 'R001', 50.0)
|
||
''')
|
||
cursor.execute('''
|
||
INSERT INTO products (product_type_id, product_name, article, min_partner_price)
|
||
VALUES (1, 'Ручка красная', 'R002', 60.0)
|
||
''')
|
||
cursor.execute('''
|
||
INSERT INTO products (product_type_id, product_name, article, min_partner_price)
|
||
VALUES (2, 'Тетрадь 48л', 'T001', 100.0)
|
||
''')
|
||
|
||
# Добавляем заказы (БЕЗ status)
|
||
cursor.execute('''
|
||
INSERT INTO orders (partner_id, order_date, discount_percent)
|
||
VALUES (1, '2026-01-01', 0)
|
||
''')
|
||
cursor.execute('''
|
||
INSERT INTO orders (partner_id, order_date, discount_percent)
|
||
VALUES (1, '2026-02-01', 15)
|
||
''')
|
||
|
||
# Добавляем позиции заказов
|
||
cursor.execute('''
|
||
INSERT INTO order_items (order_id, product_id, quantity, price_at_order)
|
||
VALUES (1, 1, 10, 50.0)
|
||
''')
|
||
cursor.execute('''
|
||
INSERT INTO order_items (order_id, product_id, quantity, price_at_order)
|
||
VALUES (1, 3, 5, 100.0)
|
||
''')
|
||
cursor.execute('''
|
||
INSERT INTO order_items (order_id, product_id, quantity, price_at_order)
|
||
VALUES (2, 2, 20, 60.0)
|
||
''')
|
||
|
||
cls.conn.commit()
|
||
|
||
def test_db_connection():
|
||
conn = sqlite3.connect(cls.db_path)
|
||
conn.row_factory = sqlite3.Row
|
||
return conn
|
||
|
||
app.config['DATABASE'] = cls.db_path
|
||
database.get_db_connection = test_db_connection
|
||
|
||
@classmethod
|
||
def tearDownClass(cls):
|
||
cls.conn.close()
|
||
os.close(cls.db_fd)
|
||
try:
|
||
os.unlink(cls.db_path)
|
||
except:
|
||
pass
|
||
|
||
def setUp(self):
|
||
self.app = app.test_client()
|
||
self.app.testing = True
|
||
|
||
def test_1_calculate_order_total(self):
|
||
"""Тест расчета общей суммы заказа с наценкой 10%"""
|
||
result = calculate_order_total(1)
|
||
self.assertIsNotNone(result)
|
||
# 10*50 + 5*100 = 1000 базовая сумма
|
||
self.assertEqual(result['subtotal_without_markup'], 1000.0)
|
||
# С наценкой 10%: 1000 * 1.1 = 1100
|
||
self.assertEqual(result['subtotal_with_markup'], 1100.0)
|
||
self.assertEqual(result['discount_percent'], 0)
|
||
self.assertEqual(result['total'], 1100.0)
|
||
|
||
result = calculate_order_total(2)
|
||
self.assertIsNotNone(result)
|
||
# 20*60 = 1200 базовая сумма
|
||
self.assertEqual(result['subtotal_without_markup'], 1200.0)
|
||
# С наценкой: 1200 * 1.1 = 1320
|
||
self.assertEqual(result['subtotal_with_markup'], 1320.0)
|
||
# Со скидкой 15%: 1320 * 0.85 = 1122
|
||
self.assertEqual(result['discount_percent'], 15)
|
||
self.assertEqual(result['discount_amount'], 198.0)
|
||
self.assertEqual(result['total'], 1122.0)
|
||
|
||
def test_2_create_order_page(self):
|
||
"""Тест страницы создания заказа"""
|
||
response = self.app.get('/add_order')
|
||
self.assertEqual(response.status_code, 200)
|
||
self.assertIn('Создание нового заказа', response.data.decode('utf-8'))
|
||
|
||
def test_3_edit_order_page(self):
|
||
"""Тест страницы редактирования заказа"""
|
||
response = self.app.get('/edit_order/1')
|
||
self.assertEqual(response.status_code, 200)
|
||
self.assertIn('Редактирование заказа #1', response.data.decode('utf-8'))
|
||
|
||
def test_4_edit_order_without_items(self):
|
||
"""Тест редактирования заказа без изменения позиций (только дата/примечания)"""
|
||
response = self.app.post('/edit_order/1', data={
|
||
'order_date': '2026-03-05',
|
||
'notes': 'Обновлён без товаров'
|
||
}, follow_redirects=True)
|
||
|
||
self.assertEqual(response.status_code, 200)
|
||
self.assertIn('Заказ обновлен', response.data.decode('utf-8'))
|
||
|
||
from database import get_db
|
||
with get_db() as conn:
|
||
count = conn.execute('SELECT COUNT(*) FROM order_items WHERE order_id = 1').fetchone()[0]
|
||
self.assertEqual(count, 2)
|
||
|
||
def test_5_edit_order_add_new_item(self):
|
||
"""Тест добавления новой позиции при редактировании"""
|
||
response = self.app.post('/edit_order/1', data={
|
||
'order_date': '2026-03-05',
|
||
'notes': 'Добавлен новый товар',
|
||
'product_id[]': ['1', '2', '2'],
|
||
'quantity[]': ['5', '2', '3'],
|
||
'price[]': ['50.0', '60.0', '60.0']
|
||
}, follow_redirects=True)
|
||
|
||
self.assertEqual(response.status_code, 200)
|
||
self.assertIn('Заказ обновлен', response.data.decode('utf-8'))
|
||
|
||
from database import get_db
|
||
with get_db() as conn:
|
||
new_count = conn.execute('SELECT COUNT(*) FROM order_items WHERE order_id = 1').fetchone()[0]
|
||
items = conn.execute('SELECT product_id, quantity FROM order_items WHERE order_id = 1').fetchall()
|
||
|
||
self.assertEqual(new_count, 3)
|
||
|
||
expected_items = [
|
||
(1, 5),
|
||
(2, 2),
|
||
(2, 3)
|
||
]
|
||
|
||
for i, (expected_product_id, expected_quantity) in enumerate(expected_items):
|
||
self.assertEqual(items[i]['product_id'], expected_product_id)
|
||
self.assertEqual(items[i]['quantity'], expected_quantity)
|
||
|
||
def test_6_no_delete_button(self):
|
||
"""Тест отсутствия кнопки удаления на странице редактирования заказа"""
|
||
# Сначала создаем заказ
|
||
response = self.app.post('/add_order', data={
|
||
'partner_id': '1',
|
||
'order_date': '2026-03-04',
|
||
'notes': 'Заказ для теста',
|
||
'product_id[]': ['1'],
|
||
'quantity[]': ['1'],
|
||
'price[]': ['50.0']
|
||
}, follow_redirects=True)
|
||
|
||
self.assertEqual(response.status_code, 200)
|
||
self.assertIn('Заказ успешно создан', response.data.decode('utf-8'))
|
||
|
||
# Получаем ID созданного заказа
|
||
from database import get_db
|
||
with get_db() as conn:
|
||
order_id = conn.execute('SELECT MAX(id) as id FROM orders').fetchone()['id']
|
||
|
||
# Проверяем, что на странице редактирования нет кнопки удаления
|
||
response = self.app.get(f'/edit_order/{order_id}')
|
||
self.assertEqual(response.status_code, 200)
|
||
|
||
# Ищем текст, который указывает на отсутствие кнопки удаления
|
||
html_content = response.data.decode('utf-8')
|
||
|
||
# Проверяем, что нет HTML-элемента с текстом "Удалить заказ"
|
||
self.assertNotIn('>Удалить заказ<', html_content)
|
||
|
||
# Проверяем, что нет кнопки с классом btn-delete в HTML (не в CSS)
|
||
import re
|
||
# Ищем теги с классом btn-delete (например, <button class="btn-delete"> или <a class="btn-delete">)
|
||
btn_delete_pattern = r'<[^>]*class="[^"]*btn-delete[^"]*"[^>]*>'
|
||
self.assertIsNone(re.search(btn_delete_pattern, html_content))
|
||
|
||
# Проверяем, что заказ все еще существует в базе
|
||
with get_db() as conn:
|
||
order = conn.execute('SELECT * FROM orders WHERE id = ?', (order_id,)).fetchone()
|
||
self.assertIsNotNone(order)
|
||
|
||
|
||
if __name__ == '__main__':
|
||
unittest.main() |