В последнее время так получилось, что я начал оплачивать сотрудникам их работу каждый день. Когда я сделал это 6 раз за день я понял, что надо это дело делегировать.
Сомнения и возможные проблемы:
- Доверия к новому ассистенту мало. В банк пускать нельзя.
- Надо сделать так, чтобы я не стал узким горлышком этой проблемы. Чтобы через меня не гонялись просьбы об оплате.
- Надо чтобы было удобно сотрудникам. Чтобы не надо было как-то выкручиваться, чтобы запросить оплату.
- Отстутствие возможности проверить, а точно ли было оплачено? А вдруг куда-то деньги слились?
- Как хранить чеки, чтобы удобно было потом найти и сопоставить оплату и работу?
Требования к схеме
- Сотрудникам удобно добавлять заявку
- Сохраняются чеки
- Можно описать выполненную работу
- Прозрачность. Можно увидеть когда и за что было заплачено
- Конфиденциальность. Важно, чтобы сотрудники видели только свои заявки
Инструмент
Я решил использовать уже имеющийся инструмент — Yougile. Это что-то вроде Трелло.
Там можно настроить видимость так, чтобы каждый сотрудник видел только один столбец.
Я создал доску со всеми сотрудниками.
Настрока ролей
Далее настроил роли в доске так, чтобы менеджер видел все столбцы, а сотрудники видели только столбец со своим именем.
Сотрудник не видит столбцов, кроме своего. Он не может влиять на саму колонку. Но может создавать задачи внутри колонки, перемещать и удалять их.
И такую роль я создал под каждого сотрудника.
Выключаем все возможности в доске, а потом в конкретной колонке даём права создавать задачи.
Добавление заявки
Сотрудник при выполнении какой-то задачи будет заходить на доску и писать какую задачи он сделал и сколько я должен ему.
Либо стоимость задачи уже мне известна и я её одобрил заранее, либо у нас с сотрудником такая система оплаты: он пишет — я оплачиваю
Делегирование оплаты
Зарегистрировал аккаунт в Юмани. Дал доступ менеджеру. Записал для неё видеоинструкцию о том, как оплачивать.
Я буду отправлять туда например 30 000₽. Этого должно хватить на какое-то время. Потом когда закончится, ассистент скажет мне, я добавлю туда снова.
Единственное, что мне не нравится, это по 100−200₽ комиссии за каждый перевод. Но для меня время стоит больше этих комиссий. Может потом смогу как-то решить. Если у вас есть идеи, буду рад выслушать!
В банк я дал доступ только для создания счетов. Оплату пока никому не доверяю, потому что там не только мои деньги.
Менеджер будет заходить каждый день на доску и проверять, есть ли новые заявки. Если есть, идет оплачивать и потом прикрепляет чек в чат задачи и ставит галочку, пометив задачу как выполненную.
Выполнение изначальных требований
- Сотрудникам удобно добавлять заявку. Один клик, ввести работу и стоимость, все.
- Сохраняются чеки. Менеджер прикладывает чек конкретно к задаче.
- Можно описать выполненную работу. Задача = чат. Можно прикладывать ссылки, картинки, видео и архивы.
- Прозрачность. Можно увидеть когда и за что было заплачено. По каждому сотруднику видно список работ, стоимость и чеки. Все изменения записываются в логи сервиса.
- Конфиденциальность. Видят только свой столбец и свои задачи.
Update
Первая проблема
Все сервисы оплаты требуют подтверждение по смс. В итоге я сижу жду 10 смс с паузой в 5 минут. Решение — ассистент сделала счёт в Тинькофф, пошерила со мной, я закидываю туда, она с него закидывает сотрудникам.
Фильтрация столбцов
В какой-то момент надо было посчитать, сколько за месяц заплатил одному сотруднику. Считать вручную устали. Нашел стикер «Сумма» в Youglie. И создал стикер на каждый месяц. Теперь там нужно у каждой задачи в виджете указать сумму и месяц. После можно просто поставить фильтр по месяцу и увидеть, сколько заплачено сотруднику.
Автоматизация
Проставлять месяц и сумму надоело, поэтому я написал код, который автоматизирует. Ставит месяц исходя из текущего, а сумму парсит из названия задачи.
Код для этого. Как его вставлять, читать здесь
Добавление стикера суммы к задаче.
// Получаем стикер "Сумма"
const sumSticker = Stickers.get('Сумма');
// Функция для извлечения суммы из названия задачи
function extractSum(taskName) {
const match = taskName.match(/^(d+(?:.d+)?)(к|р)?/);
if (match) {
let sum = parseFloat(match[1]);
if (match[2] === 'к') {
sum *= 1000;
}
return Math.round(sum);
}
return null;
}
// Обработчик события создания задачи
Items.onAdd = function(task) {
if (task.type === 'Task') {
const taskName = task.name;
const sum = extractSum(taskName);
if (sum !== null) {
// Добавляем небольшую задержку перед добавлением стикера
setTimeout(() => {
Stickers.pin(task, sumSticker, sum.toString());
console.log(`Стикер 'Сумма' со значением ${sum} добавлен к задаче '${taskName}'`);
}, 500);
} else {
console.log(`Сумма не найдена в названии задачи '${taskName}'`);
}
}
};
// Для тестирования можно добавить следующий код:
// Добавляем стикер к существующим задачам
function addStickerToExistingTasks() {
for (const project of Current.company.list()) {
for (const board of project.list()) {
for (const column of board.list()) {
for (const task of column.list()) {
if (task.type === 'Task') {
const sum = extractSum(task.name);
if (sum !== null) {
Stickers.pin(task, sumSticker, sum.toString());
console.log(`Стикер 'Сумма' со значением ${sum} добавлен к существующей задаче '${task.name}'`);
}
}
}
}
}
}
}
// Раскомментируйте следующую строку, чтобы добавить стикеры к существующим задачам
// addStickerToExistingTasks();
Добавление месяца к задаче
let buttonPanel;
function createButton(text, onClick) {
const button = UI.button(text);
button.style = {
margin: '0 10px 0 0',
padding: '10px 15px',
fontSize: '14px',
fontWeight: 'bold',
backgroundColor: '#333',
color: '#fff', // Добавим белый цвет текста для контраста
border: 'none',
borderRadius: '6px',
cursor: 'pointer'
};
button.onClick = onClick;
return button;
}
function countSubscribedTasks(board) {
return board.list().reduce((count, column) =>
count + column.list().filter(task => Chat.isUserInChat(task, Current.user)).length, 0);
}
function countTasksAsExecutor(board) {
const executorSticker = Stickers.get('User');
return board.list().reduce((count, column) =>
count + column.list().filter(task =>
Stickers.getValue(task, executorSticker) === Current.user.id
).length, 0);
}
function unsubscribeFromAllTasks(board) {
let unsubscribedCount = 0;
board.list().forEach(column => {
column.list().forEach(task => {
if (Chat.isUserInChat(task, Current.user)) {
Chat.removeUser(task, Current.user);
unsubscribedCount++;
}
});
});
Notifier.success(`Вы отписались от ${unsubscribedCount} задач на этой доске.`);
}
function removeAsExecutorFromAllTasks(board) {
const executorSticker = Stickers.get('User');
let removedCount = 0;
board.list().forEach(column => {
column.list().forEach(task => {
if (Stickers.getValue(task, executorSticker) === Current.user.id) {
Stickers.unpin(task, executorSticker);
removedCount++;
}
});
});
Notifier.success(`Вы удалены как исполнитель из ${removedCount} задач на этой доске.`);
}
function createOrUpdateButtonPanel(board) {
if (!buttonPanel) {
buttonPanel = UI.panel();
buttonPanel.style = {
display: 'flex',
justifyContent: 'center',
margin: '10px 0'
};
} else {
buttonPanel.clear();
}
const unsubscribeButton = createButton(
`Отписаться от всех задач доски`,
() => {
const count = countSubscribedTasks(board);
if (confirm(`Вы уверены, что хотите отписаться от ${count} задач на этой доске?`)) {
unsubscribeFromAllTasks(board);
}
}
);
const removeExecutorButton = createButton(
`Удалить меня как исполнителя со всех задач`,
() => {
const count = countTasksAsExecutor(board);
if (confirm(`Вы уверены, что хотите удалить себя как исполнителя из ${count} задач на этой доске?`)) {
removeAsExecutorFromAllTasks(board);
}
}
);
buttonPanel.add(unsubscribeButton);
buttonPanel.add(removeExecutorButton);
return buttonPanel;
}
function addButtonPanelToBoard(board) {
const panel = createOrUpdateButtonPanel(board);
board.ui.add(panel);
}
Current.onBoardChange = function(oldBoard, newBoard) {
if (newBoard) {
addButtonPanelToBoard(newBoard);
}
};
if (Current.board) {
addButtonPanelToBoard(Current.board);
}
Канал о фрилансе
Там я делюсь фишками о фрилансе: деньги, клиенты, автоматизация, фриланс. Раньше это был закрытый материал с платным доступом. Сейчас он открыт. Иногда подписчикам будет открываться платные материалы. Подписаться