From a41cc902f514f3dd6a6e17baf1dec93b888742dd Mon Sep 17 00:00:00 2001 From: Kocmonavtik <61938582+Kocmonavtik@users.noreply.github.com> Date: Tue, 4 Jun 2024 09:27:24 +0300 Subject: [PATCH] ref #72070 Output of bonuses accrued at checkout (#333) --- resources/pot/retailcrm-es_ES.pot | 3 + resources/pot/retailcrm-ru_RU.pot | 3 + src/include/class-wc-retailcrm-base.php | 10 ++ src/include/class-wc-retailcrm-loyalty.php | 115 +++++++++++++++++---- src/languages/retailcrm-es_ES.l10n.php | 1 + src/languages/retailcrm-es_ES.mo | Bin 18284 -> 18403 bytes src/languages/retailcrm-ru_RU.l10n.php | 1 + src/languages/retailcrm-ru_RU.mo | Bin 22526 -> 22678 bytes 8 files changed, 112 insertions(+), 21 deletions(-) diff --git a/resources/pot/retailcrm-es_ES.pot b/resources/pot/retailcrm-es_ES.pot index 356d5f0..a09c4d5 100644 --- a/resources/pot/retailcrm-es_ES.pot +++ b/resources/pot/retailcrm-es_ES.pot @@ -588,3 +588,6 @@ msgstr "bonos" msgid "Use coupon:" msgstr "Utiliza el cupón:" + +msgid "Points will be awarded upon completion of the order:" +msgstr "Los puntos se concederán al finalizar el pedido:" diff --git a/resources/pot/retailcrm-ru_RU.pot b/resources/pot/retailcrm-ru_RU.pot index 193c76e..d6cf7c0 100644 --- a/resources/pot/retailcrm-ru_RU.pot +++ b/resources/pot/retailcrm-ru_RU.pot @@ -597,3 +597,6 @@ msgstr "бонусов" msgid "Use coupon:" msgstr "Используйте купон:" + +msgid "Points will be awarded upon completion of the order:" +msgstr "По завершению заказа будет начислено баллов:" diff --git a/src/include/class-wc-retailcrm-base.php b/src/include/class-wc-retailcrm-base.php index 710a813..d732de8 100644 --- a/src/include/class-wc-retailcrm-base.php +++ b/src/include/class-wc-retailcrm-base.php @@ -120,6 +120,7 @@ if (!class_exists('WC_Retailcrm_Base')) { add_action('woocommerce_before_cart_empted', [$this, 'clear_loyalty_coupon'], 11, 1); add_action('woocommerce_removed_coupon', [$this, 'remove_coupon'], 11, 1); add_action('woocommerce_applied_coupon', [$this, 'apply_coupon'], 11, 1); + add_action('woocommerce_review_order_before_payment', [$this, 'reviewCreditBonus'], 11, 1); } // Subscribed hooks @@ -743,6 +744,15 @@ if (!class_exists('WC_Retailcrm_Base')) { } } + public function reviewCreditBonus() + { + $resultHtml = $this->loyalty->getCreditBonuses(); + + if ($resultHtml) { + echo $resultHtml; + } + } + /** * In this method we include CSS file * diff --git a/src/include/class-wc-retailcrm-loyalty.php b/src/include/class-wc-retailcrm-loyalty.php index 67ab5d7..a880535 100644 --- a/src/include/class-wc-retailcrm-loyalty.php +++ b/src/include/class-wc-retailcrm-loyalty.php @@ -113,28 +113,9 @@ if (!class_exists('WC_Retailcrm_Loyalty')) : private function getDiscountLoyalty($cartItems, $site, $customerId) { - $order = [ - 'site' => $site, - 'customer' => ['externalId' => $customerId], - 'privilegeType' => 'loyalty_level' - ]; + $response = $this->calculateDiscountLoyalty($cartItems, $site, $customerId); - $useXmlId = isset($this->settings['bind_by_sku']) && $this->settings['bind_by_sku'] === WC_Retailcrm_Base::YES; - - foreach ($cartItems as $item) { - $product = $item['data']; - - $order['items'][] = [ - 'offer' => $useXmlId ? ['xmlId' => $product->get_sku()] : ['externalId' => $product->get_id()], - 'quantity' => $item['quantity'], - 'initialPrice' => wc_get_price_including_tax($product), - 'discountManualAmount' => ($item['line_subtotal'] - $item['line_total']) / $item['quantity'] - ]; - } - - $response = $this->apiClient->calculateDiscountLoyalty($site, $order); - - if (!$response->isSuccessful() || !isset($response['calculations'])) { + if ($response === 0) { return 0; } @@ -455,6 +436,98 @@ if (!class_exists('WC_Retailcrm_Loyalty')) : return ['items' => $crmItems, 'discountType' => $discountType]; } + + public function calculateDiscountLoyalty($cartItems, $site, $customerId, $bonuses = 0) + { + $order = [ + 'site' => $site, + 'customer' => ['externalId' => $customerId], + 'privilegeType' => 'loyalty_level' + ]; + + $useXmlId = isset($this->settings['bind_by_sku']) && $this->settings['bind_by_sku'] === WC_Retailcrm_Base::YES; + + foreach ($cartItems as $item) { + $product = $item['data']; + + $order['items'][] = [ + 'offer' => $useXmlId ? ['xmlId' => $product->get_sku()] : ['externalId' => $product->get_id()], + 'quantity' => $item['quantity'], + 'initialPrice' => wc_get_price_including_tax($product), + 'discountManualAmount' => ($item['line_subtotal'] - $item['line_total']) / $item['quantity'] + ]; + } + + $response = $this->apiClient->calculateDiscountLoyalty($site, $order, (float) $bonuses); + + if (!$response->isSuccessful() || !isset($response['calculations'])) { + return 0; + } + + return $response; + } + + public function getCreditBonuses(): string + { + global $woocommerce; + + $customerId = $woocommerce->customer ? $woocommerce->customer->get_id() : null; + $site = $this->apiClient->getSingleSiteForKey(); + + if (!$customerId || !$woocommerce->cart || !$woocommerce->cart->get_cart() || !$site) { + return ''; + } + + $loyaltyCoupon = null; + $coupons = $woocommerce->cart->get_applied_coupons(); + + foreach ($coupons as $coupon) { + if ($this->isLoyaltyCoupon($coupon)) { + $loyaltyCoupon = new WC_Coupon($coupon); + + $woocommerce->cart->remove_coupon($coupon); + $woocommerce->cart->calculate_totals(); + + break; + } + } + + if ($loyaltyCoupon) { + $chargeBonuses = $loyaltyCoupon->get_amount(); + } + + $cartItems = $woocommerce->cart->get_cart(); + $response = $this->calculateDiscountLoyalty($cartItems, $site, $customerId, $chargeBonuses ?? 0); + + if ($loyaltyCoupon) { + $coupon = new WC_Coupon(); + $coupon->set_usage_limit(0); + $coupon->set_amount($loyaltyCoupon->get_amount()); + $coupon->set_email_restrictions($loyaltyCoupon->get_email_restrictions()); + $coupon->set_code($loyaltyCoupon->get_code()); + $coupon->save(); + + $woocommerce->cart->apply_coupon($coupon->get_code()); + $woocommerce->cart->calculate_totals(); + } + + if ($response === 0) { + return ''; + } + + $creditBonuses = $response['order']['bonusesCreditTotal']; + + if ($creditBonuses) { + return $this->getHtmlCreditBonuses($creditBonuses); + } + + return ''; + } + + private function getHtmlCreditBonuses($creditBonuses) + { + return '' . __("Points will be awarded upon completion of the order:", 'retailcrm') . ' ' . $creditBonuses . ''; + } } endif; diff --git a/src/languages/retailcrm-es_ES.l10n.php b/src/languages/retailcrm-es_ES.l10n.php index 7a6b3e6..5d58e8e 100644 --- a/src/languages/retailcrm-es_ES.l10n.php +++ b/src/languages/retailcrm-es_ES.l10n.php @@ -247,6 +247,7 @@ return [ "It is possible to write off" => "Es posible debitar", "bonuses" => "bonificaciones", "Use coupon:" => "Utiliza el cupón:", + "Points will be awarded upon completion of the order:" => "Los puntos se concederán al finalizar el pedido:", ], "language" => "es", "x-generator" => "GlotPress/2.4.0-alpha", diff --git a/src/languages/retailcrm-es_ES.mo b/src/languages/retailcrm-es_ES.mo index 43567c3b681012b3e10728bf0f292248c0508df0..051c9cfcec855e0095b33ddae0e6a9503a1de7f9 100644 GIT binary patch delta 3911 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 Kd)dsP-v0r~8oZYP delta 3809 zcmZA2c~DkW7{~GR$|5Q7vWRTTE6U<7O5jEiNScm{fRZ|Cq2r3?xTLtgYL;TTUiTHZ zG!>Oz%hX(}akR8?taNh8(lRHNVbZCYmg)QB-oLuT!{?lPFZZ7FJm*~Qt#CbB?(*J= z@Ly{<&Js-&fyTI87)*zwS(q`Qn27Z;4U@48Ho)PiTgPEToQ`f>i2Rt<{EEe0sOzV& z9bUv3W4z`M8qGNo7H&*eOviYfh}>W*(1SZsFFcPSco`${ChEQ#?2ADW_KOE$6#dZ{ zfODMl3!T1&DZJloq@fp{MJ8`_kNYwSA7>s48>*dI;W{K0Uj3NL1IB|p%t?^%c9a}NHTwIEJ;8#eJOeFc!VoXKd zpNT10idnb>Gw}=5{eNS73?qFScn+#G6R;Dmh$sI_?RkD_gm+LQe1c6ekS(E9C81`T zjoq;?*3ASpfJ)SiFQD$bfzRVF7>MyaOlzq*QZ18#&9IM`hHflFWug*w;}g__T+~Oa z*NvJ<6l!Mq*a8P*XPkor@F;e{0FOPOY}E4#us4oCmE<6Ay%VO?#FabU@Yo^-=J!D7nS12&iTKvKK=SF?G(E)fW8M+ zs$|pvJD_$!9tPng^y)?BG&I8Hs6X6_{F7nV zsG7Dyy|5RKz*kWdJcCO8w-|`EsEqvCmi+5PL#C025vZE>K%F0nn$dXF%x9t&*GlL7 zKGX}2p(bz{_4hRxgl-B=xlIgeZDpedQh=IBnU{vP!%EbMc02uJPX9}6#rZp^2L!RF z7`%za66}e6a4Qz$ugI+?i`h)ZGVF-AQ7L!RQO4u20KJ7YG~yjdSs!bhkX<#e(? zOr@AZ|1b{38qC7{bh`u#Fqr--48?8O6RS`edWs>~fIX}0F-S(eCY6RhvDsLJgHa_?1!T=>=FA=i^z|g+}H%kwrPt@-VDVaxD@qeyn^8vNQb70L2c6lY_0vjghqc( z_%H(Naa99~LcSTM1F8hY$WAkJQ8U_uz3?RJe!s5v2dODW(l0`lYBUZ;3$>UZp+0a= zF^>0}$Zqz7+oS%ul;BWYjg9d!s`ma|)P9aa#%eqmi?5(cHyN{W3l77ZPQNR4(%+Y( zc1Z<}!oBF#NJC!Wvx|wSReu7NvU8{rUqjt@(>Y&*%9M+@X+VuI8WS)9GqE8KLhXW5 zWI37f*a){^Q>@M=|7v{A38nb4b0M0QwuXKNrr;&a$6C~V-kQ>{=zDYMhSk z@db3D4xQKWHnE53L@Xn8XaQFd6A7&i9eW8qLr0R0H6u7G@g3THpX!b>e)lHM5>tr} z39nTZ>xgwVIC|V+S}O>KYUUHWi2`B)ag=dz?_Rm1rHC ziG{=|VkuE+6^3|RJFLke-2=AMpJr8uM3*k6^%kM8T>`O$(3;WlKEbZ5I|?0lqISb_ zr_bgwr-=cCw(W3Y3*krjh>cdOP*2Ahv~;8rvx!|qK5>T7q5XQ2&@w(w%(P~PdXhh& zl}_+!F_Vb##HU0YQBABTwpph_qr*R;wT{p>(=pfjInE?^ diff --git a/src/languages/retailcrm-ru_RU.l10n.php b/src/languages/retailcrm-ru_RU.l10n.php index 514c7e5..5afac2b 100644 --- a/src/languages/retailcrm-ru_RU.l10n.php +++ b/src/languages/retailcrm-ru_RU.l10n.php @@ -246,6 +246,7 @@ return [ "It is possible to write off" => "Возможно списать", "bonuses" => "бонусов", "Use coupon:" => "Используйте купон:", + "Points will be awarded upon completion of the order:" => "По завершению заказа будет начислено баллов:", ], "language" => "ru", "x-generator" => "GlotPress/2.4.0-alpha", diff --git a/src/languages/retailcrm-ru_RU.mo b/src/languages/retailcrm-ru_RU.mo index acd4ebf3f2a5c736dbb6e56f49e33059308c5c47..5cb7b6941debe4458e6e9b8dbd8bccc9de072cf6 100644 GIT binary patch delta 4069 zcmXxm3vg7`9mnziY6t@d2JHH!#sdML_&~PL5vCIAy`Y=n8#vM2q6y$4`C${ zlTtzA7Nk;z3PB1Y2{A%IqY)X~YU>8tQM85Hj-BG5olb3K=#10vZ}06T|9sB5_w2pr z{LlX``R0^oUzaCvH8x_ealAt$5rvUvgFR-Y(K>6kF~-b`n{Y6;VJ7auq4*kVXg?0a z-{A=S7!&Yw_k6@1X8c$TzeZy^=9mR+hI^tK)49-$)3E~+@tS-6znDsYWUTYxsW_be zER4ev)Q!ur7&jx&ws-Mc_z@1mFWvKBh5G?c^69Z$7>0Ua9+CuGgnGboWUN&pKemBi zTH#LA_2=+TJcjXj0f*oxs0Dq7nn=`0CnE`{@l$XV&$mT1Se*G$DQ!ZfycyH5-M!w8 zn&3s8ho7P{mC5q%!7|Lo{aB3`F$*V-a<*Ut&4#XT6%9$lu9f?wbwjAj{H$x40| zV1w%`IE(&u)Qu*PZ>?+vDie>QGP52R;12it`xs6CPww^4kz3fU(d@rc6w561!F(*i z`FIxw@e%C9Ihab`bmMX)t9A^Psn=2C-$QNXf3OgfN!Q)@J=FMi%*77W0)C%J{xty) zrJsjmkZbl3YC;XDnYLgu9zf<|y{Hvm#u@l2YFsjdG=Y3nW=c`xYH%uU!AR^x)zp~) z4YtvKgFd{58mRqHCh}1OTTnOJhpOTusFfT?jlY6gp*Phm1JiLDF2KdO4e!AZFkFm2 z=e~gi8uxP{8?{Fp@M&zp2#liwS)7f=D9lGq_+F&GY#FL}t5H?I1vPF5YC^l+{)?yu zoWP0Li(~ZuU#Fo|d)WtlAO)!p%R}nX9>8a@0$HTp!W>LsnIy~Z!*S?GeQp;jBS&!s zeuAo*Jf5a4+Jq#*+Ho7tw=Np_oS4Mdnr^rXZ^I{0-)OCyol9xlOssMP-* z&*3+y8}^QOw(ue<)t6A`|BQq21}f8E;UJ8dK>oF7LuqJ+BT=u#IE=yvQ4jh)YJv@@ z4>n^2wjsM`yRgw?b_%rxW3rry%)|%j7ojF_5VfF}P#NvZBLBL<2b|!u_D@s>5}Ae0 zPs0cBVO)wGI2&)`6r4^WC^I#v8xFYs1t-)07pgcjNvB@hX~^Pj3HoqzF8Obuaex!l ziH)E%Y1$Oj4J%N4*??Z$hxcIz-iu$LzOu6?IbT52&_}-lnWMF!YM>Lfz!1*DTR0O7 z0!&jk-iQU*iZS>$YC@M$6Z#sJk+FHsjTWL-RF8VVQ@9LYMjt9Yb0H0PVim5&e_%7N zXQrfy&I+*oujK|LOsU z@vnFj+whNtWEK77S@*k&x_>15wj9UcLcRZ+X?&Lx7w}9=AmR^0Ct@p@Fh6BF?QX5ckc#%?ci{;$X=BLA9k z4kt8V4r<1J*GAM9w4gHZK2E@!uIUsG^=QSIu5mbkN0IHfjm1vNdyqP}q!Q<~T!PB< zwi5Ecmc}Vg`~*`LnQh18s1#*?hd&;$2tULQd=$4XcB=j}yp4Vgm8oyaIMhTYpeA07 zD&oDUjGRPG=TzX`|T31see8FMj> zS3wh9j9YL#rLKt`!Nnf_zrdmNhdt!fR$!Fd$Ut3~gkGG1nOKC8xX!f+W9e^0t)Lw> zz7KgL?YF2cilQ=gJ`baC4zep&gv=v+?9d}A>hRGKERW8Z*+hGndnO;BC)N^5`dtLe z3jY=GDymdlGmnS+W9 zPWN0nK1VEd`{G4nx7$C3>xgqiSGPaL@10Uxy|%Hz*Hpb`jjzJ*D{m^Vuku&<)~~Bw z>#MA-S+~aDSWUBbm9O!KeqSvY>kGPnmC`YG$-z*cFLWl<89E*68F+l4Ez}cwBXo9P ww{!9w7r5vPbq%zHUS&kHkIS6{tqj>7Iv*a)=ernoo_~Fz(*@nD=Lci|2g~37mH+?% delta 3924 zcmXxm2~bs49LMoLCZYxp1r>tmp$M7?W`e0HZn=YrlxrsDXen7LxGxXXT)_Q_Ynla# zlxc!wYH3Ec*qGx~Zj)P!W@d|{Q;pU1{c&%1-v52hx%a+v&-tHoF09`h@b8`g-^H-n z#l}%h+)t#`F$)SXOApprv*#L^d2j*-;Y^Ije5{WId+{)a;&HqW&%5VuV?*lt zii9vsGV@uYdtx{?mWj zQk;NQn26pc&eRP+UC+WEn2$d7sG7n9cmW6E->8uc;Hwjkb=`(tsh>kNbRYTF$a*tXs?59ZPUn#0ZFZ9EB%)nG^g$pqocVl-9CC_R&6UnA+ zL}h9h>i$Ehsl1AvF@$ur$Ns4M3osdrQ3LoWn*6H+zjNYYY{V9zXnjx}8jI>_F2-OH z(iba7jkp>g#Z##JLbypCh(~269d+L*Ou-zigWFMSs?0}$X|#hFiziVx{)Wm#JoBO( zb5RW~My=v?sF7?&jqEdw!wdKb26)W|VMpwMg{TfyquTol`=Rd|1XUN2mu~L!~;11)(X3 zLbaQP%Is+L@O+y~L5r>kHK%2$hEL;Iyos5Z$#9kW5@eZ$z&KV>WifN^FO>QJHDU zf>49YUAJOe>bp^k^D=6?-a^J^!K619Q!y8ZB$I#EhaKkxANz$bH5kKE)m$c{2Q#q` zW@8%e#QJy*_2RjOu^97^lgTvH8puHnun4}nb=!04KEXLv??1A54A$mzy4!(g4unAjaByPfO=(|IqCxvyXP6y5+ zAG^-iB=oj7qqDXGHG;!95C27td@gUB7qJYV!U&f7bj(Aofg7mZ(XFGi4M(D;Bo~=t zpRJ&v?RO4Y(Dnyvzj{fF=Ijy7#B5Y%DsTy&Mm^wZ-oM{rB`(Dco%tsPW687H+k|TW zC_agourH=EkHfV8=TjKYi8H7aw`G{RVI*qKOOcQL%vT<^?&hTaRn!BHqEdbx>4UZI z?)V&P>Pm4uevGU`OXB7UI1=N06pm3)im#*QDypZmjTU1fbw4T-M^J0xM;wL`k2$HH zjN#O;VKm-FEv|@O{PThdd?^FZBg?`HQB(Ck`esvz>TNa!i&2X(h+(Vek+>E+x%Crx zp8BsChQ~=0vtSoc^~ios2NE%kdLQ&+4%WjWR7ZXK--_`7fXlHqc4Y zIvhd00?%N`<7_Sb0b60lAm?wyOl(Yj4yq$-P#xcgTD@Ud z^{M9$an{s)*CNz;-$n`^3MCki6<7z)x?aLC>Q_-C_zQJ^!cb@KQ}IFSlTqh4V_hsq zX2U9we$*U`_|~X(loAtI+cSb=x=g3MTqikFiI<5N2xVSb*EWBEs3c|)I^G~Eh%*1F z;D~^E{_DZfljiCI$5diJ!G1FKg1t^?usZe;fy7gUW=uySvAL$i+H`#rHJ)dPJmLtU zL;Hdkg>CRp32D=D8l{(r`w1Nz9cmV-vNn#`MT{lhC3JKp-uIsiX%k;wQzr?y%`Gp+ z8E$zyzT!{v#06~iXL`b8^jZsYuT62~ZC3N1&i5C1ydg)aEg@DBMgF%u5ly#H>P)a8 zorQ&~i9#ZQSm*!26IX8mC03%X@iz<&kC{&?o>)lenCM`8aE`xwXtb}&J(G(q-SUU7 zqcMuuOR!ihmZ&C{5+wv%&JGi^3ARXH)>2>- z*Syi6#+5`v;vn(=@s3*v#Se(L{0$pKWbCB0p3sp(yh!vSmJvF}5Sxg>s<_9ixWX;( a#>vD1;_b?54aRvYL%k&lm4Ut2g#8ECD7-TO