....................................../////.===Shadow-Here===./////................................................ > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < ------------------------------------------------------------------------------------------------------------------- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// RIFF¤ WEBPVP8 ˜ ðÑ *ôô>‘HŸK¥¤"§£±¨àð enü¹%½_F‘åè¿2ºQú³íªú`N¿­3ÿƒügµJžaÿ¯ÿ°~¼ÎùnúîÞÖô•òíôÁÉß®Sm¥Ü/ ‡ó˜f£Ùà<˜„xëJ¢Ù€SO3x<ªÔ©4¿+ç¶A`q@Ì“Úñè™ÍÿJÌ´ª-˜ÆtÊÛL]Ïq*‘Ý”ì#ŸÌÏãY]@ê`¿ /ªfkØB4·®£ó z—Üw¥Pxù–ÞLШKÇN¾AkÙTf½è'‰g gÆv›Øuh~ a˜Z— ïj*á¥t d£“uÒ ¨`K˜¹ßþ]b>˜]_ÏÔ6W—è2r4x•íÖ…"ƒÖNîä!¦å Ú}ýxGøÌ —@ ;ÆÚŠ=ɾ1ý8lªË¥ô ^yf®Œ¢u&2©nÙÇ›ñÂñŒ³ aPo['½»øFùà­+4ê“$!lövlüÞ=;N®3ð‚õ›DÉKòÞ>ÄÍ ¥ˆuߤ#ˆ$6ù™¥îЇy’ÍB¼ çxÛ;X"WL£R÷͝*ó-¶Zu}º.s¸sšXqù–DþÿvªhüïwyŸ ¯é³lÀ:KCûÄ£Ëá\…­ ~—ýóî ¼ûûÜTÓüÇy…ŽÆvc»¾×U ñ¸žþоP÷¦ó:Ò¨¨5;Ð#&#ÖúñläÿÁœ GxÉ­/ñ‡áQðìYÉtÒw޼GÔ´zàÒò ð*ëzƒ•4~H]Ø‹f ñÓÈñ`NåWçs'ÆÏW^ø¹!XžµmQ5ÃËoLœÎ: ÞËÍ¥J ù…î èo£ßPÎñ¶ž8.Œ]ʵ~5›ÙË-ù*8ÙÖß±~ ©¹rÓê‚j¶d¸{^Q'˜±Crß ÚH—#¥¥QlÀ×ëã‡DÜ«èî þ&Çæžî;ŽÏºò6ÒLÃXy&ZŒ'j‚¢Ù€IßÚù+–MGi‰*jE€‘JcÜ ÓÌ EÏÚj]o˜ Þr <¾U ûŪæÍ/šÝH¥˜b”¼ ÁñßX GP›ï2›4WŠÏà×£…íÓk†¦H·ÅíMh–*nó÷à]ÁjCº€b7<ب‹¨5車bp2:Á[UªM„QŒçiNMa#<5›áËó¸HýÊ"…×Éw¹¦ì2º–x<›»a±¸3Weü®FÝ⑱ö–î–³|LPÈ~çð~Çå‡|º kD¢µÏàÆAI %1À% ¹Ò – ”ϝS¦‰4&¶£°à Öý”û_Ò Áw°A«Å€?mÇÛgHÉ/8)á¾ÛìáöŽP í¨PŸNÙµº¦‡§Ùš"ÿ«>+ªÕ`Ê÷‡‚ß Õû˜þãÇ-PÍ.¾XV‘€ dÜ"þ4¹ ±Oú‘©t¥¦FªÄÃÄ•b‚znýu½—#cDs˜ÃiÑOˆñ×QO=*IAÊ,¶ŽZƒ;‡wøXè%EÐk:F±Ú” .Ѽ+Áu&Ç`."pÈÉw o&¿dE6‘’EqTuK@Ì¥ã™À(Êk(h‰,H}RÀIXÛš3µ1©_OqÚÒJAñ$ÊÙÜ;D3çŒ[þùœh¬Ã³™ö6ç†NY".Ú‰ï[ªŸŒ '²Ð öø_¨ÂÉ9ué¶³ÒŠõTàîMØ#û¯gN‡bÙ놚X„ö …ÉeüÌ^J ‹€.œ$Æ)βÄeæW#óüßĺŸ€ ÀzwV 9oä»f4V*uB «Ë†¹ì¯žR霓æHXa=&“I4K;¯ç‹h×·"UŠ~<•╪Vêª&ÍSÃÆÅ?ÔqÎ*mTM ˜›µwêd#[C¡©§‘D<©àb†–ÁœøvH/,í:¯( ²£|4-„Æövv„Yͼ™^Á$ˆ„¢Û[6yB.åH*V¨æ?$=˜Ñ€•ñ·­(VlŸ‘ nÀt8W÷´Bûba?q9ú¶Xƒl«ÿ\ù¶’þòUÐj/õ¢Ìµ³g$ƒÎR!¸»|Oߍë’BhîÚÑ¢ñåŒJ„®„£2Ð3•ô02Nt…!£Í]Ïc½Qÿ?ˆ<&ÃA¾Ú,JˆijÌ#5yz„‰Î|ÊŽ5QÏ:‹ÐaóVÔxW—CpeÏzÐïíçôÿÅ_[hãsÐ_/ŽTÝ?BîˆííV$<¿i>²F¬_Eß¿ †bÊŒº­ÿ®Z H“C}”¬,Mp ý/Bá£w>˜YV°aƒúh+cŠ- r/[%|üUMHäQ°X»|û/@|°¥Ð !BÔ Ç¢Ä©š+Õì D«7ìN¶ŽðÔ " ƶ’ÖçtA‰Û×}{tþz­¾GÍ›k¹OEJR$ Â׃ «ëÁ"oÉôž$oUK(Ä)Ãz³Ê-‹êN[Ò3Œñbï8P 4ƒ×q¢bo|?<ÛX¬òÄͰL–±›(™ûG?ýË©ÚÄ–ÂDØÐ_Ç¡ô ¾–ÄÏø ×e8Ë©$ÄF¹Å‹ì[©óìl:F¾f´‹‹Xì²ï®\¬ôùƒ ÿat¥óèÒùHß0äe‚;ü×h:ÆWðHž=Ã8骣"kœ'Y?³}Tûè€>?0l›e1Lòñ„aæKÆw…hÖŠùW…ÈÆÄ0ši·›[pcwËþñiêíY/~-Á5˜!¿†A›™Mÿþ(±“t@â“ö2­´TG5yé]çå僳 .·ÍïçÝ7UÚ±Ð/Nè»,_Ï ùdj7\ï Wì4›„»c¸àešg#ÒÊ⥭áØo5‘?ÌdÝô¯ ¹kzsƒ=´#ëÉK›Ø´±-¥eW?‡çßtòTã…$Ý+qÿ±ƒ÷_3Ô¥í÷:æ–ž<·Ö‡‰Å¢ š‡%Ô—utÌÈìðžgÖÀz²À—ï÷Óîäõ{K'´È÷³yaÏÁjƒô}ž§®æÊydÕÈë5¯èˆõvÕ©ã*çD„ “z„Ó‡^^xÂ3M§A´JG‚öï 3W'ˆ.OvXè¡ÊÕª?5º7†˜(˜Ç¶#çê’¶!ÌdZK§æ 0fãaN]òY³RV ™î$®K2R¨`W!1Ôó\;Ý ýB%qæK•&ÓÈe9È0êI±žeŸß -ú@žQr¦ ö4»M¼Áè¹µmw 9 EÆE_°2ó„ŸXKWÁ×Hóì^´²GѝF©óäR†¦‰ç"V»eØ<3ùd3ÿÚ¤Žú“Gi" —‘_ÙËÎ~Üö¯¥½Î»üŸEÚŽåmÞþí ;ÞólËΦMzA"Âf(´òá;Éï(/7½ûñÌ­cïÕçлþÝz¾-ÍvÑ“pH­–ðÓj$¸Äû¤‚‘ãUBË-n“2åPkS5&‹Â|+g^œ®Ì͆d!OïäîU«c;{Û!ÅŽ«ëZ9Ókóˆ]¯ƒ›né `ÇÒ+tÆš (ØKá¾—=3œ®•vuMñg²\ï Ec€ 05±d™‡×iÇ×›UúvÌ¢£Èþ¡ÕØô¶ßÎA"ß±#Ö²ˆÊŸ¦*Ä~ij|àø.-¼'»Ú¥£h ofº¦‡VsR=N½„Î v˜Z*SÌ{=jÑB‹tê…;’HžH¯8–îDù8ñ¢|Q•bÛçš–‹m³“ê¨ åÏ^m¬Žãþ©ïêO‡½6] µÆ„Ooòü ²x}N¦Ë3ïé¿»€›HA˜m%çÞ/¿í7Fø“‹léUk)É°Œµ8Q8›:ÀŠeT*šõ~ôڝG6 ¢}`ùH­–”¡k ‰P1>š†®9z11!X wKfmÁ¦xÑ,N1Q”–æB¶M…ÒÃv6SMˆhU¬ÊPŽï‘öj=·CŒ¯u¹ƒVIЃsx4’ömÛýcå¡¶7ßŠß 57^\wÒÐÆ k§h,Œý î«q^R½3]J¸ÇðN ‚çU¬ôº^Áì} ³f©Õœ§ˆã:FÄÈ‚é(€™?àýÓüè1Gô£¼éj‚OÅñ  #>×—ßtà 0G¥Åa뀐kßhc™À_ÉñÞ#±)GD" YîäË-ÿÙ̪ ¹™a¯´¢E\ÝÒö‚;™„ë]_ p8‰o¡ñ+^÷ 3‘'dT4œŽ ðVë½° :¬víÑ«£tßÚS-3¶“þ2 †üüʨòrš¹M{É_¤`Û¨0ìjœøJ‡:÷ÃáZ˜†@GP&œÑDGÏs¡þ¦þDGú‘1Yá9Ôþ¼ ûø…§÷8&–ÜÑnÄ_m®^üÆ`;ÉVÁJ£?â€-ßê}suÍ2sõA NÌúA磸‘îÿÚ»ƒìö·á¿±tÑÐ"Tÿü˜[@/äj¬€uüªìù¥Ý˜á8Ý´sõj 8@rˆð äþZÇD®ÿUÏ2ùôõrBzÆÏÞž>Ì™xœ“ wiÎ×7_… ¸ \#€MɁV¶¥üÕÿPÔ9Z‡ø§É8#H:ƒ5ÀÝå9ÍIŒ5åKÙŠ÷qÄ>1AÈøžj"µÂд/ªnÀ qªã}"iŸBå˜ÓÛŽ¦…&ݧ;G@—³b¯“•"´4í¨ôM¨åñC‹ïùÉó¯ÓsSH2Ý@ßáM‡ˆKÀªÛUeø/4\gnm¥‹ŸŒ qÄ b9ÞwÒNÏ_4Ég³ú=܆‚´ •â¥õeíþkjz>éÚyU«Íӝ݃6"8/ø{=Ô¢»G¥ äUw°W«,ô—¿ãㆅү¢³xŠUû™yŒ (øSópÐ 9\åTâ»—*oG$/×ÍT†Y¿1¤Þ¢_‡ ¼ „±ÍçèSaÓ 3ÛMÁBkxs‰’R/¡¤ˆÙçª(*õ„üXÌ´ƒ E§´¬EF"Ù”R/ÐNyÆÂ^°?™6¡œïJ·±$§?º>ÖüœcNÌù¯G ‹ñ2ЁBB„^·úìaz¨k:#¨Æ¨8LÎõލ£^§S&cŒÐU€ü(‡F±Š¼&P>8ÙÁ ‰ p5?0ÊÆƒZl¸aô š¼¡}gÿ¶zÆC²¹¬ÎÖG*HB¡O<º2#ñŒAƒ–¡B˜´É$¥›É:FÀÔx¾u?XÜÏÓvN©RS{2ʈãk9rmP¼Qq̳ è¼ÐFׄ^¡Öì fE“F4A…!ì/…¦Lƒ… … $%´¾yã@CI¬ á—3PþBÏNÿ<ý°4Ü ËÃ#ØÍ~âW«rEñw‹eùMMHß²`¬Öó½íf³:‹k˜¯÷}Z!ã¿<¥,\#öµÀ¯aÒNÆIé,Ћ–lŽ#Àæ9ÀÒS·I’½-Ïp Äz¤Š Â* ­íÄ9­< h>׍3ZkËU¹§˜ŒŠ±f­’¤º³Q ÏB?‹#µíÃ¥®@(Gs«†vI¥Mµ‹Á©e~2ú³ÁP4ìÕi‚²Ê^ö@-DþÓàlÜOÍ]n"µã:žpsŽ¢:! Aõ.ç~ÓBûH÷JCÌ]õVƒd «ú´QÙEA–¯¯Œ!.ˆˆëQ±ù œ·Ì!Õâ )ùL„ÅÀlÚè5@B…o´Æ¸XÓ&Û…O«˜”_#‡ƒ„ûÈt!¤ÁÏ›ÎÝŠ?c9 â\>lÓÁVÄÑ™£eØY]:fÝ–—ù+p{™ðè û³”g±OƒÚSù£áÁÊ„ä,ï7š²G ÕÌBk)~ÑiCµ|h#u¤¶îK¨² #²vݯGãeÖ϶ú…¾múÀ¶þÔñ‚Š9'^($¤§ò “š½{éúp÷J›ušS¹áªCÂubÃH9™D™/ZöØÁ‡¦ÝÙŸ·kð*_”.C‹{áXó€‡c¡c€§/šò/&éš÷,àéJþ‰X›fµ“C¨œ®r¬"kL‰Â_q…Z–.ÉL~O µ›zn‚¹À¦Öª7\àHµšÖ %»ÇníV[¥*Õ;ƒ#½¾HK-ÖIÊdÏEÚ#=o÷Óò³´Š: Ç?{¾+9›–‘OEáU·S€˜j"ÄaÜ ŒÛWt› á–c#a»pÔZÞdŽtWê=9éöÊ¢µ~ ë ;Öe‡Œ®:bî3±ýê¢wà¼îpêñ¹¾4 zc¾ðÖÿzdêŒÑÒŝÀ‰s6¤í³ÎÙB¿OZ”+F¤á‡3@Ñëäg©·Ž ˆèª<ù@É{&S„œÕúÀA)‰h:YÀ5^ÂÓŒ°õäU\ ùËÍû#²?Xe¬tu‰^zÒÔãë¼ÛWtEtû …‚g¶Úüâî*moGè¨7%u!]PhÏd™Ý%Îx: VÒ¦ôÊD3ÀŽKÛËãvÆî…N¯ä>Eró–ð`5 Œ%u5XkñÌ*NU%¶áœÊ:Qÿú»“úzyÏ6å-၇¾ ´ ÒÊ]y žO‘w2Äøæ…H’²f±ÎÇ.ª|¥'gîV•Ü .̘¯€šòü¤U~Ù†*¢!?ò wý,}´°ÔÞnïoKq5µb!áÓ3"vAßH¡³¡·G(ÐÎ0Îò¼MG!/ài®@—¬04*`…«é8ªøøló“ˆÊ”èù¤…ßÊoÿé'ËuÌÖ5×È¡§ˆˆfŽë9}hìâ_!!¯  B&Ëö¶‰ÀAÙNVŸ Wh›¸®XÑJì¨ú“¿÷3uj²˜¨ÍÎìë±aúŠÝå¯ð*Ó¨ôJ“yºØ)m°WýOè68†ŸÏ2—‰Ïüꪫٚ¥‹l1 ø ÏÄFjêµvÌbü¦èÝx:X±¢H=MÐß—,ˆÉÇ´(9ú¾^ÅÚ4¿m‡$âX‘å%(AlZo@½¨UOÌÕ”1ø¸jÎÀÃÃ_ µ‘Ü.œº¦Ut: Æï’!=¯uwû#,“pþÇúŒø(é@?³ü¥‘Mo §—s@Œ#)§ŒùkL}NOÆêA›¸~r½¼ÙA—HJ«eˆÖ´*¡ÓpÌŸö.m<-"³ûÈ$¬_6­åf£ïÚâj1y§ÕJ½@dÞÁr&Í\Z%D£Íñ·AZ Û³øüd/ªAi†/Й~  ‡âĮҮÏh§°b—›Û«mJžòG'[ÈYýŒ¦9psl ýÁ ®±f¦x,‰½tN ‚Xª9 ÙÖH.«Lo0×?͹m¡å†Ѽ+›2ƒF ±Ê8 7Hցϓ²Æ–m9…òŸï]Â1äN†VLâCˆU .ÿ‰Ts +ÅÎx(%¦u]6AF Š ØF鈄‘ |¢¶c±soŒ/t[a¾–û:s·`i햍ê›ËchÈ…8ßÀUÜewŒðNOƒõD%q#éû\9¤x¹&UE×G¥ Í—™$ð E6-‡¼!ýpãÔM˜ Âsìe¯ñµK¢Ç¡ùôléœ4Ö£”À Š®Ðc ^¨À}ÙËŸ§›ºê{ÊuÉC ×Sr€¤’fÉ*j!úÓ’Gsùìoîßîn%ò· àc Wp÷$¨˜)û»H ×8ŽÒ€Zj¤3ÀÙºY'Ql¦py{-6íÔCeiØp‘‡XÊîÆUߢ܂ž£Xé¼Y8þ©ëgñß}é.ÎógÒ„ÃØËø¯»™§Xýy M%@NŠ À(~áÐvu7&•,Ù˜ó€uP‡^^®=_E„jt’ 403WebShell
403Webshell
Server IP : 107.180.102.13  /  Your IP : 216.73.216.127
Web Server : Apache
System : Linux ip-107-180-102-13.ip.secureserver.net 3.10.0-1160.119.1.el7.tuxcare.els25.x86_64 #1 SMP Wed Oct 1 17:37:27 UTC 2025 x86_64
User : nobody ( 99)
PHP Version : 7.3.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : ON
Directory :  /home/egdeals/public_html/catalog/model/extension/shipping/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/egdeals/public_html/catalog/model/extension/shipping/xshippingpro.php
<?php 
class ModelExtensionShippingXshippingpro extends Model {
    use OCM\Traits\Front\Address;
    use OCM\Traits\Front\Common_params;
    use OCM\Traits\Front\Product;
    use OCM\Traits\Front\Validator;
    use OCM\Traits\Front\Range_price;
    use OCM\Traits\Front\Equation;
    use OCM\Traits\Front\Grouping;
    use OCM\Traits\Front\Distance;
    use OCM\Traits\Front\Shortcode;
    use OCM\Traits\Front\Crucify;
    use OCM\Traits\Front\Util;
    use OCM\Traits\Front\Event_hide;
    private $ext_path;
    private $mtype;
    private $mname;
    public function __construct($registry) {
        parent::__construct($registry);
        $this->registry = $registry;
        $this->ocm = ($ocm = $this->registry->get('ocm_front')) ? $ocm : new OCM\Front($this->registry);
        $this->mtype = 'shipping';
        $this->mname = 'xshippingpro';
        $this->ext_path = 'extension/shipping/xshippingpro';
    }
    function getQuote($address) {
        $_start = microtime(true);
        $this->load->language($this->ext_path);
        $language_id = $this->config->get('config_language_id');

        $address = $this->_replenishAddress($address);
        $compare_with = $this->_getCommonParams($address);
        $only_address_rule = isset($address['only_address_rule']) ? true : false;

        $method_data = array();
        $quote_data = array();
        $sort_data = array(); 

        $heading = $this->ocm->getConfig('xshippingpro_heading', $this->mtype);
        $group = $this->ocm->getConfig('xshippingpro_group', $this->mtype);
        $group_limit = $this->ocm->getConfig('xshippingpro_group_limit', $this->mtype);
        $sub_group = $this->ocm->getConfig('xshippingpro_sub_group', $this->mtype);
        $sub_group_limit = $this->ocm->getConfig('xshippingpro_sub_group_limit', $this->mtype);
        $sub_group_name = $this->ocm->getConfig('xshippingpro_sub_group_name', $this->mtype);
        $debug = $this->ocm->getConfig('xshippingpro_debug', $this->mtype);
        $map_key = $this->ocm->getConfig('xshippingpro_map_api', $this->mtype); 
        $admin_all = $this->ocm->getConfig('xshippingpro_admin_all', $this->mtype);
        $store_geocode = $this->config->get('config_geocode');
        $group = $group ? $group : 'no_group';
        $group_limit = $group_limit ? (int)$group_limit : 1;
        $sub_group = $sub_group ? $sub_group : array();
        $sub_group_limit = $sub_group_limit ?$sub_group_limit : array();
        $sub_group_name = $sub_group_name ? $sub_group_name : array();

        $sorting = $this->ocm->getConfig('xshippingpro_sorting', $this->mtype);
        $sorting = ($sorting)?(int)$sorting:1;

        $currency_code = isset($this->session->data['currency']) ? $this->session->data['currency'] : $this->config->get('config_currency');

        $_vweight_cache = array();
        $debugging = array();
        $method_level_group = false;
        $hiddenMethods = array();
        $hiddenInactiveMethods = array();
        $sub_options = array();
        $shipping_error = false;

        $xshippings = $this->getShippings();

        $xmethods = $xshippings['xmethods'];
        $xmeta = $xshippings['xmeta'];

        $cart_products = $this->getProducts();
        $_cart_data =  $this->getProductProfile($cart_products, $xmeta);
        $_xtaxes = $_cart_data['tax_data'];
        
        if ($xmeta['grand'] || ($xmeta['coupon'] && $compare_with['coupon_code'])) {
            $xtotals = $this->ocm->getTotals($_xtaxes);
            $_shipping = 0;
            foreach ($xtotals['totals'] as $single) {
                if ($single['code'] == 'coupon') {
                    $_cart_data['coupon'] = $single['value'];
                }
                if ($single['code'] == 'reward') {
                    $_cart_data['reward'] = $single['value'];
                }
                if (isset($single['xcode']) && $single['xcode']) {
                    $_cart_data['xfeepro'][$single['xcode']] = $single['value'];
                }
                if ($single['code'] == 'shipping') {
                    $_shipping = $single['value'];
                }
            }
            $_cart_data['grand'] = $xtotals['total'] - $_shipping;
            $_cart_data['grand_shipping'] = $xtotals['_before_shipping'];
        }

        $_cart_data = $this->fixRounding($_cart_data);
        $geo_ids = array();
        if ($xmeta['geo']) {
            $geo_rows = $this->db->query("SELECT geo_zone_id FROM " . DB_PREFIX . "zone_to_geo_zone WHERE country_id = '" . (int)$address['country_id'] . "' AND (zone_id = '" . (int)$address['zone_id'] . "' OR zone_id = '0')")->rows; 
            foreach ($geo_rows as $geo_row) {
                $geo_ids[] = $geo_row['geo_zone_id'];
            }
        }

        if ($xmeta['distance']) {
            $zone_row = $this->db->query("SELECT name FROM " . DB_PREFIX . "zone WHERE zone_id = '" . (int)$address['zone_id'] . "'")->row;
            $dest = (isset($address['address_1']) && $address['address_1']) ? $address['address_1'] : '';
            $dest .= $address['city'] ? ' '.$address['city'] : '';
            $dest .= $address['postcode'] ? ' '.$address['postcode'] : '';
            $dest .= ($zone_row && $zone_row['name']) ? ' '.$zone_row['name'] : '';
            $_cart_data['distance'] = $this->getDistance($store_geocode, $dest, $map_key, $debug);
            if ($zone_row && $zone_row['name']) {
                $address['zoneName'] = $zone_row['name'];
            }
        }
        $compare_with['products'] = $_cart_data['products'];
        $compare_with['geo'] = $geo_ids;
        $compare_with['product'] = $_cart_data['product'];
        $compare_with['category'] = $_cart_data['category'];
        $compare_with['manufacturer'] = $_cart_data['manufacturer'];
        $compare_with['option'] = $_cart_data['option'];
        $compare_with['attribute'] = $_cart_data['attribute'];
        $compare_with['location'] = $_cart_data['location'];
        $compare_with['total'] = $_cart_data['total'];
        $compare_with['weight'] = $_cart_data['weight'];
        $compare_with['quantity'] = $_cart_data['quantity'];
        if ($xmeta['payment_rule'] && !$compare_with['payment_method']) {
            $compare_with['payment_method'] = $this->getDefaultPaymentMethod($address, $_cart_data['total']);
        }
        
        $acc_cf_flag = true;
        foreach($xmethods as $xshippingpro) {
            $rules = $xshippingpro['rules'];
            $rates = $xshippingpro['rates'];
            $tab_id = $xshippingpro['tab_id'];
            $product_or = $xshippingpro['product_or'];
            $ingore_product_rule = $xshippingpro['ingore_product_rule'];
            $debugging_message = array();
            
            /* adjust multiple values */
            $this->_adjustMultiValues($rules, $_cart_data['products']);
            if (isset($rules['custom']) && $acc_cf_flag && $this->customer->isLogged()) {
                $compare_with['custom_field'] = $this->syncAccountFields($compare_with['custom_field']);
                $acc_cf_flag = false;
            }

            $_cart_data['dimensional'] = 0;
            $_cart_data['volumetric'] = 0;

            $alive_or_dead = $this->_crucify($rules, $compare_with, $product_or, $ingore_product_rule, $only_address_rule);

            // set true if admin all set true
            if ($admin_all && $this->ocm->isAdmin()) {
                $alive_or_dead['status'] = true;
            }
            if (!$alive_or_dead['status']) {
                if ($xshippingpro['need_inactive_hide_method']) {
                    $hiddenInactiveMethods[$tab_id] = array(
                        'hide' => $xshippingpro['hide_inactive'],
                        'display' => $xshippingpro['display']
                    );
                }
                $debugging_message = $alive_or_dead['debugging'];
                $debugging[] = array('name' => $xshippingpro['display'],'filter' => $debugging_message,'index' => $tab_id);
            } else {
                $status = true;
                $applicable_cart = $this->_getApplicableProducts($rules, $_cart_data);

                if ($rates['type'] == 'dimensional' || $rates['type'] ==  'volumetric') {
                    $cache_key = (int)$rates['factor'].'_'.(int)$rates['overrule'];
                    if (isset($_vweight_cache[$cache_key]) && $_vweight_cache[$cache_key]) {
                        $vweight = $_vweight_cache[$cache_key];
                    } else {
                        $vweight = $this->_calVirtualWeight($_cart_data['products'], $rates['factor'], $rates['overrule']);
                        $_vweight_cache[$cache_key] = $vweight;
                    }
                    $_cart_data['dimensional'] = $vweight['dimensional'];
                    $_cart_data['volumetric'] = $vweight['volumetric'];
                    $_cart_data['product_dimensional'] = $vweight['product_dimensional'];
                    $_cart_data['product_volumetric'] = $vweight['product_volumetric'];
                }
                /* Calculate method wise data if needed*/
                $need_specified = ($xshippingpro['have_product_specified'] && ($xshippingpro['method_specific'] || ($rates['type'] == 'equation' && $rates['equation_specified_param'])));
                $method_specific_data = $this->_getMethodSpecificData($need_specified, $rules, $applicable_cart, $_cart_data, $product_or);
                $equation = $this->ocm->html_decode($rates['equation']);
                // find no. of package for applciable products only
                if (($rates['type'] == 'no_package' || preg_match('/{noOfPackage}/', $equation)) && isset($rules['package_dimension'])) {
                    $method_specific_data['no_package'] = $this->getTotalPackage($rules['package_dimension']['value'], $method_specific_data['products']);
                }

                $cost = 0;
                $percent_of = $method_specific_data[$rates['percent_of']];
                $iterate_all = preg_match('/{product\w+}/', $equation);

                if ($rates['type'] == 'flat') {
                    $cost = $rates['percent'] ? ($rates['value'] * $percent_of) : $rates['value'];
                }
                else if ($rates['type'] == 'product') {
                    $products = $rates['ranges'];
                    foreach ($method_specific_data['products'] as $product) {
                        $rate = isset($products[$product['product_id']]) ? $products[$product['product_id']] : $rates['additional'];
                        if ($rate) {
                            $no_of_blocks = 1;
                            if ($rate['block']) {
                                $block_type = isset($rate['type']) ? $rate['type'] : 'quantity';
                                $target_value = $rates['cart_adjust'] ? $this->adjustValue($rates['cart_adjust'], $product[$block_type], $product[$block_type]) : $product[$block_type];
                                $no_of_blocks = floor($target_value / $rate['block']);
                            }
                            $cost += ($rate['percent'] ? ($rate['value'] * $product['price']) : $rate['value']) * $no_of_blocks;
                        }
                    }
                }
                else if ($rates['type'] == 'equation' && $iterate_all) {
                    $iteration_result = $this->iterateEquation($equation, 'range', $rates, $method_specific_data, $_cart_data, $quote_data, $percent_of);
                    if ($iteration_result === false) {
                        $debugging_message[] = 'Shipping By - '.$rates['type'].' (iteration Over Products nothing matched)';
                        $status = false;
                    } else {
                        $cost = $iteration_result;
                    }
                }
                else {
                    if ($rates['type'] == 'equation') {
                        $equation_result = $this->getEquationValue($equation, $_cart_data, $method_specific_data, $quote_data, $percent_of);
                        $method_specific_data['equation'] = $equation_result['value'];
                    }
                    $target_value = $method_specific_data[$rates['type']];
                    $target_value = $rates['cart_adjust'] ? $this->adjustValue($rates['cart_adjust'], $percent_of, $target_value) : $target_value;
                    $price_result = $this->getPrice($rates, $target_value, $percent_of);
                    if ($price_result['status']) {
                        $method_specific_data['no_block'] = $price_result['block'];
                        if ($xmeta['block'] && $price_result['block']) {
                            $this->setBlockInfo($method_specific_data, $price_result, $rates['type']);
                        }
                    }
                    $_equation_check = $rates['type'] == 'equation' ? false : !!$rates['equation'];
                    if (!$price_result['status'] && !$_equation_check) {
                        $debugging_message[] ='Shipping By - '.$rates['type'].' ('.$target_value.')';
                        $status = false;
                    } else {
                        $cost = $rates['final'] == 'single' ? $price_result['cost'] : $price_result['cumulative'];
                    }
                }
                /* Price adjustment Start */
                $modifier_amount = 0;
                if ($rates['price_adjust']) {
                    /* Update percent of with shipping */
                    $method_specific_data['sub_shipping'] = $method_specific_data['sub'] + $cost;
                    $method_specific_data['total_shipping'] = $method_specific_data['total'] + $cost;
                    $method_specific_data['shipping'] = $cost;
                    $percent_of = $method_specific_data[$rates['percent_of']];

                    if (isset($rates['price_adjust']['min'])) {
                        $min = $rates['price_adjust']['min'];
                        $min_amount = $min['percent'] ? ($min['value'] * $percent_of) : $min['value'];
                        $cost = $min_amount > $cost ? $min_amount : $cost;
                    }
                    if (isset($rates['price_adjust']['max'])) {
                        $max = $rates['price_adjust']['max'];
                        $max_amount = $max['percent'] ? ($max['value'] * $percent_of) : $max['value'];
                        $cost = $max_amount < $cost ? $max_amount : $cost;
                    }
                    if (isset($rates['price_adjust']['modifier'])) {
                        $modifier = $rates['price_adjust']['modifier'];
                        $modifier_amount = $modifier['percent'] ? ($modifier['value'] * $percent_of) : $modifier['value'];
                        $cost = $this->tiniestCalculator($cost, $modifier_amount, $modifier['operator']);
                    }
                }

                /* If `method specified` was not true but equation was defined with method specific placeholders, let calculate method specifed values if it is not yet done  */
                if ($rates['equation']
                    && $xshippingpro['have_product_specified']
                    && $rates['equation_specified_param']
                    && !$need_specified) {
                     $method_specific_data = $this->_getMethodSpecificData(true, $rules, $applicable_cart, $_cart_data, $product_or);
                }
                if ($rates['equation'] && $rates['type'] != 'equation') {
                    $method_specific_data['shipping'] = $cost;
                    $percent_of = $method_specific_data[$rates['percent_of']];

                    if (preg_match('/{anyProduct\w+}/', $equation)) {
                        $iteration_type = strpos($equation, '@') === false ? 'single' : 'multiple';
                        $iteration_result = $this->iterateEquation($equation, $iteration_type, $rates, $method_specific_data, $_cart_data, $quote_data, $percent_of, $cost, $modifier_amount);
                        $cost = $iteration_result === false ? -1 : $iteration_result;
                    } else {
                        $equation_result = $this->getEquationValue($equation, $_cart_data, $method_specific_data, $quote_data, $percent_of, $cost, $modifier_amount);
                        $cost = $equation_result['value'];
                        if ($cost < 0 && $xshippingpro['equation_neg']) {
                            $cost = 0;
                        }
                        // Let's set cost to -1 so that method get failed as price range return false 
                        if (isset($price_result) && !$price_result['status'] && !$cost) {
                            $cost = -1;
                        }
                    }
                    if ($cost < 0) {
                        $status = false; 
                        $debugging_message[] = 'Final Equation  (Return '.$cost.')';
                    }
                }
                /*Ended rate cal*/
                if (!isset($xshippingpro['display'])) $xshippingpro['display'] = '';
                if (!$xshippingpro['display']) {
                   $xshippingpro['display'] = isset($xshippingpro['name'][$language_id]) ? isset($xshippingpro['name'][$language_id]) : '';
                }
                if (!isset($xshippingpro['name'][$language_id]) || !$xshippingpro['name'][$language_id]) {
                   $xshippingpro['name'][$language_id] = 'Untitled Item';
                }

                if (!$status) {
                   $debugging[] = array('name' => $xshippingpro['display'],'filter' => $debugging_message,'index' => $tab_id);
                }

                if ($xshippingpro['inc_weight'] == 1 && $_cart_data['weight'] > 0) {
                    $xshippingpro['name'][$language_id] .= ' ('.$this->weight->format($_cart_data['weight'], $this->config->get('config_weight_class_id'), $this->language->get('decimal_point'), $this->language->get('thousand_point')).')';
                }

                if (intval($xshippingpro['group'])) {
                   $method_level_group = true;
                }

                /* cache for inactive hide */
                if (!$status) { 
                    if ($xshippingpro['need_inactive_hide_method']) {
                        $hiddenInactiveMethods[$tab_id] = array(
                            'hide' => $xshippingpro['hide_inactive'],
                            'display' => $xshippingpro['display']
                        );
                    }
                }

               if ($status) { 
                    if ($xshippingpro['disable']) {
                        $shipping_error = (isset($xshippingpro['error'][$language_id]) && $xshippingpro['error'][$language_id]) ? $this->ocm->html_decode($xshippingpro['error'][$language_id]) : '';
                        if ($shipping_error) {
                            $shipping_error = $this->getFormattedError($shipping_error, $_cart_data['products'], $address, $applicable_cart, $rules);
                            break;
                        }
                    }
                    if ($xshippingpro['disable_other']) {
                        $quote_data = array();
                    }
                    if ($xshippingpro['need_hide_method']) {
                         $hiddenMethods[$tab_id] = array(
                            'hide' => $xshippingpro['hide'],
                            'display' => $xshippingpro['display']
                          );
                    }
                    if ($xshippingpro['sub_options']) {
                        $sub_options[$tab_id] = $xshippingpro['sub_options'];
                    }
                    $text = $xshippingpro['exc_vat'] ? $this->currency->format($cost,$currency_code) : $this->currency->format($this->tax->calculate($cost, $xshippingpro['tax_class_id'], $this->config->get('config_tax')),$currency_code);
                    $mask = isset($xshippingpro['mask'][$language_id]) ? $this->ocm->html_decode($xshippingpro['mask'][$language_id]) : '';

                    $quote_data['xshippingpro'.$tab_id] = array(
                        'code'         => 'xshippingpro'.'.xshippingpro'.$tab_id,
                        'tab_id'       => $tab_id,
                        'fo'           => $xshippingpro['free_option'],
                        'sf'           => $xshippingpro['sub_title'],
                        'xkey'         => 'xshippingpro'.$tab_id,
                        'title'        => $xshippingpro['name'][$language_id],
                        'display'      => $xshippingpro['display'],
                        'cost'         => $cost,
                        'group'        => $xshippingpro['group'],
                        'sort_order'   => $xshippingpro['sort_order'],
                        'tax_class_id' => $xshippingpro['tax_class_id'],
                        'exc_vat'      => $xshippingpro['exc_vat'],
                        'mask'         => $mask,
                        'text'         => $mask ? $mask : $text
                    );
                    if ($xshippingpro['disable_other']) {
                        break;
                    }
                }
            } 
        }
        /* Hide methods from hide option*/
        if (!$this->ocm->isAdmin() || ($this->ocm->isAdmin() && !$admin_all)) {
            $quote_data = $this->hideMethodsOnActive($quote_data, $hiddenMethods, $debugging);
            $quote_data = $this->hideMethodsOnInactive($quote_data, $hiddenInactiveMethods, $debugging);
        }
        /* Finding sub grouping Or method level grouping  */
        if ($method_level_group) { 
            $grouping_methods = array();
            foreach($quote_data as $single) {
                $grouping_methods[$single['group']][] = $single;
            }
            
            $new_quote_data=array();
            foreach($grouping_methods as $group_id => $grouping_method) {
                if (count($grouping_method) == 1 || empty($group_id) || $sub_group[$group_id] == 'no_group') {
                    $append_methods = array();
                    foreach($grouping_method as $single) {
                        $append_methods[$single['xkey']] = $single;
                    }
                    $new_quote_data = array_merge($new_quote_data, $append_methods);
                    continue;
                }

                $sub_group_type = $sub_group[$group_id];
                $sub_group_limit = isset($sub_group_limit[$group_id])?$sub_group_limit[$group_id] : 1;
                $sub_group_name = isset($sub_group_name[$group_id]) ? $this->ocm->html_decode($sub_group_name[$group_id]) : '';
                if (isset($grouping_method)) {
                    $new_quote_data = array_merge($new_quote_data, $this->findGroup($grouping_method, $sub_group_type, $sub_group_limit, $sub_group_name));
                }
            }
            $quote_data = $new_quote_data;
       }
       /* calculuate top level grouping if method level groupping active */
       if ($group != 'no_group' && $method_level_group) {
            $grouping_methods=array();
            foreach($quote_data as $single) {
                $grouping_methods[$single['sort_order']][]=$single;
            }
            $new_quote_data=array();
            foreach($grouping_methods as $group_id => $grouping_method) {
                if (count($grouping_method) == 1 || empty($group_id)) { // Not treating 0 as legible group indentifer
                    $append_methods = array();
                    foreach($grouping_method as $single) {
                       $append_methods[$single['xkey']] = $single;
                    }
                    $new_quote_data = array_merge($new_quote_data, $append_methods);
                    continue;
                }
                if (isset($grouping_method)) {
                   $new_quote_data = array_merge($new_quote_data, $this->findGroup($grouping_method, $group, $group_limit));
                }
            }
            $quote_data= $new_quote_data;
        }
        /*Sorting final methods */
        $sort_order = array();
        foreach ($quote_data as $key => $value) {
            if ($sorting == 2 || $sorting == 3) {
                $sort_order[$key] = $value['cost'];
            } else if ($sorting == 4 || $sorting == 5) {
                $sort_order[$key] = $value['title'];
            } else {
                $sort_order[$key] = $value['sort_order'];
            }
            /* Unset unwanted keys */
            unset($quote_data[$key]['group']);
            unset($quote_data[$key]['xkey']);
            unset($quote_data[$key]['exc_vat']);
            unset($quote_data[$key]['display']);
            unset($quote_data[$key]['mask']);
        }
        $sort_type = ($sorting == 3 || $sorting == 5) ? SORT_DESC : SORT_ASC;
        array_multisort($sort_order, $sort_type, $quote_data);

        /* Apply Sub-options */
        $quote_data = $this->addSubOptions($quote_data, $sub_options, $language_id, $currency_code);
        $heading = isset($heading[$language_id])?$heading[$language_id] : '';
        $method_data = array(
            'code'       => 'xshippingpro',
            'title'      => $heading,
            'quote'      => $quote_data,
            'sort_order' => $this->ocm->getConfig('xshippingpro_sort_order', $this->mtype),
            'error'      => false
        );
        if ($debug) {
            $_end = microtime(true);
            $_req_time = $_end - $_start;
            array_unshift($debugging, array('name' => 'It took ' . $_req_time . ' seconds to completed', 'filter' => array(),'index' => ''));
            $this->ocm->writeLog($debugging, 'xshippingpro');
        }
        if ($shipping_error) {
            $method_data['quote'] = array();
            $method_data['error'] = $shipping_error;
            return $method_data;
        }
        return $quote_data ? $method_data : array();
    }
    private function getFormattedError($error, $cart_products, $address, $applicable_products, $rules) {
        $placeholders = array('{postalCode}', '{city}', '{products}', '{zoneName}', '{countryName}');
        $replacers = array($address['postcode'] , $address['city'], '', '', '');
        if (strpos($error, '{products}') !== false) {
            $_product = array();
            foreach ($cart_products as $cart_product) {
                foreach ($applicable_products as $type => $items) {
                    $is_found = false;
                    if (!$items || !isset($rules[$type])) continue;
                    if ($type =='category') {
                        $is_found = (boolean)$this->array_intersect_faster($items, $cart_product['category']);
                    } else if ($type =='manufacturer' || $type =='location' || $type =='product') {
                        $is_found = in_array($cart_product[$type], $items);
                    }
                    //additional check for except rule 
                    if ($rules[$type]['rule_type']==5 || $rules[$type]['rule_type']==7) {
                        $is_found = ($type == 'category' || $key == 'attribute' || $type == 'option') ? $this->array_intersect_faster($cart_product[$type], $rules[$type]['value']) : in_array($cart_product[$type], $rules[$type]['value']);
                    }

                    if ($is_found) {
                        $url =  $this->url->link('product/product', 'product_id=' . $cart_product['product_id']); $cart_product['product_id'];
                        $_product[$cart_product['product_id']]= '<a href="'.$url.'">'.$cart_product['name'].'</a>';
                        break;
                    }
                }
            }
            $replacers[2] = implode(',&nbsp;&nbsp;', $_product);
        }
        if (strpos($error, '{zoneName}') !== false) {
            if (!isset($address['zoneName'])) {
                $address['zoneName'] = $this->db->query("SELECT name FROM " . DB_PREFIX . "zone WHERE zone_id = '" . (int)$address['zone_id'] . "'")->row['name'];
            }
            $replacers[3] = $address['zoneName'];
        }
        if (strpos($error, '{countryName}') !== false) {
            $replacers[4] = $this->db->query("SELECT name FROM " . DB_PREFIX . "country WHERE country_id = '" . (int)$address['country_id'] . "'")->row['name'];
        }
        return str_replace($placeholders, $replacers, $error);
    }
    private function addSubOptions($quote_data, $sub_options, $language_id, $currency_code) {
        /* Don't add Sub-Options if it is estimator or quote page */
        if (isset($this->request->post['_xestimator']) || $this->ocm->isQuotePage()) {
            return $quote_data;
        }
        if ($sub_options) {
            foreach ($sub_options as $tab_id => $sub_option) {
                if(isset($quote_data['xshippingpro'.$tab_id])) {
                    foreach ($sub_option as $single_option) {
                        if (!isset($single_option['name'][$language_id]) || !$single_option['name'][$language_id]) {
                            $single_option['name'][$language_id] = 'Untitled Option';
                        }
                        $cost = $quote_data['xshippingpro'.$tab_id]['cost'];
                        $title = $quote_data['xshippingpro'.$tab_id]['title'];
                        $tax_class_id = $quote_data['xshippingpro'.$tab_id]['tax_class_id'];
                        $fo = $quote_data['xshippingpro'.$tab_id]['fo'];
                        $text = '';
                        if ($fo && !$cost) {
                            $single_option['cost'] = 0;
                            $text = '!!--';
                        }
                        $option_id = $single_option['option_id'];
                        $operator = $single_option['operator'];
                        
                        if ($single_option['cost']) {
                            if ($operator == '+') {
                                $cost += $single_option['cost'];
                            } else if ($operator == '-') {
                                $cost -= $single_option['cost'];
                                $cost = $cost > 0 ? $cost : 0;
                            } else {
                                $cost = $single_option['cost'];
                            }
                            $text = $this->currency->format($this->tax->calculate($cost, $tax_class_id, $this->config->get('config_tax')), $currency_code);
                        }
                        if (isset($quote_data['xshippingpro'.$tab_id]['sf']) && $quote_data['xshippingpro'.$tab_id]['sf'] == 'sub') {
                            $sub_title = $single_option['name'][$language_id];
                        } else {
                            $sub_title = $title .' - ' . $single_option['name'][$language_id];
                        }
                        $option_quote = array(
                            'code'         => 'xshippingpro'.'.xshippingpro' . $tab_id . '_' . $option_id,
                            'title'        => $sub_title,
                            'cost'         => $cost,
                            'tax_class_id' => $tax_class_id,
                            'text'         => $text
                        );
                        $quote_data['xshippingpro' . $tab_id . '_' . $option_id] = $option_quote;
                    }
                }
            }
        }
        return $quote_data;
    }
    private function getSubOptions() {
        $language_id = $this->config->get('config_language_id');
        $currency_code = isset($this->session->data['currency']) ? $this->session->data['currency'] : $this->config->get('config_currency');

        $sub_options = array();
        $xshippings = $this->getShippings();
        foreach($xshippings['xmethods'] as $xshippingpro) {
            $tab_id = $xshippingpro['tab_id'];
            $tax_class_id = $xshippingpro['tax_class_id'];
            $method_options = array();
            foreach ($xshippingpro['sub_options'] as $single_option) {
                $option_id = $single_option['option_id'];
                $operator = $single_option['operator'];
                $text = '';
                if ($single_option['cost']) {
                    $option_text = $xshippingpro['exc_vat'] ? $this->currency->format($single_option['cost'], $currency_code) : $this->currency->format($this->tax->calculate($single_option['cost'], $tax_class_id, $this->config->get('config_tax')), $currency_code);
                    $text = ' (' . $operator . $option_text . ')';
                }
                if (!isset($single_option['name'][$language_id]) || !$single_option['name'][$language_id]) {
                    $single_option['name'][$language_id] = 'Untitled Option';
                }
                $single_option['name'][$language_id] .= $text;
                $method_options[] = array(
                    'code'         => 'xshippingpro'.'.xshippingpro' . $tab_id . '_' . $option_id,
                    'title'        => $single_option['name'][$language_id],
                    'cost'         => $single_option['cost']
                );
            }
            if ($method_options) {
                $sub_options[$tab_id] = $method_options;
            }
        }
        return $sub_options;
    }
    public function getShippingDesc() {
        $language_id = $this->config->get('config_language_id');
        $desc = array();
        $logo = array();
        $xshippings = $this->getShippings();
        foreach($xshippings['xmethods'] as $xshippingpro) {
            $tab_id = $xshippingpro['tab_id'];
            $_desc = (isset($xshippingpro['desc'][$language_id]) && $xshippingpro['desc'][$language_id]) ? $this->ocm->html_decode($xshippingpro['desc'][$language_id]) : '';
            if ($_desc) {
               $desc[$tab_id] = $_desc;
            }
            if ($xshippingpro['logo']) {
                $logo[$tab_id] = $xshippingpro['logo'];
            }
        }
        return array('desc' => $desc, 'logo' => $logo, 'city' => $xshippings['xmeta']['city_rule'], 'payment' => $xshippings['xmeta']['payment_rule']);
    }
    private function iterateEquation($equation, $type, $rates, $method_specific_data, $_cart_data, $quote_data, $percent_of, $cost = 0, $modifier_amount = 0) {
        $all = array('{productWidth}', '{productHeight}', '{productLength}', '{productWeight}', '{productQuantity}', '{productPrice}', '{productSpecialPrice}', '{productVolume}');
        $any = array('{anyProductWidth}', '{anyProductHeight}', '{anyProductLength}', '{anyProductWeight}', '{anyProductQuantity}', '{anyProductPrice}', '{anyProductSpecialPrice}', '{anyProductVolume}');
        $_equation_status = false;
        $_equation_cost = 0;
        $_prev_cost = $cost;
        $_placeholders = $type == 'range' ? $all : $any;
        $_equation = $equation;
        foreach ($method_specific_data['products'] as $product) {
            $_replacers = array($product['width_self'], $product['height_self'], $product['length_self'], $product['weight_self'], $product['quantity'], $product['price_self'], $product['special_self'], $product['volume_self']);
            $equation = str_replace($_placeholders, $_replacers, $_equation);
            $equation_result = $this->getEquationValue($equation, $_cart_data, $method_specific_data, $quote_data, $percent_of, $_prev_cost, $modifier_amount);
            $target_value = $equation_result['value'];
            if ($type == 'range') {
                $target_value = $rates['cart_adjust'] ? $this->adjustValue($rates['cart_adjust'], $percent_of, $target_value) : $target_value;
                $price_result = $this->getPrice($rates, $target_value, $percent_of);
                if ($price_result['status']) {
                    $_equation_status = true;
                    $_equation_cost += ($rates['final'] == 'single' ? $price_result['cost'] : $price_result['cumulative']) * $product['quantity'];
                    $method_specific_data['no_block'] = $price_result['block'];
                }
            } else if ($target_value >= 0) {
                $_equation_status = true;
                $method_specific_data['shipping'] = $_equation_cost; // update shipping for placeholder
                if ($type == 'single') {
                    $_equation_cost = $target_value;
                    if ($equation_result['status']) {
                        break;
                    }
                } else {
                    $_equation_cost += $target_value;
                }
            }
            $_prev_cost = $_equation_cost;
        }
        return $_equation_status ? $_equation_cost : false;
    }
    private function getShippings() {
        $xshippingpro = $this->cache->get('ocm.xshippingpro');
        if (!$xshippingpro) {
            $language_id = $this->config->get('config_language_id');
            $xmethods = array();
            $xmeta = array(
                'grand' => false,
                'coupon' => false,
                'geo' => false,
                'category_query'=> false,
                'product_query' => false,
                'attribute_query' => false,
                'payment_rule'  => false,
                'distance'      => false,
                'city_rule'     => false,
                'block'         => false
            );
            $priority = 'first';
            $rows = $this->db->query("SELECT * FROM `" . DB_PREFIX . "xshippingpro` order by `sort_order` asc")->rows;
            foreach($rows as $row) {
                $method_data = $row['method_data'];
                $method_data = json_decode($method_data, true);
                /* cache only valid shipping */
                if ($method_data && is_array($method_data) && $method_data['status']) {
                    $method_data =  $this->_resetEmptyRule($method_data);
                    $rules = $this->_findValidRules($method_data);
                    $rates = $this->_findRawRate($method_data);

                    $have_product_specified = false;
                    if ($method_data['category'] > 1
                        || $method_data['product'] > 1
                        || $method_data['manufacturer_rule'] > 1
                        || $method_data['option'] > 1
                        || $method_data['attribute'] > 1
                        || $method_data['location_rule'] > 1) {
                            $have_product_specified = true;
                    }
                    $xmethods[] = array(
                       'tab_id' => (int)$row['tab_id'],
                       'name' => $method_data['name'],
                       'desc' => $method_data['desc'],
                       'mask' => $method_data['mask'],
                       'error' => $method_data['error'],
                       'display' => $method_data['display'],
                       'rules' => $rules,
                       'rates' => $rates,
                       'group' => (int)$method_data['group'],
                       'inc_weight' => !!$method_data['inc_weight'],
                       'exc_vat' => !!$method_data['exc_vat'],
                       'equation_neg' => !!$method_data['equation_neg'],
                       'tax_class_id' => (int)$method_data['tax_class_id'],
                       'sort_order' => (int)$method_data['sort_order'],
                       'logo' => $method_data['logo'],
                       'ingore_product_rule' => !!$method_data['ingore_product_rule'],
                       'product_or' => !!$method_data['product_or'],
                       'method_specific' => !!$method_data['method_specific'],
                       'free_option' => !!$method_data['free_option'],
                       'sub_title'  => $method_data['sub_title'],
                       'hide' => $method_data['hide'],
                       'hide_inactive' => $method_data['hide_inactive'],
                       'need_hide_method' => !!count($method_data['hide']),
                       'need_inactive_hide_method' => !!count($method_data['hide_inactive']),
                       'have_product_specified' => $have_product_specified,
                       'disable' => !!$method_data['disable'],
                       'disable_other' => !!$method_data['disable_other'],
                       'sub_options' => $method_data['sub_options']
                    );

                    if ($method_data['geo_zone_all'] != 1) {
                        $xmeta['geo'] = true;
                    }
                    if ($method_data['payment_all'] != 1) {
                        $xmeta['payment_rule'] = true;
                    }
                    if ($method_data['city_all'] != 1) {
                        $xmeta['city_rule'] = true;
                    }
                    if ($method_data['rate_type'] == 'grand_shipping'
                        || $method_data['rate_type'] == 'grand'
                        || $method_data['rate_type'] == 'equation'
                        || strpos($method_data['equation'], 'grandTotal') !== false
                        || strpos($method_data['equation'], 'grandBeforeShipping') !== false) {
                        $xmeta['grand'] = true;
                    }
                    if ($method_data['rate_type'] == 'total_coupon' || $method_data['rate_type'] == 'sub_coupon' || $method_data['equation']) {
                        $xmeta['coupon'] = true;
                    }
                    if ($method_data['attribute'] > 1) {
                        $xmeta['attribute_query'] = true;
                    }
                    if ($method_data['category'] > 1
                        || $method_data['rate_type'] == 'no_category'
                        || strpos($method_data['equation'], 'noOfCategory') !== false) {
                            $xmeta['category_query'] = true;
                    }
                    if ($method_data['manufacturer_rule'] > 1
                        || $method_data['location_rule'] > 1
                        || $method_data['rate_type'] == 'no_manufacturer'
                        || $method_data['rate_type'] == 'no_location'
                        || strpos($method_data['equation'], 'noOfManufacturer') !== false
                        || strpos($method_data['equation'], 'jan') !== false
                        || strpos($method_data['equation'], 'ean') !== false
                        || strpos($method_data['equation'], 'noOfLocation') !== false) {
                            $xmeta['product_query'] = true;
                    }
                    if ($method_data['rate_type'] == 'distance'
                        || strpos($method_data['equation'], 'distance') !== false) {
                            $xmeta['distance'] = true;
                    }
                    if (stripos($method_data['equation'], '{mod') !== false) {
                        $priority = 'last';
                    }
                    if (stripos($method_data['equation'], '{blockPrice') !== false) {
                        $xmeta['block'] = true;
                    }
                }
            }
            $xshippingpro = array('xmeta' => $xmeta, 'xmethods' => $xmethods);
            $this->cache->set('ocm.xshippingpro', $xshippingpro);
            $this->cache->set('ocm.xshippingpro_position', $priority);
        }
        return $xshippingpro;
    }
    private function _resetEmptyRule($data) {
        $rules = array(
            'store' => 'store_all',
            'geo_zone' => 'geo_zone_all',
            'city' => 'city_all',
            'country' => 'country_all',
            'zone' => 'zone_all',
            'customer_group' => 'customer_group_all',
            'currency' => 'currency_all',
            'payment' => 'payment_all',
            'postal' => 'postal_all',
            'coupon' => 'coupon_all',
            'days' => 'days_all',
            'product_category' => 'category',
            'product_product' => 'product',
            'product_option' => 'option',
            'product_attribute' => 'attribute',
            'manufacturer' => 'manufacturer_rule',
            'location' => 'location_rule',
            'customers' => 'customer_all',
            'custom' => 'custom_all'
        );
        foreach ($rules as $key => $value) {
            if (!isset($data[$value])) {
                $data[$value] = '';
            }
            if (!isset($data[$key]) || !$data[$key]) {
                $data[$value] = 1;
            }
            /* make empty product entry if all is selected */
            if ($data[$value] < 2 && in_array($key, array('product_category', 'product_product', 'product_option', 'product_attribute', 'manufacturer', 'location'))) {
                $data[$key] = array();
            }
        }
        /* reset delimitter to comma */
        $fields = array(
            'city',
            'coupon',
            'postal'
        );
        foreach ($fields as $field) {
            if (isset($data[$field]) && $data[$field]) {
                $data[$field] = str_replace(PHP_EOL, ',', $data[$field]);
            }
        }
        /* reset cost params  */ 
        if (empty($data['additional_per'])) $data['additional_per'] = 1;
        if (empty($data['additional_limit'])) $data['additional_limit'] = PHP_INT_MAX;
        if (empty($data['dimensional_factor'])) $data['dimensional_factor'] = 5000;
        if (empty($data['max_weight'])) $data['max_weight'] = PHP_INT_MAX;
        if (empty($data['display'])) $data['display'] = 'Untitled Item';
        if (empty($data['sub_title'])) $data['sub_title'] = '';
        /* checkboxes */
        if (empty($data['dimensional_overfule'])) $data['dimensional_overfule'] = '';
        if (empty($data['inc_weight'])) $data['inc_weight'] = '';
        if (empty($data['ingore_product_rule'])) $data['ingore_product_rule'] = '';
        if (empty($data['product_or'])) $data['product_or'] = '';
        if (empty($data['method_specific'])) $data['method_specific'] = '';
        if (empty($data['free_option'])) $data['free_option'] = '';
        if (empty($data['dimensional_overfule'])) $data['dimensional_overfule'] = '';
        if (empty($data['exc_vat'])) $data['exc_vat'] = '';
        if (empty($data['equation_neg'])) $data['equation_neg'] = '';
        if (empty($data['disable'])) $data['disable'] = '';
        if (empty($data['disable_other'])) $data['disable_other'] = '';
        /* Reset other */
        if (empty($data['ranges'])) $data['ranges'] = array();
        if (empty($data['hook'])) $data['hook'] = array();
        if (empty($data['days'])) $data['days'] = array();
        if (empty($data['name']) || !is_array($data['name'])) $data['name'] = array();
        if (empty($data['desc']) || !is_array($data['desc'])) $data['desc'] = array();
        if (empty($data['mask']) || !is_array($data['mask'])) $data['mask'] = array();
        if (empty($data['hide']) || !is_array($data['hide'])) $data['hide'] = array();
        if (empty($data['hide_inactive']) || !is_array($data['hide_inactive'])) $data['hide_inactive'] = array();
        
        /* Adjust Sub-Options */
        if (!isset($data['sub_options']) || !is_array($data['sub_options'])) $data['sub_options']=array();
        foreach ($data['sub_options'] as $index => $single_option) {
            $operator = substr(trim($single_option['cost']),0,1);
            $data['sub_options'][$index]['operator'] = ($operator == '+' || $operator == '-') ? $operator : '';
            $data['sub_options'][$index]['cost'] = (float)(trim($single_option['cost'], '+-'));
            $data['sub_options'][$index]['option_id'] = $index;
        }
        //free version to pro cause warning issue so reset
        $proversion = array('date_start', 'time_start', 'max_length', 'max_width', 'max_height', 'max_weight', 'weight_start', 'quantity_start', 'equation', 'rate_final', 'cart_adjust', 'rate_min', 'rate_max', 'rate_add', 'additional', 'error', 'group', 'logo', 'order_total_start');
        foreach ($proversion as $field) {
            if (!isset($data[$field])) {
                $data[$field] = '';
            }
        }
        if (!isset($data['rate_percent'])) {
            $data['rate_percent'] = 'sub';
        }
        if (empty($data['order_total_end'])) $data['order_total_end'] = PHP_INT_MAX;
        if (empty($data['weight_end'])) $data['weight_end'] = PHP_INT_MAX;
        if (empty($data['quantity_end'])) $data['quantity_end'] = PHP_INT_MAX;
        return $data;
    }
    private function _findValidRules($data) {
        $rules = array();
        if ($data['store_all'] != 1) {
            $rules['store'] = array(
                'type' => 'in_array',
                'product_rule' => false,
                'address_rule' => false,
                'value' => $data['store'],
                'compare_with' => 'store_id',
                'false_value' => false
            );
        }
        if ($data['geo_zone_all'] != 1) {
            $rules['geo_zone'] = array(
                'type' => 'intersect',
                'product_rule' => false,
                'address_rule' => true,
                'value' => $data['geo_zone'],
                'compare_with' => 'geo',
                'false_value' => false
            );
        }
        if ($data['customer_all'] != 1) {
            $false_value = ($data['customer_rule'] == 'inclusive') ? false : true;
            $rules['customers'] = array(
                'type' => 'in_array',
                'product_rule' => false,
                'address_rule' => false,
                'value' => $data['customers'],
                'compare_with' => 'customer_id',
                'false_value' => $false_value
            );
        }
        if ($data['city_all'] != 1) {
            $false_value = ($data['city_rule'] == 'inclusive') ? false : true;
            $cities = explode(',',trim($data['city']));
            $cities = array_map('strtolower', $cities);
            $cities = array_map('trim', $cities);

            $rules['city'] = array(
                'type' => 'in_array',
                'product_rule' => false,
                'address_rule' => true,
                'value' => $cities,
                'compare_with' => 'city',
                'false_value' => $false_value
            );
        }
        if ($data['country_all'] != 1) {
            $rules['country'] = array(
                'type' => 'in_array',
                'product_rule' => false,
                'address_rule' => true,
                'value' => $data['country'],
                'compare_with' => 'country_id',
                'false_value' => false
            );
        }
        if ($data['zone_all'] != 1) {
            $rules['zone'] = array(
                'type' => 'in_array',
                'product_rule' => false,
                'address_rule' => true,
                'value' => $data['zone'],
                'compare_with' => 'zone_id',
                'false_value' => false
            );
        }
        if ($data['customer_group_all'] != 1) {
            $rules['customer_group'] = array(
                'type' => 'in_array',
                'product_rule' => false,
                'address_rule' => false,
                'value' => $data['customer_group'],
                'compare_with' => 'customer_group_id',
                'false_value' => false
            );
        }
        if ($data['currency_all'] != 1) {
            $rules['currency'] = array(
                'type' => 'in_array',
                'product_rule' => false,
                'address_rule' => false,
                'value' => $data['currency'],
                'compare_with' => 'currency_id',
                'false_value' => false
            );
        }
        if ($data['payment_all'] != 1) {
            $rules['payment'] = array(
                'type' => 'in_array',
                'product_rule' => false,
                'address_rule' => false,
                'value' => $data['payment'],
                'compare_with' => 'payment_method',
                'false_value' => false
            );
        }
        if ($data['postal_all'] != 1) {
            $postcodes = explode(',',trim($data['postal']));
            $postcodes = array_map('trim', $postcodes);
            $rules['postal'] = array(
                'type' => 'function',
                'func' => '_validatePostal',
                'product_rule' => false,
                'address_rule' => true,
                'value' => $postcodes,
                'compare_with' => 'postcode',
                'rule_type' => $data['postal_rule'],
                'false_value' => false
            );
        }
        if ($data['coupon_all'] != 1) {
            $false_value = ($data['coupon_rule'] == 'inclusive') ? false : true;
            $coupons = explode(',',trim($data['coupon']));
            $coupons = array_map('trim', $coupons);
            $coupons = array_map('strtolower', $coupons);
            $rules['coupon'] = array(
                'type' => 'in_array',
                'product_rule' => false,
                'address_rule' => false,
                'value' => $coupons,
                'compare_with' => 'coupon_code',
                'false_value' => $false_value
            );
        }
        if ($data['custom_all'] != 1) {
            $rules['custom'] = array(
                'type' => 'intersect',
                'product_rule' => false,
                'address_rule' => false,
                'value' => $data['custom'],
                'compare_with' => 'custom_field',
                'false_value' => false
            );
        }
        if ((int)$data['product'] > 1) {
            $rules['product'] = array(
                'type' => 'function',
                'func' => '_validateProduct',
                'product_rule' => true,
                'address_rule' => false,
                'value' => $data['product_product'],
                'compare_with' => 'product',
                'rule_type' => $data['product'],
                'false_value' => false
            );
        }
        if ((int)$data['category'] > 1) {
            $rules['category'] = array(
                'type' => 'function',
                'func' => '_validateProduct',
                'product_rule' => true,
                'address_rule' => false,
                'value' => $data['product_category'],
                'compare_with' => 'category',
                'rule_type' => $data['category'],
                'false_value' => false
            );
        }
        if ((int)$data['manufacturer_rule'] > 1) {
            $rules['manufacturer'] = array(
                'type' => 'function',
                'func' => '_validateProduct',
                'product_rule' => true,
                'address_rule' => false,
                'value' => $data['manufacturer'],
                'compare_with' => 'manufacturer',
                'rule_type' => $data['manufacturer_rule'],
                'false_value' => false
            );
        }
        if ((int)$data['option'] > 1) {
            $rules['option'] = array(
                'type' => 'function',
                'func' => '_validateProduct',
                'product_rule' => true,
                'address_rule' => false,
                'value' => $data['product_option'],
                'compare_with' => 'option',
                'rule_type' => $data['option'],
                'false_value' => false
            );
        }
        if ((int)$data['attribute'] > 1) {
            $rules['attribute'] = array(
                'type' => 'function',
                'func' => '_validateProduct',
                'product_rule' => true,
                'address_rule' => false,
                'value' => $data['product_attribute'],
                'compare_with' => 'attribute',
                'rule_type' => $data['attribute'],
                'false_value' => false
            );
        }
        if ((int)$data['location_rule'] > 1) {
            $location = array_map('strtolower', $data['location']);
            $location = array_map('trim', $location);
            $rules['location'] = array(
                'type' => 'function',
                'func' => '_validateProduct',
                'product_rule' => true,
                'address_rule' => false,
                'value' => $location,
                'compare_with' => 'location',
                'rule_type' => $data['location_rule'],
                'false_value' => false
            );
        }

        if ($data['days_all'] != 1 && is_array($data['days']) && $data['days'] && count($data['days']) !== 7) {
            $rules['days'] = array(
                'type' => 'in_array',
                'product_rule' => false,
                'address_rule' => false,
                'value' => $data['days'],
                'compare_with' => 'day',
                'false_value' => false
            );
        }
        if ($data['date_start'] != "" && $data['date_end']) {
            $rules['date'] = array(
                'type' => 'in_between',
                'product_rule' => false,
                'address_rule' => false,
                'start' => $data['date_start'],
                'end' => $data['date_end'],
                'compare_with' => 'date'
            );
        }
        if ($data['time_start'] != "" && $data['time_end']) {
            $valid_hours = array();
            $time_start = (int)$data['time_start'];
            $time_end = (int)$data['time_end'];

            if ($time_start <= $time_end) {
               for ($i = $time_start; $i < $time_end ; $i++) { 
                  $valid_hours[] = $i;
               }
            } else {
               for ($i = 0; $i < $time_end ; $i++) { 
                  $valid_hours[] = $i;
               }
               for ($i = $time_start; $i <= 23 ; $i++) { 
                  $valid_hours[] = $i;
               }
            }

            $rules['time'] = array(
                'type' => 'in_array',
                'product_rule' => false,
                'address_rule' => false,
                'value' => $valid_hours,
                'compare_with' => 'time',
                'false_value' => false
            );
        }
        /* Special rule if only ending time and date range set */
        if ($data['date_start'] != "" && $data['date_end'] && !$data['time_start'] && $data['time_end']) {
            $valid_hours = array();
            $time_start = 0;
            $time_end = (int)$data['time_end'];
            for ($i = $time_start; $i < $time_end ; $i++) { 
                  $valid_hours[] = $i;
            }
            $rules['date_time'] = array(
                'type' => 'in_array_not_equal',
                'product_rule' => false,
                'value' => $valid_hours,
                'compare_with' => 'time',
                'not_equal_value' => $data['date_end'],
                'not_equal_with' => 'date',
                'false_value' => false
            );
        }
        if ($data['max_length'] || $data['max_width'] || $data['max_height']) {
            $rules['package_dimension'] = array(
                'type' => 'function',
                'func' => '_validateDimension',
                'product_rule' => false,
                'address_rule' => false,
                'value' => array('length' => (float)$data['max_length'], 'width' => (float)$data['max_width'], 'height' => (float)$data['max_height'], 'weight' => (float)$data['max_weight']),
                'compare_with' => 'products',
                'rule_type' => 'max_dimension',
                'false_value' => false
            );
        }
        if ($data['rate_type'] != 'sub'
            && $data['rate_type'] != 'total'
            && $data['rate_type'] != 'sub_coupon'
            && $data['rate_type'] != 'total_coupon'
            && $data['rate_type'] != 'grand_shipping'
            && $data['rate_type'] != 'grand'
            && $data['order_total_start'] != "" 
            && (float)$data['order_total_end']) {
                $rules['additional_total'] = array(
                    'type' => 'in_between',
                    'product_rule' => false,
                    'address_rule' => false,
                    'start' => (float)$data['order_total_start'],
                    'end' => (float)$data['order_total_end'],
                    'compare_with' => 'total'
                );
        }
        if ($data['rate_type'] != 'weight'
            && $data['weight_start'] != ""
            && (float)$data['weight_end']) {
                $rules['additional_weight'] = array(
                    'type' => 'in_between',
                    'product_rule' => false,
                    'address_rule' => false,
                    'start' => (float)$data['weight_start'],
                    'end' => (float)$data['weight_end'],
                    'compare_with' => 'weight'
                );
        }
        if ($data['rate_type'] != 'quantity'
            && $data['quantity_start'] != ""
            && (int)$data['quantity_end']) {
                $rules['additional_qunatity'] = array(
                    'type' => 'in_between',
                    'product_rule' => false,
                    'address_rule' => false,
                    'start' => (int)$data['quantity_start'],
                    'end' => (int)$data['quantity_end'],
                    'compare_with' => 'quantity'
                );
        }
        /* Hooking fields */
        if ($data['hook']) {
            foreach ($data['hook'] as $key => $value) {
                $rules[$key] = array(
                    'type' => 'function',
                    'func' => 'hook_' . $key,
                    'product_rule' => false,
                    'address_rule' => false,
                    'value' => $value,
                    'false_value' => false,
                    'rule_type' => $key,
                    'compare_with' => 'products'
                );
            }
        }
        return $rules;
    }
    private function _findRawRate($data) {
        $operators= array('+','-','/','*');
        $rates = array();
        $rates['type'] = $data['rate_type'];
        $rates['equation'] = $data['equation'];
        $rates['equation_specified_param'] = (strpos($data['equation'], 'PerProductRule') !== false);
        $rates['final'] = $data['rate_final'];
        $rates['percent_of'] = $data['rate_percent'];
        $rates['overrule'] = !!$data['dimensional_overfule'];
        $rates['factor'] = $data['dimensional_factor'];
        $rates['additional'] = array();
        $rates['cart_adjust'] = array();
        $rates['price_adjust'] = array();

        /* Shipping Cost */
        if ($data['rate_type'] == 'flat') {
            $cost = trim($data['cost']);
            if (substr($cost, -1) == '%') {
                $cost = rtrim($cost,'%');
                $rates['percent'] = true;
                $rates['value'] = (float)$cost / 100;
            } else {
                $rates['percent'] = false;
                $rates['value'] = (float)$cost;
            }
        } else {
           $ranges = array();
           foreach($data['ranges'] as $range) {
               $start = (float)$range['start'];
               $end = (float)$range['end'];
               $cost = trim(trim($range['cost']), '-');
               $block = (float)$range['block'];
               $partial = (int)$range['partial'];
               $product_id = isset($range['product_id']) ? (int)$range['product_id'] : 0; // legacy compatiblity 
               $type = isset($range['type']) ? $range['type'] : '';
               if (substr($cost, -1) == '%') {
                    $cost = rtrim($cost,'%');
                    $percent = true;
                    $value = (float)$cost / 100;
                } else {
                    $percent = false;
                    $value = (float)$cost;
                }
                if ($data['rate_type'] == 'product') {
                    $ranges[$product_id] = array('percent' => $percent, 'value' => $value, 'block' => $block, 'type' => $type);
                } else {
                    $ranges[] = array('start' => round($start, 8), 'end' => round($end, 8), 'percent' => $percent, 'value' => $value, 'block' => $block, 'partial' => $partial);
                }
            }
            $rates['ranges'] = $ranges;
        }
      
       /* Other price parameters */
       if ($data['cart_adjust']) {
            $operator = substr(trim($data['cart_adjust']),0,1);
            $operator = in_array($operator,$operators) ? $operator : '+';
            $adjust = ltrim($data['cart_adjust'], '+-*/');
            if (substr($adjust, -1) == '%') {
                $adjust = rtrim($adjust,'%');
                $rates['cart_adjust']['percent'] = true;
                $rates['cart_adjust']['value'] = (float)$adjust / 100;
                $rates['cart_adjust']['operator'] = $operator;
            } else {
                $rates['cart_adjust']['percent'] = false;
                $rates['cart_adjust']['value'] = (float)$adjust;
                $rates['cart_adjust']['operator'] = $operator;
            }
        }
        if ($data['rate_min'] && $data['rate_type'] != 'flat') {
             $rate_min = $data['rate_min'];
             $rates['price_adjust']['min'] = array();
             if (substr($rate_min, -1) == '%') {
                $rate_min = rtrim($rate_min,'%');
                $rates['price_adjust']['min']['percent'] = true;
                $rates['price_adjust']['min']['value'] = (float)$rate_min / 100;
             } else {
                $rates['price_adjust']['min']['percent'] = false;
                $rates['price_adjust']['min']['value'] = (float)$rate_min;
             }
        }
        if ($data['rate_max'] && $data['rate_type'] != 'flat') {
             $rate_max = $data['rate_max'];
             $rates['price_adjust']['max'] = array();
             if (substr($rate_max, -1) == '%') {
                $rate_max = rtrim($rate_max,'%');
                $rates['price_adjust']['max']['percent'] = true;
                $rates['price_adjust']['max']['value'] = (float)$rate_max / 100;
             } else {
                $rates['price_adjust']['max']['percent'] = false;
                $rates['price_adjust']['max']['value'] = (float)$rate_max;
             }
        }
        if ($data['rate_add'] && $data['rate_type'] != 'flat') {
            $modifier = $data['rate_add'];
            $rates['price_adjust']['modifier'] = array();
            $operator = substr(trim($modifier),0,1);
            $operator = in_array($operator,$operators) ? $operator : '+';
            $modifier = ltrim($modifier, '+-*/');
            if (substr($modifier, -1) == '%') {
                $modifier = rtrim($modifier,'%');
                $rates['price_adjust']['modifier']['percent'] = true;
                $rates['price_adjust']['modifier']['value'] = (float)$modifier / 100;
                $rates['price_adjust']['modifier']['operator'] = $operator;
            } else {
                $rates['price_adjust']['modifier']['percent'] = false;
                $rates['price_adjust']['modifier']['value'] = (float)$modifier;
                $rates['price_adjust']['modifier']['operator'] = $operator;
            }
        }
        if ($data['additional']) {
            $additional = $data['additional'];
            if (substr($additional, -1) == '%') {
                $additional = rtrim($additional,'%');
                $rates['additional']['percent'] = true;
                $rates['additional']['value'] = (float)$additional / 100;
            } else {
                $rates['additional']['percent'] = false;
                $rates['additional']['value'] = (float)$additional;
            }
            $rates['additional']['block'] = (float)$data['additional_per'];
            $rates['additional']['max'] = (float)$data['additional_limit'];
        }
        return $rates;
    }
    private function adjustValue($adjust_rate, $percent_of, $value) {
        $amount = $adjust_rate['percent'] ? ($adjust_rate['value'] * $percent_of) : $adjust_rate['value'];
        return $this->tiniestCalculator($value, $amount, $adjust_rate['operator']);
    }
    private function getProducts() {
        $product_id = isset($this->request->post['_xestimator']) && isset($this->request->post['_xestimator']['product_id']) ? $this->request->post['_xestimator']['product_id'] : 0;
        if ($product_id) {
            $product_info = $this->db->query("SELECT * FROM " . DB_PREFIX . "product WHERE product_id = '" . (int)$product_id . "'")->row;
            if ($product_info) {
                $quantity = isset($this->request->post['quantity']) && $this->request->post['quantity'] ? $this->request->post['quantity'] : 1;
                $quantity = isset($this->request->get['quantity']) && $this->request->get['quantity'] ? $this->request->get['quantity'] : $quantity;
                $product_info['stock'] = $product_info['quantity'];
                $product_info['quantity'] = $quantity;
                $price = $product_info['price'];

                $special_query = $this->db->query("SELECT price FROM " . DB_PREFIX . "product_special WHERE product_id = '" . (int)$product_id . "' AND customer_group_id = '" . (int)$this->config->get('config_customer_group_id') . "' AND ((date_start = '0000-00-00' OR date_start < NOW()) AND (date_end = '0000-00-00' OR date_end > NOW())) ORDER BY priority ASC, price ASC LIMIT 1");
                if ($special_query->num_rows) {
                    $price = $special_query->row['price'];
                }
                $option_price = 0;
                $option_weight = 0;
                if(isset($this->request->post['option']) && is_array($this->request->post['option'])) {
                    foreach($this->request->post['option'] as $product_option_value_ids) {
                        if ($product_option_value_ids) {
                            if (!is_array($product_option_value_ids)) {
                                $product_option_value_ids = array($product_option_value_ids);
                            }
                            foreach($product_option_value_ids as $product_option_value_id) {
                                $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "product_option_value WHERE product_option_value_id = '" . (int)$product_option_value_id . "'");
                                if ($query->row) {
                                    if ($query->row['price_prefix']=='+') {
                                        $option_price += (float)$query->row['price'];
                                        $option_weight += (float)$query->row['weight'];
                                    }
                                    if ($query->row['price_prefix']=='-') {
                                        $option_price -= (float)$query->row['price'];
                                        $option_weight -= (float)$query->row['weight'];
                                    }
                                }
                            }
                        }
                    }
                }
                $product_info['jan'] = (float)$product_info['ean'] * $quantity;
                $product_info['ean'] = (float)$product_info['jan'] * $quantity;
                $product_info['price'] = ($price + $option_price);
                $product_info['total'] = ($price + $option_price) * $quantity;
                $product_info['weight'] = ($product_info['weight'] + $option_weight) * $quantity;
                $product_info['ocm_special'] = $special_query->num_rows ? true : false;
            }
            return array($product_info);
        }
        return $this->cart->getProducts();
    }
    private function getEquationValue($equation, $_cart_data, $method_specific_data, $quote_data, $percent_of, $shipping_cost = 0, $modifier_amount = 0) {
        $placholder = array(
            '{subTotal}',
            '{subTotalWithTax}',
            '{special}',
            '{quantity}',
            '{weight}',
            '{volume}',
            '{dimensional}', 
            '{volumetric}',
            '{noOfProduct}', 
            '{noOfCategory}', 
            '{noOfManufacturer}', 
            '{noOfLocation}',
            '{noOfBlock}',
            '{blockPriceAsc}',
            '{blockPriceDesc}',
            '{noOfPackage}',
            '{subTotalAsPerProductRule}',
            '{subTotalWithTaxAsPerProductRule}',
            '{quantityAsPerProductRule}',
            '{weightAsPerProductRule}',
            '{volumeAsPerProductRule}',
            '{couponValue}',
            '{rewardValue}',
            '{vouchers}',
            '{shipping}',
            '{modifier}',
            '{grandTotal}',
            '{grandBeforeShipping}',
            '{distance}',
            '{jan}',
            '{ean}',
            '{highest}',
            '{lowest}',
            '{highestQnty}',
            '{lowestQnty}',
            '@'
        );
        $replacer = array(
            $_cart_data['sub'],
            $_cart_data['total'],
            $_cart_data['special'],
            $_cart_data['quantity'],
            $_cart_data['weight'],
            $_cart_data['volume'],
            $_cart_data['dimensional'],
            $_cart_data['volumetric'],
            $_cart_data['no_product'],
            $_cart_data['no_category'],
            $_cart_data['no_manufacturer'],
            $_cart_data['no_location'],
            $method_specific_data['no_block'],
            $method_specific_data['block_asc'],
            $method_specific_data['block_desc'],
            $method_specific_data['no_package'],
            $method_specific_data['sub'],
            $method_specific_data['total'],
            $method_specific_data['quantity'],
            $method_specific_data['weight'],
            $method_specific_data['volume'],
            $_cart_data['coupon'],
            $_cart_data['reward'],
            $_cart_data['vouchers'],
            $shipping_cost,
            $modifier_amount,
            $_cart_data['grand'],
            $_cart_data['grand_shipping'],
            $_cart_data['distance'],
            $_cart_data['jan'],
            $_cart_data['ean'],
            $method_specific_data['highest'],
            $method_specific_data['lowest'],
            $method_specific_data['highest_qnty'],
            $method_specific_data['lowest_qnty'],
            ''
        );
        if (preg_match('/minHeight|maxHeight|sumHeight|minWidth|maxWidth|sumWidth|minLength|maxLength|sumLength/', $equation)) {
            $placholder[] = '{minHeight}';
            $placholder[] = '{maxHeight}';
            $placholder[] = '{sumHeight}';
            $placholder[] = '{minWidth}';
            $placholder[] = '{maxWidth}';
            $placholder[] = '{sumWidth}';
            $placholder[] = '{minLength}';
            $placholder[] = '{maxLength}';
            $placholder[] = '{sumLength}';
            
            $minHeight = $minWidth = $minLength = PHP_INT_MAX;
            $maxHeight = $maxWidth = $maxLength = PHP_INT_MIN;
            $sumHeight = $sumWidth = $sumLength = 0;
            foreach ($method_specific_data['products'] as $product) {
                $sumHeight += ($product['height_self'] * $product['quantity']);
                if ($minHeight > $product['height_self']) {
                    $minHeight = $product['height_self'];
                }
                if ($maxHeight < $product['height_self']) {
                    $maxHeight = $product['height_self'];
                }
                $sumWidth += ($product['width_self'] * $product['quantity']);
                if ($minWidth > $product['width_self']) {
                    $minWidth = $product['width_self'];
                }
                if ($maxWidth < $product['width_self']) {
                    $maxWidth = $product['width_self'];
                }
                $sumLength += ($product['length_self'] * $product['quantity']);
                if ($minLength > $product['length_self']) {
                    $minLength = $product['length_self'];
                }
                if ($maxLength < $product['length_self']) {
                    $maxLength = $product['length_self'];
                }
            }
            $replacer[] = $minHeight;
            $replacer[] = $maxHeight;
            $replacer[] = $sumHeight;
            $replacer[] = $minWidth;
            $replacer[] = $maxWidth;
            $replacer[] = $sumWidth;
            $replacer[] = $minLength;
            $replacer[] = $maxLength;
            $replacer[] = $sumLength;
        }
        
        /* append other shipping method cost as placeholders */
        foreach ($quote_data as $value) {
            $placholder[] = '{shipping'.$value['tab_id'].'}';
            $replacer[] = $value['cost'];
        }
        /* xfeepro value */
        foreach ($_cart_data['xfeepro'] as $code => $value) {
            $placholder[] = '{'.$code.'}';
            $replacer[] = $value;
        }
        /* Other shipping modules */
        $ocm_shipping = $this->ocm->getCache('ocm_shipping');
        if ($ocm_shipping) {
            foreach ($ocm_shipping as $code => $value) {
                $placholder[] = '{mod'.$code.'}';
                $replacer[] = true;
            }
        }
        $equation = str_replace($placholder, $replacer, $equation);
        /* replace percentage value finally so it won't replace mod operator */
        $equation = preg_replace('/(\d+)%/', '$1*' . ($percent_of/100), $equation);
        /* Removing unwanted placeholder */
        if (strpos($equation, '{') !== false) {
            $equation = preg_replace('/{.*?}/', 0, $equation);
        }
        $condition_status = false;
        $value = (float)$this->calculate_string($equation, $condition_status);
        return array(
            'value'    => $value,
            'status'  => $condition_status 
        );
    }
    private function getDefaultPaymentMethod($address, $total) {
        $this->load->model($this->ocm->setting_ext . '/extension');
        $extension = $this->{'model_' . $this->ocm->setting_ext . '_extension'};
        $results = $extension->getExtensions('payment');
        $method_data = array();
        foreach ($results as $result) {
            if ($this->ocm->getConfig($result['code'] . '_status', 'payment')) {
                $this->load->model('extension/payment/' . $result['code']);
                $method = $this->{'model_extension_payment_' . $result['code']}->getMethod($address, $total);
                if ($method) {
                    $method_data[$result['code']] = $method;
                }
            }
        }
        if ($method_data) {
            $sort_order = array();
            foreach ($method_data as $key => $value) {
                $sort_order[$key] = $value['sort_order'];
            }
            array_multisort($sort_order, SORT_ASC, $method_data);
            $method_data = array_shift($method_data);
            return isset($method_data['code']) ? $method_data['code'] : '';
        } else {
            return '';
        }
    }
    private function getTotalPackage($container, $items) {
        $keys = array('width', 'length', 'height');
        $letMeTry = function($space, $box) use ($keys) {
            $capable = true;
            foreach ($keys as $key) {
                if ($box[$key] > $space[$key]) {
                    $capable = false;
                    break;
                }
            }
            return $capable;
        };
        $canYouContainMe = function($space, $box) use($letMeTry) {
            if ($letMeTry($space, $box)) {
                return true;
            }
            /* lets swap dimension if it can fit */
            $combinations = array(
                array('width', 'length'),
                array('length', 'height'),
                array('height', 'width')
            );
            foreach ($combinations as $combination) {
                $_box = $box;
                $_box[$combination[0]] = $box[$combination[1]];
                $_box[$combination[1]] = $box[$combination[0]];
                if ($letMeTry($space, $_box)) {
                    return true;
                }
            }
            return false;
        };
        $containerization = function(&$spaces, &$boxes, &$capacity) use ($keys, $canYouContainMe, &$containerization) {
            $space = array_pop($spaces);
            $which = false;
            foreach ($boxes as $i => $box) {
                if ($box['volume'] <= $space['volume']) {
                    if ($canYouContainMe($space, $box)) {
                        $capacity -= $box['weight'];
                        $which = $i;
                        break;
                    }
                }
            }
            if ($which !== false) {
                unset($boxes[$which]);
                foreach ($keys as $key) {
                    if ($space[$key] - $box[$key] > 0) {
                        $_space = array();
                        $_space[$key] = $space[$key] - $box[$key];
                        if ($key == 'height') {
                            $_space['length'] = $box['length'];
                            $_space['width'] = $box['width'];
                        } else {
                            $_space['height'] = $space['height'];
                            if ($key == 'width') {
                                $_space['length'] = $space['length'] - $box['length'] > 0 ? $box['length'] : $space['length'];
                            } else {
                                $_space['width'] = $space['width'];
                            }
                        }
                        $_space['volume'] = $_space['length'] * $_space['width'] * $_space['height'];
                        array_unshift($spaces, $_space);
                    }
                }
            }
            if ($spaces && $boxes && $capacity > 0) {
                $containerization($spaces, $boxes, $capacity);
            }
        };
        /* default container value */
        foreach ($keys as $key) {
            if (empty($container[$key])) {
                $container[$key] = 100000;
            }
        }
        $container['volume'] = $container['length'] * $container['width'] * $container['height'];
        /* sort boxes */
        $boxes = array();
        $sort_order = array();
        $index = 0;
        foreach ($items as $item) {
            for ($i = 1; $i <= $item['quantity']; $i++) {
                $boxes[$index] = $item['bin'];
                $sort_order[$index] = $item['bin']['capacity'];
                $index++;
            }
        }
        array_multisort($sort_order, SORT_DESC, $boxes);
        $count = 0;
        while ($boxes) {
            $spaces = array($container);
            $capacity = $container['weight'];
            $containerization($spaces, $boxes, $capacity);
            $count++;
        }
        return $count;
    }
    private function syncAccountFields($custom_field) {
        $this->load->model('account/customer');
        $customer_info = $this->model_account_customer->getCustomer($this->customer->getId());
        $acc_custom_field = VERSION >= '2.1.0.0' ? json_decode($customer_info['custom_field'], true) : unserialize($customer_info['custom_field']);
        if (is_array($acc_custom_field)) {
            foreach ($acc_custom_field as $_custom_field) {
                if (is_array($_custom_field)) {
                    $custom_field = array_merge($custom_field, $_custom_field);
                } else {
                    $custom_field[] = $_custom_field;
                }
            }
        }
        return $custom_field;
    }
    private function getCSS($estimator) {
        $css = '<style type="text/css">
                    .xshippingpro-box {
                        background: #f5f5f5;
                        margin-bottom: 10px;
                    }
                    .popup-quickview .xshippingpro-box, .popup-options .xshippingpro-box {
                        display: none;
                    }
                    .xshippingpro-box .shipping-header {
                        font-size: 15px;
                        padding: 7px 10px;
                    }
                    .xshippingpro-box .shipping-fields {
                        padding: 0px 8px 8px 8px;
                    }
                    .xshippingpro-box .shipping-field {
                        margin-bottom: 5px;
                    }
                    .xshippingpro-box .xshippingpro-error {
                        border: 1px solid #fb6969;
                    }
                    .xshippingpro-quotes {
                        background: #f5f5f5;
                        padding: 5px 10px;
                        margin-bottom: 10px;
                    }
                    .xshippingpro-quotes .xshippingpro-quote {
                        margin-bottom: 5px;
                    }
                    .xshippingpro-quotes .xshippingpro-quote:last-child {
                        margin-bottom: 0px;
                    }
                    .xshippingpro-option-error {
                        color: #dc4747;
                    }
                    .xshippingpro-options {
                        margin: 5px 0px;
                    }
                    .xshippingpro-desc {
                        color: #999999;
                        font-size: 11px;
                        display:block
                    }
                    .xshippingpro-logo {
                        margin-right: 3px; 
                        vertical-align: middle;
                        max-height: 50px;
                    }
                    /* Journal 3 laytout for suboption */
                    .quick-checkout-wrapper .radio {
                        flex-direction: column;
                        align-items: start;
                    }
                    .xform-form {
                        background: #f7f7f7;
                        padding: 10px;
                    }
            </style>';

        if ($estimator && $estimator['css']) {
          $css .= '<style type="text/css">'.$estimator['css'].'</style>';
        }
        return $css;
    }
    private function getJS($estimator) {
        $this->load->language($this->ext_path);
        $selectors = array();
        $selectors['estimator'] = '#product';
        $selectors['shipping_error'] = '#content'; // TODO - define in selector section
        $meta = array();
        $meta['country_id'] = !$this->ocm->isCheckoutPage() ? $this->config->get('config_country_id') : false;
        $meta['product_id'] = isset($this->request->get['product_id']) ? $this->request->get['product_id'] : 0;
        if ($estimator) {
            if (!isset($estimator['fields']) || !is_array($estimator['fields'])) {
                $estimator['fields'] = array();
            }
            if (in_array('country', $estimator['fields'])) {
                $meta['country'] = true;
            }
            if (in_array('zone', $estimator['fields'])) {
                $meta['zone'] = true;
            }
            if (in_array('postal', $estimator['fields'])) {
                $meta['postal'] = true;
            }
            if (isset($estimator['selector']) && $estimator['selector']) {
                $selectors['estimator'] = $estimator['selector'];
            }
        }
        $_selector = $this->ocm->getConfig('xshippingpro_selector', $this->mtype);
        if (isset($_selector['logo']) && $_selector['logo']) {
            $selectors['logo'] = $this->ocm->html_decode($_selector['logo']);
        }
        if (isset($_selector['desc']) && $_selector['desc']) {
            $selectors['desc'] = $this->ocm->html_decode($_selector['desc']);
        }
        $url = array(
            'country' => VERSION >=  '2.1.0.1' ? 'index.php?route=extension/total/shipping/country' : 'index.php?route=checkout/shipping/country',
            'estimate' => 'index.php?route=extension/shipping/xshippingpro/estimate_shipping'
        );

        $lang = array();
        $lang['header'] = $this->language->get('xshippingpro_estimator_header');
        $lang['tab'] = $this->language->get('xshippingpro_estimator_tab');
        $lang['country'] = $this->language->get('xshippingpro_estimator_country');
        $lang['zone'] = $this->language->get('xshippingpro_estimator_zone');
        $lang['postal'] = $this->language->get('xshippingpro_estimator_postal');
        $lang['no_data'] = $this->language->get('xshippingpro_estimator_no_data');
        $lang['btn'] = $this->language->get('xshippingpro_estimator_button');
        $lang['select'] = $this->language->get('xshippingpro_select');
        $lang['error'] = $this->language->get('xshippingpro_select_error');
        if (function_exists('mb_convert_encoding')) {
            foreach ($lang as $key => $value) {
                $lang[$key] = mb_convert_encoding($value, 'HTML-ENTITIES', 'UTF-8');
            }
        }
        $_xshippingpro = array();
        $_xshippingpro['url'] = $url;
        $_xshippingpro['meta'] = $meta;
        $_xshippingpro['lang'] = $lang;
        $_xshippingpro['selectors'] = $selectors;
        $_xshippingpro['sub_options'] = false;
        $_xshippingpro['desc'] = false;
        $_xshippingpro['logo'] = false;
        $_xshippingpro['tab'] = isset($estimator['tab']) ? (boolean)$estimator['tab'] : false;
        $_xshippingpro['is_checkout'] = $this->ocm->isCheckoutPage() ? true : false;
        if ($this->ocm->isCheckoutPage()) {
           $sub_options = $this->getSubOptions();
           $desc_logo = $this->getShippingDesc();
           $shortcodes = $this->applyShortcode($desc_logo['desc']);
           $_xshippingpro['xform'] = isset($shortcodes['xform']) ? $shortcodes['xform'] : false;
           if ($sub_options) {
              $_xshippingpro['sub_options'] = $sub_options;
           }
           if ($desc_logo['desc']) {
              $_xshippingpro['desc'] = $desc_logo['desc'];
           }
           if ($desc_logo['logo']) {
              $_xshippingpro['logo'] = $desc_logo['logo'];
           }
           $_xshippingpro['city'] = $desc_logo['city'];
           $_xshippingpro['payment'] = $desc_logo['payment'];
        }

        if (!$this->ocm->isCheckoutPage() && isset($meta['country'])) {
            $this->load->model('localisation/country');
            $_xshippingpro['country'] = $this->model_localisation_country->getCountries();
        }
        $js = '<script type="text/javascript">';
        $js .= 'var _xshippingpro = '.json_encode($_xshippingpro).';';
        $js .= 'if (!window.xshippingproestimator && window.XshippingproEstimator) window.xshippingproestimator = new XshippingproEstimator();';
        $js .= 'if (!window.xshippingproextender && window.XshippingproExtender) window.xshippingproextender = new XshippingproExtender();';
        $js .= '</script>';
        $js .= $this->getXFormAsset($js);
        return $js;
    }
    public function getScript() {
        $estimator =  $this->ocm->getConfig('xshippingpro_estimator', $this->mtype);
        $shipping_xshippingpro = $this->ocm->getConfig('xshippingpro_status', $this->mtype);
        $product_id = isset($this->request->get['product_id']) ? $this->request->get['product_id'] : 0;

        $store_id = $this->config->get('config_store_id');
        $estimator_on_store = true;
        if (isset($estimator['store']) && !in_array($store_id, $estimator['store'])) {
            $estimator_on_store = false;
        }
        $html = '';
        if ($shipping_xshippingpro && (($this->ocm->isCheckoutPage() && !$this->ocm->isCartPage()) || ($product_id && $estimator_on_store && isset($estimator['status'])))) {
            $html .= $this->getCSS($estimator);
            $html .= $this->getJS($estimator);
            $html .= '<script src="catalog/view/javascript/xshippingpro.min.js?v=4.0.4" defer type="text/javascript"></script>';
        }
        return $html;
    }
    //expose api for controller 
    public function getFinalDesc($desc) {
        if ($desc) {
            $desc = array('0' => $desc);
            $this->applyShortcode($desc);
            return $desc ? $desc[0] : '';
        }
        return $desc;
    }
    public function applyShortcode(&$desc) {
        $rex = '/\[(\w+)\s?([^]]*)\](.*?)\[\/\w+\]/m';
        $xform_installed = -1;
        $return = array();
        foreach($desc as $tab_id => $text) {
            if ($shortcodes = $this->ocm->parseShortcode($text)) {
                foreach ($shortcodes as $shortcode) {
                    $render = '_' . $shortcode['name'] . 'Render';
                    if (method_exists($this, $render) && $_return = $this->{$render}($shortcode)) {
                        $output = $_return['apply'] ?  $_return['output'] : '';
                        $desc[$tab_id] = str_replace($shortcode['full'], $output, $desc[$tab_id]);
                        if (!isset($return[$shortcode['name']])) $return[$shortcode['name']] = array();
                        $return[$shortcode['name']][$tab_id] = $_return['output'];
                        // if shortcode made it empty, reset 
                        if (!$desc[$tab_id]) {
                            unset($desc[$tab_id]);
                        }
                    }
                }
            }
        }
        return $return;
    }
    private function getXFormAsset($xform_str) {
        $return = '';
        if ($this->ocm->getConfig('xform_status', 'module') && strpos($xform_str, 'bootstrap-xform') !== false) {
            $xform = new \Xform($this->registry);
            $fake_fields = array();
            if (strpos($xform_str, 'xform-date') !== false || strpos($xform_str, 'xform-time') !== false) {
                $fake_fields[] = array('field_type' => 'date');
            }
            $return = $xform->getAssets(false, $fake_fields, array(), true);
        }
        return $return;
    }
    private function setBlockInfo(&$method_specific_data, $price_result, $type) {
        $sort_order = array();
        $products = $method_specific_data['products'];
        foreach ($products as $key => $product) {
            $sort_order[$key] = $product['price'];
        }
        array_multisort($sort_order, SORT_ASC, $products);
        $block_asc = 0;
        $block_value = 0;

        foreach ($products as $product) {
            for ($i=1; $i <= $product['quantity']; $i++) { 
                if ($block_value >= $price_result['blockValue']) {
                    break;
                }
                $block_asc += $product['price'];
                $block_value += $product[$type] / $product['quantity'];
            }
        }
        array_multisort($sort_order, SORT_DESC, $products);
        $block_desc = 0;
        $block_value = 0;
        foreach ($products as $product) {
            for ($i=1; $i <= $product['quantity']; $i++) { 
                if ($block_value >= $price_result['blockValue']) {
                    break;
                }
                $block_desc += $product['price'];
                $block_value += $product[$type] / $product['quantity'];
            }
        }
        $method_specific_data['block_asc'] = $block_asc;
        $method_specific_data['block_desc'] = $block_desc;
    }
    /* HOOK METHOD HERE */
    /* must start with hook_
    public function hook_custom_field($value, $cart_products, $name) {
        return true;
    } */
}

Youez - 2016 - github.com/yon3zu
LinuXploit