diff --git a/env_example b/env_example index d268cbb..68e980f 100644 --- a/env_example +++ b/env_example @@ -1,5 +1,6 @@ DIR="/dir/dir/dir" PATTERN=[A-ZА-Я]{0,1}\d{4}[A-ZА-Я]{1,2}\d{0,1} +TIMEFORMAT="%Y-%m-%dT%H:%M:%S" USERNAME = "..." PASSWORD = "..." diff --git a/server/backend/handlers/ozon_handler.py b/server/backend/handlers/ozon_handler.py index 03dd323..e6520a1 100644 --- a/server/backend/handlers/ozon_handler.py +++ b/server/backend/handlers/ozon_handler.py @@ -3,17 +3,11 @@ from server.backend.schemas.pydantic import ExcelInfo,settings,Translit from server.backend.api.nomenclature import processing import datetime import re -def report_date(df, format: str): - cell = str(df.iloc[0, 4]) - match = re.search(r"\d{2}\.\d{2}\.\d{4}", cell) - if not match: - return None - dt = datetime.datetime.strptime(match.group(0), "%d.%m.%Y") - return dt.strftime(format) +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) def process_sheet(df,real_arti: int,real_quantity: int,real_sum_1: int,real_sum_2: int): - # пропускаем служебные строки - df = df.iloc[2:].reset_index(drop=True) - # выбираем нужные колонки по индексам df = df.iloc[:, [real_arti, real_quantity, real_sum_1, real_sum_2]].copy() df.dropna(inplace=True) @@ -45,5 +39,5 @@ def process_sheet(df,real_arti: int,real_quantity: int,real_sum_1: int,real_sum_ def evaluating(dfs): validated_rows_1 = process_sheet(dfs["Отчет о реализации"], real_arti=2,real_quantity=8, real_sum_1=5,real_sum_2=6) # номера столбцов от озона validated_rows_2 = process_sheet(dfs["Отчет о реализации"], real_arti=2,real_quantity=16, real_sum_1=13,real_sum_2=14)# - date=report_date(dfs["Отчет о реализации"], format=settings.TIMEFORMAT) + date=last_day_of_month(format=settings.TIMEFORMAT) return validated_rows_1, validated_rows_2, date \ No newline at end of file diff --git a/server/backend/handlers/ozon_purchases_handler.py b/server/backend/handlers/ozon_purchases_handler.py index a768ac4..9d723ba 100644 --- a/server/backend/handlers/ozon_purchases_handler.py +++ b/server/backend/handlers/ozon_purchases_handler.py @@ -2,31 +2,47 @@ from pydantic import ValidationError from server.backend.schemas.pydantic import ExcelInfo, settings,Translit from server.backend.api.nomenclature import processing import re - +import datetime +import re +import datetime +def report_date(df, format: str): + row_text = " ".join(df.iloc[0].astype(str)) + match = re.search(r"по\s+(\d{2}\.\d{2}\.\d{4})", row_text) + if not match: + return None + dt = datetime.datetime.strptime(match.group(1), "%d.%m.%Y") + return dt.strftime(format) def process_sheet(df, real_arti:int, real_quantity:int, real_sum_1:int): - #Выборка - df = df[[real_arti, real_quantity, real_sum_1]].copy().dropna() #copy and drop all NA values - df = df[(df != 0).all(axis=1)] #drop all 0 values - df = df[[real_arti, real_quantity, real_sum_1]] - df.rename(columns={real_arti: 'arti', real_quantity: 'counts', real_sum_1: 'price'}, inplace=True) #переименовываем для pydantic + df = df.iloc[2:].reset_index(drop=True) - #Нормализация + # выбор нужных столбцов ПО ПОЗИЦИИ + df = df.iloc[:, [real_arti, real_quantity, real_sum_1]].copy().dropna() + df = df[(df != 0).all(axis=1)] + + # сразу задаём нужные имена + df.columns = ['arti', 'counts', 'price'] + + # нормализация df['arti'] = df['arti'].replace(Translit.TRANSLIT, regex=True) - df['arti'] = df['arti'].astype(str).str.upper().str.extract(f'({settings.PATTERN})') #arti под regex - df['price'] = df['price'].astype(float) #Float to Int, if exists - df['counts'] = df['counts'].astype(int) #Float to Int, if exists + df['arti'] = df['arti'].astype(str).str.upper().str.extract(f'({settings.PATTERN})') + df['price'] = df['price'].astype(float) + df['counts'] = df['counts'].astype(int) #Группировка df = processing(df) #vlookup for ref_keys validated_rows, errors = [], [] - for i, row in df.iterrows(): #проходит построчно по df, где i - индекс строки, row - данные строки + for i, row in df.iterrows(): try: - validated_rows.append(ExcelInfo(**row.to_dict())) #добавляем в список проверенные данные полученные от pydantic, которые туда передаются в виде dict + validated_rows.append(ExcelInfo(**row.to_dict())) except ValidationError as e: - errors.append((i, e.errors())) #выводит ошибку и пишет номер строки + errors.append((i, e.errors())) if errors: - raise Exception(f"There are some errors with validation in Отчет о выкупленных товарах, check it ", errors) + raise Exception( + "There are some errors with validation in Отчет о выкупленных товарах", + errors + ) return validated_rows def evaluating(dfs): validated_rows_1 = process_sheet(dfs["Отчет о выкупленных товарах"], real_arti=3,real_quantity=10, real_sum_1=11) # номера столбцов от озона - return validated_rows_1 \ No newline at end of file + date=report_date(dfs["Отчет о выкупленных товарах"], format=settings.TIMEFORMAT) + return validated_rows_1, date \ No newline at end of file diff --git a/server/backend/handlers/wb_purchases_handler.py b/server/backend/handlers/wb_purchases_handler.py index 89c362e..1c58ebb 100644 --- a/server/backend/handlers/wb_purchases_handler.py +++ b/server/backend/handlers/wb_purchases_handler.py @@ -2,14 +2,22 @@ from pydantic import ValidationError from server.backend.schemas.pydantic import ExcelInfo, settings,Translit from server.backend.api.nomenclature import processing import re - +import datetime +def report_date(df, format: str): + row_text = " ".join(df.iloc[0].astype(str)) + match = re.search(r"\d{4}-\d{2}-\d{2}", row_text) + if not match: + return None + dt = datetime.datetime.strptime(match.group(0), "%Y-%m-%d") + return dt.strftime(format) def process_sheet(df, real_arti:str, real_quantity:str, real_sum_1:str): + df = df.iloc[2:].reset_index(drop=True) #Выборка - df = df[[real_arti, real_quantity, real_sum_1]].copy().dropna() #copy and drop all NA values + df = df.iloc[:, [real_arti, real_quantity, real_sum_1]].copy().dropna() + #df = df[[real_arti, real_quantity, real_sum_1]].copy().dropna() #copy and drop all NA values df = df[(df != 0).all(axis=1)] #drop all 0 values - df = df[[real_arti, real_quantity, real_sum_1]] - df.rename(columns={real_arti: 'arti', real_quantity: 'counts', real_sum_1: 'price'}, inplace=True) #переименовываем для pydantic - + #df = df[[real_arti, real_quantity, real_sum_1]] + df.rename(columns={"Unnamed: 1": 'arti', "Unnamed: 3": 'counts', "Unnamed: 4": 'price'}, inplace=True) #переименовываем для pydantic #Нормализация df['arti'] = df['arti'].astype(str).str.upper().str.extract(f'({settings.PATTERN})') #arti под regex df['arti'] = df['arti'].replace(Translit.TRANSLIT, regex=True) @@ -18,7 +26,7 @@ def process_sheet(df, real_arti:str, real_quantity:str, real_sum_1:str): #Группировка df = df.groupby('arti', as_index=False).agg({'counts': 'sum', 'price': 'sum'}) #groupping - df = processing(df) #vlookup for ref_keys + #df = processing(df) #vlookup for ref_keys validated_rows, errors = [], [] for i, row in df.iterrows(): #проходит построчно по df, где i - индекс строки, row - данные строки try: @@ -29,6 +37,8 @@ def process_sheet(df, real_arti:str, real_quantity:str, real_sum_1:str): raise Exception(f"There are some errors with validation in Sheet1, check it ", errors) return validated_rows def evaluating(dfs): - validated_rows_1 = process_sheet(dfs["Sheet1"], real_arti='Артикул',real_quantity="Количество", real_sum_1='''Сумма выкупа, руб., -(вкл. НДС)''') # номера столбцов от озона - return validated_rows_1 \ No newline at end of file +# validated_rows_1 = process_sheet(dfs["Sheet1"], real_arti='Артикул',real_quantity="Количество", real_sum_1='''Сумма выкупа, руб., +# (вкл. НДС)''') # номера столбцов от озона + validated_rows_1 = process_sheet(dfs["Sheet1"], real_arti=1,real_quantity=3, real_sum_1=4) # номера столбцов от озона + date=report_date(dfs["Sheet1"], format=settings.TIMEFORMAT) + return validated_rows_1, date \ No newline at end of file diff --git a/server/backend/schemas/pydantic.py b/server/backend/schemas/pydantic.py index ac6b70b..3ada5e7 100644 --- a/server/backend/schemas/pydantic.py +++ b/server/backend/schemas/pydantic.py @@ -4,7 +4,7 @@ class ExcelInfo(BaseModel): arti:str = Field(..., min_length=5, max_length=12, description="arti of the clothes") counts:int = Field(..., gt=0, description="the quantity of the clothes") price:float = Field(..., gt=0, description="the price of the clothes") - ref_key:str = Field(..., description="reffering key from db") + #ref_key:str = Field(..., description="reffering key from db") class ExcelRealization(BaseModel): pass class ExcelReturning(BaseModel): diff --git a/server/backend/services/excel.py b/server/backend/services/excel.py index 1d2632d..fe8d07e 100644 --- a/server/backend/services/excel.py +++ b/server/backend/services/excel.py @@ -43,7 +43,7 @@ class WBHandler(BaseHandler): class OZONHandler(BaseHandler): def process(self): #Доставать № документа и дату - dfs = self.read(skiprows=[0,3,4,5,6,7,8,9,10,11,12,13], skipfooter=17) + dfs = self.read(skiprows=14, skipfooter=17) if "Отчет о реализации" not in dfs: raise Exception(f"В файле {self.file_path.name} отсутствуют необходимые листы") validated_data = ozon_handler.evaluating(dfs) @@ -51,19 +51,19 @@ class OZONHandler(BaseHandler): class OZONPurchasesHandler(BaseHandler): def process(self): #доставать дату и номер документа - dfs = self.read(skiprows=12, skipfooter=1) + dfs = self.read(skiprows=[0,3,4,5,6,7,8,9,10,11], skipfooter=1) if "Отчет о выкупленных товарах" not in dfs: raise Exception(f"В файле {self.file_path.name} отсутствуют необходимые листы") validated_data = ozon_purchases_handler.evaluating(dfs) - print("Выкупы OZON завершены, валидированных строк:", len(validated_data), "Реализация") + print("Выкупы OZON завершены, валидированных строк:", len(validated_data[0]), "Реализация", validated_data[1], "Дата") class WBPurchasesHandler(BaseHandler): def process(self): - dfs = self.read(skiprows=9, skipfooter=7) + dfs = self.read(skiprows=[0,3,4,5,6,7,8], skipfooter=7) if "Sheet1" not in dfs: raise Exception(f"В файле {self.file_path.name} отсутствуют необходимые листы") validated_data = wb_purchases_handler.evaluating(dfs) - print("Выкупы WB завершены, валидированных строк:", len(validated_data), "Реализация") + print("Выкупы WB завершены, валидированных строк:", len(validated_data[0]), "Реализация", validated_data[1], "Дата" ) class OZONComHandler(BaseHandler): def process(self):