Интегрирован wesp в сайт
CI / quality (push) Canceled after 0s

This commit is contained in:
влад
2026-07-17 12:57:18 +03:00
parent 5dfa06ddbe
commit 355c0ef9f1
883 changed files with 194576 additions and 177 deletions
@@ -0,0 +1,239 @@
"""Тесты API учётных документов и org_settings."""
from __future__ import annotations
import io
import os
import tempfile
import unittest
from datetime import datetime, timedelta
from pathlib import Path
from werkzeug.security import generate_password_hash
from app import create_app, db
from app.models import (
Component,
ComponentStock,
LoadingReport,
LoadingReportComponent,
OrgSettings,
WebUser,
)
from app.services.setup_state import mark_setup_complete
from config import TestingConfig
class FeedAccountingTestConfig(TestingConfig):
_TMP_DIR = tempfile.mkdtemp(prefix="wesp-fa-tests-")
SQLALCHEMY_DATABASE_URI = f"sqlite:///{os.path.join(_TMP_DIR, 'recipes_test.db')}"
SQLALCHEMY_BINDS = {"reports": f"sqlite:///{os.path.join(_TMP_DIR, 'reports_test.db')}"}
AUTH_LOGIN = "fa-admin"
AUTH_PASSWORD = "fa-secret"
class FeedAccountingExportTests(unittest.TestCase):
def setUp(self) -> None:
self.app = create_app(FeedAccountingTestConfig)
self.client = self.app.test_client()
self.ctx = self.app.app_context()
self.ctx.push()
db.create_all()
db.session.add(
WebUser(
login="fa-admin",
password_hash=generate_password_hash("fa-secret"),
is_superuser=True,
)
)
db.session.commit()
mark_setup_complete(self.app)
login = self.client.post(
"/api/auth/login",
json={"login": "fa-admin", "password": "fa-secret"},
)
self.assertEqual(login.status_code, 200, login.get_data(as_text=True))
self._seed_data()
def tearDown(self) -> None:
db.session.remove()
db.drop_all()
self.ctx.pop()
def _seed_data(self) -> None:
comp = Component(name="Сено", type="roughage")
db.session.add(comp)
db.session.flush()
stock = ComponentStock(
component_id=comp.id,
component_name=comp.name,
total_kg=1000.0,
stocktake_at=datetime.now(),
updated_at=datetime.now(),
)
db.session.add(stock)
report = LoadingReport(
recipe_id="r1",
recipe_name="Test",
start_time=datetime.now(),
dispenser_type="dispenser",
content_hash="abc",
)
db.session.add(report)
db.session.flush()
lrc = LoadingReportComponent(
report_id=report.id,
component_id=comp.id,
component_name=comp.name,
target_weight=10.0,
actual_weight=5.0,
loading_order=1,
content_hash="def",
)
db.session.add(lrc)
db.session.commit()
def test_org_settings_roundtrip(self) -> None:
put = self.client.put(
"/api/feed-accounting/org-settings",
json={"organization_name": "ООО Тест", "okpo": "12345678"},
)
self.assertEqual(put.status_code, 200)
get = self.client.get("/api/feed-accounting/org-settings")
self.assertEqual(get.status_code, 200)
body = get.get_json()
self.assertEqual(body["organization_name"], "ООО Тест")
self.assertEqual(body.get("okpo"), "12345678")
self.assertIn("available_farms", body)
self.assertIn("signatures", body)
row = db.session.get(OrgSettings, 1)
self.assertIsNotNone(row)
self.assertEqual(row.organization_name, "ООО Тест")
self.assertEqual(row.okpo, "12345678")
def test_sp20_preview_has_lines(self) -> None:
month = datetime.now().strftime("%Y-%m")
r = self.client.get(f"/api/feed-accounting/sp20-preview?month={month}")
self.assertEqual(r.status_code, 200)
body = r.get_json()
self.assertGreaterEqual(body.get("lines_count", 0), 1)
self.assertGreater(body.get("total_kg", 0), 0)
def test_signature_png_not_found(self) -> None:
from app.services.org_settings import get_signatures_dir
sig_dir = get_signatures_dir()
backup = None
target = sig_dir / "zootechnician.png"
if target.is_file():
backup = target.read_bytes()
target.unlink()
try:
r = self.client.get("/api/feed-accounting/signatures/zootechnician.png")
self.assertEqual(r.status_code, 404)
finally:
if backup is not None:
sig_dir.mkdir(parents=True, exist_ok=True)
target.write_bytes(backup)
def test_stock_balances_xlsx_requires_auth(self) -> None:
self.client.post("/api/auth/logout")
r = self.client.get("/api/feed-accounting/stock-balances.xlsx")
self.assertEqual(r.status_code, 401)
def test_stock_balances_xlsx_ok(self) -> None:
today = datetime.now().date()
start = today.replace(day=1).isoformat()
end = today.isoformat()
r = self.client.get(
f"/api/feed-accounting/stock-balances.xlsx?date_from={start}&date_to={end}"
)
self.assertEqual(r.status_code, 200)
self.assertIn("spreadsheetml", r.content_type)
self.assertGreater(len(r.data), 100)
def test_consumption_xlsx_requires_auth(self) -> None:
self.client.post("/api/auth/logout")
r = self.client.get("/api/feed-accounting/consumption.xlsx")
self.assertEqual(r.status_code, 401)
def test_consumption_xlsx_ok(self) -> None:
today = datetime.now().date()
start = today.replace(day=1).isoformat()
end = today.isoformat()
r = self.client.get(
f"/api/feed-accounting/consumption.xlsx?date_from={start}&date_to={end}"
)
self.assertEqual(r.status_code, 200)
self.assertIn("spreadsheetml", r.content_type)
cd = r.headers.get("Content-Disposition") or ""
self.assertIn("filename*=UTF-8", cd)
self.assertIn(f"Potreblenie_korma_{start}_{end}.xlsx", cd)
try:
from openpyxl import load_workbook
wb = load_workbook(io.BytesIO(r.data))
self.assertEqual(wb.sheetnames, ["Сводка", "Детализация", "Расход по дням"])
self.assertGreaterEqual(wb["Детализация"].max_row, 2)
except ImportError:
pass
def test_consumption_pdf_ok(self) -> None:
today = datetime.now().date()
start = today.replace(day=1).isoformat()
end = today.isoformat()
r = self.client.get(
f"/api/feed-accounting/consumption.pdf?date_from={start}&date_to={end}"
)
self.assertEqual(r.status_code, 200)
self.assertIn("pdf", r.content_type)
cd = r.headers.get("Content-Disposition") or ""
self.assertIn("filename*=UTF-8", cd)
self.assertIn(f"Potreblenie_korma_{start}_{end}.pdf", cd)
self.assertGreater(len(r.data), 100)
self.assertTrue(r.data.startswith(b"%PDF"))
def test_sp20_xlsx_ok(self) -> None:
month = datetime.now().strftime("%Y-%m")
r = self.client.get(f"/api/feed-accounting/sp20.xlsx?month={month}")
self.assertEqual(r.status_code, 200)
self.assertIn("spreadsheetml", r.content_type)
try:
from openpyxl import load_workbook
wb = load_workbook(io.BytesIO(r.data))
self.assertEqual(wb.sheetnames, ["стр1", "стр2"])
ws1 = wb["стр1"]
self.assertGreater(len(ws1.merged_cells.ranges), 50)
bordered = sum(
1
for row in ws1.iter_rows(max_row=31, max_col=29)
for c in row
if c.border and (c.border.left.style or c.border.top.style or c.border.bottom.style)
)
self.assertGreater(bordered, 100)
self.assertEqual(ws1.cell(row=6, column=27).value, "0325020")
except ImportError:
pass
def test_journal_xlsx_ok(self) -> None:
month = datetime.now().strftime("%Y-%m")
r = self.client.get(f"/api/feed-accounting/journal.xlsx?month={month}")
self.assertEqual(r.status_code, 200)
self.assertIn("spreadsheetml", r.content_type)
def test_documents_zip_ok(self) -> None:
month = datetime.now().strftime("%Y-%m")
today = datetime.now().date()
start = today.replace(day=1).isoformat()
end = today.isoformat()
r = self.client.get(
f"/api/feed-accounting/documents.zip?month={month}&date_from={start}&date_to={end}"
)
self.assertEqual(r.status_code, 200)
self.assertIn("zip", r.content_type)
self.assertGreater(len(r.data), 200)
if __name__ == "__main__":
unittest.main()