First create file app/code/Company/Module/etc/sales.xml with content
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Sales:etc/sales.xsd">
<section name="quote">
<group name="totals">
<item name="custom_coupon" instance="Company\Module\Model\Quote\Discount" sort_order="500"/>
</group>
</section>
</config>
Then create the file app/code/Company/Module/Model/Quote/Discount.php with content
<?php
namespace Company\Module\Model\Quote;
class Discount extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
{
/**
* @var \Magento\Checkout\Model\Session
*/
protected $_checkoutSession;
/**
* Discount calculation object
*
* @var \Magento\SalesRule\Model\Validator
*/
protected $calculator;
/**
* Core event manager proxy
*
* @var \Magento\Framework\Event\ManagerInterface
*/
protected $eventManager = null;
/**
* @var \Magento\Store\Model\StoreManagerInterface
*/
protected $storeManager;
/**
* @var \Magento\Framework\Pricing\PriceCurrencyInterface
*/
protected $priceCurrency;
/**
* @param \Magento\Framework\Event\ManagerInterface $eventManager
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
* @param \Magento\SalesRule\Model\Validator $validator
* @param \Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
*/
public function __construct(
\Magento\Checkout\Model\Session $checkoutSession,
\Magento\Framework\Event\ManagerInterface $eventManager,
\Magento\Store\Model\StoreManagerInterface $storeManager,
\Magento\SalesRule\Model\Validator $validator,
\Magento\Framework\Pricing\PriceCurrencyInterface $priceCurrency
) {
$this->setCode('custom_coupon');
$this->_checkoutSession = $checkoutSession;
$this->eventManager = $eventManager;
$this->calculator = $validator;
$this->storeManager = $storeManager;
$this->priceCurrency = $priceCurrency;
}
/**
* Collect address discount amount
*
* @param \Magento\Quote\Model\Quote $quote
* @param \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment
* @param \Magento\Quote\Model\Quote\Address\Total $total
* @return $this
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function collect(
\Magento\Quote\Model\Quote $quote,
\Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment,
\Magento\Quote\Model\Quote\Address\Total $total
) {
parent::collect($quote, $shippingAssignment, $total);
$address = $shippingAssignment->getShipping()->getAddress();
$label = __('Custom Discount');
$coupon_price = 10;
$discountAmount = -$coupon_price;
$appliedCartDiscount = 0;
if($total->getDiscountDescription()) {
// If a discount exists in cart and another discount is applied, the add both discounts.
$appliedCartDiscount = $total->getDiscountAmount();
$discountAmount = $total->getDiscountAmount()+$discountAmount;
$label = $total->getDiscountDescription().', '.$label;
}
$total->setDiscountDescription($label);
$total->setDiscountAmount($discountAmount);
$total->setBaseDiscountAmount($discountAmount);
$total->setSubtotalWithDiscount($total->getSubtotal() + $discountAmount);
$total->setBaseSubtotalWithDiscount($total->getBaseSubtotal() + $discountAmount);
if(isset($appliedCartDiscount)) {
$total->addTotalAmount($this->getCode(), $discountAmount - $appliedCartDiscount);
$total->addBaseTotalAmount($this->getCode(), $discountAmount - $appliedCartDiscount);
} else {
$total->addTotalAmount($this->getCode(), $discountAmount);
$total->addBaseTotalAmount($this->getCode(), $discountAmount);
}
return $this;
}
/**
* Add discount total information to address
*
* @param \Magento\Quote\Model\Quote $quote
* @param \Magento\Quote\Model\Quote\Address\Total $total
* @return array|null
*/
public function fetch(\Magento\Quote\Model\Quote $quote, \Magento\Quote\Model\Quote\Address\Total $total)
{
$result = null;
$amount = $total->getDiscountAmount();
//ONLY return 1 discount. Need to append existing
//see app/code/Magento/Quote/Model/Quote/Address.php
if ($amount != 0) {
$description = $total->getDiscountDescription();
$result = [
'code' => $this->getCode(),
'title' => strlen($description) ? __('Discount (%1)', $description) : __('Discount'),
'value' => $amount
];
}
return $result;
}
}