Hi,
Two things stand out in that log.
1. You are calling modifyOrder twice in a row:
$this->modifyOrder($orderId, $status);
$this->modifyOrder($orderId, $status, $history, $email);
The first (bare) call is the one that actually moves the order created -> shipped, and it runs with notified=0. That is exactly the first block in your log: update branch reached notified=0 -> send_email=0 -> SUPPRESSED. The second call then only re-saves shipped -> shipped with notified=1. Drop the first call and keep a single one that carries the notification:
$this->modifyOrder($orderId, $status, $history, $email);
That single call is the exact equivalent of changing the status by hand in the backend with the user notification ticked, which is the case that already sends for you.
2. For the recipient: mail_preset=no is good news, it means RO Payments is not pre-setting $order->mail, so HikaShop builds the recipient itself and the earlier preset-mail theory is ruled out. That leaves order_user_id=1. dst_email is filled from the customer loaded behind order_user_id, so if user 1 is not the real buyer (or has no email on file), dst_email stays empty and the mail is skipped. A test order paid while logged in as the admin can easily land on user 1.
So please:
- check that order 124's order_user_id is the buyer's HikaShop user (Customers listing) and that this user has an email,
- add one more log line that shows the recipient after it is loaded.
It goes in the same update branch of administrator/components/com_hikashop/classes/order.php where you already added the other EMAILDEBUG lines, right after the loadOrderNotification block and just before the if(!empty($order->mail)) that sends. That way it still logs when dst_email came back empty:
if(empty($order->mail) && isset($order->order_status)) {
$this->loadOrderNotification($order,'order_status_notification');
} elseif(!empty($order->mail)) {
$order->mail->data = &$order;
$order->mail->mail_name = 'order_status_notification';
}
// NEW:
hikashop_writeToLog('EMAILDEBUG order '.$order->order_id.': dst_email='.var_export(@$order->mail->dst_email,true).', user_email='.var_export(@$order->customer->user_email,true));
if(!empty($order->mail)) {
$mailClass = hikashop_get('class.mail');
if(!empty($order->mail->dst_email)) {
$mailClass->sendMail($order->mail);
}
$this->mail_success =& $mailClass->mail_success;
}
It is the companion to your "Before loadOrder ... mail_preset=no, order_user_id=1" line, which sits a few lines up: that one shows the inputs, this one shows the result of loadOrderNotification (the actual recipient).
Then, place one more RO Payments order with the single modifyOrder call and send me that line.
If dst_email does come back empty, it is one of these, all about the customer behind order_user_id (since mail_preset=no, loadOrderNotification did run and read that user record):
1. order_user_id is not the buyer. Here it is 1, which is usually the admin or the first user, so the lookup loads the wrong person. A test order paid while logged in as the admin lands on this case. It is also possible that the email server of the hosting refuses sending an email if the recipient and the sender email addresses are the same. That could be a possibility here.
2. order_user_id is the right customer but that user has no email address on file. This should normally never happen. It could indicate that $order->customer has been modified by something at some point.
3. RO Payments attaches a partial $order->customer to the order before the save (same user_id as order_user_id but without user_email). Because the user_id matches, HikaShop does not reload the customer from the database, so the empty email is kept. The fix there is the same as for the call: pass only the integer order id and let HikaShop build the order and the customer itself.
The fourth case, $order->mail preset so the recipient lookup is skipped entirely, is already ruled out by your mail_preset=no.