create([ 'source' => 'local', 'name' => 'Equipe locale', 'slug' => 'equipe-locale', ]); $existingContact = Contact::query()->create([ 'source' => 'carddav', 'external_id' => 'uid-marie', 'first_name' => 'Ancien', 'last_name' => 'Nom', 'sms_opt_out' => true, 'is_favorite' => true, ]); $existingContact->groups()->attach($localGroup); $existingContact->phoneNumbers()->create([ 'raw_number' => '04 00 00 00 00', 'is_primary' => true, ]); $missingContact = Contact::query()->create([ 'source' => 'carddav', 'external_id' => 'uid-missing', 'last_name' => 'Disparu', ]); $this->app->bind(CardDavClientInterface::class, fn (): CardDavClientInterface => new class implements CardDavClientInterface { public function fetchCards(): array { return [ new CardDavRemoteCard( href: '/remote.php/dav/addressbooks/users/david/contacts/marie.vcf', etag: 'etag-1', vcard: <<<'VCF' BEGIN:VCARD VERSION:3.0 UID:uid-marie FN:Marie Durand N:Durand;Marie;;; EMAIL:marie@example.test TEL;TYPE=CELL:064-201-4207 CATEGORIES:Benevoles,Conseil END:VCARD VCF, ), ]; } }); $run = $this->app->make(CardDavContactSyncService::class)->sync(); $this->assertSame('success', $run->status); $this->assertSame(1, $run->fetched_contacts); $this->assertSame(1, $run->synced_contacts); $this->assertSame(1, $run->deleted_contacts); $this->assertDatabaseHas('contacts', [ 'id' => $existingContact->id, 'source' => 'carddav', 'external_id' => 'uid-marie', 'remote_etag' => 'etag-1', 'first_name' => 'Marie', 'last_name' => 'Durand', 'email' => 'marie@example.test', 'sms_opt_out' => true, 'is_favorite' => true, ]); $this->assertSoftDeleted('contacts', [ 'id' => $missingContact->id, ]); $this->assertDatabaseHas('contact_phone_numbers', [ 'contact_id' => $existingContact->id, 'raw_number' => '064-201-4207', 'normalized_number' => '+33642014207', 'is_valid' => true, 'is_mobile' => true, ]); $this->assertDatabaseHas('contact_groups', [ 'source' => 'carddav', 'external_id' => 'benevoles', 'name' => 'Benevoles', ]); $this->assertDatabaseHas('contact_contact_group', [ 'contact_id' => $existingContact->id, 'contact_group_id' => $localGroup->id, ]); $this->assertSame(1, SourceSyncRun::query()->where('source', 'carddav')->where('status', 'success')->count()); } }