CluPilotCloud/app/Services/Legal/ProcessingAgreement.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(),
],
);
}
}