diff --git a/lib/CompositionManager.php b/lib/CompositionManager.php index 85d81f5..e0be254 100644 --- a/lib/CompositionManager.php +++ b/lib/CompositionManager.php @@ -465,6 +465,8 @@ class CompositionManager { ]; } + $this->compositionStore->compositionDiscard($tenantId, $userId, $identifier); + return [ 'identifier' => $identifier, 'disposition' => 'sent' diff --git a/tests/php/Unit/CompositionSynchronizationTest.php b/tests/php/Unit/CompositionSynchronizationTest.php index 76daa8f..e8eae67 100644 --- a/tests/php/Unit/CompositionSynchronizationTest.php +++ b/tests/php/Unit/CompositionSynchronizationTest.php @@ -12,6 +12,8 @@ use KTXF\Mail\Entity\EntityMutableInterface; use KTXF\Mail\Object\MessagePropertiesMutableInterface; use KTXF\Mail\Service\ServiceBaseInterface; use KTXF\Mail\Service\ServiceEntityMutableInterface; +use KTXF\Mail\Service\ServiceEntitySubmitInterface; +use KTXF\Mail\Submission\EntitySubmitResult; use KTXF\Resource\Filter\IFilter; use KTXF\Resource\Identifier\CollectionIdentifier; use KTXF\Resource\Identifier\EntityIdentifier; @@ -257,6 +259,62 @@ final class CompositionSynchronizationTest extends TestCase { )); } + public function testSendPurgesLocalCompositionOnSuccess(): void { + $this->stageComposition(); + $properties = $this->createStub(MessagePropertiesMutableInterface::class); + $service = $this->submitService($properties); + $service->method('entitySubmit')->willReturn(new EntitySubmitResult(EntitySubmitResult::DISPOSITION_SENT)); + + $mailManager = $this->createStub(\KTXM\MailManager\Manager::class); + $mailManager->method('serviceFindByAddress')->willReturn($service); + + $result = $this->compositionManager($mailManager)->send( + self::TENANT_ID, + self::USER_ID, + self::COMPOSITION_ID, + ['address' => 'sender@example.com'], + ['subject' => 'Sent draft'], + [], + ); + + $this->assertSame('sent', $result['disposition']); + $this->assertNull($this->compositionStore->compositionFetch( + self::TENANT_ID, + self::USER_ID, + self::COMPOSITION_ID, + )); + } + + public function testSendFailureKeepsLocalComposition(): void { + $this->stageComposition(); + $properties = $this->createStub(MessagePropertiesMutableInterface::class); + $service = $this->submitService($properties); + $service->method('entitySubmit')->willReturn(new EntitySubmitResult( + EntitySubmitResult::DISPOSITION_ERROR, + errorMessage: 'Transport unavailable', + )); + + $mailManager = $this->createStub(\KTXM\MailManager\Manager::class); + $mailManager->method('serviceFindByAddress')->willReturn($service); + + $result = $this->compositionManager($mailManager)->send( + self::TENANT_ID, + self::USER_ID, + self::COMPOSITION_ID, + ['address' => 'sender@example.com'], + ['subject' => 'Keep this draft'], + [], + ); + + $this->assertSame('error', $result['disposition']); + $this->assertSame('Transport unavailable', $result['error']['message']); + $this->assertNotNull($this->compositionStore->compositionFetch( + self::TENANT_ID, + self::USER_ID, + self::COMPOSITION_ID, + )); + } + private function stageComposition(?string $remoteEntity = null): void { $saveComposition = static fn(): array => [ 'identifier' => self::COMPOSITION_ID, @@ -292,6 +350,19 @@ final class CompositionSynchronizationTest extends TestCase { return $service; } + private function submitService(MessagePropertiesMutableInterface $properties): ServiceBaseInterface&ServiceEntitySubmitInterface&Stub { + $service = $this->createStubForIntersectionOfInterfaces([ + ServiceBaseInterface::class, + ServiceEntitySubmitInterface::class, + ]); + $entity = $this->createStub(EntityMutableInterface::class); + $entity->method('getProperties')->willReturn($properties); + $service->method('identifier')->willReturn('service'); + $service->method('getEnabled')->willReturn(true); + $service->method('entityFresh')->willReturn($entity); + return $service; + } + private function compositionManager(\KTXM\MailManager\Manager $mailManager): CompositionManager { return new CompositionManager( container: $this->createStub(ContainerInterface::class),