StoreCoupon.php 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. <?php
  2. namespace addons\Store\common\models;
  3. use addons\Coupon\common\enums\AddonsCouponEnum;
  4. use addons\Coupon\common\models\AddonsCoupon;
  5. use addons\Coupon\common\models\AddonsCouponUserRelate;
  6. use addons\Store\common\enums\CouponEnum;
  7. use addons\Store\common\enums\StoreEnum;
  8. use common\enums\AddonsEnum;
  9. use common\enums\StatusEnum;
  10. use common\models\base\BaseActiveRecord;
  11. use common\models\mall\MallAddons;
  12. use Yii;
  13. use yii\db\Exception;
  14. use yii\db\Expression;
  15. use yii\helpers\Json;
  16. /**
  17. * This is the model class for table "qimall_addons_store_coupon".
  18. *
  19. * @property int $id
  20. * @property int $mall_id
  21. * @property int $store_id 门店id
  22. * @property string $name 优惠券名称
  23. * @property int $type 优惠券类型,1:折扣,2:满减
  24. * @property float $discount 折扣率
  25. * @property float|null $discount_limit 折扣优惠金额上限
  26. * @property float $min_price 最低消费金额
  27. * @property float $sub_price 优惠金额
  28. * @property int $total_count 优惠券总数量
  29. * @property int $sort 排序按升序排列
  30. * @property int $expire_type 到期类型:1=领取后n天过期,2=指定有效期,3=领取后n天生效,生效后m天过期
  31. * @property int $expire_day 有效天数,expire_type=1和3时
  32. * @property int $effect_days 领取到生效之间间隔的天数(领取后n天生效)
  33. * @property int $begin_at 有效期开始时间
  34. * @property int $end_at 有效期结束时间
  35. * @property int $appoint_type 1 指定分类 2 指定商品 3全部
  36. * @property string|null $rule 使用说明
  37. * @property int $is_remind 是否开启提醒
  38. * @property int $remind_days 提前提醒天数(到期前多少天提醒),is_remind=1 时有效
  39. * @property int $is_receive_limit 是否限制领取
  40. * @property int $receive_count 每人可以领取的数量,is_receive_limit=1时有意义
  41. * @property int $is_member 是否指定会员等级
  42. * @property int $is_original_use 是否原价购买使用(如果是,则只有原价购买商品时可以使用该优惠券)
  43. * @property int $is_public_receive 是否公开领取,公开领取的优惠券会展示在商品详情页
  44. * @property int $is_giving 启用优惠券转送功能:0-否;1-是;
  45. * @property int $status 状态[-1:删除;0:禁用;1启用]
  46. * @property int $coupon_status 优惠券状态,1:未开始,2:领取中,3:已过期,4:已失效(后台操作失效)
  47. * @property int $is_giving_reward 是否开启转赠奖励,开启后转赠优惠券自己可以获得额外奖励;is_giving=1 时有效
  48. * @property int $is_consume_reward 是否开启使用奖励,开启后使用该优惠券可以获得额外奖励;is_giving=1 时有效
  49. * @property string $qrcode_url 优惠券分享二维码保存路径,二维码包含内容:页面路径+优惠券id
  50. * @property string $poster_url 优惠券分享海报图片保存路径
  51. * @property int $created_at 创建时间
  52. * @property int $updated_at
  53. * @property int $exchange_voucher_type 兑换券类型,0全部抵扣,1部分抵扣
  54. */
  55. class StoreCoupon extends BaseActiveRecord
  56. {
  57. /**
  58. * {@inheritdoc}
  59. */
  60. public static function tableName()
  61. {
  62. return '{{%addons_store_coupon}}';
  63. }
  64. /**
  65. * {@inheritdoc}
  66. */
  67. public function rules()
  68. {
  69. return [
  70. [['mall_id'], 'required'],
  71. [['mall_id', 'store_id', 'type', 'total_count', 'sort', 'expire_type', 'expire_day', 'effect_days', 'begin_at', 'end_at', 'appoint_type', 'is_remind', 'remind_days', 'is_receive_limit', 'receive_count', 'is_member', 'is_original_use',
  72. 'is_public_receive', 'is_giving', 'status', 'coupon_status', 'is_giving_reward', 'is_open_screen','is_consume_reward', 'created_at', 'updated_at','watch_times', 'exchange_voucher_type'], 'integer'],
  73. [['discount', 'discount_limit', 'min_price', 'sub_price'], 'number'],
  74. [['rule'], 'string'],
  75. [['name'], 'string', 'max' => 150],
  76. [['qrcode_url', 'poster_url','video_url','first_frame'], 'string', 'max' => 255],
  77. ];
  78. }
  79. /**
  80. * {@inheritdoc}
  81. */
  82. public function attributeLabels()
  83. {
  84. return [
  85. 'id' => 'ID',
  86. 'mall_id' => 'Mall ID',
  87. 'store_id' => '门店id',
  88. 'name' => '优惠券名称',
  89. 'type' => '优惠券类型,1:折扣,2:满减,3:兑换',
  90. 'discount' => '折扣率',
  91. 'discount_limit' => '折扣优惠金额上限',
  92. 'min_price' => '最低消费金额',
  93. 'sub_price' => '优惠金额',
  94. 'total_count' => '优惠券总数量',
  95. 'sort' => '排序按升序排列',
  96. 'expire_type' => '到期类型:1=领取后n天过期,2=指定有效期,3=领取后n天生效,生效后m天过期',
  97. 'expire_day' => '有效天数,expire_type=1和3时',
  98. 'effect_days' => '领取到生效之间间隔的天数(领取后n天生效)',
  99. 'begin_at' => '有效期开始时间',
  100. 'end_at' => '有效期结束时间',
  101. 'appoint_type' => '1 指定分类 2 指定商品 3全部',
  102. 'rule' => '使用说明',
  103. 'is_remind' => '是否开启提醒',
  104. 'remind_days' => '提前提醒天数(到期前多少天提醒),is_remind=1 时有效',
  105. 'is_receive_limit' => '是否限制领取',
  106. 'receive_count' => '每人可以领取的数量,is_receive_limit=1时有意义',
  107. 'is_member' => '是否指定会员等级',
  108. 'is_original_use' => '是否原价购买使用(如果是,则只有原价购买商品时可以使用该优惠券)',
  109. 'is_public_receive' => '是否公开领取,公开领取的优惠券会展示在商品详情页',
  110. 'is_giving' => '启用优惠券转送功能:0-否;1-是;',
  111. 'status' => '状态[-1:删除;0:禁用;1启用]',
  112. 'coupon_status' => '优惠券状态,1:未开始,2:领取中,3:已过期,4:已失效(后台操作失效)',
  113. 'is_giving_reward' => '是否开启转赠奖励,开启后转赠优惠券自己可以获得额外奖励;is_giving=1 时有效',
  114. 'is_consume_reward' => '是否开启使用奖励,开启后使用该优惠券可以获得额外奖励;is_giving=1 时有效',
  115. 'qrcode_url' => '优惠券分享二维码保存路径,二维码包含内容:页面路径+优惠券id',
  116. 'poster_url' => '优惠券分享海报图片保存路径',
  117. 'exchange_voucher_type' => '抵扣券类型',
  118. 'created_at' => '创建时间',
  119. 'updated_at' => 'Updated At',
  120. ];
  121. }
  122. /**
  123. * 商品
  124. * @return \yii\db\ActiveQuery
  125. */
  126. public function getGoods()
  127. {
  128. return $this->hasMany(StoreGoods::class, ['id' => 'goods_id'])
  129. ->via('goodsRelate');
  130. }
  131. /**
  132. * 商品关系
  133. * @return \yii\db\ActiveQuery
  134. */
  135. public function getGoodsRelate()
  136. {
  137. return $this->hasMany(StoreCouponGoodsRelate::class, ['coupon_id' => 'id']);
  138. }
  139. /**
  140. * 分类关系
  141. * @return \yii\db\ActiveQuery
  142. */
  143. public function getCateRelate()
  144. {
  145. return $this->hasMany(StoreCouponCatRelate::class, ['coupon_id' => 'id']);
  146. }
  147. /**
  148. * 等级关系
  149. * @return \yii\db\ActiveQuery
  150. */
  151. public function getMemberRelate()
  152. {
  153. return $this->hasMany(StoreCouponMemberRelate::class, ['coupon_id' => 'id']);
  154. }
  155. /**
  156. * 会员关系
  157. * @return \yii\db\ActiveQuery
  158. */
  159. public function getUserRelate()
  160. {
  161. return $this->hasMany(StoreCouponUserRelate::class, ['coupon_id' => 'id']);
  162. }
  163. /**
  164. * 会员关系
  165. * @return \yii\db\ActiveQuery
  166. */
  167. public function getUserRelateOne()
  168. {
  169. return $this->hasOne(StoreCouponUserRelate::class, ['coupon_id' => 'id']);
  170. }
  171. /**
  172. * 保存数据
  173. * @param array $params
  174. * @return StoreCoupon|bool
  175. * @throws \yii\db\Exception
  176. */
  177. public static function setData(array $params, string $scenarios = 'create')
  178. {
  179. $transaction = \Yii::$app->db->beginTransaction();
  180. try {
  181. if (empty($params['coupon_info'])) throw new \Exception('优惠券数据为空');
  182. if (isset($params['coupon_info']['type']) && $params['coupon_info']['type'] == 3) { // 兑换券是指定产品
  183. $params['coupon_info']['appoint_type'] = 2;
  184. }
  185. $coupon_info = $params['coupon_info'];
  186. unset($coupon_info['effect_expire_days']);
  187. $member_level_limits = $params['member_level_limits'] ?? [];
  188. $goods_id_list = $params['goods_id_list'] ?? [];
  189. $giving_rewards = $params['giving_reward'] ?? [];
  190. $consume_rewards = $params['consume_reward'] ?? [];
  191. $category_ids = $params['category_ids'] ?? [];
  192. $time = time();
  193. // 检查优惠券使用场景
  194. self::checkUseScene($params);
  195. if (!empty($coupon_info['id'])) {
  196. // 更新
  197. $model = self::findOne(['id' => $coupon_info['id'], 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED], 'mall_id' => $coupon_info['mall_id'], 'store_id' => $coupon_info['store_id']]);
  198. if (empty($model)) throw new Exception('优惠券不存在或已删除');
  199. // if ($model->total_count > $coupon_info['total_count']) throw new \Exception('优惠券发放数量不能减少');
  200. if ($coupon_info['total_count'] < 1) {
  201. //禅道优惠1458 调整优惠券编辑发放数量
  202. throw new \Exception('优惠券发放数量不能小于1');
  203. }
  204. } else {
  205. // 添加
  206. $model = new self();
  207. $model->loadDefaultValues();
  208. // 计算优惠券 有效期起止时间
  209. if (in_array($coupon_info['expire_type'], [StoreEnum::EXPIRE_TYPE1, StoreEnum::EXPIRE_TYPE3])) {
  210. // 领取后立即生效,n天过期
  211. // 领取后n天生效,m天过期
  212. $begin_at = $time;
  213. $end_at = 0;
  214. $coupon_status = 2;
  215. } else {
  216. $begin_at = $coupon_info['begin_at'];
  217. $end_at = $coupon_info['end_at'];
  218. $coupon_status = $begin_at <= $time ? 2 : 1;
  219. }
  220. $coupon_info['begin_at'] = $begin_at;
  221. $coupon_info['end_at'] = $end_at;
  222. $coupon_info['coupon_status'] = $coupon_status;
  223. }
  224. if (!$model->load($coupon_info, '') || !$model->save()) throw new \PHPUnit\Util\Exception($model->getErrorMessage());
  225. if (!empty($category_ids)) {
  226. $res = StoreCouponCatRelate::setData($model->id, $category_ids);
  227. if (!$res) throw new Exception(StoreCouponCatRelate::getStaticError());
  228. }
  229. if (!empty($goods_id_list)) {
  230. $res = StoreCouponGoodsRelate::setData($model->id, $goods_id_list);
  231. if (!$res) throw new Exception(StoreCouponGoodsRelate::getStaticError());
  232. }
  233. if (1 == $coupon_info['is_member'] && !empty($member_level_limits)) {
  234. $res = StoreCouponMemberRelate::setData($model->mall_id, $model->id, $model->store_id, $member_level_limits);
  235. if (!$res) throw new Exception(StoreCouponMemberRelate::getStaticError());
  236. }
  237. if (
  238. 1 == $coupon_info['is_giving'] &&
  239. 1 == $coupon_info['is_giving_reward'] &&
  240. !empty($giving_rewards)
  241. ) {
  242. $res = StoreCouponReward::setData($model->mall_id, $model->id, $model->store_id, StoreEnum::REWARD_TYPE_GIVING, $giving_rewards);
  243. if (!$res) throw new Exception(StoreCouponReward::getStaticError());
  244. }
  245. if (1 == $coupon_info['is_consume_reward'] && !empty($consume_rewards)) {
  246. $res = StoreCouponReward::setData($model->mall_id, $model->id, $model->store_id, StoreEnum::REWARD_TYPE_CONSUME, $consume_rewards);
  247. if (!$res) throw new Exception(StoreCouponReward::getStaticError());
  248. }
  249. $transaction->commit();
  250. return $model;
  251. } catch (Exception $e) {
  252. $transaction->rollBack();
  253. self::$static_error = $e->getMessage();
  254. return false;
  255. }
  256. }
  257. /**
  258. * @name:
  259. * @msg: 检查优惠券的使用场景(指定适用类型、是否可以转赠、转赠和使用奖励、适用会员)
  260. * @param {array} $post
  261. * @return {*}
  262. */
  263. private static function checkUseScene(array $coupon_data)
  264. {
  265. $coupon_info = $coupon_data['coupon_info'] ?? [];
  266. $giving_rewards = $coupon_data['giving_reward'] ?? [];
  267. $consume_rewards = $coupon_data['consume_reward'] ?? [];
  268. $goods_id_list = $coupon_data['goods_id_list'] ?? [];
  269. $member_level_limits = $coupon_data['member_level_limits'] ?? [];
  270. $category_ids = $coupon_data['category_ids'] ?? [];
  271. if (1 == $coupon_info['appoint_type']) {
  272. // 指定分类可用
  273. if (empty($category_ids)) {
  274. throw new \Exception('指定分类可用的优惠券,请指定可用分类');
  275. }
  276. } elseif (2 == $coupon_info['appoint_type']) {
  277. // 指定商品可用
  278. if (empty($goods_id_list)) {
  279. throw new \Exception('指定商品可用的优惠券,请指定可用商品');
  280. }
  281. }
  282. if (1 == $coupon_info['is_giving']) {
  283. // 开启转赠
  284. if (1 == $coupon_info['is_giving_reward'] && empty($giving_rewards)) {
  285. throw new \Exception('请填写转赠奖励');
  286. }
  287. if (1 == $coupon_info['is_consume_reward'] && empty($consume_rewards)) {
  288. throw new \Exception('请填写使用奖励');
  289. }
  290. }
  291. if (1 == $coupon_info['is_member']) {
  292. // 指定会员等级
  293. if (empty($member_level_limits)) {
  294. throw new \Exception('请指定可以领取优惠券的会员等级');
  295. }
  296. }
  297. }
  298. /**
  299. * @name:
  300. * @msg: 解析优惠券信息
  301. * @param {array} $coupon_data 优惠券原始数据
  302. * @param {bool} $is_user_coupon 是否会员已经领取的优惠券的数据,默认 false
  303. * @return array
  304. */
  305. public static function parseCouponInfo(array $coupon_data, bool $is_user_coupon = false): array
  306. {
  307. $coupon_data['min_price'] = floatval($coupon_data['min_price']);
  308. $coupon_data['sub_price'] = floatval($coupon_data['sub_price']);
  309. $coupon_data['discount'] = floatval($coupon_data['discount']);
  310. $coupon_data['discount_limit'] = floatval($coupon_data['discount_limit']);
  311. $sub_price = 0;
  312. if (1 == $coupon_data['type']) {
  313. $content = '消费满' . $coupon_data['min_price'] . '元打' . $coupon_data['discount'] . '折';
  314. if ($coupon_data['discount_limit'] > 0) {
  315. $content .= ',最高优惠' . $coupon_data['discount_limit'] . '元';
  316. $sub_price = $coupon_data['discount_limit'];
  317. }
  318. } elseif (2 == $coupon_data['type']) {
  319. $content = '消费满' . $coupon_data['min_price'] . '元减' . $coupon_data['sub_price'] . '元';
  320. $sub_price = $coupon_data['sub_price'];
  321. } else if (3 == $coupon_data['type']) {
  322. if ($coupon_data['exchange_voucher_type'] == 0) {
  323. $content = '全额抵扣';
  324. } else {
  325. $content = '消费满0元减' . $coupon_data['sub_price'] . '元';
  326. $sub_price = $coupon_data['sub_price'];
  327. }
  328. } else {
  329. $content = '';
  330. }
  331. $superposition = '';
  332. if (1 == $coupon_data['is_original_use']) $superposition = '仅原价购买时可用';
  333. if ($is_user_coupon) {
  334. $begin_at = date('Y-m-d H:i', $coupon_data['start_time']);
  335. $end_at = date('Y-m-d H:i', $coupon_data['end_time']);
  336. $use_time = $begin_at . ' 至 ' . $end_at;
  337. } else {
  338. switch ($coupon_data['expire_type']) {
  339. case StoreEnum::APPOINT_TYPE1:
  340. $use_time = str_replace('N', $coupon_data['expire_day'], StoreEnum::getExpireTypeMap()[StoreEnum::APPOINT_TYPE1]);
  341. break;
  342. case StoreEnum::APPOINT_TYPE2:
  343. $begin_at = date('Y-m-d H:i', $coupon_data['begin_at']);
  344. $end_at = date('Y-m-d H:i', $coupon_data['end_at']);
  345. $use_time = $begin_at . ' 至 ' . $end_at;
  346. break;
  347. case StoreEnum::APPOINT_TYPE3:
  348. $use_time = str_replace('N', $coupon_data['expire_day'], StoreEnum::getExpireTypeMap()[StoreEnum::APPOINT_TYPE3]);
  349. $use_time = str_replace('M', $coupon_data['effect_days'], StoreEnum::getExpireTypeMap()[StoreEnum::APPOINT_TYPE3]);
  350. break;
  351. default:
  352. $use_time = '';
  353. break;
  354. }
  355. $begin_at = date('Y-m-d H:i', $coupon_data['begin_at']);
  356. $end_at = $coupon_data['end_at'] ? date('Y-m-d H:i', $coupon_data['end_at']) : '';
  357. }
  358. $coupon_info = [
  359. 'name' => $coupon_data['name'],
  360. 'appoint_type' => $coupon_data['appoint_type'],
  361. 'status_text' => StoreEnum::getCouponStatusMap($coupon_data['coupon_status'], true),
  362. 'use_time' => $use_time,
  363. 'content' => $content,
  364. 'begin_at' => $begin_at,
  365. 'end_at' => $end_at,
  366. 'sub_price' => floatval($sub_price),
  367. 'min_price' => floatval($coupon_data['min_price']),
  368. 'rule' => $coupon_data['rule'],
  369. 'superposition_use' => $superposition,
  370. ];
  371. return $coupon_info;
  372. }
  373. public static function formatData($store_coupon)
  374. {
  375. $item['name'] = $store_coupon['name'];
  376. $item['discount_method'] = $store_coupon['type'] == 1 ? $store_coupon['discount'] . '折' : '优惠' . $store_coupon['sub_price'] . '元';
  377. return $item;
  378. }
  379. public static function getCanUseCouponList($form, $isNewRecord)
  380. {
  381. if (!empty($isNewRecord)) return $form;
  382. $data = is_array($form->data) ? $form->data : Json::decode($form->data, true);
  383. $user_coupon_ids = $data['user_coupon_ids']??[];
  384. $mall_id = $form['mall_id'];
  385. $is_install = MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_COUPON);
  386. $store_arr = [];
  387. $store_ids = '';
  388. foreach ($form['group_order_goods'] as $item) {
  389. $store_ids = $item['mch_order_info']['store_id'];
  390. }
  391. $store_extra = StoreExtra::lists(['where'=>[['store_id'=>$store_ids]]]);
  392. $is_open_coupon_deduct = true;
  393. foreach ($store_extra as $k=>$v){
  394. $deduct_setting = json_decode($v['deduct_setting'],true);
  395. if(empty($deduct_setting['is_open_coupon_deduct'])){
  396. $is_open_coupon_deduct = false;
  397. break;
  398. }
  399. $store_ids= $v['store_id'];
  400. }
  401. if($is_open_coupon_deduct==false) return $form;
  402. $params = [];
  403. $time = time();
  404. $where[] = ['status' => StatusEnum::ENABLED];
  405. $where[] = ['coupon_status' => AddonsCouponEnum::STATUS_RECEIVING];
  406. $where[] = ['is_use' => AddonsCouponEnum::IS_USE0];
  407. $where[] = ['or', ['is_giving' => AddonsCouponEnum::GIVING_N], ['is_giving' => AddonsCouponEnum::GIVING, 'giving_status' => AddonsCouponEnum::GIVING_STATUS1]];
  408. $where[] = ['giving_status' => [AddonsCouponEnum::GIVING_STATUS0, AddonsCouponEnum::GIVING_STATUS1]];
  409. $where[] = ['user_id' => $form['user_id']];
  410. $where[] = ['<=', 'start_time', $time];
  411. $where[] = ['>=', 'end_time', $time];
  412. $where[] = new Expression("FIND_IN_SET({$store_ids},store_id)");
  413. $params['where'] = $where;
  414. $list = StoreCouponUserRelate::lists($params);
  415. $platform_coupon_ids = [];
  416. $store_coupon_ids = [];
  417. foreach ($list as $value) {
  418. $value['from_type'] == 1 ? $platform_coupon_ids[] = $value['coupon_id'] : $store_coupon_ids[] = $value['coupon_id'];
  419. }
  420. // 优惠券ID去重
  421. $platform_coupon_ids = array_unique($platform_coupon_ids);
  422. $store_coupon_ids = array_unique($store_coupon_ids);
  423. if ($is_install) $platform_coupon_list = AddonsCoupon::lists(['where' => [['id' => $platform_coupon_ids]], 'index' => 'id','with'=>['goodsRelate','cateRelate', 'storeGoods']]);
  424. $store_coupon_list = StoreCoupon::lists(['where' => [['id' => $store_coupon_ids]], 'index' => 'id','with'=>['goodsRelate','cateRelate']]);
  425. $goods_id_arr = $goods_arr = [];
  426. $total_coupon_discount_money = 0;
  427. $is_original_goods_price = 1;
  428. foreach ($form['group_order_goods'] as $item) {
  429. if(empty($user_coupon_ids)) {
  430. if (
  431. // 精确对比2个数字
  432. bccomp($item['mch_order_info']['goods_price'], $item['mch_order_info']['original_goods_price'], 2) != 0
  433. ) {
  434. $is_original_goods_price = 0;
  435. }
  436. }
  437. $store_arr[$item['mch_order_info']['store_id']] = $item['mch_order_info']['goods_price'];
  438. if (!empty($item['goods'])) {
  439. foreach ($item['goods'] as $v) {
  440. $coupon_discount_money = 0;
  441. foreach ($v['goods_details'] as $val) {
  442. $coupon_discount_money += $val['marketing']['coupon_discount_money'] ?? 0;
  443. }
  444. $total_coupon_discount_money+=$coupon_discount_money;
  445. $goods_id_arr[] = $v['goods_id'];
  446. $goods_arr[$v['goods_id']] = ['num' => $v['num'], 'goods_price' => $v['goods_price'], 'coupon_discount_money' => $coupon_discount_money, 'store_id' => $v['goods_details'][0]['store_id']];
  447. }
  448. }
  449. }
  450. self::getCateArr($goods_id_arr,$goods_arr, $cate_id_arr, $cate_arr);
  451. $can_use_list = $can_use_list1 = $can_use_list2 = $can_use_list3 = $can_use_list4 = $can_use_list6 = [];
  452. // 优惠券今日剩余可使用次数
  453. $exchangeTypeCouponMaxUseNum = [];
  454. foreach ($list as &$v) {
  455. switch ($v['from_type']) {
  456. case 1:
  457. if (!empty($platform_coupon_list[$v['coupon_id']])) {
  458. $coupon = $platform_coupon_list[$v['coupon_id']];
  459. $coupon['from_type'] = $v['from_type'];
  460. //因为平台优惠券,指定门店支持多门店,且下单时,不同门店不能一起下单,所以可在此把优惠券的store_id 替换成下单商品的门店id
  461. $coupon['store_id'] = $store_ids;
  462. }
  463. break;
  464. case 2:
  465. if (!empty($store_coupon_list[$v['coupon_id']])) {
  466. $coupon = $store_coupon_list[$v['coupon_id']];
  467. $coupon['from_type'] = $v['from_type'];
  468. }
  469. break;
  470. }
  471. if (empty($coupon)) continue;
  472. $coupon_user_relate_arr[$v['from_type']][$coupon['id']] = $v;
  473. $coupon['user_coupon_id'] = $v['id'];
  474. // 判断是否原价使用优惠券
  475. if (!empty($coupon['is_original_use'])) {
  476. if ($is_original_goods_price == 0) {
  477. continue;
  478. }
  479. }
  480. if ($v['from_type'] == 1) {
  481. // 是否是转赠后才能使用
  482. if (!AddonsCoupon::checkCouponSourceIsFromSharing(array_merge($v, ['coupon' => $coupon]), 2)) {
  483. continue;
  484. }
  485. // 指定门店,相当于指定门店的全场通用
  486. unset($coupon['goodsRelate']);
  487. unset($coupon['cateRelate']);
  488. if (!empty($coupon['store_id'])) {
  489. if ($coupon['appoint_type'] == AddonsCouponEnum::APPOINT_TYPE6) {
  490. if($coupon['type'] == AddonsCouponEnum::EXCHANGE) {
  491. // 多件商品下单不能使用该券
  492. if (count($form['order_goods']) > 1) {
  493. continue;
  494. }
  495. $num = AddonsCoupon::getTodayLimit($form['mall_id'], $form['user_id'], $coupon, 0, 2);
  496. // 验证该券每日使用次数
  497. if (!$num) {
  498. continue;
  499. }
  500. $exchangeTypeCouponMaxUseNum[$coupon['id']] = $num;
  501. }
  502. $gs_id_arr = array_column($coupon['storeGoodsRelate'], 'goods_id');
  503. unset($coupon['storeGoodsRelate']);
  504. self::packagingArr($coupon, $goods_id_arr, $goods_arr, $can_use_list6, $gs_id_arr, $coupon_user_relate_arr, $v['from_type'], $coupon['appoint_type'],0,$user_coupon_ids);
  505. continue;
  506. }
  507. // 该券属于平台指的门店优惠券
  508. if (!empty($store_arr[$coupon['store_id']])) {
  509. unset($coupon['storeGoodsRelate']);
  510. $store_total_goods_price = $store_arr[$coupon['store_id']];
  511. self::packagingArr($coupon, [], [], $can_use_list4, [], $coupon_user_relate_arr, $v['from_type'], 3, $store_total_goods_price,$user_coupon_ids);
  512. }
  513. }
  514. continue;
  515. } else {
  516. //1 指定分类 2 指定商品 3全部
  517. if ($coupon['appoint_type'] == AddonsCouponEnum::APPOINT_TYPE1) {
  518. $ct_id_arr = array_column($coupon['cateRelate'], 'cate_id');
  519. unset($coupon['cateRelate']);
  520. unset($coupon['goodsRelate']);
  521. self::packagingArr($coupon, $ct_id_arr, $cate_arr, $can_use_list1, $ct_id_arr, $coupon_user_relate_arr, $v['from_type'], $coupon['appoint_type'],0,$user_coupon_ids,$total_coupon_discount_money);
  522. continue;
  523. }
  524. if ($coupon['appoint_type'] == AddonsCouponEnum::APPOINT_TYPE2) {
  525. $gs_id_arr = array_column($coupon['goodsRelate'], 'goods_id');
  526. unset($coupon['goodsRelate']);
  527. unset($coupon['cateRelate']);
  528. self::packagingArr($coupon, $goods_id_arr, $goods_arr, $can_use_list2, $gs_id_arr, $coupon_user_relate_arr, $v['from_type'], $coupon['appoint_type'],0,$user_coupon_ids);
  529. continue;
  530. }
  531. if ($coupon['appoint_type'] == AddonsCouponEnum::APPOINT_TYPE3) {
  532. unset($coupon['goodsRelate']);
  533. unset($coupon['cateRelate']);
  534. if (!empty($coupon['store_id'])) {
  535. //该券属于某个门店的全场通用券
  536. $store_total_goods_price = $store_arr[$coupon['store_id']];
  537. if(empty($store_total_goods_price)) continue;
  538. self::packagingArr($coupon, [], [], $can_use_list3, [], $coupon_user_relate_arr, $v['from_type'], $coupon['appoint_type'], $store_total_goods_price, $user_coupon_ids, $total_coupon_discount_money);
  539. }
  540. continue;
  541. }
  542. }
  543. }
  544. if (!empty($can_use_list1)) self::formatArr($can_use_list1, $can_use_list, 2);
  545. if (!empty($can_use_list2)) self::formatArr($can_use_list2, $can_use_list, 2);
  546. if (!empty($can_use_list3)) self::formatArr($can_use_list3, $can_use_list, 2);
  547. if (!empty($can_use_list4)) self::formatArr($can_use_list4, $can_use_list, 2);
  548. if (!empty($can_use_list6)) self::formatArr($can_use_list6, $can_use_list, 2);
  549. $discount_money = $form['marketing']['deduct']['coupon']['money'] ?? 0;
  550. $form->marketing['deduct']['coupon'] = [
  551. 'list' => $can_use_list,
  552. 'type_map' => CouponEnum::getTypeMap(),
  553. 'expire_type_map' => StoreEnum::getExpireTypeMap(),
  554. 'appoint_type_map' => StoreEnum::getAppointTypeMap(),
  555. 'discount_money' => $discount_money,
  556. 'exchange_type_coupon_max_use_num' => $exchangeTypeCouponMaxUseNum ?: null,
  557. ];
  558. return $form;
  559. }
  560. public static function packagingArr($coupon, $id_arr, $arr, &$can_use_list, $have_id_arr, $coupon_user_relate_arr, $from_type, $appoint_type = 1, $total_price = 0,$user_coupon_ids =[],$total_coupon_discount_money = 0)
  561. {
  562. $coupon['coupon_discount_money'] = 0;
  563. // 获取用户优惠券有效期结束时间 替换结束时间
  564. $end_at = $coupon_user_relate_arr[$from_type][$coupon['id']]['end_time'];
  565. $coupon['end_at'] = $end_at;
  566. if ($appoint_type == StoreEnum::APPOINT_TYPE1) {
  567. // foreach ($id_arr as $id) {
  568. // if (in_array($id, $have_id_arr)) {
  569. // $price = $arr[$id]['goods_price'];
  570. // if (($coupon['min_price'] && ($total_coupon_discount_money + $price) >= $coupon['min_price'])||(in_array($coupon['user_coupon_id'],$user_coupon_ids))) {
  571. // if ($coupon['type'] == StoreEnum::DISCOUNT) $coupon['sub_price'] = bcmul($coupon['discount'] / 10, $price, 2);
  572. // /* if (!empty( $can_use_list[$from_type][$coupon['store_id']][$coupon['id']])) {
  573. // //优惠额度更大的优先
  574. // if ( $can_use_list[$from_type][$coupon['store_id']][$coupon['id']]['sub_price'] < $coupon['sub_price']) {
  575. // $can_use_list[$from_type][$coupon['store_id']][$coupon['id']] = $coupon;
  576. // continue;
  577. // }
  578. // //有效期更短的优先
  579. // $end_at = $coupon_user_relate_arr[$from_type][$coupon['id']]['end_at'];
  580. // if ( $can_use_list[$from_type][$coupon['store_id']][$coupon['id']]['sub_price'] == $coupon['sub_price'] && $end_at > time()) {
  581. // $can_use_list[$from_type][$coupon['store_id']][$coupon['id']] = $coupon;
  582. // }
  583. // } else {
  584. // $can_use_list[$from_type][$coupon['store_id']][$coupon['id']] = $coupon;
  585. // } */
  586. // $can_use_list[$from_type][$coupon['store_id']][] = $coupon;
  587. // }
  588. // }
  589. // }
  590. // 优惠券支持的分类
  591. // $id_arr;
  592. // 当前全部商品
  593. // $arr;
  594. if (count(array_diff($id_arr, array_keys($arr))) == 0) {
  595. $can_use_list[$from_type][$coupon['store_id']][] = $coupon;
  596. }
  597. }
  598. if ($appoint_type == StoreEnum::APPOINT_TYPE2 || ($from_type == 1 && $appoint_type == AddonsCouponEnum::APPOINT_TYPE6)) {
  599. foreach ($id_arr as $id) {
  600. if (in_array($id, $have_id_arr)) {
  601. if ($coupon['type'] == AddonsCouponEnum::EXCHANGE) {
  602. $can_use_list[$from_type][$coupon['store_id']][] = $coupon;
  603. break;
  604. }
  605. $price = $arr[$id]['goods_price'];
  606. if (empty($coupon['min_price'])) { // 考虑到抵扣券全部抵扣并没有 最低消费金额
  607. if (($coupon['type'] == 3 && empty($coupon['exchange_voucher_type'])) || (in_array($coupon['user_coupon_id'],$user_coupon_ids))) {
  608. if ($coupon['type'] == StoreEnum::DISCOUNT) $coupon['sub_price'] = bcmul($coupon['discount'] / 10, $price, 2);
  609. $can_use_list[$from_type][$coupon['store_id']][] = $coupon;
  610. break;
  611. }
  612. } else {
  613. if ((($arr[$id]['coupon_discount_money'] + $price) >= $coupon['min_price']) || (in_array($coupon['user_coupon_id'],$user_coupon_ids))) {
  614. if ($coupon['type'] == StoreEnum::DISCOUNT) $coupon['sub_price'] = bcmul($coupon['discount'] / 10, $price, 2);
  615. $can_use_list[$from_type][$coupon['store_id']][] = $coupon;
  616. break;
  617. }
  618. }
  619. }
  620. }
  621. // 当前购买的ID
  622. // $have_id_arr;
  623. // 支持的ID
  624. // $id_arr;
  625. /*if (count(array_diff($id_arr, array_keys($arr))) == 0) {
  626. $can_use_list[$from_type][$coupon['store_id']][] = $coupon;
  627. }*/
  628. }
  629. if ($appoint_type == AddonsCouponEnum::APPOINT_TYPE3) {
  630. // 计算优惠前金额
  631. // $total_price = bcadd($total_price, $total_coupon_discount_money, 2);
  632. if (empty($coupon['min_price'])) {
  633. if (($coupon['type'] == 3 && empty($coupon['exchange_voucher_type'])) || (in_array($coupon['user_coupon_id'],$user_coupon_ids))) {
  634. if ($coupon['type'] == AddonsCouponEnum::DISCOUNT) $coupon['sub_price'] = bcmul($coupon['discount'] / 10, $total_price, 2);
  635. $can_use_list[$from_type][$coupon['store_id']][] = $coupon;
  636. }
  637. } else {
  638. if (($total_price >= $coupon['min_price']) || (in_array($coupon['user_coupon_id'], $user_coupon_ids))) {
  639. if ($coupon['type'] == AddonsCouponEnum::DISCOUNT) $coupon['sub_price'] = bcmul($coupon['discount'] / 10, $total_price, 2);
  640. $can_use_list[$from_type][$coupon['store_id']][] = $coupon;
  641. }
  642. }
  643. }
  644. }
  645. /**
  646. * 获取分类数据
  647. * @Author: hua
  648. * @DateTime: 2021/10/15 10:56
  649. * @Copyright: copyright (c) 2021 广东七件事集团
  650. * @param $goods_id_arr
  651. * @param $goods_arr
  652. * @param $cate_id_arr
  653. * @param $cate_arr
  654. * @return string
  655. */
  656. public static function getCateArr($goods_id_arr, $goods_arr,&$cate_id_arr, &$cate_arr)
  657. {
  658. $goods_cate_relate_list = StoreGoodsCateRelate::findAll(['goods_id' => $goods_id_arr]);
  659. foreach ($goods_cate_relate_list as $v) {
  660. $cate_id_arr[] = $v['cate_id'];
  661. $cate_arr[$v['cate_id']]['store_id'] = $goods_arr[$v['goods_id']]['store_id'] ?? 0;
  662. if (isset($cate_arr[$v['cate_id']])) {
  663. if (!isset($cate_arr[$v['cate_id']]['goods_price'])) $cate_arr[$v['cate_id']]['goods_price'] = 0;
  664. $cate_arr[$v['cate_id']]['goods_price'] += $goods_arr[$v['goods_id']]['goods_price'] ?? 0;
  665. } else {
  666. $cate_arr[$v['cate_id']]['goods_price'] = $goods_arr[$v['goods_id']]['goods_price'] ?? 0;
  667. }
  668. }
  669. return '';
  670. }
  671. /**
  672. * 格式化
  673. * @Author: hua
  674. * @DateTime: 2021/10/15 10:04
  675. * @Copyright: copyright (c) 2021 广东七件事集团
  676. * @param $input_arr
  677. * @param $output_arr
  678. * @param int $deep
  679. */
  680. public static function formatArr($input_arr, &$output_arr, $deep = 1)
  681. {
  682. if ($deep == 1) {
  683. foreach ($input_arr as $from_type=>$val){
  684. foreach ($val as $store_id=>$coupon){
  685. $output_arr[] = $coupon;
  686. }
  687. }
  688. }
  689. if ($deep == 2) {
  690. foreach ($input_arr as $from_type=>$val){
  691. foreach ($val as $store_id=>$rows){
  692. foreach ($rows as $coupon_id=>$coupon){
  693. $output_arr[] = $coupon;
  694. }
  695. }
  696. }
  697. }
  698. }
  699. public static function deleteCoupon(int $coupon_id, int $mall_id)
  700. {
  701. $transaction = \Yii::$app->db->beginTransaction();
  702. try {
  703. $model = StoreCoupon::findOne(['mall_id' => $mall_id, 'id' => $coupon_id, 'status' => StatusEnum::ENABLED]);
  704. if (empty($model)) {
  705. throw new \Exception('优惠券不存在或已删除');
  706. }
  707. $model->status = StatusEnum::DISABLED;
  708. $model->coupon_status = AddonsCouponEnum::STATUS_FAILURE;
  709. $model->updated_at = time();
  710. $res_coupon = $model->save();
  711. $res_user_coupon = StoreCouponUserRelate::updateAll(['status' => StatusEnum::DISABLED, 'coupon_status' => AddonsCouponEnum::STATUS_FAILURE], ['mall_id' => $mall_id,'from_type'=>2, 'id' => $coupon_id, 'status' => StatusEnum::ENABLED]);
  712. if ($res_coupon === false || $res_user_coupon === false) {
  713. throw new \Exception('删除失败: res_coupon => ' . $model->getErrorMessage() . ', res_user_coupon => ' . StoreCouponUserRelate::getStaticError());
  714. }
  715. $transaction->commit();
  716. return true;
  717. } catch (\Exception $e) {
  718. $transaction->rollBack();
  719. self::$static_error = $e->getMessage();
  720. return false;
  721. }
  722. }
  723. public static function getCouponListByDiy($params)
  724. {
  725. $list = self::listPage([
  726. 'where' => $params,
  727. 'select' => 'id,name,type,min_price,discount,exchange_voucher_type,sub_price',
  728. 'limit' => 10
  729. ]);
  730. $type_map = CouponEnum::getTypeMap();
  731. if ($list['list']) {
  732. foreach ($list['list'] as &$item) {
  733. $item['type_text'] = $type_map[$item['type']] . '券';
  734. if (1 == $item['type']) {
  735. $content = '消费满' . $item['min_price'] . '元打' . $item['discount'] . '折';
  736. if ($item['discount_limit'] > 0) {
  737. $content .= ',最高优惠' . $item['discount_limit'] . '元';
  738. }
  739. } elseif (2 == $item['type']) {
  740. $content = '消费满' . $item['min_price'] . '元减' . $item['sub_price'] . '元';
  741. } else if (3 == $item['type']) {
  742. if ($item['exchange_voucher_type'] == 0) {
  743. $content = '全额抵扣';
  744. } else {
  745. $content = '消费满0元减' . $item['sub_price'] . '元';
  746. }
  747. } else {
  748. $content = '';
  749. }
  750. $item['content'] = $content;
  751. }
  752. }
  753. return $list;
  754. }
  755. }