1<?php 2/** 3 * Copyright since 2007 PrestaShop SA and Contributors 4 * PrestaShop is an International Registered Trademark & Property of PrestaShop SA 5 * 6 * NOTICE OF LICENSE 7 * 8 * This source file is subject to the Open Software License (OSL 3.0) 9 * that is bundled with this package in the file LICENSE.md. 10 * It is also available through the world-wide-web at this URL: 11 * https://opensource.org/licenses/OSL-3.0 12 * If you did not receive a copy of the license and are unable to 13 * obtain it through the world-wide-web, please send an email 14 * to license@prestashop.com so we can send you a copy immediately. 15 * 16 * DISCLAIMER 17 * 18 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer 19 * versions in the future. If you wish to customize PrestaShop for your 20 * needs please refer to https://devdocs.prestashop.com/ for more information. 21 * 22 * @author PrestaShop SA and Contributors <contact@prestashop.com> 23 * @copyright Since 2007 PrestaShop SA and Contributors 24 * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) 25 */ 26 27function migrate_orders() 28{ 29 $array_errors = array(); 30 $res = true; 31 if (!defined('PS_TAX_EXC')) { 32 define('PS_TAX_EXC', 1); 33 } 34 35 if (!defined('PS_TAX_INC')) { 36 define('PS_TAX_INC', 0); 37 } 38 39 $col_order_detail_old = Db::getInstance()->executeS('SHOW FIELDS FROM `'._DB_PREFIX_.'order_detail`'); 40 foreach ($col_order_detail_old as $k => $field) { 41 if ($field['Field'] != 'id_order_invoice') { 42 $col_order_detail[$k] = $field['Field']; 43 } 44 } 45 46 if (!$col_order_detail_old) { 47 return array('error' => 1, 'msg' => 'unable to get fields list from order_detail table'); 48 } 49 50 $insert_order_detail = 'INSERT INTO `'._DB_PREFIX_.'order_detail_2` (`'.implode('`, `', $col_order_detail).'`) VALUES '; 51 52 $col_orders = array(); 53 $col_orders_old = Db::getInstance()->executeS('SHOW FIELDS FROM `'._DB_PREFIX_.'orders`'); 54 55 if (!$col_orders_old) { 56 return array('error' => 1, 'msg' => 'unable to get fields list from orders table'); 57 } 58 59 foreach ($col_orders_old as $k => $field) { 60 $col_orders[$k] = $field['Field']; 61 } 62 63 $insert_order = 'INSERT INTO `'._DB_PREFIX_.'orders_2` (`'.implode('`, `', $col_orders).'`) VALUES '; 64 65 // create temporary tables 66 $res = mo_duplicateTables(); 67 if (!$res) { 68 $array_errors[] = 'unable to duplicate tables orders and order_detail'; 69 } 70 71 // this was done like that previously 72 $wrapping_tax_rate = 1 + ((float)Db::getInstance()->getValue('SELECT value 73 FROM `'._DB_PREFIX_.'configuration` 74 WHERE name = "PS_GIFT_WRAPPING_TAX"') / 100); 75 76 $step = 3000; 77 $count_orders = Db::getInstance()->getValue('SELECT count(id_order) FROM '._DB_PREFIX_.'orders'); 78 $nb_loop = $start = 0; 79 if ($count_orders > 0) { 80 $nb_loop = ceil($count_orders / $step); 81 } 82 for ($i = 0; $i < $nb_loop; $i++) { 83 $order_res = Db::getInstance()->query('SELECT * FROM `'._DB_PREFIX_.'orders` LIMIT '.(int)$start.', '.(int)$step); 84 $start = (int) (($i+1) * $step); 85 $cpt = 0; 86 $flush_limit = 200; 87 while ($order = Db::getInstance()->nextRow($order_res)) { 88 $sum_total_products = 0; 89 $sum_tax_amount = 0; 90 $default_group_id = mo_getCustomerDefaultGroup((int)$order['id_customer']); 91 $price_display_method = mo_getPriceDisplayMethod((int)$default_group_id); 92 $order_details_list = Db::getInstance()->query(' 93 SELECT od.* 94 FROM `'._DB_PREFIX_.'order_detail` od 95 WHERE od.`id_order` = '.(int)$order['id_order']); 96 97 while ($order_details = Db::getInstance()->nextRow($order_details_list)) { 98 // we don't want to erase order_details data in order to create the insert query 99 $products = mo_setProductPrices($order_details, $price_display_method); 100 $tax_rate = 1 + ((float)$products['tax_rate'] / 100); 101 $reduction_amount_tax_incl = (float)$products['reduction_amount']; 102 103 // cart::getTaxesAverageUsed equivalent 104 $sum_total_products += $products['total_price']; 105 106 $sum_tax_amount += $products['total_wt'] - $products['total_price']; 107 108 $order_details['reduction_amount_tax_incl'] = $reduction_amount_tax_incl; 109 $order_details['reduction_amount_tax_excl'] = (float)mo_ps_round($reduction_amount_tax_incl / $tax_rate); 110 $order_details['total_price_tax_incl'] = (float)$products['total_wt']; 111 $order_details['total_price_tax_excl'] = (float)$products['total_price']; 112 $order_details['unit_price_tax_incl'] = (float)$products['product_price_wt']; 113 $order_details['unit_price_tax_excl'] = (float)$products['product_price']; 114 115 foreach (array_keys($order_details) as $k) { 116 if (!in_array($k, $col_order_detail)) { 117 unset($order_details[$k]); 118 } else { 119 if (in_array($order_details[$k], array('product_price', 'reduction_percent', 'reduction_amount', 'group_reduction', 'product_quantity_discount', 'tax_rate', 'ecotax', 'ecotax_tax_rate'))) { 120 $order_details[$k] = (float)$order_details[$k]; 121 } else { 122 $order_details[$k] = Db::getInstance()->escape($order_details[$k]); 123 } 124 } 125 } 126 if (count($order_details)) { 127 $values_order_detail[] = '(\''.implode('\', \'', $order_details).'\')'; 128 } 129 unset($order_details); 130 } 131 132 $average_tax_used = 1; 133 if ($sum_total_products > 0) { 134 $average_tax_used += $sum_tax_amount / $sum_total_products; 135 } 136 $average_tax_used = round($average_tax_used, 4); 137 $carrier_tax_rate = 1; 138 if (isset($order['carrier_tax_rate'])) { 139 $carrier_tax_rate + ((float)$order['carrier_tax_rate'] / 100); 140 } 141 142 $total_discount_tax_excl = $order['total_discounts'] / $average_tax_used; 143 $order['total_discounts_tax_incl'] = (float)$order['total_discounts']; 144 $order['total_discounts_tax_excl'] = (float)$total_discount_tax_excl; 145 146 $order['total_shipping_tax_incl'] = (float)$order['total_shipping']; 147 $order['total_shipping_tax_excl'] = (float)($order['total_shipping'] / $carrier_tax_rate); 148 $shipping_taxes = $order['total_shipping_tax_incl'] - $order['total_shipping_tax_excl']; 149 150 $order['total_wrapping_tax_incl'] = (float)$order['total_wrapping']; 151 $order['total_wrapping_tax_excl'] = ((float)$order['total_wrapping'] / $wrapping_tax_rate); 152 $wrapping_taxes = $order['total_wrapping_tax_incl'] - $order['total_wrapping_tax_excl']; 153 154 $product_taxes = $order['total_products_wt'] - $order['total_products']; 155 $order['total_paid_tax_incl'] = (float)$order['total_paid']; 156 $order['total_paid_tax_excl'] = (float)$order['total_paid'] - $shipping_taxes - $wrapping_taxes - $product_taxes; 157 // protect text and varchar fields 158 $order['gift_message'] = Db::getInstance()->escape($order['gift_message']); 159 $order['payment'] = Db::getInstance()->escape($order['payment']); 160 $order['module'] = Db::getInstance()->escape($order['module']); 161 162 $values_order[] = '(\''.implode('\', \'', $order).'\')'; 163 164 unset($order); 165 $cpt++; 166 167 // limit to $cpt 168 if ($cpt >= $flush_limit) { 169 $cpt = 0; 170 if (isset($values_order_detail) && count($values_order_detail) && !Db::getInstance()->execute($insert_order_detail. implode(',', $values_order_detail))) { 171 $res = false; 172 $array_errors[] = '[insert order detail 1] - '.Db::getInstance()->getMsgError(); 173 } 174 if (isset($values_order) && count($values_order) && !Db::getInstance()->execute($insert_order. implode(',', $values_order))) { 175 $res = false; 176 $array_errors[] = '[insert order 2] - '.Db::getInstance()->getMsgError(); 177 } 178 if (isset($values_order)) { 179 unset($values_order); 180 } 181 if (isset($values_order_detail)) { 182 unset($values_order_detail); 183 } 184 } 185 } 186 } 187 188 if (isset($values_order_detail) && count($values_order_detail) && !Db::getInstance()->execute($insert_order_detail. implode(',', $values_order_detail))) { 189 $res = false; 190 $array_errors[] = '[insert order detail 3] - '.Db::getInstance()->getMsgError(); 191 } 192 if (isset($values_order) && count($values_order) && !Db::getInstance()->execute($insert_order. implode(',', $values_order))) { 193 $res = false; 194 $array_errors[] = '[insert order 4] - '.Db::getInstance()->getMsgError(); 195 } 196 if (isset($values_order)) { 197 unset($values_order); 198 } 199 if (isset($values_order_detail)) { 200 unset($values_order_detail); 201 } 202 if (!mo_renameTables()) { 203 $res = false; 204 $array_errors[] = 'unable to rename tables orders_2 and order_detail_2 to orders and order_detail'; 205 } 206 207 if (!$res) { 208 return array('error' => 1, 'msg' => count($array_errors).' error(s) : <br/>'.implode('<br/>', $array_errors)); 209 } 210} 211 212/** 213 * mo_ps_round is a simplification of Tools::ps_round: 214 * - round is always 2 215 * - no call to Configuration class 216 * 217 * @param mixed $val 218 * @return void 219 */ 220function mo_ps_round($val) 221{ 222 static $ps_price_round_mode; 223 if (empty($ps_price_round_mode)) { 224 $ps_price_round_mode = Db::getInstance()->getValue('SELECT value 225 FROM `'._DB_PREFIX_.'configuration` 226 WHERE name = "PS_PRICE_ROUND_MODE"'); 227 } 228 229 switch ($ps_price_round_mode) { 230 case 0: 231 return ceil($val * 100)/100; 232 case 1: 233 return floor($val * 100)/100; 234 default: 235 return round($val, 2); 236 } 237} 238 239function mo_duplicateTables() 240{ 241 $res = true; 242 $res &= Db::getInstance()->execute('CREATE TABLE 243 `'._DB_PREFIX_.'orders_2` LIKE `'._DB_PREFIX_.'orders`'); 244 $res &= Db::getInstance()->execute('CREATE TABLE 245 `'._DB_PREFIX_.'order_detail_2` LIKE `'._DB_PREFIX_.'order_detail`'); 246 247 return $res; 248} 249 250function mo_renameTables() 251{ 252 $res = true; 253 $res &= Db::getInstance()->execute('DROP TABLE `'._DB_PREFIX_.'orders`'); 254 $res &= Db::getInstance()->execute('DROP TABLE `'._DB_PREFIX_.'order_detail`'); 255 256 $res &= Db::getInstance()->execute('RENAME TABLE `'._DB_PREFIX_.'orders_2` TO `'._DB_PREFIX_.'orders`'); 257 $res &= Db::getInstance()->execute('RENAME TABLE `'._DB_PREFIX_.'order_detail_2` TO `'._DB_PREFIX_.'order_detail`'); 258 259 return $res; 260} 261 262function mo_getCustomerDefaultGroup($id_customer) 263{ 264 static $cache; 265 if (!isset($cache[$id_customer])) { 266 $cache[$id_customer] = Db::getInstance()->getValue('SELECT `id_default_group` FROM `'._DB_PREFIX_.'customer` WHERE `id_customer` = '.(int)$id_customer); 267 } 268 269 return $cache[$id_customer]; 270} 271 272function mo_getPriceDisplayMethod($id_group) 273{ 274 static $cache; 275 276 if (!isset($cache[$id_group])) { 277 $cache[$id_group] = Db::getInstance()->getValue(' 278 SELECT `price_display_method` 279 FROM `'._DB_PREFIX_.'group` 280 WHERE `id_group` = '.(int)$id_group); 281 } 282 283 return $cache[$id_group]; 284} 285 286function mo_setProductPrices($row, $tax_calculation_method) 287{ 288 if ($tax_calculation_method == PS_TAX_EXC) { 289 $row['product_price'] = mo_ps_round($row['product_price']); 290 } else { 291 $row['product_price_wt'] = mo_ps_round($row['product_price'] * (1 + $row['tax_rate'] / 100)); 292 } 293 294 $group_reduction = 1; 295 if ($row['group_reduction'] > 0) { 296 $group_reduction = 1 - $row['group_reduction'] / 100; 297 } 298 299 if ($row['reduction_percent'] != 0) { 300 if ($tax_calculation_method == PS_TAX_EXC) { 301 $row['product_price'] = ($row['product_price'] - $row['product_price'] * ($row['reduction_percent'] * 0.01)); 302 } else { 303 $reduction = mo_ps_round($row['product_price_wt'] * ($row['reduction_percent'] * 0.01)); 304 $row['product_price_wt'] = mo_ps_round(($row['product_price_wt'] - $reduction)); 305 } 306 } 307 308 if ($row['reduction_amount'] != 0) { 309 if ($tax_calculation_method == PS_TAX_EXC) { 310 $row['product_price'] = ($row['product_price'] - ($row['reduction_amount'] / (1 + $row['tax_rate'] / 100))); 311 } else { 312 $row['product_price_wt'] = mo_ps_round(($row['product_price_wt'] - $row['reduction_amount'])); 313 } 314 } 315 316 if ($row['group_reduction'] > 0) { 317 if ($tax_calculation_method == PS_TAX_EXC) { 318 $row['product_price'] = $row['product_price'] * $group_reduction; 319 } else { 320 $row['product_price_wt'] = mo_ps_round($row['product_price_wt'] * $group_reduction); 321 } 322 } 323 324 if (($row['reduction_percent'] || $row['reduction_amount'] || $row['group_reduction']) && $tax_calculation_method == PS_TAX_EXC) { 325 $row['product_price'] = mo_ps_round($row['product_price']); 326 } 327 328 if ($tax_calculation_method == PS_TAX_EXC) { 329 $row['product_price_wt'] = mo_ps_round($row['product_price'] * (1 + ($row['tax_rate'] * 0.01))) + mo_ps_round($row['ecotax'] * (1 + $row['ecotax_tax_rate'] / 100)); 330 } else { 331 $row['product_price_wt_but_ecotax'] = $row['product_price_wt']; 332 $row['product_price_wt'] = mo_ps_round($row['product_price_wt'] + $row['ecotax'] * (1 + $row['ecotax_tax_rate'] / 100)); 333 } 334 335 if ($tax_calculation_method != PS_TAX_EXC) { 336 $row['product_price'] = $row['product_price_wt'] / (1 + $row['tax_rate'] / 100); 337 } 338 339 $row['total_wt'] = $row['product_quantity'] * $row['product_price_wt']; 340 $row['total_price'] = $row['product_quantity'] * $row['product_price']; 341 342 return $row; 343} 344