Rose debug info
---------------

Позднее Ctrl + ↑

Как я вышел из бизнеса после 19 месяцев работы

В конце 2018 года, после нескольких лет работы на «дядю», я решил, что не хочу больше ни на кого работать. Так мы с другом открыли интернет-магазин, над которым совместно проработали 19 месяцев. В итоге, я ушёл.

За это время я многому научился, набрался нового опыта и снял розовые очки. Об этом и хочу написать серию заметок. Они, в основном, будут касаться моей стороны работы.

Интернет-магазин andbo.uz

Период работы: с 25 ноября 2018 года по 15 июня 2020 года.

Должность: сооснователь, директор по маркетингу.

Темы, которые я хочу затронуть

  • Предыстория: эмоциональное выгорание
  • Партнёрское соглашение или как работать с лучшим другом
  • Как делали проморолики для товаров
  • Как искали, нанимали и обучали людей
  • Мои слабые стороны руководителя
  • Что почитать руководителю


В предыдущей серии: Школа PROWEB.

 534   2020   кейс   работа

OpenCart: как на странице товара вывести SKU и UPC

Эти значения вводятся в админке, но на странице товара не отображаются. А иногда нужно, чтобы отображались.

Что делать

  1. Открываем сайт/catalog/controller/product/product.php
  1. Находим код (~240 строка):
$data['model'] = $product_info['model'];
  1. После вставляем:
$data['sku'] = $product_info['sku'];
$data['upc'] = $product_info['upc'];
  1. Сохраняем, обновляем кэш.
  1. Открываем сайт/catalog/view/theme/тема/template/product/product.twig
  1. Находим место для выведения и вписываем:
{{ sku }}
{{ upc }}
  1. Сохраняем, обновляем кэш.
  1. Готово.
 871   2020   OpenCart 3   работа

OpenCart: как добавить фильтр по артикулу в админке

В стандартном фильтре в админке нельзя «фильтровать» товары по артикулу. Когда у вас тысячи товаров, такой фильтр в разы ускоряет поиск конкретного товара.

Что делать

  1. Открываем сайт/admin/controller/catalog/product.php
  1. Находим код (~227 строка):
protected function getList() {
  1. После фигурной скобки вставляем:
if (isset($this->request->get['filter_sku'])) {
	$filter_sku = $this->request->get['filter_sku'];
} else {
	$filter_sku = '';
}
$data['filter_sku'] = $filter_sku;
  1. В том же файле находим (~276 строка):
$url = ''
  1. После вставляем:
if (isset($this->request->get['filter_sku'])) {
	$url .= '&filter_sku=' . $this->request->get['filter_sku'];
}
  1. В том же файле находим (~324 строка):
$filter_data = array(
  1. После скобки вставляем:
'filter_sku' => isset($filter_sku) ? $filter_sku : '',
  1. Сохраняем, обновляеем кэш.
  1. Открываем сайт/admin/model/catalog/product.php
  1. Находим код (~361 строка):
if (!empty($data['filter_name'])) {
	$sql .= " AND pd.name LIKE '" . $this->db->escape($data['filter_name']) . "%'";
}
  1. После него вставляем:
if (isset($this->request->get['filter_sku']) && !empty($data['filter_sku'])) {
	$sql .= " AND p.sku = '" . $this->db->escape($data['filter_sku']) . "'";
}
  1. Сохраняем, обновляем кэш.
  1. Открываем сайт/admin/view/template/catalog/product_list.twig
  1. Находим код (~68 строка):
<div class="form-group">
	<label class="control-label" for="input-quantity">{{ entry_quantity }}</label>
	<input type="text" name="filter_quantity" value="{{ filter_quantity }}" id="input-quantity" class="form-control" />
</div>
  1. После него вставляем:
<div class="form-group">
	<label class="control-label" for="input-sku">Артикул</label>
	<input type="text" name="filter_sku" value="{{ filter_sku }}" id="input-sku" class="form-control" />
</div>
  1. В том же файле находим (~227 строка):
var filter_status = $('select[name=\'filter_status\']').val();
  1. После него вставляем:
var filter_sku = $('input[name=\'filter_sku\']').val();

if (filter_sku) {
	url += '&filter_sku=' + encodeURIComponent(filter_sku);
}
  1. Сохраняем, обновляем кэш.
  1. Готово.
 1331   2020   OpenCart 3   работа

OpenCart: как отключить кнопку покупки, когда товара нет в наличии

Когда товара нет в наличии, его, по умолчанию, можно добавить в корзину. В таком сценарии нет необходимости.

Что делать

  1. Открываем сайт/catalog/controller/product/product.php
  1. Находим код (~251 строка):
if ($product_info['quantity'] <= 0) {
	$data['stock'] = $product_info['stock_status'];
} elseif ($this->config->get('config_stock_display')) {
	$data['stock'] = $product_info['quantity'];
} else {
	$data['stock'] = $this->language->get('text_instock');
}
  1. Перед ним добавляем:
$data['stock_quantity'] = $product_info['quantity'];
$data['text_out_of_stock'] = $product_info['stock_status'];
  1. В том же файле находим (~436 строка):
$data['products'][] = array(
…
);
  1. После скобки добавляем:
'quantity' => $result['quantity'],
'text_out_of_stock' => $result['stock_status'],
  1. Сохраняем, обновляем кэш.
  1. Открываем сайт/catalog/theme/тема/template/product/product.twig
  1. Находим код:
<button type="button" id="button-cart" data-loading-text="{{ text_loading }}" class="btn button-cart">{{ button_cart }}</button>
  • В завимости от темы, код может отличаться, но button-cart остаётся константой.
  1. Заменяем его на:
{% if stock_quantity < 1 %} 
    <button type="button" id="button-outstock" disabled="disabled" data-loading-text="{{ text_loading }}" class="btn button-cart"><i class="fa fa-exclamation-triangle"></i> {{ text_out_of_stock }}</button>
{% else %}
    <button type="button" id="button-cart" data-loading-text="{{ text_loading }}" class="btn button-cart">{{ button_cart }}</button>
{% endif %}
  1. В том же файле находим:
<input type="text" name="quantity" value="{{ minimum }}" size="2" id="input-quantity" class="form-control" />
  1. Заменяем его на:
{% if stock_quantity > 1 %} 
    <input type="text" name="quantity" value="{{ minimum }}" size="2" id="input-quantity" class="form-control" />
{% endif %}
  1. В том же файле находим:
<label class="control-label" for="input-quantity">{{ entry_qty }}</label>
  1. Заменяем его на:
{% if stock_quantity > 1 %} 
    <label class="control-label" for="input-quantity">{{ entry_qty }}</label>
{% endif %}
  1. Сохраняем, обновляем кэш.
  1. Готово. На странице товара, когда его не будет в наличии, кнопка «Купить» станет неактивной.

Возникает вопрос. Вот мы отключили кнопку на странице товара. Славно. Но как быть, если кнопка есть ещё и в категориях, поиске, страницах производителей?

Всё зависит от конкретной темы. Но шаги остаются теми же, — меняются только редактируемые файлы. Например, category.php, manufacturer.php, search.php и пр.

 2954   2020   OpenCart 3   работа

Книга Д. Фрайда и Д. Х. Хенссона «Не сходите с ума на работе»

За последние три года я проработал в двух компаниях, философия которых мало чем отличалась от типичных историй из книг про успех: не останавливаемся ни на секунду, двигаемся вперёд, добиваемся максимальных результатов, включаем режим 24/7, 12 недель в году и вот это всё. Добились результатов? Хорошо. Но этого недостаточно! Двигаемся дальше.

Больше я не сторонник такого подхода. Книга об этом — перестать гнаться за успешным успехом и трудогольничать, успокоиться, начать спокойно работать и наладить жизнь.

Законспектировал, что больше всего откликнулось. А именно — рабочую философию.

Про спокойствие

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

Про амбиции

Нам, людям, всегда мало. Нам недостаточно заработать долю рынка, мы хотим захватить весь рынок. Мы боремся. Стремимся к доминированию. Хотим «раздавить» конкурентов.

«Какова наша доля рынка? Да какая разница! Достаточно ли у нас клиентов, чтобы покрыть издержки и получить прибыль? Да. Растёт ли ежегодно их число? Да. И нам этого достаточно. Ничего не зависит от доли рынка, будь она два процента, четыре или 75. Важно, что у нас здоровый бизнес с крепкой экономикой, который нас полностью устраивает. Издержки под контролем, продажи прибыльные»

Чтобы получить своё, необязательно отнимать чужое. Противоположность завоеванию — это не поражение, а участие. Быть одним из многих вариантов на рынке значит действительно давать потребителям выбор.

Про цели

Цели — квартальные, годовые, стратегические — фикция, почти всегда надуманные показатели ради самих показателей. Это выглядит как замкнутый круг: ставим цели → входим в стресс → пытаемся их достичь или аннулинируем → выбираем новые цели → входим в стресс.

«Хотим ли мы зарабатывать больше? Да. Увеличить доход? Да. Повысить эффективность? Да. Сделать продукт проще, быстрее и удобнее? Да. Сделать клиентов и сотрудников счастливее? Конечно, да. Любим ли мы усовершенствования? О, да! Стремимся ли мы делать лучше? Да, всегда. Но хотим ли мы поднимать планку „лучше“ в постоянной погоне за целью? Нет»

Чтобы хорошо работать, не нужно ничего выдумывать. Если без цели никак, пусть это будет «удержаться на рынке». Или «качественно обслуживать клиентов». Или «создать идеальную рабочую обстановку». Такие цели не измеряются числами, но от этого они не менее важны.

Про планы

Нет нужды строить планы на годы вперёд. Достаточно смотреть на то, что происходит сейчас, а не фантазировать о будущем.

«Примерно каждые шесть недель мы определяем направление дальнейшей работы. Это наш единственный план. Всё за пределами этого периода входит в категорию „там видно будет“»

Лучше корректировать курс корабля, поворачивая штурвал тысячу раз по чуть-чуть, чем как следует крутанув его единожды.

Про зону комфорта

Быть в зоне комфорта — это нормально.

«Испытывать дискомфорт, а тем более страдать ради прогресса — занятие, лишённое всякой логики. […] Конечно, иногда, на пороге прорыва, несколько последних шагов могут принести вре́менные неудобства и бывают выстраданными. Но это исключение, а не правило»

Деятельность, не доставляющая неудобств, свидетельствует о недостаточном старании. Да что вы говорите?

Про рабочие часы

По мнению авторов, 40 часов в неделю хватит, чтобы хорошо поработать, создать конкурентный продукт и сделать всё самое важное. Никаких сверхурочных допоздна и по выходным, никаких «У нас аврал, поэтому на этой неделе работаем 70-80 часов».

«Если за сорокачасовую рабочую неделю вы не успеваете сделать всё, что считаете нужным, учитесь фильтровать дела, а не сидите над ними до ночи. […] После отказа от всего лишнего останется самое необходимое. И на это как раз достаточно восьми часов в день пять раз в неделю»

Большинство людей работают не восемь часов в день, а примерно два. Остальное время съедают отвлекающие факторы.

Про эффект «присутствия»

Неважно, сколько человек работает, где находится и что делает. Главное — результат.

«„Как быть уверенным, что люди работают, если их не видишь?“ Ответ такой же, как и на другой вопрос: „А как быть уверенным, что люди работают, если их видишь?“ Никак. Единственный способ — это посмотреть на результат, в чём, собственно, и заключаются обязанности руководителя. Если результата нет, пусть сотрудник ищет другое место»

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

Про «семью» в компании

Нет никакой семьи в компании. Коллеги — да. И это не означает равнодушие друг к другу. Но это не семья.

«Basecamp — не „наше детище“. Это наш продукт. Мы хотим сделать его как можно лучше, но не пойдём за него в огонь и в воду. И вам не советуем.

Мы не пудрим мозги ни себе, ни другим. Мы вместе работаем над продуктом. И гордимся этим. Этого достаточно.

Если руководитель говорит, что ваш коллектив как одна семья — держите ухо востро. Обычно это утверждение не подразумевает, что компания будет вас любить и встанет на вашу сторону, что бы ни случилось, как положено между родственниками. Скорее вы должны будете принести единоличную жертву на корпоративный „семейный“ алтарь»

Хорошая компания — не семья. Это помощник семьи и её союзник.

Что ещё понравилось

  • Баланс — это когда здравомыслящие люди делают разумный выбор. Тогда и компания будет вменяемая.
  • Гораздо приятнее развить чей-то потенциал, чем заполучить уже состоявшегося специалиста. Большинство сотрудников в Бэйскампе наняли не за то, какими они были, а за то, какими они могли бы стать.
  • Сотрудники в Бэйскампе на одинаковых должностях и на одном уровне получают равные деньги. Одна и та же работа — одна и та же зарплата.
  • Новая схема распределения прибыли: если общий доход за год вырос, 25% распределяется между сотрудниками независимо от должности и личной эффективности. Это не комиссионное вознаграждение. Свою долю получает каждый или никто.
  • В офисах с открытой планировкой невозможна нормальная творческая деятельность, потому что для создания достойных продуктов профессионалы нуждаются в покое, тишине и уединении.
  • Если не объяснять причины увольнения, люди сами их придумают. Чтобы этого избежать, достаточно честно и внятно озвучить всем, что произошло. Даже если это трудно. Поэтому, когда кто-то уходит из Бэйскампа, всем рассылают прощальное письмо.
  • Дедлайны строгие, но фиксированные и разумные. Дата не сдвигается ни вперёд, ни назад. Меняться может только объём работы — но лишь в меньшую сторону. Нельзя устанавливать дедлайн, а потом увеличивать объём.
  • Команды действуют автономно друг от друга, а не шагают в ногу. Одно подгоняется к другому, а не приклеивается. Клиенты получают результат, как только он оказывается готовым, без оглядки на состояние других процессов.
  • Слово предоставляют каждому, кто желает предложить свои идеи и обосновать их, но решение остаётся за кем-то одним. В ситуациях «несогласия и принятия» главное, чтобы мотивы принятия итогового решения всем чётко разъяснили. Не «решили — и вперёд», а «решили, разъяснили — и вперёд».
  • «Нормально» — идеальный результат для основной части выполняемой работы. А скрупулезность лучше приберечь для выполнения действительно важных задач.
  • Почти вся работа по продукту в Бэйскампе выполняется командами в составе трёх человек. Это достаточно сильная команда, чтобы многое построить, и достаточно слабая, чтобы что-то не сломать. Проблема четверых в том, что им почти всегда нужен пятый — руководитель. А проблема пяти в том, что их слишком много.
  • Ответив сейчас «нет», позже всегда можно сказать «да». Сразу согласившись, потом труднее отказаться. Лучше знать, от чего отказаться, чем на что согласиться.
  • Чтобы создать спокойную компанию, надо решить, кто вы, кому будете служить и с кем не хотите иметь дела. Надо знать, ради чего работаешь. Единственно правильного выбора нет, нерешительность или отсутствие выбора — вот что неправильно.
  • Начинать легко — трудно удержаться на плаву. Обеспечить шоу долгую популярность сложнее, чем впервые выйти на сцену.
  • Спокойная компания — это вопрос выбора.

Вместо заключения

Этот конспект больше про философию управления компанией, про образ мысли руководителя. Но книга этим не ограничивается. Лучше читать её целиком.

А ещё, если не читали, рекомендую почитать две другие книги этих же авторов — «Rework. Бизнес без предрассудков» и «Remote. Офис не обязателен».

Про ответственность

Не понимаю людей, которые берут на себя какую-либо ответственность, а затем уворачиваются от неё. Зачем тогда браться?

На этот счёт у меня есть простой принцип:

Если что-то пообещал, сказал или взял на себя какое-либо обязательство — делаю это. Если не хочу делать — ничего не обещаю, не говорю и не беру.

Бывает и по-другому, — когда есть уважительная причина, когда ты открыто об этом говоришь и не уходишь от обязательств, а пытаешься решить вопрос. Да, при таком раскладе что-то пойдёт не по плану, но, в итоге, дело будет сделано.

 423   2020   жизнь   принципы

Как получать удовольствие от чтения

Вот что нужно запомнить.

  1. Необязательно читать книги от корки до корки.
  2. Необязательно читать с самого начала. Можно начать с любого места.
  3. Не хочется читать «воду», истории, отдельные страницы или главы — не читать.
  4. Не нравится книга — перестать читать, отложить и не париться.
  5. Хочется перечитать книгу — надо перечитать.
  6. Хочется читать тридцать книг одновременно — нет проблем, надо читать.
  7. Захотелось почитать глубокой ночью или в любое другое время — вперёд.
  8. Необязательно читать книги одинаково. Одни мы читаем, тщательно перерабатываем, анализируем, обсуждаем. Другие просто «проглатываем» и забываем. Это нормально.

В общем, вывод такой:

Читать — что хочется, сколько хочется, как хочется и когда хочется.

 1231   2020   книги   принципы   чтение

OpenCart: как скрыть товары, которых нет в наличии

Чтобы были доступны и по ссылке, и в поисковиках.

В чём проблема

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

Что делать

  1. Открыть сайт/catalog/model/catalog/product.php
  1. Открыть поиск и найти все условия:
AND p.status = '1'
  • Это условие отвечает за показ товара, когда он включён.
  1. Заменить все найденные условия (кроме одного ↓) на:
AND p.status = '1' AND p.stock_status_id != '5'
  • Это условие, при котором товар не будет отображаться: включён и нет в наличии.
  1. Не заменять условие в самом начале файла:
public function getProduct($product_id) {
…
}
  1. Сохранить, обновить кэш.
  1. Готово. Товары, которых нет в наличии, не отображаются, но доступны по прямой ссылке и отображаются в поисковиках.

Другой вариант

Допустим, что товара нет в наличии временно. И нам нужно, чтобы его видели на сайте. Тогда можно всё немного переиграть.

Что делать

  1. В том же файле открыть поиск и найти те же условия.
  1. Заменить их (также, кроме одного) на:
AND p.status = '1' AND p.minimum != '0'
  1. Сохранить, обновить кэш.
  1. Готово. Товары, которых нет в наличии, будут отображаться как обычно. Но товары, у которых минимальное количество будет равно нулю, отображаться не будут. Для них можно создать и отдельный статус, например «Снят с производства».
 3040   2020   OpenCart 3   работа

OpenCart: автогенерация сопутствующих товаров

Все сопутствующие товары, по умолчанию, добавляются вручную. Когда на сайте тысячи товаров, это становится проблемой.

Что делать

  1. Открываем сайт/catalog/model/catalog/product.php
  1. Находим код (~392 строка):
$query = $this->db->query("SELECT * FROM " . DB_PREFIX . "product_related pr LEFT JOIN " . DB_PREFIX . "product p ON (pr.related_id = p.product_id) LEFT JOIN " . DB_PREFIX . "product_to_store p2s ON (p.product_id = p2s.product_id) WHERE pr.product_id = '" . (int)$product_id . "' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "'");
  1. Заменяем его на:
$query = $this->db->query("SELECT *, (p.product_id) AS related_id FROM
  " . DB_PREFIX . "product_to_category p2c 
    LEFT JOIN " . DB_PREFIX . "product p ON (p2c.product_id = p.product_id)
    LEFT JOIN " . DB_PREFIX . "product_to_store p2s ON (p.product_id = p2s.product_id)
  WHERE 
    p2c.category_id IN (SELECT p2c2.category_id FROM " . DB_PREFIX . "product_to_category p2c2 WHERE p2c2.product_id = " . (int) $product_id . ")
      AND p.product_id <> " . (int) $product_id . "
      AND p.status = '1'
      AND p.stock_status_id != '5'
      AND p.date_available <= NOW()
      AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "'
    ORDER BY RAND() ASC
  LIMIT 0,8");
  1. Сохраняем, обновляем кэш.
  1. Готово.

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

 1540   2020   OpenCart 3   работа

OpenCart: как защитить админку

Админка, по умолчанию, находится по адресу сайт.ру/admin. Это проблема.

Что делать

  1. Открываем сайт/admin/controller/common/login.php
  1. Находим код:
$this->load->language('common/login');
  1. После него вставляем:
$pass = null;
if (!isset($_GET[PASS_KEY]) || $_GET[PASS_KEY] != PASS) {
    $this->response->redirect('http://'.$_SERVER['HTTP_HOST']."/");
}
else {
    $pass = '&'.PASS_KEY.'='.PASS;
}
  1. Находим код:
$data['action'] = $this->url->link('common/login', '', true);
  1. Заменяем его на:
$data['action'] = $this->url->link('common/login', '', true).$pass;
  1. Открываем сайт/admin/config.php
  1. После тега <?php, на новой строке, вставляем:
define('PASS_KEY', 'ключ');
define('PASS', 'пароль');
  1. Заменяем ключ, например, на access, а пароль на hellohacker.
  1. Сохраняем, обновляем кэш.
  1. Готово.
  1. Админка будет находиться по адресу сайт.ру/admin?access=hellohacker.
  1. Если адрес ввести неверно, произойдёт переадресация на главную страницу.
Ранее Ctrl + ↓