MPreferentialProcess.Class.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. <?php
  2. /**
  3. * 计算优惠类
  4. */
  5. namespace JinDouYun\Model\Cart;
  6. use Mall\Framework\Core\ErrorCode;
  7. use Mall\Framework\Core\ResultWrapper;
  8. use Mall\Framework\Core\StatusCode;
  9. use JinDouYun\Model\Market\MUserCoupon;
  10. use JinDouYun\Model\Market\MVipCard;
  11. class MPreferentialProcess{
  12. private $onlineUserCenterid;
  13. private $onlineEnterPriseId;
  14. private $userCouponIsMutex; // 用户领取过优惠劵是否互斥
  15. public function __construct($onlineUserCenterid, $onlineEnterPriseId)
  16. {
  17. $this->onlineUserCenterid = $onlineUserCenterid;
  18. $this->onlineEnterPriseId = $onlineEnterPriseId;
  19. }
  20. /**
  21. * 计算优惠核心方法
  22. * @param array $cartGoodsData 购物车商品数据
  23. * @param int $vipCardId 要使用的会员卡id
  24. * @params int $userCouponId 要使用的优惠劵id
  25. */
  26. public function Preferential($cartGoodsData, $vipCardId, $userCouponId)
  27. {
  28. $tmpCartGoodsData = $cartGoodsData;
  29. // 未指定要使用的会员卡id或优惠劵id
  30. if( !$vipCardId && !$userCouponId ) {
  31. return ResultWrapper::success($cartGoodsData);
  32. }
  33. $vipCartData = [];
  34. // 处理vip会员卡主流程
  35. if( $vipCardId ){
  36. // 获取vip会员卡信息
  37. $vipCartData = self::vipCartData($vipCardId);
  38. if(!$vipCartData->isSuccess()){
  39. return ResultWrapper::fail($vipCartData->getData(), $vipCartData->getErrorCode());
  40. }
  41. $vipCartData = $vipCartData->getData();
  42. // 没有折扣的会员卡不计算折扣
  43. if($vipCartData['vipDiscount'] == StatusCode::$delete){
  44. return ResultWrapper::success($cartGoodsData);
  45. }
  46. // 计算vip会员卡折后金额
  47. $cartGoodsData = self::vipCartCompute($cartGoodsData, $vipCartData);
  48. if(!$cartGoodsData->isSuccess()){
  49. return ResultWrapper::fail($cartGoodsData->getData(), $cartGoodsData->getErrorCode());
  50. }
  51. $cartGoodsData = $cartGoodsData->getData();
  52. }
  53. // 处理优惠券主流程
  54. if( $userCouponId ){
  55. // 获取优惠劵信息
  56. $userCouponData = self::couponData($userCouponId);
  57. if(!$userCouponData->isSuccess()){
  58. return ResultWrapper::fail($userCouponData->getData(), $userCouponData->getErrorCode());
  59. }
  60. $userCouponData = $userCouponData->getData();
  61. $this->userCouponIsMutex = $userCouponData['isMutex']; // 优惠劵与其他活动互斥
  62. /*if ($this->userCouponIsMutex == StatusCode::$standard){
  63. return ResultWrapper::success($cartGoodsData);
  64. }*/
  65. // 判断会员卡是否有优惠,且vip折扣后实付金额 小于 优惠金额,则先优惠后折扣
  66. if( $cartGoodsData['vipDiscount'] > 0 && ($cartGoodsData['payMoney'] < $userCouponData['reducePrice']) ) {
  67. // 计算优惠劵优惠后金额
  68. $tmpCartGoodsData = self::userCouponCompute($tmpCartGoodsData, $userCouponData);
  69. if(!$tmpCartGoodsData->isSuccess()){
  70. return ResultWrapper::fail($tmpCartGoodsData->getData(), $tmpCartGoodsData->getErrorCode());
  71. }
  72. $tmpCartGoodsData = $tmpCartGoodsData->getData();
  73. // 计算vip会员卡折后金额
  74. $tmpCartGoodsData = self::vipCartCompute($tmpCartGoodsData, $vipCartData);
  75. if(!$tmpCartGoodsData->isSuccess()){
  76. return ResultWrapper::fail($tmpCartGoodsData->getData(), $tmpCartGoodsData->getErrorCode());
  77. }
  78. $cartGoodsData = $tmpCartGoodsData->getData();
  79. }else{
  80. // 计算优惠劵优惠后金额
  81. $cartGoodsData = self::userCouponCompute($cartGoodsData, $userCouponData);
  82. if(!$cartGoodsData->isSuccess()){
  83. return ResultWrapper::fail($cartGoodsData->getData(), $cartGoodsData->getErrorCode());
  84. }
  85. $cartGoodsData = $cartGoodsData->getData();
  86. }
  87. }
  88. return ResultWrapper::success($cartGoodsData);
  89. }
  90. /**
  91. * 优惠劵计算流程
  92. * @params $vipCardId int 会员卡id
  93. * @return ResultWrapper
  94. */
  95. public function userCouponCompute($cartGoodsData, $userCouponData)
  96. {
  97. switch ($userCouponData['applyRange']){
  98. case StatusCode::$applyRange['allGoods']: // 全部商品
  99. // 判断是否满足优惠券使用门槛
  100. if( $userCouponData['minPrice'] == 0 || $cartGoodsData['payMoney'] >= $userCouponData['minPrice'] ){
  101. $result = self::userCouponDiscountCommon($cartGoodsData['payMoney'], $userCouponData['reducePrice']);
  102. $cartGoodsData['payMoney'] = $result['discountEndPayMoney']; // 修改订单总实际支付金额
  103. $cartGoodsData['preferential'] = $result['discountIngPayMoney']; // 修改订单优惠劵总优惠金额
  104. }
  105. break;
  106. case StatusCode::$applyRange['appointCategory']: // 指定分类
  107. $result = self::userCouponDiscountByGoods('categoryId', 'categoryCollect', $cartGoodsData,$userCouponData);
  108. if(!$result->isSuccess()){
  109. return ResultWrapper::fail($result->getErrorCode(), $result->getData());
  110. }
  111. $cartGoodsData = $result->getData();
  112. break;
  113. case StatusCode::$applyRange['appointBrand']: // 指定品牌
  114. $result = self::userCouponDiscountByGoods('brandId', 'brandCollect', $cartGoodsData,$userCouponData);
  115. if(!$result->isSuccess()){
  116. return ResultWrapper::fail($result->getErrorCode(), $result->getData());
  117. }
  118. $cartGoodsData = $result->getData();
  119. break;
  120. case StatusCode::$applyRange['goodsCollect']: // 指定商品
  121. $result = self::userCouponDiscountByGoods('goodsId', 'goodsCollect', $cartGoodsData, $userCouponData);
  122. if(!$result->isSuccess()){
  123. return ResultWrapper::fail($result->getErrorCode(), $result->getData());
  124. }
  125. $cartGoodsData = $result->getData();
  126. break;
  127. }
  128. if ($cartGoodsData['payMoney'] < 0) {
  129. $cartGoodsData['payMoney'] = 0; // 如果折后金额小于0,统一归零处理
  130. }
  131. return ResultWrapper::success($cartGoodsData);
  132. }
  133. /**
  134. * 指定商品分类/商品品牌/商品 计算优惠统一方法
  135. * @params string $typeField 指定类型
  136. * @params string $typeField 类型对应字段名
  137. */
  138. public function userCouponDiscountByGoods($type, $typeField, $cartGoodsData, $userCouponData)
  139. {
  140. if( empty($userCouponData[$typeField]) ){
  141. return ResultWrapper::success($cartGoodsData);
  142. }
  143. $goodsAmount = 0; // 满足优惠劵指定分类下的商品总金额
  144. $couponBrand = explode(',', $userCouponData[$typeField]);
  145. // 累加订单中每个店铺下参与优惠劵的商品总金额
  146. foreach ($cartGoodsData['goodsData'] as $shop) {
  147. foreach ($shop['shopGoodsData'] as $value) {
  148. if (in_array($value[$type], $couponBrand)) {
  149. $goodsAmount = bcadd($goodsAmount, $value['totalMoney']);
  150. }
  151. }
  152. }
  153. if( $goodsAmount <= 0 ){
  154. return ResultWrapper::fail('参与优惠劵优惠的商品总金额异常', ErrorCode::$notAllowAccess);
  155. }
  156. // 判断是否满足优惠券使用门槛
  157. if( $userCouponData['minPrice'] == 0 || $goodsAmount >= $userCouponData['minPrice'] ){
  158. $result = self::userCouponDiscountCommon($goodsAmount, $userCouponData['reducePrice']);
  159. $cartGoodsData['payMoney'] = bcsub($cartGoodsData['payMoney'], $result['discountIngPayMoney'], 2); // 修改订单总实际支付金额
  160. $cartGoodsData['preferential'] = $result['discountIngPayMoney']; // 修改订单优惠劵总优惠金额
  161. }
  162. return ResultWrapper::success($cartGoodsData);
  163. }
  164. /**
  165. * 优惠劵优惠统一方法
  166. * @params float $discountBeforePayMoney 优惠劵优惠前金额
  167. * @params float $discountMoney 优惠劵优惠金额
  168. * @return array 优惠后金额
  169. */
  170. public function userCouponDiscountCommon($discountBeforePayMoney, $discountMoney)
  171. {
  172. $discountEndPayMoney = bcsub($discountBeforePayMoney, $discountMoney, 2);
  173. // 如果优惠后的金额小于0,说明优惠金额大于商品原价了,优惠金额 = 商品金额, 多余优惠浪费掉了
  174. $discountIngPayMoney = ($discountEndPayMoney < 0 ) ? $discountBeforePayMoney : $discountMoney;
  175. return [
  176. 'discountEndPayMoney' => ($discountEndPayMoney < 0) ? 0 : $discountEndPayMoney,
  177. 'discountIngPayMoney' => $discountIngPayMoney,
  178. ];
  179. }
  180. /**
  181. * vip会员卡优惠计算流程
  182. * @params $vipCardId int 会员卡id
  183. * @return ResultWrapper
  184. */
  185. public function vipCartCompute($cartGoodsData, $vipCartData)
  186. {
  187. $discount = bcdiv($vipCartData['discount'], 10, 2); //折扣率
  188. // 所有商品
  189. if ($vipCartData['mode'] == StatusCode::$standard) {
  190. $result = self::vipCartDiscountCommon($cartGoodsData['payMoney'], $discount);
  191. $cartGoodsData['payMoney'] = $result['discountEndPayMoney']; // 修改订单总实际支付金额
  192. $cartGoodsData['vipDiscount'] = $result['discountIngPayMoney']; // 修改订单总会员卡优惠金额
  193. //是否开启折上折 暂时不支持 代码需要测试
  194. /*if ($cardInfo['doubleDiscount'] == StatusCode::$standard) {
  195. $data['vipDoubleDiscount'] = bcsub($data['payMoney'], bcmul($data['payMoney'], $discount, 2), 2);//折上折优惠金额
  196. $data['payMoney'] = bcmul($data['payMoney'], $discount, 2);
  197. if ($data['payMoney'] < 0) {
  198. $data['payMoney'] = 0;//若优惠券后价格小于0(可能是由于优惠券设计不合理)
  199. }
  200. }*/
  201. }else{ // 部分商品
  202. if( empty($vipCartData['goodsIds']) ){
  203. return ResultWrapper::success($cartGoodsData);
  204. }
  205. $goodsAmount = 0; // 参与会员卡折扣的商品总金额
  206. $vipGoodsIds = explode(',', $vipCartData['goodsIds']); // 会员卡设置的参与折扣商品
  207. // 累加订单中每个店铺下参与会员卡折扣的商品总金额
  208. foreach ($cartGoodsData['goodsData'] as $shop) {
  209. foreach ($shop['shopGoodsData'] as $value) {
  210. if (in_array($value['goodsId'], $vipGoodsIds)) {
  211. $goodsAmount = bcadd($goodsAmount, $value['totalMoney']);
  212. }
  213. }
  214. }
  215. if( $goodsAmount <= 0 ){
  216. return ResultWrapper::fail('参与会员卡优惠的商品总金额异常', ErrorCode::$notAllowAccess);
  217. }
  218. $result = self::vipCartDiscountCommon($goodsAmount, $discount);
  219. $cartGoodsData['payMoney'] = bcsub($cartGoodsData['payMoney'], $result['discountIngPayMoney']); // 修改订单总实际支付金额
  220. $cartGoodsData['vipDiscount'] = $result['discountIngPayMoney']; // 修改订单总会员卡优惠金额
  221. //是否开启折上折 暂时不支持 代码需要测试
  222. /*if ($cardInfo['doubleDiscount'] == StatusCode::$standard) {
  223. $data['vipDoubleDiscount'] = bcsub($data['payMoney'], bcmul($data['payMoney'], $discount, 2), 2);//折上折优惠金额
  224. $data['payMoney'] = bcmul($data['payMoney'], $discount, 2);
  225. if ($data['payMoney'] < 0) {
  226. $data['payMoney'] = 0;//若优惠券后价格小于0(可能是由于优惠券设计不合理)
  227. }
  228. }*/
  229. }
  230. if ($cartGoodsData['payMoney'] < 0) {
  231. $cartGoodsData['payMoney'] = 0; // 如果折后金额小于0,统一归零处理
  232. }
  233. return ResultWrapper::success($cartGoodsData);
  234. }
  235. /**
  236. * 计算会员卡折扣统一方法
  237. * @params float $discountBeforePayMoney 会员卡优惠前金额
  238. * @params float $discount 会员卡折扣率
  239. * @return array 优惠后金额
  240. */
  241. public function vipCartDiscountCommon($discountBeforePayMoney, $discount)
  242. {
  243. $discountEndPayMoney = bcmul( $discountBeforePayMoney, $discount, 2); // vip会员卡打折以后的订单金额 0.19
  244. $discountIngPayMoney = bcsub($discountBeforePayMoney, $discountEndPayMoney, 2); // vip会员卡打折免掉的金额 18.81
  245. return [
  246. 'discountEndPayMoney' => ($discountEndPayMoney < 0) ? 0 : $discountEndPayMoney,
  247. 'discountIngPayMoney' => ($discountIngPayMoney < 0) ? 0 : $discountIngPayMoney,
  248. ];
  249. }
  250. /**
  251. * 获取vip会员卡信息
  252. * @params $vipCardId int 会员卡id
  253. * @return ResultWrapper
  254. */
  255. public function vipCartData($vipCardId)
  256. {
  257. $objMVipCard = new MVipCard($this->onlineEnterPriseId, $this->onlineUserCenterid, true);
  258. $dbResult = $objMVipCard->getVipCardInfo($vipCardId);
  259. if(!$dbResult->isSuccess()){
  260. return ResultWrapper::fail($dbResult->getData(), $dbResult->getErrorCode());
  261. }
  262. $vipCartData = $dbResult->getData();
  263. if( empty($vipCardId) ){
  264. return ResultWrapper::fail('要使用的会员卡不存在', ErrorCode::$contentNotExists);
  265. }
  266. // 判断是否删除
  267. if($vipCartData['deleteStatus'] == StatusCode::$delete){
  268. return ResultWrapper::fail('当前购买的vip会员卡被删除了', ErrorCode::$notAllowAccess);
  269. }
  270. // 判断是否禁用
  271. if($vipCartData['enableStatus'] == StatusCode::$delete){
  272. return ResultWrapper::fail('当前购买的vip会员卡被禁用了', ErrorCode::$notAllowAccess);
  273. }
  274. return ResultWrapper::success($vipCartData);
  275. }
  276. /**
  277. * 获取优惠劵信息
  278. * @params $userCouponId int 用户领取优惠劵id
  279. * @return ResultWrapper
  280. */
  281. public function couponData($userCouponId)
  282. {
  283. // 查询用户领取过的优惠劵数据
  284. $objMUserCoupon = new MUserCoupon($this->onlineUserCenterid, $this->onlineEnterPriseId);
  285. $condition = [
  286. 'id' => $userCouponId,
  287. ];
  288. $userCouponData = $objMUserCoupon->getUserCoupon($condition);
  289. if(!$userCouponData->isSuccess()){
  290. return ResultWrapper::fail($userCouponData->getData(), $userCouponData->getErrorCode());
  291. }
  292. $userCouponData = $userCouponData->getData();
  293. if(empty($userCouponData)){
  294. return ResultWrapper::fail('要使用的优惠劵不存在', ErrorCode::$contentNotExists);
  295. }
  296. $userCouponData = array_pop($userCouponData);
  297. // 判断是否使用过了
  298. if($userCouponData['isUse'] == StatusCode::$delete){
  299. return ResultWrapper::fail('当前领取的优惠券已经使用过了', ErrorCode::$notAllowAccess);
  300. }
  301. // 判断下有效期
  302. if (time() <= $userCouponData['startTime'] || time() >= $userCouponData['endTime']){
  303. return ResultWrapper::fail('当前领取的优惠券已经过期了', ErrorCode::$notAllowAccess);
  304. }
  305. return ResultWrapper::success($userCouponData);
  306. }
  307. }