ultimatepos/Modules/Crm/Services/OfferMatchingService.php

107 lines
3.9 KiB
PHP

<?php
namespace Modules\Crm\Services;
use Modules\Crm\Entities\CrmCallAssessment;
use Modules\Crm\Entities\CrmCompany;
use Modules\Crm\Entities\CrmCompanyContact;
use Modules\Crm\Entities\CrmOfferCatalog;
class OfferMatchingService
{
public function matchForCompany(CrmCompany $company, ?CrmCallAssessment $assessment = null): array
{
$catalog = CrmOfferCatalog::where('business_id', $company->business_id)
->where('is_active', true)
->get();
$cooperation = (int) ($assessment->cooperation_score ?? 0);
$reception = (int) ($assessment->reception_score ?? 0);
$requirements = $company->requirements()->get();
$contacts = $company->contacts()->get();
$matched = [];
foreach ($catalog as $offer) {
if ($cooperation < ($offer->min_cooperation_score ?? 1)) {
continue;
}
if (! empty($offer->target_industries) && ! in_array($company->industry_category_id, $offer->target_industries)) {
continue;
}
$signals = $offer->required_signals ?? [];
if (! $this->signalsMatch($signals, $company, $requirements, $contacts, $assessment)) {
continue;
}
$matched[] = $offer;
}
if (empty($matched)) {
$matched = $this->defaultOffers($company, $contacts, $cooperation, $reception);
}
return $matched;
}
protected function signalsMatch(array $signals, CrmCompany $company, $requirements, $contacts, ?CrmCallAssessment $assessment): bool
{
if (empty($signals)) {
return true;
}
foreach ($signals as $signal) {
switch ($signal) {
case 'technical_service_needed':
if ($requirements->where('requirement_type', 'technical_service')->isEmpty()) {
return false;
}
break;
case 'raw_material_match':
if ($requirements->where('requirement_type', 'raw_material')->isEmpty()) {
return false;
}
break;
case 'partner_potential':
$hasPartner = $contacts->where('is_potential_partner', true)->isNotEmpty()
|| ($assessment && in_array($assessment->partner_potential, ['medium', 'high']));
if (! $hasPartner) {
return false;
}
break;
case 'training_needed':
if ($requirements->where('requirement_type', 'training')->isEmpty()) {
return false;
}
break;
}
}
return true;
}
protected function defaultOffers(CrmCompany $company, $contacts, int $cooperation, int $reception): array
{
$suggestions = [];
if ($cooperation >= 3 && $company->requirements()->where('requirement_type', 'technical_service')->exists()) {
$suggestions[] = (object) ['id' => null, 'name' => __('crm::lang.suggest_annual_service'), 'offer_type' => 'technical_service', 'description' => ''];
}
$partner = $contacts->first(function (CrmCompanyContact $c) use ($reception) {
return $c->is_potential_partner && $reception >= 4;
});
if ($partner) {
$suggestions[] = (object) ['id' => null, 'name' => __('crm::lang.suggest_regional_agency'), 'offer_type' => 'partnership', 'description' => ''];
}
if ($company->requirements()->where('requirement_type', 'raw_material')->exists()) {
$suggestions[] = (object) ['id' => null, 'name' => __('crm::lang.suggest_raw_material_quote'), 'offer_type' => 'spare_parts', 'description' => ''];
}
return $suggestions;
}
}