CRM/backend/app/Services/DuplicateService.php

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

مخزن ambiguous runes header

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

<?php
namespace App\Services;
use App\Models\Company;
use App\Models\Contact;
use App\Models\Lead;
use App\Models\MergeHistory;
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): 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 ($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): array
{
$phone = self::normalizePhone($payload['phone'] ?? null);
$email = strtolower((string) ($payload['email'] ?? ''));
$company = self::normalizeName($payload['company'] ?? null);
$query = Lead::query()->limit(10);
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]);
\App\Models\Deal::where('company_id', $source->id)->update(['company_id' => $target->id]);
\App\Models\Attachment::where('attachable_type', Company::class)->where('attachable_id', $source->id)->update(['attachable_id' => $target->id]);
\App\Models\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']);
});
}
}