GoodsReserve.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <?php
  2. namespace common\models\goods;
  3. use common\enums\StatusEnum;
  4. use common\helpers\ArrayHelper;
  5. use common\models\common\Region;
  6. use Exception;
  7. use yii\helpers\Json;
  8. /**
  9. * 预约商品模型
  10. * This is the model class for table "{{%goods_reserve}}"
  11. * @property int int $id
  12. * @property int $mall_id 商城id
  13. * @property int $mch_id 商家id
  14. * @property int $goods_id 商品id
  15. * @property float $price 售价
  16. * @property float $original_price 原价(划线价仅展示)
  17. * @property float $cost_price 成本价
  18. * @property int $reserve_date_type 可预约时间类型(1范围 2自选日期)
  19. * @property string $reserve_date 可预约日期
  20. * @property int $reserve_time_range_type 预约模式(1按天预约 2按时间段预约)
  21. * @property int $time_slot_type 时间段划分方式(1自定义划分 2自动划分)
  22. * @property string $reserve_time_slot 时间段划分
  23. * @property int $reserve_price_type 价格设置方式(0统一售价 1按日期时间段设置)
  24. * @property int $reserve_time_slot_price 时间段价格设置
  25. * @property int $reserve_max_buy 每天最大预约数量
  26. * @property int $reserve_advance_hourse 提前预约时间(小时)
  27. * @property int $reserve_days_range 限制选择并购买的时间在设置内天数的商品
  28. * @property int $reserve_date_range 限制选择并购买N天以内的时间段
  29. * @property string $reserve_week 可预约周(逗号分隔)
  30. * @property int $cancel_type 取消类型(1不允许取消 2服务开始前取消 3订单类型取消)
  31. * @property string $cancel_rule 取消规则
  32. * @property int $expired_handle_type 预约码过期后处理方式(1不退款 2自动退款)
  33. * @property int $province_id 省ID
  34. * @property int $city_id 城市ID
  35. * @property int $district_id 区县ID
  36. * @property string $detail 详细地址
  37. * @property string $lat 纬度
  38. * @property string $lng 经度
  39. * @property int $created_at 创建时间
  40. * @property int $updated_at 修改时间
  41. * @property int $service_type 服务方式(1上门 2到店,3上门/到店)
  42. * @property int $reserve_type 0商品预约,1项目服务预约
  43. * @property int $service_min 0商品预约,1项目服务预约
  44. * @property string $ordering_information
  45. * @property string $information_detail
  46. * @property string $region_name
  47. * @property float $distance
  48. */
  49. class GoodsReserve extends \common\models\base\BaseActiveRecord
  50. {
  51. const RESERVE_TYPE_HOME_MARKING = 0; //项目预约
  52. const RESERVE_TYPE_SERVICE = 1; //技师预约
  53. const RESERVE_SERVICE_TO = 1;
  54. const RESERVE_SERVICE_FROM = 2;
  55. const RESERVE_SERVICE_ALL = 3;
  56. /**
  57. * {@inheritdoc}
  58. */
  59. public static function tableName()
  60. {
  61. return '{{%goods_reserve}}';
  62. }
  63. /**
  64. * {@inheritdoc}
  65. */
  66. public function rules()
  67. {
  68. return [
  69. [['mall_id', 'mch_id', 'goods_id', 'reserve_date_type', 'reserve_time_range_type', 'time_slot_type', 'reserve_price_type',
  70. 'reserve_max_buy', 'reserve_advance_hourse','reserve_days_range', 'cancel_type', 'expired_handle_type', 'province_id',
  71. 'city_id', 'district_id', 'created_at', 'updated_at', 'reserve_type', 'service_min'], 'integer'],
  72. [['price', 'original_price', 'cost_price', 'distance'], 'number'],
  73. [['reserve_date', 'reserve_time_slot', 'reserve_time_slot_price', 'reserve_week', 'cancel_rule', 'detail','region_name'], 'string'],
  74. [['information_detail'],'string'],
  75. [[ 'lat', 'lng','ordering_information'],'safe'],
  76. [['service_type'],'integer']
  77. ];
  78. }
  79. /**
  80. * {@inheritdoc}
  81. */
  82. public function attributeLabels()
  83. {
  84. return [
  85. 'id' => 'ID',
  86. 'mall_id' => '商城id',
  87. 'mch_id' => '商家id',
  88. 'goods_id' => '商品id',
  89. 'price' => '售价',
  90. 'original_price' => '原价(划线价仅展示)',
  91. 'cost_price' => '成本价',
  92. 'reserve_date_type' => '可预约时间类型(1范围 2自选日期)',
  93. 'reserve_week' => '可预约周',
  94. 'reserve_date' => '可预约日期',
  95. 'reserve_time_range_type' => '预约模式(1按天预约 2按时间段预约)',
  96. 'time_slot_type' => '时间段划分方式(1自定义划分 2自动划分)',
  97. 'reserve_time_slot' => '时间段划分',
  98. 'reserve_price_type' => '价格设置方式(0统一售价 1按日期时间段设置)',
  99. 'reserve_time_slot_price' => '时间段价格设置',
  100. 'reserve_max_buy' => '每天最大预约数量',
  101. 'reserve_advance_hourse' => '提前预约时间(小时)',
  102. 'reserve_days_range' => '限制选择并购买的时间在设置内天数的商品',
  103. 'cancel_type' => '取消类型',
  104. 'cancel_rule' => '取消规则',
  105. 'expired_handle_type' => '预约码过期后处理方式',
  106. "province_id" => "省ID",
  107. "city_id" => "城市ID",
  108. "district_id" => "区县ID",
  109. "detail" => "详细地址",
  110. "lat" => "纬度",
  111. "lng" => "经度",
  112. "region_name" => '地区字符串',
  113. 'created_at' => '创建时间',
  114. 'updated_at' => '修改时间',
  115. ];
  116. }
  117. public function getSkus()
  118. {
  119. return $this->hasMany(GoodsReserveSku::class, ['goods_id' => 'goods_id']);
  120. }
  121. public function getGoods()
  122. {
  123. return $this->hasOne(Goods::class, ['id' => 'goods_id']);
  124. }
  125. // 预约商品
  126. public static function setData(&$goods, $params)
  127. {
  128. try {
  129. $model = self::findOne(['goods_id' => $goods['id']]);
  130. if (empty($model)) {
  131. $model = new self();
  132. $model->loadDefaultValues();
  133. }
  134. $goodsAttributes = [
  135. 'mall_id' => $goods['mall_id'],
  136. 'mch_id' => $goods['mch_id'],
  137. 'goods_id' => $goods['id'],
  138. 'price' => $goods['price'] ?? min(array_column($params['skus'], "price")),
  139. 'original_price' => $goods['original_price'] ?? min(array_column($params['skus'], "original_price")),
  140. 'cost_price' => $goods['cost_price'] ?? min(array_column($params['skus'], !empty($params['skus'][0]["cost_price"]) ? "cost_price" : "price")),
  141. ];
  142. $params['information_detail'] = $params['information_detail'] ?? '';
  143. $params['ordering_information'] = $params['ordering_information'] ?? '';
  144. $params['ordering_information'] = (string)$params['ordering_information'];
  145. $params['district_id'] = empty($params['district_id']) ? 0 : intval($params['district_id']);
  146. $params['province_id'] = empty($params['province_id']) ? 0 : intval($params['province_id']);
  147. $params['city_id'] = empty($params['city_id']) ? 0 : intval($params['city_id']);
  148. $params['reserve_advance_hourse'] = empty($params['reserve_advance_hourse']) ? 0 : intval($params['reserve_advance_hourse']);
  149. $params['distance'] = empty($params['distance']) ? 0 : intval($params['distance']);
  150. $params['service_min'] = empty($params['service_min']) ? 0 : intval($params['service_min']);
  151. if (!empty($params['province_id'])) {
  152. $params['region_name'] = implode(" ", Region::find()
  153. ->where(['id' => [$params['province_id'], $params['city_id'], $params['district_id']]])
  154. ->orderBy('id asc')->select('name')->column());
  155. }
  156. if (empty($goods['is_attr'])) { // 如果
  157. $params['price'] = $goods['price'] ?? $goodsAttributes['price'];
  158. }
  159. $attributes = array_merge($goodsAttributes, $params);
  160. is_array($attributes['reserve_week']) && $attributes['reserve_week'] = implode(',',$attributes['reserve_week']);
  161. is_array($attributes['reserve_date']) && $attributes['reserve_date'] = json_encode($attributes['reserve_date'],JSON_UNESCAPED_SLASHES);
  162. is_array($attributes['reserve_time_slot']) && $attributes['reserve_time_slot'] = json_encode($attributes['reserve_time_slot'],JSON_UNESCAPED_SLASHES);
  163. is_array($attributes['reserve_time_slot_price']) && $attributes['reserve_time_slot_price'] = json_encode($attributes['reserve_time_slot_price'],JSON_UNESCAPED_SLASHES);
  164. if(empty($attributes['cancel_rule']['cancel_hour'])){
  165. $attributes['cancel_rule']['cancel_hour'] = 0;
  166. }
  167. if(empty($attributes['cancel_rule']['cancel_fee_percent'])){
  168. $attributes['cancel_rule']['cancel_fee_percent'] = 0;
  169. }
  170. is_array($attributes['cancel_rule']) && $attributes['cancel_rule'] = json_encode($attributes['cancel_rule'],JSON_UNESCAPED_SLASHES);
  171. if (!empty($attributes['reserve_type'])) { // 项目服务人预约
  172. $attributes['service_type'] = StatusEnum::ENABLED; // 项目服务人预约只能上门服务
  173. }
  174. //($attributes['service_type'] ?? false) && $attributes['service_type'] = json_encode($attributes['service_type'],JSON_UNESCAPED_SLASHES);
  175. if (!$model->load($attributes, '') || !$model->save()) {
  176. throw new Exception($model->getErrorMessage());
  177. }
  178. // 处理预约商品规格
  179. $reserveGoods = ArrayHelper::toArray($model);
  180. if($goods['is_attr'] == 1){
  181. // 多规格预约商品
  182. $skus = $params['skus'];
  183. // 因为预约商品按天设置时商品售价存储位置不同,所以需要单独处理
  184. $is_day = true;
  185. $timeSlotPriceList = [];
  186. foreach ($skus as $item) {
  187. if ($item['reserve_price_type'] == 2 || $item['reserve_price_type'] == 1) {
  188. $timeSlotPriceList = array_merge($timeSlotPriceList, array_values($item['reserve_time_slot_price']));
  189. } else {
  190. $is_day = false;
  191. }
  192. }
  193. if (!empty($timeSlotPriceList) && $is_day) {
  194. $timeSkusGoods = array_column($timeSlotPriceList, 'price');
  195. $timeMinSkusGoods = array_search(min($timeSkusGoods), $timeSkusGoods);
  196. $timeSlotPriceList = $timeSlotPriceList[$timeMinSkusGoods] ?? [];
  197. }
  198. $skusGoods = array_column($skus, 'price');
  199. $minSkusGoods = array_search(min($skusGoods), $skusGoods);
  200. $reserveSkusGoods = $skus[$minSkusGoods] ?? [];
  201. $goodsModel = Goods::findOne($goods['id']);
  202. if (!empty($goodsModel)) { // 赋值给主商品对应的商品
  203. if ($is_day) {
  204. $goodsModel->price = $timeSlotPriceList['price'] ?? 0;
  205. $goodsModel->original_price = $timeSlotPriceList['original_price'] ?? 0;
  206. } else {
  207. $goodsModel->price = $reserveSkusGoods['price'] ?? 0;
  208. $goodsModel->original_price = $reserveSkusGoods['original_price'] ?? 0;
  209. }
  210. $goodsModel->save();
  211. }
  212. $res = GoodsReserveSku::setSkus($goods, $skus, $model);
  213. }else{
  214. $reserveGoods['service_min'] = $params['service_min'];
  215. $reserveGoods['unit'] = $goods['unit'] ?? '';
  216. is_array($reserveGoods['reserve_time_slot_price']) && $reserveGoods['reserve_time_slot_price'] =
  217. Json::encode($reserveGoods['reserve_time_slot_price']);
  218. $reserveGoods['price'] = $goodsAttributes['price'];
  219. $reserveGoods['name'] = '';
  220. $res = GoodsReserveSku::setSku($reserveGoods);
  221. }
  222. if($res === false) throw new Exception('处理预约商品规格出现异常,msg:'.GoodsReserveSku::getStaticError());
  223. return $model;
  224. } catch (Exception $e) {
  225. if (isset($trans)) $trans->rollback();
  226. self::$static_error = $e->getMessage();
  227. return false;
  228. }
  229. }
  230. }