feat(mcp) : outils MCP Directory pour prestataires, contacts, adresses et rapports
Ajoute 20 nouveaux outils MCP pour permettre à Claude (ou tout client MCP) de remplir un dossier client / prospect / prestataire complet — onglets Information, Contact, Adresse et Rapport — sans passer par l'UI. Entités couvertes (CRUD complet, 5 outils chacune) : - Prestataire : create / update / get / list / delete - Contact : create / update / get / list / delete - Address : create / update / get / list / delete - CommercialReport : create / update / get / list / delete Détails : - Contact / Address / CommercialReport doivent être rattachés à exactement un parent parmi clientId, prospectId, prestataireId (validation côté tool). - get-client, get-prospect et get-prestataire renvoient désormais un payload enrichi avec la liste de leurs contacts, adresses et rapports liés : un seul appel pour reconstruire l'onglet entier. - Pour CommercialReport, le type (note / call / meeting / email) et la date occurredAt sont validés ; l'auteur est rempli automatiquement par le listener existant. - Sécurité : ROLE_ADMIN aligné sur les autres outils MCP de Directory (pas de migration vers les permissions RBAC fines pour rester cohérent). Plumbing : - Repositories Contact / Address / CommercialReport : ajout de findBy() sur les interfaces (l'implémentation Doctrine l'a déjà via ServiceEntityRepository). - Bindings interface -> implémentation Doctrine ajoutés dans services.yaml pour Prestataire / Contact / Address / CommercialReport. - Sérialiseur partagé étendu : prestataire / contact / address / commercialReport / reportDocument. Vérification : 86 outils MCP exposés au total (66 avant + 20 ajoutés), test end-to-end via le transport HTTP (create-prestataire + create-contact + create-address + create-commercial-report + get-prestataire renvoyant le dossier complet). Suite PHPUnit verte. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,8 +8,13 @@ use App\Module\Absence\Domain\Entity\AbsenceBalance;
|
||||
use App\Module\Absence\Domain\Entity\AbsencePolicy;
|
||||
use App\Module\Absence\Domain\Entity\AbsenceRequest;
|
||||
use App\Module\Core\Domain\Entity\User;
|
||||
use App\Module\Directory\Domain\Entity\Address;
|
||||
use App\Module\Directory\Domain\Entity\Client;
|
||||
use App\Module\Directory\Domain\Entity\CommercialReport;
|
||||
use App\Module\Directory\Domain\Entity\Contact;
|
||||
use App\Module\Directory\Domain\Entity\Prestataire;
|
||||
use App\Module\Directory\Domain\Entity\Prospect;
|
||||
use App\Module\Directory\Domain\Entity\ReportDocument;
|
||||
use App\Module\ProjectManagement\Domain\Entity\Project;
|
||||
use App\Module\ProjectManagement\Domain\Entity\TaskDocument;
|
||||
use App\Module\ProjectManagement\Domain\Entity\TaskEffort;
|
||||
@@ -374,6 +379,98 @@ final class Serializer
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function prestataire(Prestataire $p): array
|
||||
{
|
||||
return [
|
||||
'id' => $p->getId(),
|
||||
'name' => $p->getName(),
|
||||
'email' => $p->getEmail(),
|
||||
'phone' => $p->getPhone(),
|
||||
'website' => $p->getWebsite(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function contact(Contact $c): array
|
||||
{
|
||||
return [
|
||||
'id' => $c->getId(),
|
||||
'firstName' => $c->getFirstName(),
|
||||
'lastName' => $c->getLastName(),
|
||||
'jobTitle' => $c->getJobTitle(),
|
||||
'email' => $c->getEmail(),
|
||||
'phonePrimary' => $c->getPhonePrimary(),
|
||||
'phoneSecondary' => $c->getPhoneSecondary(),
|
||||
'clientId' => $c->getClient()?->getId(),
|
||||
'prospectId' => $c->getProspect()?->getId(),
|
||||
'prestataireId' => $c->getPrestataire()?->getId(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function address(Address $a): array
|
||||
{
|
||||
return [
|
||||
'id' => $a->getId(),
|
||||
'label' => $a->getLabel(),
|
||||
'street' => $a->getStreet(),
|
||||
'streetComplement' => $a->getStreetComplement(),
|
||||
'postalCode' => $a->getPostalCode(),
|
||||
'city' => $a->getCity(),
|
||||
'country' => $a->getCountry(),
|
||||
'clientId' => $a->getClient()?->getId(),
|
||||
'prospectId' => $a->getProspect()?->getId(),
|
||||
'prestataireId' => $a->getPrestataire()?->getId(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function reportDocument(ReportDocument $d): array
|
||||
{
|
||||
return [
|
||||
'id' => $d->getId(),
|
||||
'originalName' => $d->getOriginalName(),
|
||||
'mimeType' => $d->getMimeType(),
|
||||
'size' => $d->getSize(),
|
||||
'createdAt' => $d->getCreatedAt()?->format('c'),
|
||||
'uploadedBy' => self::user($d->getUploadedBy()),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public static function commercialReport(CommercialReport $r): array
|
||||
{
|
||||
return [
|
||||
'id' => $r->getId(),
|
||||
'subject' => $r->getSubject(),
|
||||
'body' => $r->getBody(),
|
||||
'occurredAt' => $r->getOccurredAt()?->format('Y-m-d'),
|
||||
'type' => $r->getType()->value,
|
||||
'typeLabel' => $r->getType()->label(),
|
||||
'author' => self::user($r->getAuthor()),
|
||||
'clientId' => $r->getClient()?->getId(),
|
||||
'prospectId' => $r->getProspect()?->getId(),
|
||||
'prestataireId' => $r->getPrestataire()?->getId(),
|
||||
'documents' => array_map(
|
||||
fn (ReportDocument $d) => self::reportDocument($d),
|
||||
$r->getDocuments()->toArray()
|
||||
),
|
||||
'createdAt' => $r->getCreatedAt()?->format('c'),
|
||||
'updatedAt' => $r->getUpdatedAt()?->format('c'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user