Switch merchant email based on products in the cart

Is it possible to switch the email to, for the merchant when a certain product is in the cart?
We have a shop that also sells spare-parts, when a spare-part is added to the cart, the whole order should be send to another email address, sparparts@ instead of sales@. Is this possible with commerce out- of the box? or do we need to create a hook?

Hey Dimitri,

That’s not possible out of the box. While you could send to both, the email status change action does not support conditional recipients.

To implement this, you’ll need a custom status change action that can execute your logic for switching the email address. Once that class is created, you’ll add it to your status workflow to replace the default email status change action.

I’ve just made a quick change to the built-in comStatusChangeActionEmail class (for inclusion in the next v1.1 release) that allows you to override the recipient in an extended class, without having to duplicate all the other behavior.

class MyEmailStatusChangeAction extends comStatusChangeActionEmail
{
    public function getRecipient(comOrder $order)
    {
        $items = $order->getItems();
        // determine which email to use based on items
        return 'spareparts@site.com';
    }
}

Before that release, you’ll need to override the full process() function and make sure to keep that up-to-date with any future changes to the email sending.

(To also customise the fields available when adding the action to a status change, for example so you can
enter the various emailaddresses as configuration instead of in the code directly, you can also override the getModelFields function to add form fields and then access them with $this->getProperty().)

If you need some help with this, I can probably whip together an extension for you in about 2 hours of work, but I’d need a bit more information about how to identify from the products what email address to use (e.g. is that based on a delivery type, or something else?).

Thank you Mark,

This option will be used when a certain field from my customProduct has a value “x”
The task is not in our sprint yet, I needed to know if its possible and how big the issue would be.

I will come back to you once this issue is in our backlog.

:+1:

If you’d like me to build it for you, it’s better to let me know before it’s part of your sprint. That way I can work on it and have it ready by the time you need it. :slight_smile:

Its in the sprint now …:grin:

I mailed you

Ok, I think I almost got it:

I added this line to my schema:
<object class="customEmailStatusChangeAction" extends="comStatusChangeActionEmail" inherit="single" />

then parsed the schema, I got some new files.

Then for the test I changed the comStatusChangeActionEmail class like this:

{

    /**
     * @param comOrder $order
     *
     * @return mixed|string|null
     */
    public function getRecipient(comOrder $order)
    {
        $recipient = $this->getProperty('recipient', false);
        if (!$recipient && $billingAddress = $order->getBillingAddress()) {
            $recipient = $billingAddress->get('email');
        }

        return $recipient;
    }

    /**
     * Prepare the email for sending. This actually creates a comOrderMessage object that handles the actual
     * sending of the email.
     *
     * @param comOrder        $order
     * @param comStatus       $oldStatus
     * @param comStatus       $newStatus
     * @param comStatusChange $statusChange
     *
     * @return bool;
     */
    public function process(comOrder $order, comStatus $oldStatus, comStatus $newStatus, comStatusChange $statusChange)
    {

        $recipient = $this->getRecipient($order);
... more stuff that I did not alter

}

So far so good, the mail is still working, but now I created this class file in /mycomponent/model/mycomponent/customemailstatuschangeaction.class.php

and this is the content:

<?php

class customEmailStatusChangeAction extends comStatusChangeActionEmail
{
    /**
     * @param comOrder $order
     *
     * @return mixed|string|null
     */
    public function getRecipient(comOrder $order)
    {
        $recipient = $this->getProperty('recipient', false);
        if (!$recipient && $billingAddress = $order->getBillingAddress()) {
            $recipient = $billingAddress->get('email');
        }

        $items = $order->getItems();

        foreach ($items as $item) {
            //var_dump($item);
            if ($item->getType() == 'Onderdelen') {
                $recipient = 'mymail@myfacedomain.nl';
            }
        }

// determine which email to use based on items
        return 'mymail@myfacedomain.nl';
    }
}

So I expected this function to replace the one I created above, But that did not happen.
I must forget something… I did add my mycomponent to extentionPackages in settings. but it seems not to fire t he extended class.

Do I need to do more to make this work?

My component with custom products and also custom shippingmethod works in the frontend.
In the test with this custom mail change action I change the status in de commerce cmp. could that be the problem?

p.s. I used this as guide: https://docs.modmore.com/en/Commerce/v1/Developer/Custom_Shipping_Methods.html

That’s something I haven’t tried before for a Commerce extension. Typically, you’d load the xPDO package in the module, at which point xPDO knows what comStatusChangeActionEmail is and what your extension means. It might work but I just haven’t tried it and wanted to highlight it as something to look at.

From your description it sounds like you haven’t updated the status workflow yet to use your custom status change. Commerce > Configuration > Statuses > click on the name of the relevant status change (“Payment Received” most likely) > edit the action that sends the merchant email > change the type to your custom type.

If the custom type doesn’t show up as an option, I think you’ll need to load the package in the module.

After that it will use your custom implementation.

Note that an order item is not the same as the product so your code is not valid. Change this:

    foreach ($items as $item) {
        if ($item->getType() == 'Onderdelen') {
            $recipient = 'mymail@myfacedomain.nl';
        }
    }

to

    foreach ($items as $item) {
        if (($product = $item->getProduct()) && ($product instanceof MyCustomProductType)) {
            if ($product->getType() == 'Onderdelen') {
                $recipient = 'mymail@myfacedomain.nl';
            }
        }
    }

That also adds validation to make sure it doesn’t try to call getType on any other product type which would cause a fatal error otherwise.

Thanks mark!!

Forgot to change the method to my custom method, Now it works like a charm, Hope that your update, that you stated in the first post, wil be called the same, then it should keep on working I think…

1 Like

Great!

It does look like you made the exact same changes I committed for the next release:

Was hoping to release that today but got hit with some migraine so that will probably be a few days later.

1 Like