Product.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. <?php
  2. namespace addons\TinyShop\common\models\product;
  3. use Yii;
  4. use yii\db\ActiveQuery;
  5. use common\behaviors\MerchantBehavior;
  6. use common\enums\StatusEnum;
  7. use common\models\base\BaseModel;
  8. use common\traits\HasOneMerchant;
  9. use common\helpers\StringHelper;
  10. use addons\TinyShop\common\enums\CommonModelMapEnum;
  11. use addons\TinyShop\common\enums\OrderStatusEnum;
  12. use addons\TinyShop\common\models\common\Collect;
  13. use addons\TinyShop\common\models\order\OrderProduct;
  14. use addons\TinyShop\common\enums\MarketingEnum;
  15. use addons\TinyShop\common\models\marketing\MarketingProduct;
  16. use addons\TinyShop\common\models\common\Supplier;
  17. use addons\TinyShop\common\models\marketing\MarketingProductSku;
  18. use addons\TinyShop\common\models\repertory\Stock;
  19. /**
  20. * This is the model class for table "{{%addon_tiny_shop_product}}".
  21. *
  22. * @property int $id
  23. * @property int|null $merchant_id 商家编号
  24. * @property string|null $name 商品标题
  25. * @property string|null $picture 商品主图
  26. * @property int|null $cate_id 商品分类编号
  27. * @property int|null $brand_id 品牌编号
  28. * @property int|null $type 商品类型
  29. * @property string|null $sketch 简述
  30. * @property string|null $intro 商品描述
  31. * @property string|null $keywords 商品关键字
  32. * @property string|null $tags 标签
  33. * @property string|null $sku_no 商品编码
  34. * @property string|null $barcode 商品条码
  35. * @property int|null $sales 虚拟购买量
  36. * @property int|null $real_sales 实际销量
  37. * @property int|null $total_sales 总销量
  38. * @property float|null $price 商品价格
  39. * @property float|null $market_price 市场价格
  40. * @property float|null $cost_price 成本价
  41. * @property int|null $stock 库存量
  42. * @property int|null $stock_warning_num 库存警告数量
  43. * @property int|null $stock_deduction_type 库存扣减类型
  44. * @property string|null $covers 幻灯片
  45. * @property string|null $extend 扩展
  46. * @property string|null $video_url 展示视频
  47. * @property int|null $sort 排序
  48. * @property array|null $delivery_type 配送方式
  49. * @property int|null $shipping_type 运费类型 1免邮2买家付邮费3固定运费
  50. * @property float|null $shipping_fee 运费
  51. * @property int|null $shipping_fee_id 物流模板id
  52. * @property int|null $shipping_fee_type 计价方式1.计件2.体积3.重量
  53. * @property float|null $weight 商品重量
  54. * @property float|null $volume 商品体积
  55. * @property int|null $marketing_id 促销活动ID
  56. * @property string|null $marketing_type 促销类型
  57. * @property float|null $marketing_price 商品促销价格
  58. * @property int|null $point_exchange_type 积分兑换类型
  59. * @property int|null $point_exchange 积分兑换
  60. * @property int|null $point_give_type 积分赠送类型 0固定值 1按比率
  61. * @property int|null $give_point 购买商品赠送积分
  62. * @property int|null $max_use_point 积分抵现最大可用积分数 0为不可使用
  63. * @property int|null $min_buy 最少买几件
  64. * @property int|null $max_buy 限购 0 不限购
  65. * @property int|null $order_max_buy 单笔订单限购 0 不限购
  66. * @property int|null $view 商品点击数量
  67. * @property int|null $star 好评星级
  68. * @property int|null $collect_num 收藏数量
  69. * @property int|null $comment_num 评价数
  70. * @property int|null $transmit_num 分享数
  71. * @property int|null $province_id 所在省
  72. * @property int|null $city_id 所在市
  73. * @property int|null $area_id 所在区
  74. * @property string|null $address_name 地址
  75. * @property int|null $attribute_id 参数
  76. * @property int|null $is_spec 启用商品规格
  77. * @property int|null $is_stock_visible 库存显示 0不显示1显示
  78. * @property int|null $is_sales_visible 销量显示 0不显示1显示
  79. * @property int|null $is_hot 是否热销商品
  80. * @property int|null $is_recommend 是否推荐
  81. * @property int|null $is_new 是否新品
  82. * @property int|null $is_bill 是否开具增值税发票 1是,0否
  83. * @property string|null $spec_format 商品规格
  84. * @property float|null $match_point 实物与描述相符(根据评价计算)
  85. * @property float|null $match_ratio 实物与描述相符(根据评价计算)百分比
  86. * @property int|null $production_date 生产日期
  87. * @property int|null $shelf_life 保质期
  88. * @property int|null $growth_give_type 成长值赠送类型 0固定值 1按比率
  89. * @property int|null $give_growth 购买商品赠送成长值
  90. * @property string|null $unit 商品单位
  91. * @property int|null $supplier_id 供货商id
  92. * @property int|null $spec_template_id 规格模板
  93. * @property int|null $is_commission 是否支持分销
  94. * @property int|null $is_member_discount 是否支持会员折扣
  95. * @property int|null $member_discount_type 折扣类型 1:系统;2:自定义
  96. * @property int|null $active_blacklist 活动黑名单
  97. * @property int|null $is_list_visible 列表可见
  98. * @property int|null $start_time 上架时间
  99. * @property int|null $end_time 下架时间
  100. * @property string|null $refusal_cause 拒绝原因
  101. * @property int $audit_status 审核状态[0:申请;1通过;-1失败]
  102. * @property int|null $audit_time 审核时间
  103. * @property int|null $status 状态
  104. * @property int $created_at 创建时间
  105. * @property int $updated_at 更新时间
  106. */
  107. class Product extends BaseModel
  108. {
  109. use MerchantBehavior, HasOneMerchant;
  110. /**
  111. * {@inheritdoc}
  112. */
  113. public static function tableName()
  114. {
  115. return '{{%addon_tiny_shop_product}}';
  116. }
  117. /**
  118. * {@inheritdoc}
  119. */
  120. public function rules()
  121. {
  122. return [
  123. [
  124. [
  125. 'name',
  126. 'cate_id',
  127. 'price',
  128. 'market_price',
  129. 'cost_price',
  130. 'shipping_fee',
  131. 'intro',
  132. 'covers',
  133. 'stock',
  134. 'stock_warning_num',
  135. 'weight',
  136. 'volume',
  137. 'min_buy',
  138. 'max_buy',
  139. 'give_point',
  140. 'give_growth',
  141. 'order_max_buy',
  142. ],
  143. 'required',
  144. ],
  145. [['delivery_type',], 'required', 'on' => 'entity'],
  146. [
  147. [
  148. 'merchant_id',
  149. 'cate_id',
  150. 'brand_id',
  151. 'type',
  152. 'sales',
  153. 'real_sales',
  154. 'total_sales',
  155. 'stock',
  156. 'stock_warning_num',
  157. 'stock_deduction_type',
  158. 'sort',
  159. 'shipping_type',
  160. 'shipping_fee_id',
  161. 'shipping_fee_type',
  162. 'marketing_id',
  163. 'point_exchange_type',
  164. 'point_exchange',
  165. 'point_give_type',
  166. 'give_point',
  167. 'max_use_point',
  168. 'min_buy',
  169. 'max_buy',
  170. 'order_max_buy',
  171. 'view',
  172. 'star',
  173. 'collect_num',
  174. 'comment_num',
  175. 'transmit_num',
  176. 'province_id',
  177. 'city_id',
  178. 'area_id',
  179. 'is_spec',
  180. 'is_stock_visible',
  181. 'is_sales_visible',
  182. 'is_hot',
  183. 'is_recommend',
  184. 'is_new',
  185. 'is_bill',
  186. 'shelf_life',
  187. 'growth_give_type',
  188. 'give_growth',
  189. 'supplier_id',
  190. 'spec_template_id',
  191. 'is_commission',
  192. 'is_member_discount',
  193. 'member_discount_type',
  194. 'active_blacklist',
  195. 'is_list_visible',
  196. 'audit_status',
  197. 'audit_time',
  198. 'created_at',
  199. 'updated_at',
  200. ],
  201. 'integer',
  202. 'min' => 0,
  203. ],
  204. [['intro'], 'string'],
  205. [
  206. [
  207. 'price',
  208. 'market_price',
  209. 'cost_price',
  210. 'shipping_fee',
  211. 'weight',
  212. 'volume',
  213. 'marketing_price',
  214. 'match_point',
  215. 'match_ratio',
  216. ],
  217. 'number',
  218. 'min' => 0,
  219. 'max' => 9999999,
  220. ],
  221. [
  222. [
  223. 'covers',
  224. 'extend',
  225. 'spec_format',
  226. 'delivery_type',
  227. 'production_date',
  228. 'start_time',
  229. 'end_time',
  230. ],
  231. 'safe',
  232. ],
  233. [['name', 'picture'], 'string', 'max' => 255],
  234. [['sketch', 'keywords', 'video_url', 'address_name', 'refusal_cause'], 'string', 'max' => 200],
  235. [['sku_no', 'barcode'], 'string', 'max' => 100],
  236. [['marketing_type', 'unit'], 'string', 'max' => 50],
  237. [['min_buy'], 'integer', 'min' => 1],
  238. [['attribute_id', 'status'], 'integer'],
  239. [['tags'], 'safe'],
  240. ];
  241. }
  242. /**
  243. * {@inheritdoc}
  244. */
  245. public function attributeLabels()
  246. {
  247. return [
  248. 'id' => 'ID',
  249. 'merchant_id' => '商家编号',
  250. 'name' => '商品名称',
  251. 'picture' => '商品主图',
  252. 'cate_id' => '商品分类',
  253. 'brand_id' => '品牌',
  254. 'type' => '商品类型',
  255. 'sketch' => '商品卖点',
  256. 'intro' => '商品描述',
  257. 'keywords' => '商品关键字',
  258. 'tags' => '标签',
  259. 'sku_no' => '商品编码',
  260. 'barcode' => '商品条码',
  261. 'sales' => '虚拟购买量',
  262. 'real_sales' => '实际销量',
  263. 'total_sales' => '总销量',
  264. 'price' => '商品价格',
  265. 'market_price' => '划线价',
  266. 'cost_price' => '成本价',
  267. 'stock' => '库存',
  268. 'stock_warning_num' => '库存预警',
  269. 'stock_deduction_type' => '库存扣减类型',
  270. 'covers' => '幻灯片',
  271. 'extend' => '扩展',
  272. 'video_url' => '展示视频',
  273. 'sort' => '排序',
  274. 'delivery_type' => '配送方式',
  275. 'shipping_type' => '运费类型',
  276. 'shipping_fee' => '运费',
  277. 'shipping_fee_id' => '物流模板',
  278. 'shipping_fee_type' => '计价方式', // 1.计件2.体积3.重量
  279. 'weight' => '商品重量',
  280. 'volume' => '商品体积',
  281. 'marketing_id' => '促销活动ID',
  282. 'marketing_type' => '促销类型',
  283. 'marketing_price' => '商品促销价格',
  284. 'point_exchange_type' => '积分兑换类型',
  285. 'point_exchange' => '积分兑换',
  286. 'point_give_type' => '积分赠送类型', // 0固定值 1按比率
  287. 'give_point' => '购买单件商品赠送积分',
  288. 'max_use_point' => '积分抵现最大可用积分数', // 0为不可使用
  289. 'min_buy' => '最少买几件',
  290. 'max_buy' => '总限购', // 0 不限购
  291. 'order_max_buy' => '单笔下单限购', // 0 不限购
  292. 'view' => '商品点击数量',
  293. 'star' => '好评星级',
  294. 'collect_num' => '收藏数量',
  295. 'comment_num' => '评价数',
  296. 'transmit_num' => '分享数',
  297. 'province_id' => '所在省',
  298. 'city_id' => '所在市',
  299. 'area_id' => '所在区',
  300. 'address_name' => '地址',
  301. 'attribute_id' => '商品参数模板',
  302. 'is_spec' => '商品规格',
  303. 'is_stock_visible' => '库存显示', // 0 不显示1显示
  304. 'is_sales_visible' => '销量显示', // 0 不显示1显示
  305. 'is_hot' => '热销',
  306. 'is_recommend' => '推荐',
  307. 'is_new' => '新品',
  308. 'is_bill' => '是否开具增值税发票', // 1是,0否
  309. 'spec_format' => '商品规格',
  310. 'match_point' => '实物与描述相符(根据评价计算)',
  311. 'match_ratio' => '实物与描述相符(根据评价计算)百分比',
  312. 'production_date' => '生产日期',
  313. 'shelf_life' => '保质期',
  314. 'growth_give_type' => '成长值赠送类型', // 0固定值 1按比率
  315. 'give_growth' => '购买单件商品赠送成长值',
  316. 'unit' => '商品单位',
  317. 'spec_template_id' => '规格模板',
  318. 'supplier_id' => '供货商',
  319. 'is_commission' => '分销设置',
  320. 'is_member_discount' => '会员折扣',
  321. 'member_discount_type' => '折扣类型', // 1:系统;2:自定义
  322. 'active_blacklist' => '活动黑名单',
  323. 'is_list_visible' => '搜索/列表可见',
  324. 'start_time' => '定时上架时间',
  325. 'end_time' => '下架时间',
  326. 'refusal_cause' => '拒绝原因',
  327. 'audit_status' => '审核状态',
  328. 'audit_time' => '审核时间',
  329. 'status' => '商品状态',
  330. 'created_at' => '创建时间',
  331. 'updated_at' => '更新时间',
  332. ];
  333. }
  334. /**
  335. * 关联规格
  336. *
  337. * @return ActiveQuery
  338. */
  339. public function getSpec()
  340. {
  341. return $this->hasMany(Spec::class, ['product_id' => 'id']);
  342. }
  343. /**
  344. * 关联规格值
  345. *
  346. * @return ActiveQuery
  347. */
  348. public function getSpecValue()
  349. {
  350. return $this->hasMany(SpecValue::class, ['product_id' => 'id']);
  351. }
  352. /**
  353. * 关联sku
  354. *
  355. * @return ActiveQuery
  356. */
  357. public function getSku()
  358. {
  359. return $this->hasMany(Sku::class, ['product_id' => 'id']);
  360. }
  361. /**
  362. * 关联第一个sku
  363. *
  364. * @return ActiveQuery
  365. */
  366. public function getFirstSku()
  367. {
  368. return $this->hasOne(Sku::class, ['product_id' => 'id'])
  369. ->orderBy('id asc');
  370. }
  371. /**
  372. * 关最小sku
  373. *
  374. * @return ActiveQuery
  375. */
  376. public function getMinPriceSku()
  377. {
  378. return $this->hasOne(Sku::class, ['product_id' => 'id'])->orderBy('price');
  379. }
  380. /**
  381. * 分销配置
  382. *
  383. * @return ActiveQuery
  384. */
  385. public function getCommissionRate()
  386. {
  387. return $this->hasOne(CommissionRate::class, ['product_id' => 'id']);
  388. }
  389. /**
  390. * 会员折扣
  391. *
  392. * @return ActiveQuery
  393. */
  394. public function getMemberDiscount()
  395. {
  396. return $this->hasOne(MemberDiscount::class, ['product_id' => 'id']);
  397. }
  398. /**
  399. * 关联当前营销
  400. *
  401. * @return ActiveQuery
  402. */
  403. public function getMarketingProduct()
  404. {
  405. return $this->hasOne(MarketingProduct::class, ['product_id' => 'id'])
  406. ->where(['status' => StatusEnum::ENABLED])
  407. ->andWhere([
  408. 'in',
  409. 'marketing_type',
  410. [
  411. MarketingEnum::DISCOUNT,
  412. MarketingEnum::SECOND_HALF_DISCOUNT,
  413. MarketingEnum::BALE,
  414. MarketingEnum::MEMBER_DISCOUNT,
  415. ],
  416. ])
  417. ->andWhere(['<', 'start_time', time()])
  418. ->andWhere(['>', 'end_time', time()])
  419. ->orderBy('id desc');
  420. }
  421. /**
  422. * 关联分类
  423. *
  424. * @return ActiveQuery
  425. */
  426. public function getCate()
  427. {
  428. return $this->hasOne(Cate::class, ['id' => 'cate_id'])
  429. ->select(['id', 'title']);
  430. }
  431. /**
  432. * 关联分类
  433. *
  434. * @return ActiveQuery
  435. */
  436. public function getCateMap()
  437. {
  438. return $this->hasMany(CateMap::class, ['product_id' => 'id']);
  439. }
  440. /**
  441. * 关联品牌
  442. *
  443. * @return ActiveQuery
  444. */
  445. public function getBrand()
  446. {
  447. return $this->hasOne(Brand::class, ['id' => 'brand_id'])->select(['id', 'title']);
  448. }
  449. /**
  450. * 关联供应商
  451. *
  452. * @return ActiveQuery
  453. */
  454. public function getSupplier()
  455. {
  456. return $this->hasOne(Supplier::class, ['id' => 'supplier_id']);
  457. }
  458. /**
  459. * 关联仓库库存
  460. *
  461. * @return ActiveQuery
  462. */
  463. public function getRepertoryStock()
  464. {
  465. return $this->hasMany(Stock::class, ['product_id' => 'id']);
  466. }
  467. /**
  468. * 关联仓库库存
  469. *
  470. * @return ActiveQuery
  471. */
  472. public function getFirstRepertoryStock()
  473. {
  474. return $this->hasOne(Stock::class, ['product_id' => 'id'])->andWhere(['sku_id' => 0]);
  475. }
  476. /**
  477. * 营销
  478. *
  479. * @return ActiveQuery
  480. */
  481. public function getMarketing()
  482. {
  483. return $this->hasOne(MarketingProductSku::class, ['product_id' => 'id'])
  484. ->andWhere(['<', 'prediction_time', time()])
  485. ->andWhere(['>', 'end_time', time()])
  486. ->andWhere(['is_min_price' => StatusEnum::ENABLED, 'is_template' => 0])
  487. ->andWhere(['status' => StatusEnum::ENABLED])
  488. ->andWhere(['in', 'marketing_type', array_keys(MarketingEnum::getBackendSearchMap())]);
  489. }
  490. /**
  491. * 关联评价标签
  492. *
  493. * @return ActiveQuery
  494. */
  495. public function getEvaluateStat()
  496. {
  497. return $this->hasOne(EvaluateStat::class, ['product_id' => 'id']);
  498. }
  499. /**
  500. * 关联评价
  501. *
  502. * @return ActiveQuery
  503. */
  504. public function getEvaluate()
  505. {
  506. return $this->hasMany(Evaluate::class, ['product_id' => 'id'])
  507. ->limit(10)
  508. ->andWhere(['status' => StatusEnum::ENABLED])
  509. ->orderBy('id desc')
  510. ->asArray();
  511. }
  512. /**
  513. * 关联第一条评价
  514. *
  515. * @return ActiveQuery
  516. */
  517. public function getFirstEvaluate()
  518. {
  519. return $this->hasOne(Evaluate::class, ['product_id' => 'id'])
  520. ->select([
  521. 'id',
  522. 'product_id',
  523. 'sku_name',
  524. 'content',
  525. 'member_id',
  526. 'member_nickname',
  527. 'member_head_portrait',
  528. 'is_anonymous',
  529. 'scores',
  530. 'explain_type',
  531. 'created_at',
  532. ])
  533. ->andWhere([
  534. 'status' => StatusEnum::ENABLED,
  535. 'is_auto' => StatusEnum::DISABLED,
  536. 'scores' => 5
  537. ])
  538. ->orderBy('id desc');
  539. }
  540. /**
  541. * 关联参数
  542. *
  543. * @return ActiveQuery
  544. */
  545. public function getAttributeValue()
  546. {
  547. return $this->hasMany(AttributeValue::class, ['product_id' => 'id'])
  548. ->select(['product_id', 'title', 'data'])
  549. ->andWhere(['status' => StatusEnum::ENABLED])
  550. ->asArray();
  551. }
  552. /**
  553. * 阶梯优惠
  554. *
  555. * @return ActiveQuery
  556. */
  557. public function getLadderPreferential()
  558. {
  559. return $this->hasMany(LadderPreferential::class, ['product_id' => 'id'])->orderBy('quantity desc, id asc')->asArray();
  560. }
  561. /**
  562. * 我的收藏
  563. *
  564. * @return ActiveQuery
  565. */
  566. public function getMyCollect()
  567. {
  568. return $this->hasOne(Collect::class, ['topic_id' => 'id'])
  569. ->where(['topic_type' => CommonModelMapEnum::PRODUCT])
  570. ->andWhere(['status' => StatusEnum::ENABLED]);
  571. }
  572. /**
  573. * 我的购买总数量
  574. *
  575. * @return ActiveQuery
  576. */
  577. public function getMyGet()
  578. {
  579. return $this->hasOne(OrderProduct::class, ['product_id' => 'id'])
  580. ->select(['sum(num) as all_num', 'product_id'])
  581. ->where(['status' => StatusEnum::ENABLED])
  582. ->andWhere(['in', 'order_status', OrderStatusEnum::haveBought()])
  583. ->groupBy('product_id');
  584. }
  585. /**
  586. * @param bool $insert
  587. * @return bool
  588. */
  589. public function beforeSave($insert)
  590. {
  591. $this->production_date = StringHelper::dateToInt($this->production_date);
  592. $this->start_time = StringHelper::dateToInt($this->start_time);
  593. $this->end_time = StringHelper::dateToInt($this->end_time);
  594. empty($this->supplier_id) && $this->supplier_id = 0;
  595. empty($this->brand_id) && $this->brand_id = 0;
  596. empty($this->province_id) && $this->province_id = 0;
  597. empty($this->city_id) && $this->city_id = 0;
  598. empty($this->area_id) && $this->area_id = 0;
  599. // 让sku失效
  600. if (in_array($this->status, [StatusEnum::DELETE, StatusEnum::DISABLED]) || $this->audit_status == StatusEnum::DISABLED) {
  601. Yii::$app->tinyShopService->memberCartItem->loseByProductIds([$this->id]);
  602. // 下架产品
  603. // Yii::$app->tinyShopService->marketing->unShelveProduct([$this->id]);
  604. }
  605. return parent::beforeSave($insert);
  606. }
  607. /**
  608. * @param bool $insert
  609. * @param array $changedAttributes
  610. */
  611. public function afterSave($insert, $changedAttributes)
  612. {
  613. // 增加关联的评价统计
  614. if ($insert) {
  615. $stat = new EvaluateStat();
  616. $stat = $stat->loadDefaultValues();
  617. $stat->product_id = $this->id;
  618. $stat->save();
  619. }
  620. parent::afterSave($insert, $changedAttributes);
  621. }
  622. }
粤ICP备19079148号