def order_shipment() -> DataFrame: """Список отгрузок заказов Если Полная_отгрузка == 1, то значит эта позиция отгрузилась и в расчете не участвует """ path = r"W:\Analytics\Илья\!outloads\Открузки_заказов (ANSITXT).txt" data = read_csv(path, sep='\t', encoding='ansi', dtype={ 'Номер победы': str }).rename( columns={ 'Заказ пр-ва (Победа)': 'Номер победы', 'Заказ (с учетом отмен)': 'Заказано' }) data = data[~data['Договор'].isna()] data['Полная_отгрузка'] = 0 data['Заказано'] = modify_col(data['Заказано'], instr=1, space=1, comma=1, numeric=1) data['Отгружено'] = modify_col(data['Отгружено'], instr=1, space=1, comma=1, numeric=1) data['Полная_отгрузка'] = data['Полная_отгрузка'].\ where(~(data['Отгружено'] >= data['Заказано']), 1) data = data[['Номер победы', 'Полная_отгрузка']].drop_duplicates() return data
def load_orders_to_supplier() -> DataFrame: """Загрузка данных о новых заказах поставщику""" path_for_date = PATH_FOR_DATE date = datetime.fromtimestamp(os_path.getmtime(path_for_date)) path = r"W:\Analytics\Илья\!outloads\Анализ_заказов_поставщикам_метизы (ANSITXT).txt" data = read_csv( path, sep='\t', encoding='ansi' ).rename( columns={'Заказ поставщику.Дата': 'Дата', 'Поступило': 'Доставлено'} ) data = data[~data['Номенклатура'].isna()] data['Заказано'] = modify_col(data['Заказано'], instr=1, space=1, comma=1, numeric=1) data['Доставлено'] = modify_col(data['Доставлено'], instr=1, space=1, comma=1, numeric=1) data['Заказано остаток'] = modify_col(data['Заказано остаток'], instr=1, space=1, comma=1, numeric=1) data['Дата'] = data['Дата'].map(lambda x: datetime.strptime(x, "%d.%m.%Y %H:%M:%S")) data = data[data['Дата'] >= date].\ groupby(by=['Номенклатура']) \ [['Заказано', 'Доставлено']].\ sum() data = data.reset_index() return data
def tn_rests(dictionary: DataFrame, short_term_plan=False) -> DataFrame: """Загузка таблицы с остатками на центральном складе, форматирование таблицы. Колонка с количеством остатком должна иметь наименование "Количество". :param dictionary: таблица из nomenclature() - справочник номенклатуры :param short_term_plan: если True, то запись остаток в папку для сохранения прошлых расчетов """ path = r"\\oemz-fs01.oemz.ru\Works$\Analytics\Илья\!outloads\!metal_tn_free (ANSITXT).txt" data = read_csv( path, sep='\t', encoding='ansi', ) data = data.rename(columns={'Доступно': "Количество", 'Артикул': 'Код'}) data = data[~data['Номенклатура'].isna()] data['Количество'] = data['Количество'].fillna(0) data['Количество'] = modify_col(data['Количество'], instr=1, space=1, comma=1, numeric=1, minus=1) data['Склад'] = 'ТН' data['Дата'] = datetime(NOW.year, NOW.month, NOW.day) data = data.merge(dictionary, on='Номенклатура', how='left').fillna('') if short_term_plan is True: data.to_csv( f'W:\\Analytics\\Илья\\!deficit_metiz_work_files\\rests_tn {NOW.strftime("%y%m%d %H_%M_%S")}.csv', sep=";", encoding='ansi', index=False ) # запись используемых файлов, для взгляда в прошлое logging.info('Остатки склада ТН загрузились') return data
def future_inputs(dictionary: DataFrame, short_term_plan=False) -> DataFrame: """Загузка таблицы с остатками на центральном складе, форматирование таблицы. Колонка с количеством остатком должна иметь наименование "Количество". :param dictionary: таблица из nomenclature() - справочник номенклатуры :param short_term_plan: если True, то запись остаток в папку для сохранения прошлых расчетов """ path = r"\\oemz-fs01.oemz.ru\Works$\Analytics\Илья\!outloads\Остатки заказов поставщикам металл (ANSITXT).txt" data = read_csv( path, sep='\t', encoding='ansi', usecols=['Дата поступления', 'Номенклатура', 'Заказано остаток']).rename(columns={ 'Дата поступления': 'Дата', 'Заказано остаток': 'Количество' }).dropna() data['Дата'] = data['Дата'].map(lambda x: datetime.strptime(x, '%d.%m.%Y')) data['Количество'] = modify_col(data['Количество'], instr=1, space=1, comma=1, numeric=1) data['Склад'] = 'Поступления' data = data.\ fillna(0).\ sort_values(by='Дата') data = data.merge(dictionary, on='Номенклатура', how='left') if short_term_plan is True: data = DataFrame(data=None, columns=list( data.columns)) # дневной дефицит без поступлений data.to_csv( r".\support_data\outloads\rest_futures_inputs.csv", sep=";", encoding='ansi', index=False) # запись используемых файлов, для взгляда в прошлое logging.info('Поступления загрузились') return data
def requirements(short_term_plan: bool = False) -> DataFrame: """Загузка таблицы с первичной потребностью (дефицитом), форматирование таблицы.""" path = r"\\oemz-fs01.oemz.ru\Works$\Analytics\Илья\!outloads\Расчет метизы (ANSITXT).txt" data = read_csv( path, sep='\t', encoding='ansi', parse_dates=['Дата запуска', 'Дата начала факт', 'Дата поступления КМД'], dayfirst=True ) if short_term_plan is True: # для краткосрочного планирования сразу обрезаем по дате end_date = NOW + timedelta(days=DAYS_AFTER) data = data[data['Дата запуска'] <= end_date] data = data[~data['Номенклатура'].isna()] data = data.fillna(value=0) data = data.rename(columns={'Обеспечена метизы': 'Заказ обеспечен'}) data['Заказ обеспечен'] = data['Заказ обеспечен'].replace({'Нет': 0, 'Да': 1}) data['Пометка удаления'] = data['Пометка удаления'].replace({'Нет': 0, 'Да': 1}) data['Номер победы'] = modify_col(data['Номер победы'], instr=1, space=1) data['Партия'] = data['Партия'].map(int) data['Партия'] = modify_col(data['Партия'], instr=1, space=1).replace({'0': '1', '0.0': '1'}) data['Количество в заказе'] = modify_col(data['Количество в заказе'], instr=1, space=1, comma=1, numeric=1) data['Дефицит'] = modify_col(data['Дефицит'], instr=1, space=1, comma=1, numeric=1).map(replace_minus) data['Перемещено'] = modify_col(data['Перемещено'], instr=1, space=1, comma=1, numeric=1, minus=1) data['Заказ обеспечен'] = modify_col(data['Заказ обеспечен'], instr=1, space=1, comma=1, numeric=1) data['Пометка удаления'] = modify_col(data['Пометка удаления'], instr=1, space=1, comma=1, numeric=1) data['Заказ-Партия'] = data['Номер победы'] + "-" + data['Партия'] data['Изделие'] = modify_col(data['Изделие'], instr=1).map(extract_product_name) data['Нельзя_заменять'] = 0 # в будущем в выгрузку добавиться колонка о запрете замены data['Количество штук'] = data['Количество штук'].map(in_float) data['Документ заказа.Статус'] = data['Документ заказа.Статус'].map(in_float) # добавляет колонки 'Закуп подтвержден', 'Возможный заказ' по данным из ПОБЕДЫ appr_orders = approved_orders(tuple(data['Номер победы'].unique())) data = merge(data, appr_orders, how='left', on='Номер победы', copy=False) # расчет Дефицита с фильтрами non_complect_orders = non_complect() order_shipments = order_shipment() data = data.\ merge(non_complect_orders, how='left', on=['Номер победы', 'Номенклатура']).\ merge(order_shipments, how='left', on='Номер победы') data['Некомплектная_отгрузка'] = data['Некомплектная_отгрузка'].fillna(0) data['Полная_отгрузка'] = data['Полная_отгрузка'].fillna(0) data['Закуп подтвержден'] = data['Закуп подтвержден'].where( ~((data['Номенклатура'].str.contains(r'5.6', regex=True)) & (data['Заказчик'] == 'СУРГУТНЕФТЕГАЗ ПАО')), 0 ) data['Дефицит'] = (data['Количество в заказе'] - data['Перемещено']).\ map(lambda x: 0 if x < 0 else x) data['Дефицит'] = data['Дефицит'].\ where( ((data['Заказ обеспечен'] == 0) & (data['Пометка удаления'] == 0) & (data['Закуп подтвержден'] == 1) & (data['Документ заказа.Статус'] != "Закрыт") & (data['Полная_отгрузка'] == 0) & (data['Изделие.Вид номенклатуры'] != 'Металл под оцинковку')), 0 ).where( ~((data['Некомплектная_отгрузка'] == 1) & (data['Полная_отгрузка'] == 1)), (data['Количество в заказе'] - data['Перемещено']).map(lambda x: 0 if x < 0 else x) ) del data['Обеспечена МП'] # del data['Обеспечена МП'], data['Заказчик'], data['Спецификация'] tn_ord = tn_orders() data = merge(data, tn_ord, how='left', on='Заказ-Партия', copy=False) # индикатор ТН в таблицу потребности if short_term_plan is True: # для краткосрочного планирования data = multiple_sort(data) # сортировка потребности и определение else: # ТОЛЬКО ДЛЯ МЕТИЗОВ # если номенклатура с ГЦ, то дату запуска делаем сегодняшней, все остальное + 1 день data['Дата запуска'] = data['Дата запуска']\ .map(lambda x: x + timedelta(days=1) if x > NOW else NOW + timedelta(days=1))\ .where(~data['Номенклатура'].str.contains(r'ГЦ|Гц', regex=True), NOW) data = data.sort_values(by='Дата запуска') # сортировка потребности и определение data = data.reset_index().rename(columns={ 'index': 'Поряд_номер', 'Документ заказа.Статус': 'Статус' }) # определение поряд номера logging.info('Потребность загрузилась') return data
def nomenclature() -> DataFrame: """Загузка таблицы со структурными данными для замен. А так же создание справочников по покрытию и прочности""" path = r"\\oemz-fs01.oemz.ru\Works$\Analytics\Илья\!outloads\Справочник_метизов_лэп (ANSITXT).txt" data = read_csv( path, sep='\t', encoding='ansi', dtype={'Номенклатура.Толщина покрытия (только для ТД)': str} ) rename_columns = { 'Номенклатура.Вид номенклатуры': 'Вид', 'Номенклатура.Марка стали (метизы только для чертежа)': 'Марка_стали', 'Номенклатура.Толщина покрытия (только для ТД)': 'Покрытие', 'Номенклатура.Стандарт на изделие': 'Гост', 'Номенклатура.Класс прочности (без чертежа)': 'Класс_прочности', 'Номенклатура.Единица для отчетов': 'Единица отчета', 'Номенклатура.Коэффициент единицы для отчетов': 'coeff' } data = data.rename(columns=rename_columns) data['coeff'] = modify_col(data['coeff'], instr=1, space=1, comma=1, numeric=1) # помещение названия в индекс # колонка названия номенклатуры остается и в таблице и в индексе для дальнейшей работы data = data.\ rename(columns={'Номенклатура': 'index'}).\ set_index('index', drop=False).\ rename(columns={'index': 'Номенклатура'}). \ fillna('') # Работы с покрытием # преобразование значений покрытия в таблице и формирование справочника data['Покрытие'] = modify_col(data['Покрытие'], instr=1, space=1) replacements_pokrit = DataFrame( data=data['Покрытие'][data['Покрытие'] != ''].unique(), columns=['Покрытие'] ) replacements_pokrit['Покрытие'] = replacements_pokrit['Покрытие'].map(int) replacements_pokrit = replacements_pokrit.sort_values(by='Покрытие') replacements_pokrit['Покрытие'] = 'ТД' + replacements_pokrit['Покрытие'].map(str) replacements_pokrit = concat([DataFrame(data=['Гл'], columns=['Покрытие']), replacements_pokrit]) replacements_pokrit = concat([replacements_pokrit, DataFrame(data=['ГЦ'], columns=['Покрытие'])]) replacements_pokrit.to_csv( r".\support_data\outloads\dict_replacement_pokrit.csv", sep='\t', encoding='ansi', index=False ) data['Покрытие'] = data['Покрытие'].\ where(data['Покрытие'] == '', 'ТД' + data['Покрытие']).\ where(~data['Номенклатура'].str.contains(r'Гл|ГЛ', regex=True), 'Гл' + data['Покрытие']).\ where(~data['Номенклатура'].str.contains(r'ГЦ|Гц', regex=True), 'ГЦ' + data['Покрытие']) # Работы с классом прочности # преобразование класса в таблице и формирование справочника data['Класс_прочности'] = modify_col(data['Класс_прочности'], instr=1, space=1, comma=1) data['Класс_прочности'] = data['Класс_прочности']. \ where(data['Класс_прочности'] == '', data['Класс_прочности'].map(in_float)) replacements_prochn = DataFrame( data=data['Класс_прочности'][data['Класс_прочности'] != ''].unique(), columns=['Класс_прочности'] ).sort_values(by='Класс_прочности') replacements_prochn.to_csv( r".\support_data\outloads\dict_replacement_prochn.csv", sep='\t', encoding='ansi', index=False ) logging.info('Номенклатура загрузилась') return data
def requirements(short_term_plan: bool = False) -> DataFrame: """Загузка таблицы с первичной потребностью (дефицитом), форматирование таблицы.""" path = r"\\oemz-fs01.oemz.ru\Works$\Analytics\Илья\!outloads\Расчет металл (ANSITXT).txt" data = read_csv(path, sep='\t', encoding='ansi', parse_dates=[ 'Дата запуска', 'Дата начала факт', 'Дата поступления КМД' ], dayfirst=True) if short_term_plan is True: # для краткосрочного планирования сразу обрезаем по дате end_date = NOW + timedelta(days=DAYS_AFTER) data = data[data['Дата запуска'] <= end_date] data = data[~data['Номенклатура'].isna()] data = data.fillna(value=0) data = data.rename(columns={'Обеспечен МП': 'Заказ обеспечен'}) data['Заказ обеспечен'] = data['Заказ обеспечен'].replace({ 'Нет': 0, 'Да': 1 }) data['Обеспечена метизы'] = data['Обеспечена метизы'].replace({ 'Нет': 0, 'Да': 1 }) data['Пометка удаления'] = data['Пометка удаления'].replace({ 'Нет': 0, 'Да': 1 }) data['Номер победы'] = modify_col(data['Номер победы'], instr=1, space=1) data['Партия'] = data['Партия'].map(int) data['Партия'] = modify_col(data['Партия'], instr=1, space=1).replace({ '0': '1', '0.0': '1' }) data['Количество в заказе'] = modify_col(data['Количество в заказе'], instr=1, space=1, comma=1, numeric=1) data['Дефицит'] = modify_col(data['Дефицит'], instr=1, space=1, comma=1, numeric=1).map(replace_minus) data['Перемещено'] = modify_col(data['Перемещено'], instr=1, space=1, comma=1, numeric=1, minus=1) data['Заказ обеспечен'] = modify_col(data['Заказ обеспечен'], instr=1, space=1, comma=1, numeric=1) data['Обеспечена метизы'] = modify_col(data['Обеспечена метизы'], instr=1, space=1, comma=1, numeric=1) data['Пометка удаления'] = modify_col(data['Пометка удаления'], instr=1, space=1, comma=1, numeric=1) data['Заказ-Партия'] = data['Номер победы'] + "-" + data['Партия'] data[ 'Нельзя_заменять'] = 0 # в будущем в выгрузку добавиться колонка о запрете замены # добавляет колонки 'Закуп подтвержден', 'Возможный заказ' по данным из ПОБЕДЫ appr_orders = approved_orders(tuple(data['Номер победы'].unique())) data = merge(data, appr_orders, how='left', on='Номер победы', copy=False) order_shipments = order_shipment() data = data.merge(order_shipments, how='left', on='Номер победы') data['Полная_отгрузка'] = data['Полная_отгрузка'].fillna(0) # если позиция это метиз, то проверяется по столбцу 'Обеспечена метизы' metiz_names = read_csv( r"\\oemz-fs01.oemz.ru\Works$\Analytics\Илья\!outloads\Справочник_только_метизов (ANSITXT).txt", sep='\t', encoding='ansi') data['Заказ обеспечен'] = data['Заказ обеспечен'].where( ~data['Номенклатура'].isin(metiz_names['Номенклатура']), data['Обеспечена метизы']) data['Дефицит'] = data['Дефицит'].where( (data['Заказ обеспечен'] == 0) & (data['Пометка удаления'] == 0) & (data['Закуп подтвержден'] == 1) & (data['Документ заказа.Статус'] != "Закрыт") & (data['Полная_отгрузка'] == 0) & (data['Изделие.Вид номенклатуры'] != 'Металл под оцинковку'), 0) data['Изделие'] = modify_col(data['Изделие'], instr=1).map(extract_product_name) del data[ 'Обеспечена метизы'] # del data['Обеспечена метизы'], data['Заказчик'], data['Спецификация'] tn_ord = tn_orders() data = merge(data, tn_ord, how='left', on='Заказ-Партия', copy=False) # индикатор ТН в таблицу потребности if short_term_plan is True: # для краткосрочного планирования сразу обрезаем по дате data = multiple_sort(data) # сортировка потребности и определение data = data[~data['Номенклатура'].str.contains( r'Табличка', regex=True)] # убираем все таблички else: data = data.sort_values( by='Дата запуска') # сортировка потребности и определение data = data.reset_index().\ rename(columns={'index': 'Поряд_номер', 'Документ заказа.Статус': 'Статус'}) # определение поряд номера logging.info('Потребность загрузилась') return data