2

Here is the scenario - I have credit memo id's, I need to check in those id's if credit memo is created from same order (if credit memo created for same order, then i need to merge those credit memo data (such as product, credit memo amount etc) then i need to send a credit memo to customer. So eventually it will be like ONE EMAIL SENT AS CREDIT MEMO FOR 3 INDIVIDUAL CREDIT MEMO. I hope it makes sense.

Actually I have created a script that is used to bulk refund to store credit based on given order number & item & qty. The only issue I face is when there are consecutive orders(same order id), then also it creates credit memo for for each item at once so two credit memo created for two items for same order. That is fine. but two times email sent of credit memo to customer.

I am trying to find a way that I can send credit memo email of processed credit memo by its id. (If same order's multiple credit memo generated for item single mail should send for two items).

4
  • I have credit memo id's I need to check in those id's where there is same order (if credit memo created for same order if yes then send a credit memo custom email to customer containing details of both credit memo. (i.e items,total,discount if there) etc.
    – devhs
    Commented May 25, 2021 at 5:49
  • Any thoughts on this, how to implement this ?
    – devhs
    Commented May 25, 2021 at 12:24
  • Hi! Provide your question with your custom script placing creditmemo. In my opinion it should not create one credit memo for each item, but only one for whole order then notification email won't fire multiple times.
    – dudzio
    Commented May 30, 2021 at 19:36
  • Sure, let me share code
    – devhs
    Commented May 31, 2021 at 4:52

2 Answers 2

2

I think you want to do the following:

You want to find a particular Order ID, and see if it has any Credit memo IDs, and then get those totals. Then collate the product items/credit memo IDs and totals into a singular 'email as credit memo'?

Even though I do not have a full solution for you at the moment (work not permitting me), maybe this will point you into the right direction:

  • A quick MySQL query confirmed there are orders with credit memo items:

Update: swapped sales_order and sales_creditmemo in query for corresponding join in PHP.

SELECT SUM(sc.base_grand_total) as FullTotal, sc.order_id as OrderId, sc.base_grand_total as CreditGT, so.base_grand_total as OrderGT,
sc.*, so.* FROM sales_order so
INNER JOIN sales_creditmemo sc
ON sc.order_id = so.entity_id
WHERE sc.order_id IN (3009)
GROUP BY sc.order_id;

**The resultant join in PHP can be converted into this: ** This was not tested, but this shows you the from, join, where parts.

/**
 Assume that you provide the order id as input
*/
protected function filterOrder($orderId)
{
    
    $this->sales_order_table = $this->getTable("sales_order");
    $this->sales_creditmemo_table = $this->getTable("sales_creditmemo");
    $this->getSelect()
        ->from(array('so' => $this->sales_order_table),
            array(
                'so.base_grand_total as OrderGT'
            )
        ->join(
            array('sales_creditmemo' => $this->sales_order_payment_table), 
                $this->sales_order_table . '.entity_id = ' . $this->sales_creditmemo_table . '.order_id',
                array(
                    'SUM(so.base_grand_total) as FullTotal', 
                    'sc.order_id as OrderId',
                    'sc.base_grand_total as CreditMemoGt'
                )
                );
    $this->getSelect()->where('sc.order_id IN (' . $orderId . ')' );
}

Using the query above, notice CreditGT and OrderGT totals are the same, which confirms that this could be used to find the sales_creditmemo items attached to a sales order.

NOTE: I do not have any orders that have multiple credit memos, so I am not sure FullTotal column sums the credit memo item' totals for the order, so make sure it works. (Technically Credit Memo A+B+C = OrderID Total, or in my case Credit Memo A = OrderID Total).

  • Next step, try to join the working MySQL query into Magento 2 code and create a new Magento 2 module, most likely adding a custom Model:

An example of joining and filtering tables to get you started: How to join 2 tables in Magento 2.

You will most likely want to create a Helper, or a custom Model that overrides the core functions.

Research on creating a new module, there are plenty of answers here on magento.stackexchange.

The section I think you should target there are most likely these sections:

<!--truncated-->
<h1>{{trans "Your Credit Memo #%creditmemo_id for Order #%order_id" creditmemo_id=$creditmemo.increment_id order_id=$order.increment_id}}</h1>
<!--truncated-->
{{layout handle="sales_email_order_creditmemo_items" creditmemo_id=$creditmemo_id order_id=$order_id}}

To extend it further, this looks like that credit memo template uses this credit memo items template:

For templates and email templates you have to override the templates in your active theme folder:

Notes on email templates, and where they are to be overridden/edited: NOTE: email templates are .html files located at the discussed place here email/, while the items templates (.phtml files) are in templates/email/

In summary :

./app/design/frontend/Vendor/ThemeName/{Module_Name}/email has .html email templates AND

./app/design/frontend/Vendor/ThemeName/{Module_Name}/templates/email will have .phtml templates

Email templates are stored in the <module_dir>/view//email directory of their respective modules. For example, the template for the new order transactional email for the Sales module is located in <Magento_Sales_module_dir>/view/frontend/email/order_new.html.

We strongly recommend you not change the default Magento files. If you want to customize the default templates, you should create your custom templates and configure Magento to use them instead of the default templates.

You can add custom templates as physical files in your custom theme or create them using the Magento Admin. Both approaches are described in the following sections.

Override email templates by creating templates in a new directory in your custom theme, using this pattern: <theme_dir>/_/email. For example, to override the New Order email template, create a template named order_new.html in the <theme_dir>/Magento_Sales/email directory.

Template fallback is supported for email templates, so parent themes of your current theme are searched for templates.

Customize email templates using the Magento Admin Any templates configured in the Magento Admin take precedence over default or theme-based templates.

In the Magento Admin, navigate to MARKETING > Communications > Email Templates Click Add New Template. If you want to use a default template as a starting point, in the Load default template section, choose the template and click Load Template. The path to the configuration settings for each default template displays in the Currently Used For field in the Template Information section.

Make note of this path because you will need it later when you configure this new template to be used instead of the default template.

Credit Memo Items template

        <thead>
            <tr>
                <th class="item-info">
                    <?= $block->escapeHtml(__('Items')) ?>
                </th>
                <th class="item-qty">
                    <?= $block->escapeHtml(__('Qty')) ?>
                </th>
                <th class="item-subtotal">
                    <?= $block->escapeHtml(__('Subtotal')) ?>
                </th>
            </tr>
        </thead>
        <?php foreach ($_creditmemo->getAllItems() as $_item) : ?>
            <?php if (!$_item->getOrderItem()->getParentItem()) : ?>
                <tbody>
                    <?= $block->getItemHtml($_item) ?>
                </tbody>
            <?php endif; ?>
        <?php endforeach; ?>
        <tfoot class="order-totals">
            <?= $block->getChildHtml('creditmemo_totals') ?>
        </tfoot>

As you can see creditmemo_totals block seems to render the totals for the credit memo.

The blocks is located at:

./vendor/magento/module-sales/Block/Order/Creditmemo.php

and its subfolder contains the credit memo files:

./vendor/magento/module-sales/Block/Order/Creditmemo/

The model seems to be located at:

/vendor/magento/module-sales/Model/Order/Creditmemo.php

and its subfolder contains the `Item.php` at

/vendor/magento/module-sales/Model/Order/Creditmemo/

Summary

As mentioned, this is not a full solution, there seems alot of things in this puzzle.

I hope I pointed you in the right direction - as from my understanding this is what you are attempting to do.

Steps:

  1. Convert a working MySQL query (sample provided where I joined the tables) into a Magento 2 PHP coded filter version. Links provided on how to do that
  2. Most likely need to create a custom module to override some of the mentioned blocks/models or create Helper.
  3. Override the _email templates (.html), and optionally the templates used _inside_ the email templates (.phtml)` and put them into the theme folder location as discussed.
5
  • Thankyou very much for the detailed answer & suggestion. I appreciate it. I missed to add that, i have not used sql query to perform any operation. So i am not able to add it in code. The overriding email part is also useful. I appreciate it i will utilize part of this in question requirement.
    – devhs
    Commented May 25, 2021 at 11:59
  • The difficult thing in this is passing data of (common credit memo details to credit memo email). I am not clear about that as answer.
    – devhs
    Commented May 25, 2021 at 12:15
  • 1
    Pleasure, I hoped it helped a little bit. I added a corresponding PHP section for the Zend Magento 2 syntax that should give the same result as the MySQL query which I ran against the database. Note: (not tested!). Also, in order for me to assist more on the passing data from the cm details to the cm memo email are related to this result that this filter gives you. Unfortunately though, this means creating a module, overriding/extending the correct models/blocks and then calling the custom function inside the templates. Commented May 25, 2021 at 12:58
  • For that though, at the moment I cannot directly investigate further to debug which ones. For a start see if you can read model vendor/magento/module-sales/Model/Order/Creditmemo.php and block vendor/magento/module-sales/Block/Order/Creditmemo.php where the total functions are located. Then the subfolder Creditmemo has the children (details items) ({M/B}/Order/Creditmemo/). Commented May 25, 2021 at 13:01
  • Really sorry to not be able to able to help further right now, I am busy working sorry! To really help I would have to investigate the exact code files to target. Commented May 25, 2021 at 13:03
1

Note: Answer is Related to magento 2.3.x

Step 1. Create di.xml

/app/code/Vendor/Module/etc/di.xml

add below code in di.xml

<?xml version="1.0" ?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Sales\Model\Order\Email\SenderBuilder" type="Vendor\Module\Rewrite\Sales\Model\Order\Email\SenderBuilder" />
</config>

Step 2. Create SenderBuilder.php

/app/code/Vendor/Module/Rewrite/Sales/Model/Order/Email/SenderBuilder.php


<?php
namespace Vendor\Module\Rewrite\Sales\Model\Order\Email;
class SenderBuilder extends \Magento\Sales\Model\Order\Email\SenderBuilder
{
    
    public function send()
    {
        $this->configureEmailTemplate();
        $this->transportBuilder->addTo(
            $this->identityContainer->getCustomerEmail(),
            $this->identityContainer->getCustomerName()
        );
        $copyTo = $this->identityContainer->getEmailCopyTo();
        if (!empty($copyTo) && $this->identityContainer->getCopyMethod() == 'bcc') {
            foreach ($copyTo as $email) {
                $this->transportBuilder->addBcc($email);
            }
        }
        $transport = $this->transportBuilder->getTransport();
        $transport->sendMessage();
    }

    protected function configureEmailTemplate()
    {   
        
        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();  

        $creditmemo_order_emails = array('sales_email_creditmemo_template','sales_email_creditmemo_guest_template');

        $getTemplateVars = $this->templateContainer->getTemplateVars();
        $getTemplateVars['custom_variable_add'] = 'Custom Variable Text';

        if(isset($getTemplateVars['order'])){
            $order = $getTemplateVars['order'];
            if(in_array($this->templateContainer->getTemplateId(), $creditmemo_order_emails) && $order->getShippingMethod() == 'mpcustomshipping_mpcustomshipping'){
                $this->transportBuilder->setTemplateIdentifier('creditmemo_new_pickup');
            }else{
                $this->transportBuilder->setTemplateIdentifier($this->templateContainer->getTemplateId()); 
            }
        }else{
                $this->transportBuilder->setTemplateIdentifier($this->templateContainer->getTemplateId()); 
        }
        
        $this->transportBuilder->setTemplateOptions($this->templateContainer->getTemplateOptions());
        $this->transportBuilder->setTemplateVars($getTemplateVars);
        $this->transportBuilder->setFromByScope(
            $this->identityContainer->getEmailIdentity(),
            $this->identityContainer->getStore()->getId()
        );      
    }
}

in email template add variable

"var custom_variable_add":"Custom Variable"

and use like

{{trans 'Order total: %custom_variable_add' custom_variable_add=$custom_variable_add|raw}}

accept solution if works for you.

3
  • Hello gohil, thanks for the answer, however i don't understand how it can help the need or ask of the question posted.
    – devhs
    Commented May 25, 2021 at 10:17
  • Let me add some details, Here is the scenario - I have credit memo id's, I need to check in those id's if credit memo is created from same order (if credit memo created for same order, then i need to merge those credit memo data (such as product, credit memo amount etc) then i need to send a credit memo to customer. So eventually it will be like ONE EMAIL SENT AS CREDIT MEMO FOR 3 INDIVIDUAL CREDIT MEMO. I hope it makes sense.
    – devhs
    Commented May 25, 2021 at 10:22
  • my code is just for send custom email template for creditmemo or add custom variable. but you can add your code as per your need in SenderBuilder.php Commented May 25, 2021 at 11:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.