Как обрабатывать сложные пользовательские статусы?

Мое приложение имеет дело с пользовательскими платежами. В компании этот пользователь имеет следующий статус:

  • соответствует требованиям (пока пользователь оплатил все долги)
  • просроченный / дефолт (пользователь зарегистрирован минимум за 3 месяца и не выплатил хотя бы 1 долг)
  • неактивен (пользователь зарегистрирован менее 3 месяцев и не погасил задолженность)

Как лучше всего обращаться с этими правилами в нескольких местах (и правилах) внутри приложения?

Нужно ли поле как status_id а cron обновлять это каждый час?

нет status_id поле и написать правило SQL в каждом запросе, который должен показать статус?

Загрузить User модель и вызов ->status() метод, который имеет правило? В этом случае, как я могу показать «итоги», например: у нас 3000 просроченных пользователей, 15000 неактивных пользователей и т. Д.

Это вызывает у меня головную боль в течение нескольких месяцев, и мне действительно нужна помощь, ха-ха. В настоящее время у нас есть решение, но оно слишком сложное, чтобы иметь с ним дело. Поскольку в приложениях, имеющих дело с оплатой, кажется, что-то распространенное, должен быть более простой способ сделать это: P

Спасибо!

Заметки

  • Приложение в настоящее время 90.000 пользователей
  • Нам нужна эта информация в режиме реального времени.
  • Эта информация используется в отчетах для генерации символов.
  • Эта информация отображается внутри профиля пользователя.
  • Эта информация отображается в списках.
  • Пользователи получают уведомление, когда пользователь меняет статус (например, «у вас есть долги», когда пользователь входит в «просроченный»).
  • Эта информация не является управляется пользователями приложения.
  • Статус нужно отслеживать.

3

Решение

Интересный вопрос, но тоже не один с единственным ответом.

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

Одно из возможных решений, и я предполагаю некоторый уровень MVC или аналогичный.

Учитывая вашу модель, userи расширение ORM как Eloquent (я буду Eloquent от Laravel, потому что я с ним наиболее знаком, но любой ORM будет работать):

use Illuminate\Database\Eloquent\Model;
use App\DebtCollector;

public class User extends Model
{
// Assuming model has the following fields
// id, status, registration_date, and a one to many
// relationship with debts

protected $fillable = [
'raw_status',
'registration_date',
];

public function debts()
{
return $this->hasMany(Debt::class);
}

public function refreshStatus()
{
$dc = new DebtCollector();

// Business logic inside the "DebtCollector" class
$this->raw_status = $dc->resolveStatus($this->debts, $this->registration_date);

// Save value to the underlying datebase
$this->save();
}

// If you fetch a status directly, it will refresh first,
// then return the value
//
public function getStatusAttribute()
{
$this->refreshStatus();
return $this->raw_status;
}
}// Schedule task somewhere - ran nightly, or whenever
//
// This way you can refresh the status only on certain groups
// of data - for example, if the business flow means that once
// they become compliant, they can't go back, there is no need
// to refresh their status anymore
//
User::where('raw_status', '<>', 'compliant')->refreshStatus();

// Alternatively, the schedule could chunk results and do an update
// only to those not updated in the last 24 hours
//
$date = new DateTime;
$date->modify('-24 hours');
$formatted_date = $date->format('Y-m-d H:i:s');
User::where('last_updated', '>', $formatted_data)->refreshStatus();
1

Другие решения

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

Если статус изменяется из-за некоторых действий пользователя (например, обработки платежа), вы можете использовать триггер для действия. Тем не менее, изменения вашего статуса, похоже, основаны на времени после события. В этом случае вам следует запускать запланированное задание (как задание cron или событие базы данных).

Я немного озадачен тем, почему вы делаете это каждый час. Кажется, что один раз в день будет наиболее подходящим. Если «долги» выплачиваются в произвольные сроки, то в процессе оплаты следует обновить статус. Для понижения статуса достаточно одной работы в день.

3

Я бы сказал, что есть несколько решений этой проблемы.

Я бы предложил не иметь какого-либо определенного статуса. Из того, что я вижу, вы всегда можете «выяснить» текущее состояние на основе некоторых других данных.
Например, «пользователь оплатил все долги». Это то, что вы просто знаете, просто анализируя все изменения за данный период. Вы можете объединять данные, чтобы выяснить все, что вам нужно знать. Тогда вам вообще не нужно сохранять статус. Это просто происходит от всех изменений в учетной записи клиента, которые произошли за определенный период.

То же самое для итогов. Вы можете сделать это легко на уровне базы данных или даже с помощью некоторых баз данных на основе документов или ElasticSearch.

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

1
По вопросам рекламы [email protected]