Initial commit
This commit is contained in:
BIN
services/__pycache__/contractors.cpython-313.pyc
Normal file
BIN
services/__pycache__/contractors.cpython-313.pyc
Normal file
Binary file not shown.
BIN
services/__pycache__/documents.cpython-313.pyc
Normal file
BIN
services/__pycache__/documents.cpython-313.pyc
Normal file
Binary file not shown.
BIN
services/__pycache__/excel_import.cpython-313.pyc
Normal file
BIN
services/__pycache__/excel_import.cpython-313.pyc
Normal file
Binary file not shown.
BIN
services/__pycache__/sbis_import.cpython-313.pyc
Normal file
BIN
services/__pycache__/sbis_import.cpython-313.pyc
Normal file
Binary file not shown.
115
services/contractors.py
Normal file
115
services/contractors.py
Normal file
@@ -0,0 +1,115 @@
|
||||
def get_contractors(conn):
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
SELECT id, name
|
||||
FROM contractors
|
||||
WHERE active = 1
|
||||
ORDER BY name
|
||||
""")
|
||||
|
||||
return cursor.fetchall()
|
||||
|
||||
|
||||
def get_all_contractors(conn):
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
SELECT id, name, active
|
||||
FROM contractors
|
||||
ORDER BY name
|
||||
""")
|
||||
|
||||
return cursor.fetchall()
|
||||
|
||||
|
||||
def add_contractor(conn, name):
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
INSERT OR IGNORE INTO contractors(name)
|
||||
VALUES(?)
|
||||
""", (name,))
|
||||
|
||||
conn.commit()
|
||||
return cursor.rowcount > 0
|
||||
|
||||
|
||||
def add_contractors_bulk(conn, text):
|
||||
cursor = conn.cursor()
|
||||
added = 0
|
||||
exists = 0
|
||||
|
||||
for line in text.splitlines():
|
||||
name = line.strip()
|
||||
if not name:
|
||||
continue
|
||||
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT OR IGNORE INTO contractors(name)
|
||||
VALUES(?)
|
||||
""",
|
||||
(name,),
|
||||
)
|
||||
|
||||
if cursor.rowcount:
|
||||
added += 1
|
||||
else:
|
||||
exists += 1
|
||||
|
||||
conn.commit()
|
||||
return added, exists
|
||||
|
||||
|
||||
def activate_contractor(conn, contractor_id):
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
UPDATE contractors
|
||||
SET active = 1
|
||||
WHERE id = ?
|
||||
""", (contractor_id,))
|
||||
|
||||
conn.commit()
|
||||
|
||||
|
||||
def disable_contractor(conn, contractor_id):
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
UPDATE contractors
|
||||
SET active = 0
|
||||
WHERE id = ?
|
||||
""", (contractor_id,))
|
||||
|
||||
conn.commit()
|
||||
|
||||
|
||||
def delete_contractor(conn, contractor_id):
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute(
|
||||
"""
|
||||
UPDATE documents_1c
|
||||
SET contractor_id = NULL
|
||||
WHERE contractor_id = ?
|
||||
""",
|
||||
(contractor_id,),
|
||||
)
|
||||
|
||||
cursor.execute(
|
||||
"""
|
||||
DELETE FROM contractors
|
||||
WHERE id = ?
|
||||
""",
|
||||
(contractor_id,),
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
55
services/documents.py
Normal file
55
services/documents.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def update_comment_1c(conn, doc_id, comment):
|
||||
cursor = conn.cursor()
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
cursor.execute(
|
||||
"""
|
||||
UPDATE documents_1c
|
||||
SET comment = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(comment.strip(), now, doc_id),
|
||||
)
|
||||
conn.commit()
|
||||
return cursor.rowcount > 0
|
||||
|
||||
|
||||
def update_comment_sbis(conn, doc_id, comment):
|
||||
cursor = conn.cursor()
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
cursor.execute(
|
||||
"""
|
||||
UPDATE documents_sbis
|
||||
SET comment = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(comment.strip(), now, doc_id),
|
||||
)
|
||||
conn.commit()
|
||||
return cursor.rowcount > 0
|
||||
|
||||
|
||||
def get_distinct_states_1c(conn):
|
||||
rows = conn.execute(
|
||||
"""
|
||||
SELECT DISTINCT state
|
||||
FROM documents_1c
|
||||
WHERE state IS NOT NULL AND TRIM(state) != ''
|
||||
ORDER BY state COLLATE NOCASE
|
||||
"""
|
||||
).fetchall()
|
||||
return [r[0] for r in rows]
|
||||
|
||||
|
||||
def get_distinct_states_sbis(conn):
|
||||
rows = conn.execute(
|
||||
"""
|
||||
SELECT DISTINCT state
|
||||
FROM documents_sbis
|
||||
WHERE state IS NOT NULL AND TRIM(state) != ''
|
||||
ORDER BY state COLLATE NOCASE
|
||||
"""
|
||||
).fetchall()
|
||||
return [r[0] for r in rows]
|
||||
121
services/excel_import.py
Normal file
121
services/excel_import.py
Normal file
@@ -0,0 +1,121 @@
|
||||
import pandas as pd
|
||||
from datetime import datetime
|
||||
|
||||
from services.contractors import get_contractors
|
||||
|
||||
|
||||
def _find_column(df, aliases):
|
||||
for name in aliases:
|
||||
if name in df.columns:
|
||||
return name
|
||||
return None
|
||||
|
||||
|
||||
def import_excel(file, conn):
|
||||
contractors = {
|
||||
name: contractor_id
|
||||
for contractor_id, name in get_contractors(conn)
|
||||
}
|
||||
|
||||
cursor = conn.cursor()
|
||||
df = pd.read_excel(file)
|
||||
|
||||
required = {
|
||||
"contractor": _find_column(df, ["Контрагент"]),
|
||||
"doc_type": _find_column(df, ["Вид документа", "Тип документа"]),
|
||||
"doc_date": _find_column(df, ["Дата", "Дата документа"]),
|
||||
"doc_number": _find_column(df, ["Номер", "Номер документа"]),
|
||||
"amount": _find_column(df, ["Сумма"]),
|
||||
"state": _find_column(df, ["Состояние ЭДО", "Состояние", "Статус"]),
|
||||
}
|
||||
|
||||
missing = [key for key, col in required.items() if col is None]
|
||||
if missing:
|
||||
raise ValueError(
|
||||
f"В файле не найдены обязательные колонки: {', '.join(missing)}"
|
||||
)
|
||||
|
||||
imported = 0
|
||||
updated = 0
|
||||
skipped = 0
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
for _, row in df.iterrows():
|
||||
contr = str(row[required["contractor"]]).strip()
|
||||
|
||||
if contr not in contractors:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
contractor_id = contractors[contr]
|
||||
doc_type = row[required["doc_type"]]
|
||||
doc_date = row[required["doc_date"]]
|
||||
number = row[required["doc_number"]]
|
||||
summ = row[required["amount"]]
|
||||
state = row[required["state"]]
|
||||
|
||||
amount = float(summ) if pd.notna(summ) else 0
|
||||
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT id
|
||||
FROM documents_1c
|
||||
WHERE contractor_id = ?
|
||||
AND doc_type = ?
|
||||
AND doc_date = ?
|
||||
AND doc_number = ?
|
||||
AND amount = ?
|
||||
""",
|
||||
(
|
||||
contractor_id,
|
||||
str(doc_type),
|
||||
str(doc_date),
|
||||
str(number),
|
||||
amount,
|
||||
),
|
||||
)
|
||||
|
||||
document = cursor.fetchone()
|
||||
|
||||
if document:
|
||||
cursor.execute(
|
||||
"""
|
||||
UPDATE documents_1c
|
||||
SET state = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(str(state), now, document[0]),
|
||||
)
|
||||
updated += 1
|
||||
else:
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO documents_1c (
|
||||
contractor_id,
|
||||
doc_type,
|
||||
doc_date,
|
||||
doc_number,
|
||||
amount,
|
||||
state,
|
||||
comment,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
contractor_id,
|
||||
str(doc_type),
|
||||
str(doc_date),
|
||||
str(number),
|
||||
amount,
|
||||
str(state),
|
||||
"",
|
||||
now,
|
||||
now,
|
||||
),
|
||||
)
|
||||
imported += 1
|
||||
|
||||
conn.commit()
|
||||
return imported, updated, skipped
|
||||
152
services/sbis_import.py
Normal file
152
services/sbis_import.py
Normal file
@@ -0,0 +1,152 @@
|
||||
import pandas as pd
|
||||
from datetime import datetime
|
||||
|
||||
from services.contractors import get_contractors
|
||||
|
||||
|
||||
def _find_column(df, aliases):
|
||||
for name in aliases:
|
||||
if name in df.columns:
|
||||
return name
|
||||
return None
|
||||
|
||||
|
||||
def import_sbis_excel(file, conn):
|
||||
contractors = {
|
||||
name: contractor_id
|
||||
for contractor_id, name in get_contractors(conn)
|
||||
}
|
||||
|
||||
cursor = conn.cursor()
|
||||
df = pd.read_excel(file)
|
||||
|
||||
required = {
|
||||
"contractor": _find_column(
|
||||
df, ["Контрагент", "Наименование контрагента", "Организация"]
|
||||
),
|
||||
"doc_date": _find_column(df, ["Дата", "Дата документа"]),
|
||||
"doc_number": _find_column(df, ["Номер", "Номер документа"]),
|
||||
"doc_type": _find_column(df, ["Вид документа", "Тип документа", "Тип"]),
|
||||
"amount": _find_column(df, ["Сумма"]),
|
||||
"state": _find_column(df, ["Состояние", "Статус", "Состояние документа"]),
|
||||
}
|
||||
|
||||
missing = [key for key, col in required.items() if col is None]
|
||||
if missing:
|
||||
raise ValueError(
|
||||
f"В файле не найдены обязательные колонки: {', '.join(missing)}"
|
||||
)
|
||||
|
||||
responsible_col = _find_column(
|
||||
df, ["Ответственный", "Ответственный сотрудник"]
|
||||
)
|
||||
description_col = _find_column(df, ["Описание", "Комментарий", "Примечание"])
|
||||
|
||||
imported = 0
|
||||
updated = 0
|
||||
skipped = 0
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# Получаем максимальный row_order для новых записей
|
||||
cursor.execute("SELECT COALESCE(MAX(row_order), 0) FROM documents_sbis")
|
||||
max_order = cursor.fetchone()[0] or 0
|
||||
|
||||
for idx, (_, row) in enumerate(df.iterrows()):
|
||||
contr = str(row[required["contractor"]]).strip()
|
||||
|
||||
if contr not in contractors:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
doc_type = row[required["doc_type"]]
|
||||
doc_date = row[required["doc_date"]]
|
||||
number = row[required["doc_number"]]
|
||||
summ = row[required["amount"]]
|
||||
state = row[required["state"]]
|
||||
|
||||
amount = float(summ) if pd.notna(summ) else 0
|
||||
responsible = (
|
||||
str(row[responsible_col]).strip()
|
||||
if responsible_col and pd.notna(row[responsible_col])
|
||||
else None
|
||||
)
|
||||
description = (
|
||||
str(row[description_col]).strip()
|
||||
if description_col and pd.notna(row[description_col])
|
||||
else None
|
||||
)
|
||||
|
||||
# Проверяем существование документа
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT id
|
||||
FROM documents_sbis
|
||||
WHERE contractor = ?
|
||||
AND doc_type = ?
|
||||
AND doc_date = ?
|
||||
AND doc_number = ?
|
||||
AND amount = ?
|
||||
""",
|
||||
(
|
||||
contr,
|
||||
str(doc_type),
|
||||
str(doc_date),
|
||||
str(number),
|
||||
amount,
|
||||
),
|
||||
)
|
||||
|
||||
document = cursor.fetchone()
|
||||
|
||||
if document:
|
||||
cursor.execute(
|
||||
"""
|
||||
UPDATE documents_sbis
|
||||
SET state = ?,
|
||||
responsible = COALESCE(?, responsible),
|
||||
description = COALESCE(?, description),
|
||||
updated_at = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(str(state), responsible, description, now, document[0]),
|
||||
)
|
||||
updated += 1
|
||||
else:
|
||||
row_order = max_order + idx + 1
|
||||
cursor.execute(
|
||||
"""
|
||||
INSERT INTO documents_sbis (
|
||||
raw_text,
|
||||
doc_date,
|
||||
doc_number,
|
||||
contractor,
|
||||
doc_type,
|
||||
amount,
|
||||
description,
|
||||
state,
|
||||
responsible,
|
||||
created_at,
|
||||
updated_at,
|
||||
row_order
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
None,
|
||||
str(doc_date),
|
||||
str(number),
|
||||
contr,
|
||||
str(doc_type),
|
||||
amount,
|
||||
description,
|
||||
str(state),
|
||||
responsible,
|
||||
now,
|
||||
now,
|
||||
row_order,
|
||||
),
|
||||
)
|
||||
imported += 1
|
||||
|
||||
conn.commit()
|
||||
return imported, updated, skipped
|
||||
Reference in New Issue
Block a user