Автоматизация отчетности в python

Использование Python для формирования отчетов в отдельно взятой компании

Эта история случилась в реальной компании, несмотря на то, что некоторые имена и события вымышлены.

Слава был рядовым разработчиком в небольшой фирме в городе N. Фирма занималась предоставлением услуг образовательным организациям. В наличии было несколько приложений, которые необходимо поддерживать, дорабатывая помаленьку, понемногу. Вот только начальство Славы не верило в его усилия и то, что он ест свой хлеб не просто так. Кроме того, начальство в информационных технологиях не так чтобы очень, но хотело понимать, что делают сотрудники и какая продуктивность у отдела продаж (который надо сказать состоял из одного с половиной человека).

Хитрым глазом смотрело начальство на менеджера по продажам и вопрошало: а что ты сделал сегодня для Родины. Продавец отвечал: провел столько то встреч, предлагал услуги стольким то людям. Руководство пришло к Славе и говорит: скажи, правду ли говорят сотрудники или так, отсебятину несут. Нужна статистика.

— Пользователи оплачивают услугу через сторонний сервис для приема онлайн платежей? Так?
— Так.
— Доступ к данному сервису у руководства компании есть?
— Есть.
— Так, наверное, там и выгрузка по платежам есть.
— Есть.
— Но нужно, чтобы был еще дополнительный отчет?
— Нужен.
— Почему?
— Потому что так удобнее, потому что ты должен, потому что “так и так”.

Справедливости ради надо сказать, что нужны были дополнительные данные.

Не долго думая Слава исполнил простенький запрос с последующим выбором в Excel.

Отчет представлял из себя набор данных в один столбец на одной странице. По началу к Славе подходили в хаотичном порядке, посередине дня и спрашивали. А вот дай ка ты отчет по этой организации, а вот теперь по этой. Не долго думая Слава решил, что хватит это терпеть и нужно делать что-то прекрасное и унифицированное, которое удовлетворяло потребности запрашивающих.

Читайте также:  Как установить рабочий сервер apache дома на windows

Возник небольшой скрипт, который позволял делать рассылку заинтересованным персоналиям:

import openpyxl, pymysql, os from smtplib import SMTP_SSL from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase from email import encoders import datetime # Excel Settings today = datetime.date.today().strftime('%d.%m.%Y') excel_file = 'Oplata_polzovateley_' + today + '.xlsx' # SQL settings host = '' user = '' passwd = '' db = '' port=0000 headers = ['id', 'email', 'Контрагент', 'Тариф', 'дата оплаты', 'дата окончания', 'Группа', 'Кол-во входов', 'тип оплаты'] # SMTP Mail settings smtp_server = 'smtp.gmail.com' mail_login = '' mail_passwd = '' receiver = [''] cc = [''] def main(): # Fetch Data from SQL server conn = pymysql.connect(host=host, user=user, passwd=passwd, db=db, port=port) cursor = conn.cursor() cursor.execute('''select * from table''') data = cursor.fetchall() conn.close() # Write Data to Excel file wb = openpyxl.Workbook() contractors = <> for item in data: diff = item[6] - item[5] item = list(item) # print(item) if diff.days > 10: item.append('полный') else: item.append('триальный') item = tuple(item) if item[0][:30] in contractors: contractors[item[0][:30]] += 1 else: wb.create_sheet(item[0][:30]) contractors[item[0][:30]] = 2 for i in range(1, len(headers) + 1): letter = openpyxl.utils.get_column_letter(i) wb[item[0][:30]][letter + '1'] = headers[i - 1] wb[item[0][:30]]['A' + str(contractors[item[0][:30]])] = contractors[item[0][:30]] - 1 for i in range(2, len(headers) + 1): letter = openpyxl.utils.get_column_letter(i) wb[item[0][:30]][letter + str(contractors[item[0][:30]])] = item[i] wb.save(excel_file) wb.remove(wb['Sheet']) wb.save(excel_file) # Compose attachment part = MIMEBase('application', "octet-stream") part.set_payload(open(excel_file, "rb").read()) encoders.encode_base64(part) part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(excel_file)) # Compose message msg = MIMEMultipart() msg['From'] = mail_login msg['To'] = ', '.join(receiver) msg['Cc'] = ', '.join(cc) msg['Subject'] = excel_file msg.attach(part) # Send mail tosend = receiver + cc smtp = SMTP_SSL('smtp.gmail.com') smtp.connect(smtp_server) smtp.login(mail_login, mail_passwd) smtp.sendmail(mail_login, tosend, msg.as_string()) smtp.quit() # Wipe file os.remove(excel_file) if __name__ == '__main__': main() 

Сделано, конечно, не очень подумал Слава. Но как говорится: “А, и так сойдет”.

Каждое утро Слава приходил на работу, запускал скрипт и отправлял письмо на почту заинтересованным лицам.
Следующим этапом стала настройка автоматической отправки. Работало это примерно так:

docker build —tag=reports.
docker run -it —rm reports

И прописью в кроне:
0 8 * * * docker run —rm foo

Каждый день в 8 утра письмо уходило. Руководство было довольно и даже начало думать, что Слава каждый день, ровно в 8 утра приходил на работу, составлял отчет в Excel, а затем руками отправлял на почту. Причем делал это и в субботу, и в воскресенье, и в снег, и в дождь, и в полярную ночь.

До поры, до времени всё было нормально и руководство терпело, но недолго. Однажды состоялась встреча, на которой объявили новый приказ. Слушайте, слушайте и не говорите, что не слышали. Сим объявляю, что каждый сотрудник, каждый день должен отчитываться вышестоящему по званию, а то еще вышестоящему. Ну в общем вы поняли.

— Каждый день?, — спросил Слава.
— Каждый день. — ответил начальник технического отдела.
— А может быть не надо?
— Надо Слава, надо.

У Славы возникло несколько вопросов по данной ситуации. Непосредственной обязанностью была доработка программного обеспечения и его отчеты должны состоять из чего-то вроде этого:
feat(Module) Fixed a bug in NoteLineCount… not seriously…
upd(Module2) Pay no attention to the man behind the curtain
fixed(Module3) I was told to leave it alone, but I have this thing called OCD, you see

* Примечание: название сообщений к коммитам взяты отсюда

Слава решил, что будет составлять отчет на их основе. Прошла неделя. Состоялся новый разговор примерно такого содержания:

— Вот вы присылаете отчеты каждый день, но прогресса не видно. Что к примеру такое: “добавлена маска при вводе номера телефона на фронт-энде”.
— Ну, вот смотрите. Раньше приходилось вводить свой номер телефона и сверять количество циферок и было неудобно. А вот так — удобно.
— Хм. Хорошо. Понятно. А как вы объясните вот это: “Рефакторинг кода для модуля Контрагенты. Функция для валидации вынесена в отдельный метод”.
— Ну, понимаете. Есть такая штука — система контроля версий, в которой указывается кто, когда и что делал. Вот смотрите. Здесь коммиты, а здесь код, который был изменен. Вот код добавлен, вот код удален.
— Хорошо. Давайте тогда так. Делайте отчет на основании этих ваших коммитов, а мы потом будем собираться и сверять как да что вы там написали.

В итоге — получилось вот что:

Скрипт брал изменения в репозитории и отправлял письмецо о том, что было сделано, а что нет.

Ранее Слава постеснялся сообщить о том, что те кто будут проверять ничегошеньки не понимают в написании кода. Может быть, руководство смыслит в продажах, покупках и прочей всякой всячине и платит деньги, но видеть будет определенные строчки кода на не очень знакомом языке, наблюдать как мерцают зеленые и красные строчки при переходе с коммита на коммит.

Да, Слава человек ответственный и работу работал, но бывали эти дни, когда код дорабатывался с трудом или было лень. Да и вообще, в целом система работала без сбоев и добавлять еще 15 слоев абстракции не хотелось, но отчеты требовалось отправлять каждый день.

Ничего не оставалось делать как стать новым Маяковским и писать отсебятину лесенкой. Но каждый день придумывать новое не слишком то хотелось. В итоге Вячеслав начал разрабатывать первое решение, которое пришло в голову и получился нехитрый код, где при отсутствии каких бы то ни было выполненных работ и запушенных изменений, составлялся отчет. Выглядело это примерно вот так:

Оставалось сделать так, чтобы формировался фейковый код с последующими коммитами. Нужно ли это делать? Время покажет.

P.S.: На этом история Славы не закончилась. Было еще несколько событий, которые повлияли на его судьбу, но это совсем другая история. Интересно почитать в комментариях схожие истории из жизни и решения, которые создавались на их основе. Вполне возможно, что проект в последующем будет дорабатываться на основе данных комментариев.

Источник

Оцените статью