LocalDeliveryFreight.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <?php
  2. /**
  3. * 厦门云联储网络科技有限公司
  4. * https://www.baokuaiyun.com
  5. * Copyright (c) 2023 爆块云 All rights reserved.
  6. */
  7. namespace app\models;
  8. use Yii;
  9. use yii\helpers\Json;
  10. use yii\db\ActiveRecord;
  11. use yii\behaviors\TimestampBehavior;
  12. /**
  13. * This is the model class for table "{{%local_delivery_freight}}".
  14. *
  15. * @property integer $is_enable
  16. * @property integer $level
  17. * @property string $name
  18. * @property string $detail
  19. * @property string $begin_time
  20. * @property string $end_time
  21. * @property integer $created_at
  22. * @property integer $updated_at
  23. * @property integer $is_delete
  24. * @property integer $day
  25. * @property integer $price_type
  26. * @property integer $order_price_type
  27. * @property integer $is_scan
  28. */
  29. class LocalDeliveryFreight extends \yii\db\ActiveRecord
  30. {
  31. const IS_DELETE_YES = 1;//已删除
  32. const IS_DELETE_NO = 0;//未删除
  33. const IS_ENABLE_YES = 1;//启用
  34. const IS_ENABLE_NO = 0;//关闭
  35. const TYPE_LOCAL = 0;//平台自配
  36. const TYPE_MAIYATIAN = 1;//麦芽田
  37. const TYPE_STORE_LOCAL = 2;//商城自配
  38. const PRICE_TYPE_ORDER = 1;//计价规则-按订单
  39. const PRICE_TYPE_DISTANCE = 0;//计价规则-按距离
  40. const ORDER_PRICE_TYPE_ORDER = 1;//订单计价规则-百分比
  41. const ORDER_PRICE_TYPE_DISTANCE = 0;//订单计价规则-金额
  42. const IS_SCAN_YES = 1;//扫码抢单规则
  43. const IS_SCAN_NO = 0;//非扫码抢单规则
  44. /**
  45. * @inheritdoc
  46. */
  47. public static function tableName()
  48. {
  49. return '{{%local_delivery_freight}}';
  50. }
  51. public function behaviors()
  52. {
  53. return [
  54. [
  55. 'class' => TimestampBehavior::class,
  56. 'attributes' => [
  57. ActiveRecord::EVENT_BEFORE_INSERT => ['updated_at', 'created_at'],
  58. ActiveRecord::EVENT_BEFORE_UPDATE => 'updated_at'
  59. ]
  60. ]
  61. ];
  62. }
  63. /**
  64. * @inheritdoc
  65. */
  66. public function rules()
  67. {
  68. return [
  69. [['is_enable', 'level', 'is_delete', 'day', 'type', 'store_id', 'price_type', 'order_price_type', 'is_scan'], 'integer'],
  70. [['name'], 'string', 'max' => 255],
  71. [['detail', 'begin_time','end_time'], 'string'],
  72. ];
  73. }
  74. /**
  75. * @inheritdoc
  76. */
  77. public function attributeLabels()
  78. {
  79. return [
  80. 'id' => 'ID',
  81. 'is_enable' => '是否启用:0=否,1=是',
  82. 'type' => '配送方式;0:平台自配 1:麦芽田',
  83. 'level' => '规则优先级,值越大优先级越高',
  84. 'name' => '名称',
  85. 'detail' => '规则详细',
  86. 'begin_time' => '开始时间段',
  87. 'end_time' => '结束时间段',
  88. 'created_at' => '创建时间',
  89. 'updated_at' => '最后一次修改时间',
  90. 'is_delete' => '是否删除:0=否;1=是;',
  91. 'day' => '可预约天数',
  92. 'price_type' => '计价规则 1 = 按订单 0 = 按距离',
  93. 'order_price_type' => '订单计价规则 1百分比 0金额',
  94. 'is_scan' => '是否为扫码抢单规则'
  95. ];
  96. }
  97. //$is_front_delivery 仓库配送单
  98. public static function getFreight($store_id, $address, $delivery_time, $type = 0, $goods_list = [], $is_scan = LocalDeliveryFreight::IS_SCAN_NO, $is_front_delivery = DeliveryInfo::IS_FRONT_DELIVERY_NO, $front_agent_admin_id = 0) {
  99. $store = Store::findOne($store_id);
  100. $latitude = $store->latitude;
  101. $longitude = $store->longitude;
  102. //取货地址
  103. if ($is_front_delivery) {
  104. $front_agent = Admin::findOne($front_agent_admin_id);
  105. $latitude = $front_agent->lat ?: 0;
  106. $longitude = $front_agent->lng ?: 0;
  107. }
  108. //收货地址
  109. if(!is_object($address)){
  110. $address = (object)($address);
  111. }
  112. //距离(单位:km)
  113. $distance_str = \app\utils\Tools::getDistance($latitude, $longitude, $address->latitude, $address->longitude);
  114. if (strpos($distance_str, 'km') !== false) {
  115. // 如果包含 'km' 则将字符串转换为浮点数并乘以 1000
  116. $distance = (float) str_replace('km', '', $distance_str) * 1000;
  117. } elseif (strpos($distance_str, 'm') !== false) {
  118. // 如果包含 'm' 则将字符串转换为整数
  119. $distance = (int) str_replace('m', '', $distance_str);
  120. }
  121. $distance = bcdiv($distance,1000,2);
  122. //配送时间戳
  123. $delivery_time_stamp = strtotime($delivery_time) ?: time();
  124. //获取同城配送的计价规则
  125. // 构建查询对象
  126. $query = LocalDeliveryFreight::find()
  127. ->where(['is_enable' => 1, 'is_delete' => 0])
  128. ->orderBy(['level' => SORT_DESC]);
  129. if(in_array($type, [self::TYPE_MAIYATIAN, self::TYPE_STORE_LOCAL])){
  130. $query->andWhere(['store_id' => $store_id]);
  131. }
  132. if(in_array($type, [self::TYPE_LOCAL, self::TYPE_STORE_LOCAL])){
  133. $query->andWhere(['type' => self::TYPE_LOCAL]);
  134. }
  135. if($type == self::TYPE_LOCAL){
  136. $query->andWhere(['store_id' => 0]);
  137. }
  138. if($type == self::TYPE_MAIYATIAN){
  139. $query->andWhere(['type' => self::TYPE_MAIYATIAN]);
  140. }
  141. if ($is_scan == self::IS_SCAN_YES) {
  142. $query->andWhere(['is_scan' => self::IS_SCAN_YES]);
  143. }
  144. // 获取所有数据
  145. $data = $query->asArray()->all();
  146. // 过滤出符合条件的数据
  147. $filteredData = [];
  148. foreach ($data as $item) {
  149. $hour = strtotime(date('H:i',$delivery_time_stamp));//实际
  150. $beginTime = strtotime($item['begin_time']);//开始
  151. $endTime = strtotime($item['end_time']);//结束
  152. if ($beginTime <= $endTime) {
  153. // 普通时间段,直接判断时间是否在范围内
  154. if ($hour >= $beginTime && $hour <= $endTime) {
  155. $filteredData[] = $item;
  156. break;
  157. }
  158. } else {
  159. // 跨越日期的时间段,第一个条件范围是当日的开始时间和次日的结束时间例如:当日23:00至次日5:00,第二个条件为次日的开始时间例如:次日23:00,$delivery_time_stamp的取值范围为当前时间到次日的24点,所以要考虑次日的开始时间。
  160. if (($delivery_time_stamp >= $beginTime && $delivery_time_stamp <= $endTime+86400) || $delivery_time_stamp >= $beginTime+86400) {
  161. $filteredData[] = $item;
  162. break;
  163. }
  164. }
  165. }
  166. // 获取最终结果(根据需求自行处理)
  167. if (!empty($filteredData)) {
  168. $result = $filteredData[0]; // 这里只取第一条符合条件的数据作为示例
  169. $freight_detail = json_decode($result['detail'],true)[0];
  170. //配送费计算
  171. $freight = 0;
  172. if (intval($result['price_type'])) {
  173. $total_price = 0;
  174. foreach ($goods_list as $goods) {
  175. $total_price += ($goods['price']);//$goods['num'] *
  176. }
  177. if (intval($result['order_price_type'])) {
  178. $freight = sprintf('%.2f', ($total_price * ($freight_detail['distance_price'] / 100)));
  179. } else {
  180. $freight = $freight_detail['distance_price'];
  181. }
  182. } else {
  183. if($distance <= $freight_detail['distance']) {
  184. $freight = $freight_detail['distance_price'];
  185. } else {
  186. $freight = bcadd($freight_detail['distance_price'],bcmul(ceil(bcdiv(bcsub($distance,$freight_detail['distance'],2),$freight_detail['second'],2)),$freight_detail['second_price'],2),2);
  187. }
  188. }
  189. }else{
  190. $freight = 100;
  191. return [
  192. 'code' => 1,
  193. 'msg' => '配送计价规则匹配错误,请稍后重试',
  194. ];
  195. }
  196. return [
  197. 'code' => 0,
  198. 'data' => (float)$freight,
  199. 'info' => [
  200. 'resultcode' => 0,
  201. 'address' => $address,
  202. 'store' => $store,
  203. 'distance' => $distance,
  204. 'delivery_time' => $delivery_time,
  205. 'delivery_time_stamp' => $delivery_time_stamp,
  206. 'LocalDeliveryFreight' => $result,
  207. 'freight_detail' => $freight_detail,
  208. 'fee' => (float)$freight,
  209. 'endTime' => $endTime
  210. ],
  211. ];
  212. }
  213. }