Decision now support auto mailing
This commit is contained in:
@@ -2,19 +2,21 @@
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Activity;
|
||||
use App\Models\Client;
|
||||
use App\Models\ClientCase;
|
||||
use App\Models\Contract;
|
||||
use App\Models\Person\Person;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class EmailTemplateRenderer
|
||||
{
|
||||
/**
|
||||
* Render subject and bodies using a simple {{ key }} replacement.
|
||||
* Supported entities: client, person, client_case, contract
|
||||
* Supported entities: client, person, client_case, contract, activity
|
||||
*
|
||||
* @param array{subject:string, html?:string|null, text?:string|null} $template
|
||||
* @param array{client?:Client, person?:Person, client_case?:ClientCase, contract?:Contract, extra?:array} $ctx
|
||||
* @param array{client?:Client, person?:Person, client_case?:ClientCase, contract?:Contract, activity?:Activity, extra?:array} $ctx
|
||||
* @return array{subject:string, html?:string, text?:string}
|
||||
*/
|
||||
public function render(array $template, array $ctx): array
|
||||
@@ -40,16 +42,66 @@ public function render(array $template, array $ctx): array
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{client?:Client, person?:Person, client_case?:ClientCase, contract?:Contract, extra?:array} $ctx
|
||||
* @param array{client?:Client, person?:Person, client_case?:ClientCase, contract?:Contract, activity?:Activity, extra?:array} $ctx
|
||||
*/
|
||||
protected function buildMap(array $ctx): array
|
||||
{
|
||||
$formatDateEu = static function ($value): string {
|
||||
if ($value === null || $value === '') {
|
||||
return '';
|
||||
}
|
||||
try {
|
||||
if ($value instanceof \DateTimeInterface) {
|
||||
return Carbon::instance($value)->format('d.m.Y');
|
||||
}
|
||||
|
||||
// Accept common formats (Y-m-d, Y-m-d H:i:s, etc.)
|
||||
return Carbon::parse((string) $value)->format('d.m.Y');
|
||||
} catch (\Throwable $e) {
|
||||
return (string) $value;
|
||||
}
|
||||
};
|
||||
|
||||
$formatMoneyEu = static function ($value): string {
|
||||
if ($value === null || $value === '') {
|
||||
return '';
|
||||
}
|
||||
$num = null;
|
||||
if (is_numeric($value)) {
|
||||
$num = (float) $value;
|
||||
} elseif (is_string($value)) {
|
||||
// Try to normalize string numbers like "1,234.56" or "1.234,56"
|
||||
$normalized = str_replace([' ', '\u{00A0}'], '', $value);
|
||||
$normalized = str_replace(['.', ','], ['.', '.'], $normalized);
|
||||
$num = is_numeric($normalized) ? (float) $normalized : null;
|
||||
}
|
||||
if ($num === null) {
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
return number_format($num, 2, ',', '.').' €';
|
||||
};
|
||||
|
||||
$out = [];
|
||||
if (isset($ctx['client'])) {
|
||||
$c = $ctx['client'];
|
||||
$out['client'] = [
|
||||
'id' => data_get($c, 'id'),
|
||||
'uuid' => data_get($c, 'uuid'),
|
||||
// Expose nested person for {{ client.person.full_name }} etc.
|
||||
'person' => [
|
||||
'first_name' => data_get($c, 'person.first_name'),
|
||||
'last_name' => data_get($c, 'person.last_name'),
|
||||
'full_name' => (function ($c) {
|
||||
$fn = (string) data_get($c, 'person.first_name', '');
|
||||
$ln = (string) data_get($c, 'person.last_name', '');
|
||||
$stored = data_get($c, 'person.full_name');
|
||||
|
||||
return (string) ($stored ?: trim(trim($fn.' '.$ln)));
|
||||
})($c),
|
||||
'email' => data_get($c, 'person.email'),
|
||||
'phone' => data_get($c, 'person.phone'),
|
||||
],
|
||||
];
|
||||
}
|
||||
if (isset($ctx['person'])) {
|
||||
@@ -68,6 +120,23 @@ protected function buildMap(array $ctx): array
|
||||
'id' => data_get($c, 'id'),
|
||||
'uuid' => data_get($c, 'uuid'),
|
||||
'reference' => data_get($c, 'reference'),
|
||||
// Expose nested person for {{ case.person.full_name }}; prefer direct relation, fallback to client.person
|
||||
'person' => [
|
||||
'first_name' => data_get($c, 'person.first_name') ?? data_get($c, 'client.person.first_name'),
|
||||
'last_name' => data_get($c, 'person.last_name') ?? data_get($c, 'client.person.last_name'),
|
||||
'full_name' => (function ($c) {
|
||||
$stored = data_get($c, 'person.full_name') ?? data_get($c, 'client.person.full_name');
|
||||
if ($stored) {
|
||||
return (string) $stored;
|
||||
}
|
||||
$fn = (string) (data_get($c, 'person.first_name') ?? data_get($c, 'client.person.first_name') ?? '');
|
||||
$ln = (string) (data_get($c, 'person.last_name') ?? data_get($c, 'client.person.last_name') ?? '');
|
||||
|
||||
return trim(trim($fn.' '.$ln));
|
||||
})($c),
|
||||
'email' => data_get($c, 'person.email') ?? data_get($c, 'client.person.email'),
|
||||
'phone' => data_get($c, 'person.phone') ?? data_get($c, 'client.person.phone'),
|
||||
],
|
||||
];
|
||||
}
|
||||
if (isset($ctx['contract'])) {
|
||||
@@ -76,13 +145,30 @@ protected function buildMap(array $ctx): array
|
||||
'id' => data_get($co, 'id'),
|
||||
'uuid' => data_get($co, 'uuid'),
|
||||
'reference' => data_get($co, 'reference'),
|
||||
'amount' => data_get($co, 'amount'),
|
||||
// Format amounts in EU style for emails
|
||||
'amount' => $formatMoneyEu(data_get($co, 'amount')),
|
||||
];
|
||||
$meta = data_get($co, 'meta');
|
||||
if (is_array($meta)) {
|
||||
$out['contract']['meta'] = $meta;
|
||||
}
|
||||
}
|
||||
if (isset($ctx['activity'])) {
|
||||
$a = $ctx['activity'];
|
||||
$out['activity'] = [
|
||||
'id' => data_get($a, 'id'),
|
||||
'note' => data_get($a, 'note'),
|
||||
// EU formatted date and amount by default in emails
|
||||
'due_date' => $formatDateEu(data_get($a, 'due_date')),
|
||||
'amount' => $formatMoneyEu(data_get($a, 'amount')),
|
||||
'action' => [
|
||||
'name' => data_get($a, 'action.name'),
|
||||
],
|
||||
'decision' => [
|
||||
'name' => data_get($a, 'decision.name'),
|
||||
],
|
||||
];
|
||||
}
|
||||
if (! empty($ctx['extra']) && is_array($ctx['extra'])) {
|
||||
$out['extra'] = $ctx['extra'];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user