CRM/backend/app/Services/DuplicateService.php

151 خطوط
5.5 KiB
PHP
خام سرزنش تاریخچه

مخزن ambiguous runes header

راهنمای مخزن ambiguous runes توضیحات

<?php
namespace App\Services;
use App\Models\Attachment;
use App\Models\Company;
use App\Models\Contact;
use App\Models\Deal;
use App\Models\Lead;
use App\Models\MergeHistory;
use App\Models\Note;
use App\Models\User;
use App\Support\AccessControl;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class DuplicateService
{
public static function normalizePhone(?string $phone): ?string
{
if (! $phone) {
return null;
}
$digits = preg_replace('/\D+/', '', strtr($phone, ['۰' => '0', '۱' => '1', '۲' => '2', '۳' => '3', '۴' => '4', '۵' => '5', '۶' => '6', '۷' => '7', '۸' => '8', '۹' => '9', '٠' => '0', '١' => '1', '٢' => '2', '٣' => '3', '٤' => '4', '٥' => '5', '٦' => '6', '٧' => '7', '٨' => '8', '٩' => '9']));
if (! $digits) {
return null;
}
if (str_starts_with($digits, '0098')) {
$digits = '0'.substr($digits, 4);
}
if (str_starts_with($digits, '98')) {
$digits = '0'.substr($digits, 2);
}
return $digits;
}
public static function normalizeWebsite(?string $website): ?string
{
if (! $website) {
return null;
}
$value = strtolower(trim($website));
$value = preg_replace('#^https?://#', '', $value);
$value = preg_replace('#^www\.#', '', $value);
return rtrim($value, '/');
}
public static function normalizeName(?string $name): ?string
{
return $name ? Str::of($name)->lower()->squish()->toString() : null;
}
public function companySuggestions(array $payload, ?int $excludeId = null, ?User $user = null): array
{
$name = self::normalizeName($payload['name'] ?? null);
$website = self::normalizeWebsite($payload['website'] ?? null);
$email = strtolower((string) ($payload['email'] ?? ''));
$phone = self::normalizePhone($payload['phone'] ?? null);
$query = Company::query()->with('owner:id,name')->limit(10);
if ($user) {
AccessControl::scopeCompanies($query, $user);
}
if ($excludeId) {
$query->whereKeyNot($excludeId);
}
$query->where(function ($q) use ($name, $website, $email, $phone) {
if ($name) {
$q->orWhere('normalized_name', $name);
}
if ($website) {
$q->orWhere('normalized_website', $website);
}
if ($email) {
$q->orWhereHas('contacts', fn ($contact) => $contact->where('email', $email));
}
if ($phone) {
$q->orWhereHas('contacts.phones', fn ($phoneQuery) => $phoneQuery->where('phone', 'like', "%{$phone}%"));
}
});
return $query->get()->map(fn (Company $company) => [
'id' => $company->id,
'type' => 'company',
'title' => $company->name,
'reason' => 'شباهت در نام شرکت، وب‌سایت، ایمیل یا شماره تماس',
])->values()->all();
}
public function leadSuggestions(array $payload, ?int $excludeId = null, ?User $user = null): array
{
$phone = self::normalizePhone($payload['phone'] ?? null);
$email = strtolower((string) ($payload['email'] ?? ''));
$company = self::normalizeName($payload['company'] ?? null);
$query = Lead::query()->limit(10);
if ($user) {
AccessControl::scopeLeads($query, $user, false);
}
if ($excludeId) {
$query->whereKeyNot($excludeId);
}
$query->where(function ($q) use ($phone, $email, $company) {
if ($phone) {
$q->orWhere('phone', 'like', "%{$phone}%")->orWhere('phone_secondary', 'like', "%{$phone}%");
}
if ($email) {
$q->orWhere('email', $email);
}
if ($company) {
$q->orWhereRaw('LOWER(company) = ?', [$company]);
}
});
return $query->get()->map(fn (Lead $lead) => [
'id' => $lead->id,
'type' => 'lead',
'title' => $lead->company ?: $lead->full_name,
'reason' => 'شباهت در تلفن، ایمیل یا نام شرکت',
])->values()->all();
}
public function mergeCompanies(Company $source, Company $target, int $userId): Company
{
return DB::transaction(function () use ($source, $target, $userId) {
Contact::where('company_id', $source->id)->update(['company_id' => $target->id]);
Lead::where('company_id', $source->id)->update(['company_id' => $target->id]);
Deal::where('company_id', $source->id)->update(['company_id' => $target->id]);
Attachment::where('attachable_type', Company::class)->where('attachable_id', $source->id)->update(['attachable_id' => $target->id]);
Note::where('notable_type', Company::class)->where('notable_id', $source->id)->update(['notable_id' => $target->id]);
MergeHistory::create([
'entity_type' => 'company',
'source_id' => $source->id,
'target_id' => $target->id,
'merged_fields' => $source->only(['name', 'website', 'city', 'industry']),
'merged_by' => $userId,
]);
$source->delete();
ActivityLogger::log('company_merged', "Company {$source->id} merged into {$target->id}", $target);
return $target->fresh(['contacts.phones', 'leads', 'deals']);
});
}
}