← Назад в «Блог»
306

Делегирование оплат сотрудникам

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

Сомнения и возможные проблемы:

  • Доверия к новому ассистенту мало. В банк пускать нельзя.
  • Надо сделать так, чтобы я не стал узким горлышком этой проблемы. Чтобы через меня не гонялись просьбы об оплате.
  • Надо чтобы было удобно сотрудникам. Чтобы не надо было как-то выкручиваться, чтобы запросить оплату.
  • Отстутствие возможности проверить, а точно ли было оплачено? А вдруг куда-то деньги слились?
  • Как хранить чеки, чтобы удобно было потом найти и сопоставить оплату и работу?

Требования к схеме

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

Инструмент

Я решил использовать уже имеющийся инструмент — Yougile. Это что-то вроде Трелло.

Там можно настроить видимость так, чтобы каждый сотрудник видел только один столбец.

Я создал доску со всеми сотрудниками.

Делегирование оплат сотрудникам 1

Настрока ролей

Далее настроил роли в доске так, чтобы менеджер видел все столбцы, а сотрудники видели только столбец со своим именем.

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

И такую роль я создал под каждого сотрудника.

Делегирование оплат сотрудникам 2

Выключаем все возможности в доске, а потом в конкретной колонке даём права создавать задачи.

Список настроек

Добавление заявки

Сотрудник при выполнении какой-то задачи будет заходить на доску и писать какую задачи он сделал и сколько я должен ему.

Либо стоимость задачи уже мне известна и я её одобрил заранее, либо у нас с сотрудником такая система оплаты: он пишет — я оплачиваю

Делегирование оплат сотрудникам 3

Делегирование оплаты

Зарегистрировал аккаунт в Юмани. Дал доступ менеджеру. Записал для неё видеоинструкцию о том, как оплачивать.

Я буду отправлять туда например 30 000₽. Этого должно хватить на какое-то время. Потом когда закончится, ассистент скажет мне, я добавлю туда снова.

Единственное, что мне не нравится, это по 100−200₽ комиссии за каждый перевод. Но для меня время стоит больше этих комиссий. Может потом смогу как-то решить. Если у вас есть идеи, буду рад выслушать!

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

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

Делегирование оплат сотрудникам 4

Выполнение изначальных требований

  • Сотрудникам удобно добавлять заявку. Один клик, ввести работу и стоимость, все.
  • Сохраняются чеки. Менеджер прикладывает чек конкретно к задаче.
  • Можно описать выполненную работу. Задача = чат. Можно прикладывать ссылки, картинки, видео и архивы.
  • Прозрачность. Можно увидеть когда и за что было заплачено. По каждому сотруднику видно список работ, стоимость и чеки. Все изменения записываются в логи сервиса.
  • Конфиденциальность. Видят только свой столбец и свои задачи.

Update

Первая проблема

Все сервисы оплаты требуют подтверждение по смс. В итоге я сижу жду 10 смс с паузой в 5 минут. Решение — ассистент сделала счёт в Тинькофф, пошерила со мной, я закидываю туда, она с него закидывает сотрудникам.

Фильтрация столбцов

В какой-то момент надо было посчитать, сколько за месяц заплатил одному сотруднику. Считать вручную устали. Нашел стикер «Сумма» в Youglie. И создал стикер на каждый месяц. Теперь там нужно у каждой задачи в виджете указать сумму и месяц. После можно просто поставить фильтр по месяцу и увидеть, сколько заплачено сотруднику.

Делегирование оплат сотрудникам 5

Автоматизация

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

Код для этого. Как его вставлять, читать здесь

Добавление стикера суммы к задаче.

// Получаем стикер "Сумма"
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);
}
Полезно
1
Непонятно
Поделиться
Отправить
Линкануть
Вотсапнуть

Канал о фрилансе

Там я делюсь фишками о фрилансе: деньги, клиенты, автоматизация, фриланс. Раньше это был закрытый материал с платным доступом. Сейчас он открыт. Иногда подписчикам будет открываться платные материалы. Подписаться

← Назад в «Блог»

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *