Completed
Push — master ( 6476e7...cde684 )
by
unknown
06:06
created

Mygento_Payture_Helper_Discount::addTaxValue()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 9
nc 3
nop 3
1
<?php
2
3
/**
4
 *
5
 *
6
 * @category Mygento
7
 * @package Mygento_Payture
8
 * @copyright 2017 NKS LLC. (https://www.mygento.ru)
9
 */
10
class Mygento_Payture_Helper_Discount extends Mage_Core_Helper_Abstract
11
{
12
13
    protected $_code = 'kkm';
14
15
    /** Returns item's data as array with properly calculated discount
16
     * @param $entity Mage_Sales_Model_Order | Mage_Sales_Model_Order_Invoice | Mage_Sales_Model_Order_Creditmemo
17
     * @param $itemSku
18
     * @param string $taxValue
19
     * @param string $taxAttributeCode
20
     * @param string $shippingTaxValue
21
     * @return array|mixed
22
     */
23
    public function getItemWithDiscount(
24
        $entity,
25
        $itemSku,
26
        $taxValue = '',
27
        $taxAttributeCode = '',
28
        $shippingTaxValue = ''
29
    ) {
30
    
31
        $items = $this->getRecalculated($entity, $taxValue, $taxAttributeCode, $shippingTaxValue)['items'];
32
33
        return isset($items[$itemSku]) ? $items[$itemSku] : [];
34
    }
35
36
    /** Returns all items of the entity (order|invoice|creditmemo) with properly calculated discount and properly calculated Sum
37
     * @param $entity Mage_Sales_Model_Order | Mage_Sales_Model_Order_Invoice | Mage_Sales_Model_Order_Creditmemo
38
     * @param string $taxValue
39
     * @param string $taxAttributeCode Set it if info about tax is stored in product in certain attr
40
     * @param string $shippingTaxValue
41
     * @return array with calculated items and sum
42
     */
43
    public function getRecalculated(
44
        $entity,
45
        $taxValue = '',
46
        $taxAttributeCode = '',
47
        $shippingTaxValue = ''
48
    ) {
49
    
50
        $generalHelper = Mage::helper($this->_code);
51
        $generalHelper->addLog("== START == Recalculation of entity prices. Entity class: " . get_class($entity) . ". Entity id: {$entity->getId()}");
52
53
        $subTotal       = $entity->getData('subtotal');
54
        $shippingAmount = $entity->getData('shipping_amount');
55
        $grandTotal     = $entity->getData('grand_total');
56
        $grandDiscount  = $grandTotal - $subTotal - $shippingAmount;
57
58
        $percentageSum = 0;
59
60
        $items      = $entity->getAllVisibleItems() ? $entity->getAllVisibleItems() : $entity->getAllItems();
61
        $itemsFinal = [];
62
        $itemsSum   = 0.00;
63
        foreach ($items as $item) {
64
            if (!$this->isValidItem($item)) {
65
                continue;
66
            }
67
68
            $taxValue = $this->addTaxValue($taxAttributeCode, $entity, $item);
69
70
            $price    = $item->getData('price');
71
            $qty      = $item->getQty() ?: $item->getQtyOrdered();
72
            $rowTotal = $item->getData('row_total');
73
74
            //Calculate Percentage. The heart of logic.
75
            $rowPercentage = $rowTotal / $subTotal;
76
            $percentageSum += $rowPercentage;
77
78
            $discountPerUnit   = $rowPercentage * $grandDiscount / $qty;
79
            $priceWithDiscount = $this->slyFloor($price + $discountPerUnit);
80
81
            $entityItem = $this->_buildItem($item, $priceWithDiscount, $taxValue);
82
83
            $itemsFinal[$item->getSku()] = $entityItem;
84
            $itemsSum                    += $entityItem['sum'];
85
        }
86
87
        $generalHelper->addLog("Sum of all percentages: {$percentageSum}");
88
89
        //Calculate DIFF!
90
        $itemsSumDiff = $this->slyFloor($grandTotal - $itemsSum - $shippingAmount);
91
92
        $generalHelper->addLog("Items sum: {$itemsSum}. All Discounts: {$grandDiscount} Diff value: {$itemsSumDiff}");
93
        if (bccomp($itemsSumDiff, 0.00, 2) < 0) {
94
            //if: $itemsSumDiff < 0
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
95
            $generalHelper->addLog("Notice: Sum of all items is greater than sumWithAllDiscount of entity. ItemsSumDiff: {$itemsSumDiff}");
96
            $itemsSumDiff = 0.0;
97
        }
98
99
        $receipt = [
100
            'sum'            => $itemsSum,
101
            'origGrandTotal' => floatval($grandTotal)
102
        ];
103
104
        $shippingName = $entity->getShippingDescription() ?: ($entity->getOrder() ? $entity->getOrder()->getShippingDescription() : '');
105
106
        $shippingItem = [
107
            'name'     => $shippingName,
108
            'price'    => $entity->getShippingAmount() + $itemsSumDiff,
109
            'quantity' => 1.0,
110
            'sum'      => $entity->getShippingAmount() + $itemsSumDiff,
111
            'tax'      => $shippingTaxValue,
112
        ];
113
114
        $itemsFinal['shipping'] = $shippingItem;
115
        $receipt['items']       = $itemsFinal;
116
117
        if (!$this->_checkReceipt($receipt)) {
118
            $generalHelper->addLog("WARNING: Calculation error! Sum of items is not equal to grandTotal!");
119
        }
120
        $generalHelper->addLog("Final result of recalculation:");
121
        $generalHelper->addLog($receipt);
122
        $generalHelper->addLog("== STOP == Recalculation of entity prices. ");
123
124
        return $receipt;
125
    }
126
127
    protected function _buildItem($item, $price, $taxValue = '')
128
    {
129
        $generalHelper = Mage::helper($this->_code);
130
131
        $qty = $item->getQty() ?: $item->getQtyOrdered();
132
        if (!$qty) {
133
            throw new Exception('Divide by zero. Qty of the item is equal to zero! Item: ' . $item->getId());
134
        }
135
136
        $entityItem = [
137
            'price'    => round($price, 2),
138
            'name'     => $item->getName(),
139
            'quantity' => round($qty, 2),
140
            'sum'      => round($price * $qty, 2),
141
            'tax'      => $taxValue,
142
        ];
143
144
        $generalHelper->addLog("Item calculation details:");
145
        $generalHelper->addLog("Item id: {$item->getId()}. Orig price: {$price} Item rowTotal: {$item->getRowTotal()} Price of 1 piece: {$price}. Result of calc:");
146
        $generalHelper->addLog($entityItem);
147
148
        return $entityItem;
149
    }
150
151
    /*     * Validation method. It sums up all items and compares it to grandTotal.
152
     * @param array $receipt
153
     * @return bool True if all items price equal to grandTotal. False - if not.
154
     */
155
    protected function _checkReceipt(array $receipt)
156
    {
157
        $sum = array_reduce(
158
            $receipt['items'],
159
            function ($carry, $item) {
160
                $carry += $item['sum'];
161
                return $carry;
162
            }
163
        );
164
165
        return bcsub($sum, $receipt['origGrandTotal'], 2) === '0.00';
166
    }
167
168
    public function isValidItem($item)
169
    {
170
        return $item->getRowTotal() && $item->getRowTotal() !== '0.0000';
171
    }
172
173
    public function slyFloor($val, $precision = 2)
174
    {
175
        $factor  = 1.00;
176
        $divider = pow(10, $precision);
177
178
        if ($val < 0) {
179
            $factor = -1.00;
180
        }
181
182
        return (floor(abs($val) * $divider) / $divider) * $factor;
183
    }
184
185
    protected function addTaxValue($taxAttributeCode, $entity, $item)
186
    {
187
        if ($taxAttributeCode) {
188
            $storeId = $entity->getStoreId();
189
            $store   = $storeId ? Mage::app()->getStore($storeId) : Mage::app()->getStore();
190
191
            return Mage::getResourceModel('catalog/product')->getAttributeRawValue(
192
                $item->getProductId(),
193
                $taxAttributeCode,
194
                $store
195
            );
196
        }
197
        return '';
198
    }
199
}
200