79 lines
2.4 KiB
PHP
79 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Legal;
|
|
|
|
use App\Models\Customer;
|
|
use App\Models\DpaAcceptance;
|
|
use App\Models\DpaVersion;
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
/**
|
|
* Which agreement is in force, and whether a customer has accepted it.
|
|
*
|
|
* One place, because the same questions are asked by the customer's own page, by
|
|
* the console's register and by anything that later chases the ones outstanding
|
|
* — and three implementations of "has this customer accepted?" is three chances
|
|
* to answer differently a question that is evidence.
|
|
*
|
|
* ## Accepting an OLD version is not accepting
|
|
*
|
|
* A new version supersedes the last, so this asks about the version in force and
|
|
* nothing else. The old acceptance is kept — it was true when it was made, and
|
|
* the history is the point — but it stops satisfying the question.
|
|
*/
|
|
final class ProcessingAgreement
|
|
{
|
|
public function current(): ?DpaVersion
|
|
{
|
|
return DpaVersion::current();
|
|
}
|
|
|
|
/** The acceptance of the version in force, if there is one. */
|
|
public function acceptanceOf(?Customer $customer): ?DpaAcceptance
|
|
{
|
|
$current = $this->current();
|
|
|
|
if ($customer === null || $current === null) {
|
|
return null;
|
|
}
|
|
|
|
return DpaAcceptance::query()
|
|
->where('customer_id', $customer->id)
|
|
->where('dpa_version_id', $current->id)
|
|
->first();
|
|
}
|
|
|
|
public function accepted(?Customer $customer): bool
|
|
{
|
|
return $this->acceptanceOf($customer) !== null;
|
|
}
|
|
|
|
/**
|
|
* Record an acceptance.
|
|
*
|
|
* firstOrCreate over the pair the unique index covers: pressing twice is not
|
|
* two agreements, and a double click must not become a duplicate-key error
|
|
* in front of somebody agreeing to a contract.
|
|
*
|
|
* The address is read here rather than passed in, so no caller can record an
|
|
* acceptance as coming from somewhere it invented.
|
|
*/
|
|
public function accept(Customer $customer, ?string $ip = null): ?DpaAcceptance
|
|
{
|
|
$current = $this->current();
|
|
|
|
if ($current === null) {
|
|
return null;
|
|
}
|
|
|
|
return DpaAcceptance::query()->firstOrCreate(
|
|
['customer_id' => $customer->id, 'dpa_version_id' => $current->id],
|
|
[
|
|
'user_id' => Auth::id(),
|
|
'ip' => $ip ?? request()->ip(),
|
|
'accepted_at' => now(),
|
|
],
|
|
);
|
|
}
|
|
}
|