diff --git a/server/backend/api/realisation.py b/server/backend/api/realisation.py deleted file mode 100644 index 4eb4bec..0000000 --- a/server/backend/api/realisation.py +++ /dev/null @@ -1,170 +0,0 @@ -import requests -import json -import pandas as pd -from server.backend.schemas.pydantic import settings -from server.backend.api.session import get_session - -class DocumentCreation: - def __init__(self, URL): - self.session = get_session({ - "Content-Type": "application/json", - "Accept": "application/json", - }) - self.url = URL - - def save_key_txt(self, document_key: str, filename: str = "./excel_files/documents.txt"): - with open(filename, "a", encoding="utf-8") as f: - f.write(document_key + "\n") - - def build_dict(self, **kwargs) -> dict: - return dict(kwargs) - - def create_document(self, **kwargs) -> str: - data = self.build_dict(**kwargs) - - self.contragent = kwargs.get("Контрагент_Key") - response = self.session.post(self.url, json=data) - response.raise_for_status() - result = response.json() - document_key = result.get("Ref_Key") or result.get("Ссылка_Key") - - if not document_key: - raise RuntimeError(f"Не удалось получить ключ документа: {result}") - - self.save_key_txt(document_key) - return document_key - - def fill_document_items_purchase(self, document_key: str, validated_rows: list): - line_url = f"{self.url}({document_key})" - - response = self.session.get(line_url) - response.raise_for_status() - document_data = response.json() - - items = document_data.get("Товары", []) - start_line = len(items) - - for idx, row in enumerate(validated_rows, start=1): - new_item = { - "LineNumber": str(start_line + idx), - "Номенклатура_Key": row.ref_key, - "Количество": row.counts, - "ЕдиницаИзмерения_Key": settings.MEASURE, - "Цена": row.price / row.counts if row.counts else 0, - "Сумма": row.price, - "СчетУчета_Key": settings.A45_02, - "СчетДоходов_Key": settings.A90_01_1, - "СчетРасходов_Key": settings.A90_02_1, - "СтавкаНДС": "НДС5", - "СуммаНДС": row.price * 5 / 105, - "СчетУчетаНДСПоРеализации_Key": settings.A90_03, - } - items.append(new_item) - - document_data["Товары"] = items - patch_response = self.session.patch(line_url, json=document_data) - patch_response.raise_for_status() - def fill_document_items_to_real(self, document_key: str, validated_rows: list): - line_url = f"{self.url}({document_key})" - - response = self.session.get(line_url) - response.raise_for_status() - document_data = response.json() - - items = document_data.get("Товары", []) - start_line = len(items) - - for idx, row in enumerate(validated_rows, start=1): - new_item = { - "LineNumber": str(start_line + idx), - "Номенклатура_Key": row.ref_key, - "Количество": row.counts, - "ЕдиницаИзмерения_Key": settings.MEASURE, - "Цена": row.price / row.counts if row.counts else 0, - "Сумма": row.price, - "СчетУчета_Key": settings.A43, - "ПереданныеСчетУчета_Key": settings.A45_02, - "СтавкаНДС": "НДС5", - "СуммаНДС": row.price * 5 / 105, - } - items.append(new_item) - - document_data["Товары"] = items - patch_response = self.session.patch(line_url, json=document_data) - patch_response.raise_for_status() -def fill_document_items_report(self, document_key:str, validated_rows:list): - line_url = f"{self.url}({document_key})" - - response = self.session.get(line_url) - response.raise_for_status() - document_data = response.json() - items = document_data.get("Покупатели",[]) - new_item={ - "LineNumber": str(len(items) + 1), - "Покупатель_Key": self.contragent - } - items.append(new_item) - document_data["Покупатели"] = items - patch_response = self.session.patch(line_url, json=document_data) - patch_response.raise_for_status() - - items = document_data.get("Товары", []) - start_line = len(items) - - for idx, row in enumerate(validated_rows, start=1): - new_item = { - "LineNumber": str(start_line + idx), - "Номенклатура_Key": row.ref_key, - "Количество": row.counts, - "ЕдиницаИзмерения_Key": settings.MEASURE, - "Цена": row.price / row.counts if row.counts else 0, - "Сумма": row.price, - "СчетУчета_Key": settings.A45_02, - "СчетДоходов_Key": settings.A90_01_1, - "СчетРасходов_Key": settings.A90_02_1, - "СтавкаНДС": "НДС5", - "СуммаНДС": row.price * 5 / 105, - "СчетУчетаНДСПоРеализации_Key": settings.A90_03, - } - items.append(new_item) - - document_data["Товары"] = items - patch_response = self.session.patch(line_url, json=document_data) - patch_response.raise_for_status() - - items = document_data.get("Возвраты", []) - new_item = { - "LineNumber": str(len(items) + 1), - "Покупатель_Key": settings.BUYER - } - items.append(new_item) - document_data["Возвраты"] = items - patch_response = self.session.patch(line_url, json=document_data) - patch_response.raise_for_status() - - - items = document_data.get("ТоварыВозвращенные", []) - start_line = len(items) - - for idx, row in enumerate(validated_rows, start=1): - new_item = { - "LineNumber": str(start_line + idx), - "Номенклатура_Key": row.ref_key, - "Количество": row.counts, - "ЕдиницаИзмерения_Key": settings.MEASURE, - "Цена": row.price / row.counts if row.counts else 0, - "Сумма": row.price, - "СчетУчета_Key": settings.A45_02, - "СчетДоходов_Key": settings.A90_01_1, - "СчетРасходов_Key": settings.A90_02_1, - "СтавкаНДС": "НДС5", - "СуммаНДС": row.price * 5 / 105, - "СчетУчетаНДСПоРеализации_Key": settings.A90_03, - "Себестоимость": 100, - "ОтражениеВУСН": "Принимаются", - } - items.append(new_item) - - document_data["ТоварыВозвращенные"] = items - patch_response = self.session.patch(line_url, json=document_data) - patch_response.raise_for_status() \ No newline at end of file diff --git a/server/backend/api/report.py b/server/backend/api/report.py index c15ad74..0a031cd 100644 --- a/server/backend/api/report.py +++ b/server/backend/api/report.py @@ -1,30 +1,170 @@ import requests import json import pandas as pd -from server.backend.schemas.pydantic import settings, CreateDocumentParams +from server.backend.schemas.pydantic import settings from server.backend.api.session import get_session -session = get_session({ - "Content-Type": "application/json", - "Accept": "application/json", -}) +class DocumentCreation: + def __init__(self, URL): + self.session = get_session({ + "Content-Type": "application/json", + "Accept": "application/json", + }) + self.url = URL -def create_document(params: CreateDocumentParams) -> int: - data = { - "Дата": params.DATE, - "ВидОперации": params.OPERATION, - "Организация_Key": settings.COMPANY, - "Контрагент_Key": params.CONTRACTOR, - "Склад_Key": settings.STORE, - "ДоговорКонтрагента_Key": params.CONTRACT, - "ДокументБезНДС": "false", - "СуммаВключаетНДС": "true", - "СчетУчетаРасчетовЗаПосредническиеУслуги_Key": params.ACCOUNT_INTERMEDIARY_SERVICES, - "СчетУчетаРасчетовПоАвансамПолученным_Key": params.ACCOUNT_ADVANCES_RECEIVED, - "СчетУчетаРасчетовПоАвансамВыданным_Key": params.ACCOUNT_ADVANCES_ISSUED, - "СчетУчетаРасчетовСКонтрагентом_Key": params.ACCOUNT_WITH_COUNTERPARTY, - } + def save_key_txt(self, document_key: str, filename: str = "./excel_files/documents.txt"): + with open(filename, "a", encoding="utf-8") as f: + f.write(document_key + "\n") - response = session.post(settings.URL_REPORT, json=data) - response.raise_for_status() - return response.status_code \ No newline at end of file + def build_dict(self, **kwargs) -> dict: + return dict(kwargs) + + def create_document(self, **kwargs) -> str: + data = self.build_dict(**kwargs) + + self.contragent = kwargs.get("Контрагент_Key") + response = self.session.post(self.url, json=data) + response.raise_for_status() + result = response.json() + document_key = result.get("Ref_Key") or result.get("Ссылка_Key") + + if not document_key: + raise RuntimeError(f"Не удалось получить ключ документа: {result}") + + self.save_key_txt(document_key) + return document_key + + def fill_document_items_purchase(self, document_key: str, validated_rows: list): + line_url = f"{self.url}({document_key})" + + response = self.session.get(line_url) + response.raise_for_status() + document_data = response.json() + + items = document_data.get("Товары", []) + start_line = len(items) + + for idx, row in enumerate(validated_rows, start=1): + new_item = { + "LineNumber": str(start_line + idx), + "Номенклатура_Key": row.ref_key, + "Количество": row.counts, + "ЕдиницаИзмерения_Key": settings.MEASURE, + "Цена": row.price / row.counts if row.counts else 0, + "Сумма": row.price, + "СчетУчета_Key": settings.A45_02, + "СчетДоходов_Key": settings.A90_01_1, + "СчетРасходов_Key": settings.A90_02_1, + "СтавкаНДС": "НДС5", + "СуммаНДС": row.price * 5 / 105, + "СчетУчетаНДСПоРеализации_Key": settings.A90_03, + } + items.append(new_item) + + document_data["Товары"] = items + patch_response = self.session.patch(line_url, json=document_data) + patch_response.raise_for_status() + def fill_document_items_to_real(self, document_key: str, validated_rows: list): + line_url = f"{self.url}({document_key})" + + response = self.session.get(line_url) + response.raise_for_status() + document_data = response.json() + + items = document_data.get("Товары", []) + start_line = len(items) + + for idx, row in enumerate(validated_rows, start=1): + new_item = { + "LineNumber": str(start_line + idx), + "Номенклатура_Key": row.ref_key, + "Количество": row.counts, + "ЕдиницаИзмерения_Key": settings.MEASURE, + "Цена": row.price / row.counts if row.counts else 0, + "Сумма": row.price, + "СчетУчета_Key": settings.A43, + "ПереданныеСчетУчета_Key": settings.A45_02, + "СтавкаНДС": "НДС5", + "СуммаНДС": row.price * 5 / 105, + } + items.append(new_item) + + document_data["Товары"] = items + patch_response = self.session.patch(line_url, json=document_data) + patch_response.raise_for_status() + def fill_document_items_report(self, document_key:str, validated_rows_real:list, validated_rows_refund:list): + line_url = f"{self.url}({document_key})" + + response = self.session.get(line_url) + response.raise_for_status() + document_data = response.json() + items = document_data.get("Покупатели",[]) + new_item={ + "LineNumber": str(len(items) + 1), + "Покупатель_Key": self.contragent + } + items.append(new_item) + document_data["Покупатели"] = items + patch_response = self.session.patch(line_url, json=document_data) + patch_response.raise_for_status() + + items = document_data.get("Товары", []) + start_line = len(items) + + for idx, row in enumerate(validated_rows_real, start=1): + new_item = { + "LineNumber": str(start_line + idx), + "Номенклатура_Key": row.ref_key, + "Количество": row.counts, + "ЕдиницаИзмерения_Key": settings.MEASURE, + "Цена": row.price / row.counts if row.counts else 0, + "Сумма": row.price, + "СчетУчета_Key": settings.A45_02, + "СчетДоходов_Key": settings.A90_01_1, + "СчетРасходов_Key": settings.A90_02_1, + "СтавкаНДС": "НДС5", + "СуммаНДС": row.price * 5 / 105, + "СчетУчетаНДСПоРеализации_Key": settings.A90_03, + } + items.append(new_item) + + document_data["Товары"] = items + patch_response = self.session.patch(line_url, json=document_data) + patch_response.raise_for_status() + + items = document_data.get("Возвраты", []) + new_item = { + "LineNumber": str(len(items) + 1), + "Покупатель_Key": settings.BUYER + } + items.append(new_item) + document_data["Возвраты"] = items + patch_response = self.session.patch(line_url, json=document_data) + patch_response.raise_for_status() + + + items = document_data.get("ТоварыВозвращенные", []) + start_line = len(items) + + for idx, row in enumerate(validated_rows_refund, start=1): + new_item = { + "LineNumber": str(start_line + idx), + "Номенклатура_Key": row.ref_key, + "Количество": row.counts, + "ЕдиницаИзмерения_Key": settings.MEASURE, + "Цена": row.price / row.counts if row.counts else 0, + "Сумма": row.price, + "СчетУчета_Key": settings.A45_02, + "СчетДоходов_Key": settings.A90_01_1, + "СчетРасходов_Key": settings.A90_02_1, + "СтавкаНДС": "НДС5", + "СуммаНДС": row.price * 5 / 105, + "СчетУчетаНДСПоРеализации_Key": settings.A90_03, + "Себестоимость": 100, + "ОтражениеВУСН": "Принимаются", + } + items.append(new_item) + + document_data["ТоварыВозвращенные"] = items + patch_response = self.session.patch(line_url, json=document_data) + patch_response.raise_for_status() \ No newline at end of file diff --git a/server/backend/handlers/ozon_handler.py b/server/backend/handlers/ozon_handler.py index e6520a1..602c6fc 100644 --- a/server/backend/handlers/ozon_handler.py +++ b/server/backend/handlers/ozon_handler.py @@ -4,9 +4,10 @@ from server.backend.api.nomenclature import processing import datetime import re def last_day_of_month(format: str): - next_month = datetime.datetime.now().replace(day=28) + datetime.timedelta(days=4) - last_day = next_month - datetime.timedelta(days=next_month.day) - return last_day.strftime(format) + today = datetime.datetime.now() + first_day_current_month = today.replace(day=1) + last_day_prev_month = first_day_current_month - datetime.timedelta(days=1) + return last_day_prev_month.strftime(format) def process_sheet(df,real_arti: int,real_quantity: int,real_sum_1: int,real_sum_2: int): # выбираем нужные колонки по индексам df = df.iloc[:, [real_arti, real_quantity, real_sum_1, real_sum_2]].copy() diff --git a/server/backend/handlers/ozon_wb_yandex_com_handler.py b/server/backend/handlers/ozon_wb_yandex_com_handler.py index 00c4f6c..3209fdb 100644 --- a/server/backend/handlers/ozon_wb_yandex_com_handler.py +++ b/server/backend/handlers/ozon_wb_yandex_com_handler.py @@ -4,9 +4,10 @@ from server.backend.api.nomenclature import processing import re import datetime def last_day_of_month(format: str): - next_month = datetime.datetime.now().replace(day=28) + datetime.timedelta(days=4) - last_day = next_month - datetime.timedelta(days=next_month.day) - return last_day.strftime(format) + today = datetime.datetime.now() + first_day_current_month = today.replace(day=1) + last_day_prev_month = (first_day_current_month - datetime.timedelta(days=1)).replace(day=1) + return last_day_prev_month.strftime(format) def process_sheet(df, real_arti:str, real_quantity:str, real_sum_1:str): df= df.iloc[2:].reset_index(drop=True) #Выборка diff --git a/server/backend/handlers/wb_handler.py b/server/backend/handlers/wb_handler.py index d321703..76a8307 100644 --- a/server/backend/handlers/wb_handler.py +++ b/server/backend/handlers/wb_handler.py @@ -2,11 +2,12 @@ from pydantic import ValidationError from server.backend.schemas.pydantic import ExcelInfo, settings,Translit from server.backend.api.nomenclature import processing import datetime - -def last_day_of_month(date_format: str): - next_month = datetime.datetime.now().replace(day=28) + datetime.timedelta(days=4) - last_day = next_month - datetime.timedelta(days=next_month.day) - return last_day.strftime(date_format) +#Доставать дату из колонки +def last_day_of_month(format: str): + today = datetime.datetime.now() + first_day_current_month = today.replace(day=1) + last_day_prev_month = first_day_current_month - datetime.timedelta(days=1) + return last_day_prev_month.strftime(format) def process_sheet(df, document_type:str): #Выборка df = df[['Артикул поставщика', 'Тип документа', 'Кол-во', 'Вайлдберриз реализовал Товар (Пр)']].copy().dropna() #copy and drop all NA values diff --git a/server/backend/handlers/yandex_handler.py b/server/backend/handlers/yandex_handler.py index 054e74b..86db072 100644 --- a/server/backend/handlers/yandex_handler.py +++ b/server/backend/handlers/yandex_handler.py @@ -4,9 +4,10 @@ from server.backend.api.nomenclature import processing import datetime import re def last_day_of_month(format: str): - next_month = datetime.datetime.now().replace(day=28) + datetime.timedelta(days=4) - last_day = next_month - datetime.timedelta(days=next_month.day) - return last_day.strftime(format) + today = datetime.datetime.now() + first_day_current_month = today.replace(day=1) + last_day_prev_month = first_day_current_month - datetime.timedelta(days=1) + return last_day_prev_month.strftime(format) def process_sheet(df, multiply_price=1, sheet_name=''): #Выборка df = df[['Ваш SKU', 'Количество, шт.', 'Сумма транзакции, ₽']].copy().dropna() #выбираем нужные колонки, делаем копию, чтобы можно было удалить None inline модом diff --git a/server/backend/schemas/pydantic.py b/server/backend/schemas/pydantic.py index 4023708..463917d 100644 --- a/server/backend/schemas/pydantic.py +++ b/server/backend/schemas/pydantic.py @@ -30,6 +30,7 @@ class Settings(BaseSettings): CONTRAGENT_OZON:str CONTRAGENT_YANDEX:str CONTRACT_RWB:str + CONTRACT_RWB1:str CONTRACT_YAN:str CONTRACT_OZON:str MEASURE:str @@ -38,6 +39,7 @@ class Settings(BaseSettings): A60_02:str A62_01:str A45_02:str + A43:str A90_01_1:str A90_02_1:str A90_03:str diff --git a/server/backend/services/excel.py b/server/backend/services/excel.py index 0ee465c..937bfa8 100644 --- a/server/backend/services/excel.py +++ b/server/backend/services/excel.py @@ -6,7 +6,7 @@ import server.backend.handlers.ozon_purchases_handler as ozon_purchases_handler import server.backend.handlers.wb_purchases_handler as wb_purchases_handler import server.backend.handlers.ozon_wb_yandex_com_handler as ozon_wb_yandex_com_handler from server.backend.schemas.pydantic import settings -from server.backend.api.realisation import fill_document_items, create_document +from server.backend.api.report import DocumentCreation class BaseHandler: def __init__(self, file_path): self.file_path = file_path @@ -32,7 +32,7 @@ class YandexHandler(BaseHandler): print("Реализация Яндекс завершена, валидированных строк:", len(validated_data[0]), "Реализация", len(validated_data[1]), "Возвраты", validated_data[2], "Дата") doc_creator = DocumentCreation(URL=settings.URL_REPORT) doc_key = doc_creator.create_document( - Date=date, + Date=validated_data[2], ВидОперации=settings.TYPE3, Контрагент_Key=settings.CONTRAGENT_YANDEX, ДоговорКонтрагента_Key=settings.CONTRACT_YAN, @@ -49,7 +49,7 @@ class YandexHandler(BaseHandler): СчетУчетаЗатрат_Key=settings.A44_01, СчетУчетаНДС_Key=settings.A19_04 ) - doc_creator.fill_document_items_purchase(doc_key, validated_data) + doc_creator.fill_document_items_report(doc_key, validated_data[0], validated_data[1]) class WBHandler(BaseHandler): def process(self): dfs = self.read() @@ -59,7 +59,7 @@ class WBHandler(BaseHandler): print("Реализация WB завершена, валидированных строк:", len(validated_data[0]), "Реализация", len(validated_data[1]), "Возвраты", validated_data[2], "Дата") doc_creator = DocumentCreation(URL=settings.URL_REPORT) doc_key = doc_creator.create_document( - Date=date, + Date=validated_data[2], ВидОперации=settings.TYPE3, Контрагент_Key=settings.CONTRAGENT_RWB, ДоговорКонтрагента_Key=settings.CONTRACT_RWB, @@ -76,7 +76,7 @@ class WBHandler(BaseHandler): СчетУчетаЗатрат_Key=settings.A44_01, СчетУчетаНДС_Key=settings.A19_04 ) - doc_creator.fill_document_items_purchase(doc_key, validated_data) + doc_creator.fill_document_items_report(doc_key, validated_data[0], validated_data[1]) class OZONHandler(BaseHandler): def process(self): dfs = self.read(skiprows=14, skipfooter=17) @@ -86,7 +86,7 @@ class OZONHandler(BaseHandler): print("Реализация OZON завершена, валидированных строк:", len(validated_data[0]), "Реализация", len(validated_data[1]), "Возвраты", validated_data[2], "Дата") doc_creator = DocumentCreation(URL=settings.URL_REPORT) doc_key = doc_creator.create_document( - Date=date, + Date=validated_data[2], ВидОперации=settings.TYPE3, Контрагент_Key=settings.CONTRAGENT_OZON, ДоговорКонтрагента_Key=settings.CONTRACT_OZON, @@ -103,7 +103,7 @@ class OZONHandler(BaseHandler): СчетУчетаЗатрат_Key=settings.A44_01, СчетУчетаНДС_Key=settings.A19_04 ) - doc_creator.fill_document_items_purchase(doc_key, validated_data) + doc_creator.fill_document_items_report(doc_key, validated_data[0], validated_data[1]) class OZONPurchasesHandler(BaseHandler): def process(self): @@ -119,7 +119,6 @@ class OZONPurchasesHandler(BaseHandler): Контрагент_Key=settings.CONTRAGENT_OZON, ДоговорКонтрагента_Key=settings.CONTRACT_OZON, Организация_Key=settings.COMPANY, - Склад_Key=settings.STORE, ДокументБезНДС="false", СуммаВключаетНДС="true", СчетУчетаРасчетовПоАвансам_Key=settings.A62_02, @@ -138,9 +137,8 @@ class WBPurchasesHandler(BaseHandler): Date=date, ВидОперации=settings.TYPE1, Контрагент_Key=settings.CONTRAGENT_RWB, - ДоговорКонтрагента_Key=settings.CONTRACT_RWB, + ДоговорКонтрагента_Key=settings.CONTRACT_RWB1, Организация_Key=settings.COMPANY, - Склад_Key=settings.STORE, ДокументБезНДС="false", СуммаВключаетНДС="true", СчетУчетаРасчетовПоАвансам_Key=settings.A62_02, @@ -183,8 +181,8 @@ class WBComHandler(BaseHandler): cont = df.iloc[1, 0] if cont != '"Вайлдберриз" ООО': raise Exception(f"В файле {self.file_path.name} неверный контрагент") - validated_data = ozon_wb_yandex_com_handler.evaluating(dfs) - print("Передача на коммисию WB завершена, валидированных строк:", len(validated_data[0]), "Реализация", validated_data[1], "Дата") + validated_data, date = ozon_wb_yandex_com_handler.evaluating(dfs) + print("Передача на коммисию WB завершена, валидированных строк:", len(validated_data), "Реализация", date, "Дата") doc_creator = DocumentCreation(URL=settings.URL_REALISATION) doc_key = doc_creator.create_document( Date=date, @@ -210,8 +208,8 @@ class YandexComHandler(BaseHandler): cont = df.iloc[1, 0] if cont != "Яндекс Маркет ООО": raise Exception(f"В файле {self.file_path.name} неверный контрагент") - validated_data = ozon_wb_yandex_com_handler.evaluating(dfs) - print("Передача на коммисию YANDEX завершена, валидированных строк:", len(validated_data[0]), "Реализация", validated_data[1], "Дата") + validated_data, date = ozon_wb_yandex_com_handler.evaluating(dfs) + print("Передача на коммисию YANDEX завершена, валидированных строк:", len(validated_data), "Реализация", date, "Дата") doc_creator = DocumentCreation(URL=settings.URL_REALISATION) doc_key = doc_creator.create_document( Date=date,