Merge the CustomerService / CustomerThread endpoints into one domain PR - #418
Open
PrestaEdit wants to merge 9 commits into
Open
PrestaEdit wants to merge 9 commits into
PrestaEdit wants to merge 9 commits into
Conversation
Add the Admin API endpoints to manage customer service threads:
- PUT /customer-threads/{customerThreadId}/set-status (UpdateCustomerThreadStatusCommand)
- DELETE /customer-threads/{customerThreadId} (DeleteCustomerThreadCommand)
- DELETE /customer-threads/bulk-delete (BulkDeleteCustomerThreadCommand)
set-status takes a {status} body (open/closed/pending1/pending2) mapped to the command
newCustomerThreadStatus argument; an invalid status returns 422. There is no add command for
threads (they are created from customer messages), so the integration test seeds threads via the
CustomerThread model. The reply/forward actions (which send e-mails) and the rich
GetCustomerThreadForViewing read are intentionally left out of this first resource.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Expose GetCustomerThreadForViewing as GET /customer-threads/{customerThreadId}/details
(scope customer_service_read). Mirrors the CustomerDetails heavy-aggregate read:
the nested CustomerThreadView result (customer information, available actions,
messages and timeline) is mapped to array properties, value objects collapse to
their scalar id. 404 maps from CustomerThreadNotFoundException.
Related to PrestaShop/PrestaShop#39630
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fill the ReplyToCustomerThreadCommand gap: PUT /customer-threads/{customerThreadId}/messages
(scope customer_service_write) to reply to a customer service thread. The test disables
real mail sending (PS_MAIL_METHOD) so the reply email succeeds without an SMTP server.
Related to PrestaShop/PrestaShop#39630
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GET /customer-services/signatures/{languageId} (GetCustomerServiceSignature) returns the customer
service e-mail signature for a language. The scalar result is mapped to the signature property
(ShowcaseCard pattern). The integration test reads it for the default language.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds POST /customer-threads/{customerThreadId}/forwards using CQRSCreate
with ForwardCustomerThreadCommand. Body: {comment, employeeId? | email?}
— pass one of the two to select the forwarding target.
Safe in CI: test env has PS_MAIL_METHOD = METHOD_DISABLE (3) so
Mail::send returns true without contacting an MTA.
Depends on PrestaShop/PrestaShop#42047 which exposes the Command's
public constructor. Until #42047 lands the resource is registered but
Symfony can't denormalize the request body at runtime.
Related to PrestaShop/PrestaShop#39630
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Consolidates PrestaShop#244, PrestaShop#291, PrestaShop#323, PrestaShop#281 and PrestaShop#381. PrestaShop#381 had to join the four others rather than stay with PrestaShop#281: it declared /customer-services/{customerThreadId}/forwards, addressing a customer THREAD under the customer-services prefix, only because the class sat in the CustomerService namespace and ApiResourceUriTemplateRector derives the first segment from it. The class moves to the CustomerThread namespace and the URI becomes /customer-threads/{customerThreadId}/forwards, which is both correct and Rector compliant. Its scope also becomes customer_service_write: customer_thread_write existed nowhere else in the domain. Tests: the three thread test classes are merged into one. Customer threads are created by the front-office contact form and the CustomerService domain has no add command, so a thread still has to be seeded through the legacy object — but that is now the single place where it happens, and every assertion goes back through the API: - set-status is asserted through the actions of the details endpoint (an open thread offers "close", a closed one offers "re-open") instead of reloading the ObjectModel - reply is asserted through the messages of the details endpoint instead of a raw COUNT on ps_customer_message - delete and bulk-delete are asserted by the details endpoint answering 404 instead of Validate::isLoadedObject() - the forward endpoint gets an actual test: it had none, only the protected-endpoint declaration The forward endpoint requires PrestaShop/PrestaShop#42047. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does
Merges #244, #291, #323, #281 and #381 into one PR, following the mutualisation done on the Product domain in #410.
Endpoints
/customer-threads/{customerThreadId}/detailsGetCustomerThreadForViewingcustomer_service_read/customer-threads/{customerThreadId}/set-statusUpdateCustomerThreadStatusCommandcustomer_service_write/customer-threads/{customerThreadId}/messagesReplyToCustomerThreadCommandcustomer_service_write/customer-threads/{customerThreadId}/forwardsForwardCustomerThreadCommandcustomer_service_write/customer-threads/{customerThreadId}DeleteCustomerThreadCommandcustomer_service_write/customer-threads/bulk-deleteBulkDeleteCustomerThreadCommandcustomer_service_write/customer-services/signatures/{languageId}GetCustomerServiceSignaturecustomer_service_readWhy #381 is in here
The original grouping put #281 and #381 together because both classes sat in
Resources/CustomerService/. That namespace was the problem, not the grouping.ApiResourceUriTemplateRectorderives the first URI segment from the resource namespace. BecauseCustomerThreadForwardwas declared underCustomerService, the rule forced/customer-services/{customerThreadId}/forwards— a customer thread id addressed under the customer-services prefix, while the other four thread endpoints used/customer-threads/{customerThreadId}/.... The source branch even carries a commit named "Fix Rector ApiResourceUriTemplateRector (customer-services prefix)", which bent the URI to satisfy the rule instead of moving the class.Here the class moves to the
CustomerThreadnamespace and the URI becomes/customer-threads/{customerThreadId}/forwards. Same fix for its scope: it declaredcustomer_thread_write, which exists nowhere else — every other resource in the domain usescustomer_service_write.CustomerServiceSignaturegenuinely belongs toCustomerService(/customer-services/signatures/{languageId}) and stays where it is.Tests
The three customer-thread test classes become one
CustomerThreadEndpointTest.On fixtures: customer threads are created by the front-office contact form. The
CustomerServicedomain exposes no "add thread" command, so there is no Admin API way to create one — a thread still has to be seeded through the legacyCustomerThreadobject. What changed is that this now happens in one documented helper instead of three slightly different copies, and every assertion goes back through the API:new \CustomerThread($id)->statusafter set-statusactionsof the details endpoint — an open thread offersclosed, a closed one offersopenSELECT COUNT(*) FROM ps_customer_messageafter replymessagesof the details endpoint, content includedValidate::isLoadedObject()after delete / bulk-delete404The forward endpoint also gets an actual test — #381 shipped with none, only the
getProtectedEndpoints()declaration. Forwarding builds its email from the thread's last message, so the test chains it after the reply, which is only possible now that both endpoints live in the same PR.POST /customer-threads/{customerThreadId}/forwardsrequires PrestaShop/PrestaShop#42047.ForwardCustomerThreadCommand::__construct()isprivateon the current cores — the command is only reachable through itstoAnotherEmployee()/toSomeoneElse()named constructors, which the serializer cannot use.testForwardCustomerThreadstays red until that core PR is merged into the target branches. Every other endpoint here is independent of it.How to test
Covered by
CustomerThreadEndpointTestandCustomerServiceSignatureEndpointTest.Supersedes
All five will be closed once the CI is green here.