Files
ZangShiQi/app/model/order/ordercreate/DeliveryTool.php
2026-04-04 17:27:12 +08:00

444 lines
20 KiB
PHP
Executable File

<?php
/**
* Niushop商城系统 - 团队十年电商经验汇集巨献!
* =========================================================
* Copy right 2019-2029 上海牛之云网络科技有限公司, 保留所有权利。
* ----------------------------------------------
* 官方网址: https://www.niushop.com
* =========================================================
*/
namespace app\model\order\ordercreate;
use app\model\express\Express;
use app\model\express\Local;
use app\model\store\Store;
/**
* 订单创建 可调用的工具类
*/
trait DeliveryTool
{
/**
* 获取配送配置数据
* @return true
*/
public function getDeliveryData()
{
$curr_store_id = $this->param['store_id'] ?? 0;
$jielong_id = $this->param['jielong_id'] ?? 0;
$express_type = [];
if ($this->is_virtual == 0) {
//todo 没有活动才会参与计算
if (empty($this->promotion_type)) $trade_result = event('OrderCreateCommonData', ['type' => 'trade', 'order_object' => $this], true);
if (!empty($trade_result)) {
if ($trade_result['code'] >= 0) {
$express_type = $trade_result['data'];
}
} else {
$deliver_type_sort = $this->config('delivery_type_sort');
$deliver_sort_list = explode(',', $deliver_type_sort['value']['deliver_type']);
//根据当前的定位查询本地配送门店或自提门店
$latitude = $this->param['latitude'] ?? 0;
$longitude = $this->param['longitude'] ?? 0;
foreach ($deliver_sort_list as $type) {
// 物流
if ($type == 'express') {
$express_config = $this->config('express');
if ($express_config['is_use'] == 1) {
$title = $express_config['value']['express_name'];
if ($title == '') {
$title = Express::express_type['express']['title'];
}
$express_type[] = ['title' => $title, 'name' => 'express'];
}
}
// 自提
if ($type == 'store') {
$store_config = $this->config('store');
if ($store_config['is_use'] == 1) {
//根据坐标查询门店
$store_model = new Store();
$store_condition = [
['site_id', '=', $this->site_id],
//['is_pickup', '=', 1],
//['status', '=', 1],
['', 'exp', \think\facade\Db::raw('(is_pickup = 1 && status = 1) or store_id = '.$curr_store_id)],
['is_frozen', '=', 0],
];
//考虑门店库存和上下架,进一步过滤可以选择的门店
$this->getAvailableStoreIds();
if($this->available_store_ids != 'all'){
$store_condition[] = ['store_id', 'in', $this->available_store_ids];
}
$latlng = [
'lat' => $latitude,
'lng' => $longitude,
];
$store_list = $store_model->getLocationStoreList($store_condition, '*', $latlng)['data'] ?? [];
$store_list = $this->currStoreToFirstData($store_list);
$title = $store_config['value']['store_name'];
if ($title == '') {
$title = Express::express_type['store']['title'];
}
$express_type[] = ['title' => $title, 'name' => 'store', 'store_list' => $store_list];
}
}
// 外卖
if ($type == 'local') {
$local_config = $this->config('local');
if ($local_config['is_use'] == 1) {
//查询本店的通讯地址
$title = $local_config['value']['local_name'];
if ($title == '') {
$title = '外卖配送';
}
$store_model = new Store();
$store_condition = [
['site_id', '=', $this->site_id],
];
if (addon_is_exit('store', $this->site_id)) {
//$store_condition[] = ['is_o2o', '=', 1];
//$store_condition[] = ['status', '=', 1];
$store_condition[] = ['', 'exp', \think\facade\Db::raw('(is_o2o = 1 && status = 1) or store_id = '.$curr_store_id)];
$store_condition[] = ['is_frozen', '=', 0];
} else {
$store_condition[] = ['is_default', '=', 1];
}
//考虑门店库存和上下架,进一步过滤可以选择的门店
$this->getAvailableStoreIds();
if($this->available_store_ids != 'all'){
$store_condition[] = ['store_id', 'in', $this->available_store_ids];
}
$latlng = [
'lat' => $latitude,
'lng' => $longitude,
];
$store_list_result = $store_model->getLocationStoreList($store_condition, '*', $latlng);
$store_list = $store_list_result['data'];
$store_list = $this->currStoreToFirstData($store_list);
$express_type[] = ['title' => $title, 'name' => 'local', 'store_list' => $store_list];
}
}
}
}
}
if(!empty($jielong_id)){
//社群接龙只保留门店自提
foreach ($express_type as $key => $value){
if($value['name'] != 'store'){
unset($express_type[$key]);
continue;
}
$store_list = $value['store_list'] ?? [];
if(empty($store_list)){
$this->setError(1, '没有可以自提的门店!');
}
}
$this->jielong_info = model('promotion_jielong')->getInfo([ [ 'jielong_id', '=', $jielong_id ] ], '*');
$express_type = array_values($express_type);
}
$this->delivery['express_type'] = $express_type;
return true;
}
/**
* 配送计算
* @return true
*/
public function calculateDelivery()
{
//整理配送时间格式
$this->getDeliveryTime();
//计算邮费
if ($this->is_virtual == 1) {
//虚拟订单 运费为0
$delivery_money = 0;
$this->delivery['delivery_type'] = '';
} else {
$deliver_type_sort = $this->config('delivery_type_sort');
$deliver_sort_list = explode(',', $deliver_type_sort['value']['deliver_type']);
//查询店铺是否开启快递配送
$express_config = $this->config('express');
//查询店铺是否开启门店自提
$store_config = $this->config('store');
//查询店铺是否开启外卖配送
$local_config = $this->config('local');
//todo 没有活动才会参与计算
if (empty($this->promotion_type)) {
$trade_calc_result = event('OrderCreateCommonData', ['type' => 'trade_calc', 'order_object' => $this, 'deliver_sort_list' => $deliver_sort_list], true);
}
if (empty($trade_calc_result)) {
//如果本地配送开启, 则查询出本地配送的配置
if ($local_config['is_use'] == 1 && isset($this->param['delivery']['store_id'])) {
$local_model = new Local();
$local_info = $local_model->getLocalInfo([['site_id', '=', $this->site_id], ['store_id', '=', $this->param['delivery']['store_id']]])['data'];
$this->delivery['local']['info'] = $local_info;
} else {
$this->delivery['local']['info'] = [];
}
$delivery_array = $this->param['delivery'] ?? [];
$delivery_type = $delivery_array['delivery_type'] ?? 'express';
if ($delivery_type == 'store') {
//门店自提
$delivery_money = 0;
$this->delivery['delivery_type'] = 'store';
if ($store_config['is_use'] == 0) {
$this->setError(1, '门店自提方式未开启!');
}
if (empty($this->param['delivery']['store_id'])) {
$this->setError(1, '门店未选择!');
}
$this->delivery['store_id'] = $this->param['delivery']['store_id'] ?? 0;
$this->storeOrderData();
$this->store_id = $this->param['delivery']['store_id'] ?? 0;
} else {
if (empty($this->delivery['member_address'])) {
$delivery_money = 0;
$this->delivery['delivery_type'] = 'express';
$this->setError(1, '未配置默认收货地址!');
} else {
if ($delivery_type == 'express') {
if ($express_config['is_use'] == 1) {
//物流配送
$express = new Express();
$express_fee_result = $express->calculate(['order_object' => $this]);
if ($express_fee_result['code'] < 0) {
$this->setError(1, $express_fee_result['message']);
$delivery_fee = 0;
} else {
$delivery_fee = $express_fee_result['data']['delivery_fee'];
}
} else {
$this->setError(1, '物流配送方式未开启!');
$delivery_fee = 0;
}
$this->delivery_money = $delivery_fee;
$this->delivery['delivery_type'] = 'express';
} else if ($delivery_type == 'local') {
//外卖配送
$delivery_money = 0;
$this->delivery['delivery_type'] = 'local';
if ($local_config['is_use'] == 0) {
$this->setError(1, '外卖配送方式未开启!');
} else {
if (empty($this->param['delivery']['store_id'])) {
$this->setError(1, '门店未选择!');
}
$this->store_id = $this->param['delivery']['store_id'] ?? 0;
$local_model = new Local();
$local_result = $local_model->calculate(['order_object' => $this]);
$this->delivery['start_money'] = 0;
if ($local_result['code'] < 0) {
$this->delivery['start_money'] = $local_result['data']['start_money_array'][0] ?? 0;
$this->setError($local_result['data']['code'], $local_result['message'], 1);
} else {
$this->delivery_money = $local_result['data']['delivery_money'];
if (!empty($local_result['data']['code'])) {
$this->setError($local_result['data']['code'], $local_result['data']['error'], 1);
}
}
$this->delivery['error'] = $this->error;
$this->delivery['error_msg'] = $this->error_msg;
}
}
}
}
}
//检测门店是否可用
if($this->available_store_ids != 'all' && !empty($this->store_id)){
$available_store_ids = $this->available_store_ids ? explode(',', trim($this->available_store_ids, ',')) : [];
if(!in_array($this->store_id,$available_store_ids)){
$this->setError(1, '所选门店不可用!');
}
}
//是否符合免邮
if ($this->is_free_delivery) {
$this->delivery_money = 0;
}
//重新计算订单总额
$this->getOrderMoney();
}
return true;
}
/**
* 校验商品项的配送方式支持方式
* @param $goods
* @return true
*/
public function checkDeliveryType($goods)
{
$delivery_type = $this->param['delivery']['delivery_type'] ?? '';
if ($delivery_type && strpos($goods['support_trade_type'], $delivery_type) === false) {
$express_type_list = $this->config('delivery_type');
$delivery_type_name = $express_type_list[$delivery_type] ?? '';
$this->error = 1;
$this->error_msg = '有商品不支持' . $delivery_type_name;
}
return true;
}
/**
* 批量校验配送方式
* @return true
*/
public function batchCheckDeliveryType()
{
$delivery_type = $this->param['delivery']['delivery_type'] ?? '';
if (!$this->is_virtual) {
if (!$delivery_type) {
$this->error = 1;
$this->error_msg = '请选择有效的配送方式';
} else {
$express_type_list = $this->config('delivery_type');
$delivery_type_name = $express_type_list[$delivery_type] ?? '';
foreach ($this->goods_list as $v) {
if (strpos($v['support_trade_type'], $delivery_type) === false) {
$this->error = 1;
//$this->error_msg = '商品' . $v['goods_name'] . '不支持' . $delivery_type_name;
$this->error_msg = '部分商品不支持' . $delivery_type_name;
}
}
}
}
return true;
}
/**
* 获取配送时间格式
* @return true
*/
public function getDeliveryTime(){
$delivery_time = $this->param['delivery']['buyer_ask_delivery_time'] ?? [];
$remark = '';
$start_date = $delivery_time['start_date'] ?? '';
$end_date = $delivery_time['end_date'] ?? '';
if($start_date && $end_date){
$start_time = strtotime($start_date);
$end_time = strtotime($end_date);
$start_ymd = date('Y-m-d', $start_time);
$end_ymd = date('Y-m-d', $end_time);
if($start_ymd == $end_ymd){
$remark = $start_ymd.' '.date('H:i:s', $start_time).' ~ '.date('H:i:s', $end_time);
}else{
$remark = $start_date .' ~ '. $end_date;
}
}else if($start_date && !$end_date){
$remark = $start_date;
$start_time = strtotime($start_date);
}else if(!$start_date && $end_date){
$remark = $end_date;
$end_time = strtotime($end_date);
}
if(!empty($this->jielong_id)){
$jielong_info = model('promotion_jielong')->getInfo([ [ 'jielong_id', '=', $this->jielong_id ] ], '*');
if(!empty($jielong_info)){
$start_time = $jielong_info['take_start_time'];
$start_date = date("Y-m-d",$jielong_info['take_start_time']);
$end_time = $jielong_info['take_end_time'];
$end_date = date("Y-m-d",$jielong_info['take_end_time']);
$remark = $start_date.' ~ '.$end_date;
}
}
$this->delivery['buyer_ask_delivery_time'] = [
'start_date' => $start_date,
'start_time' => $start_time ?? '',
'end_date' => $end_date,
'end_time' => $end_time ?? '',
'remark' => $remark
];
return true;
}
/**
* 获取可以购买的门店数据
* @return int[]|string[]
*/
protected function getAvailableStoreIds()
{
if(addon_is_exit('store')){
//要注意是独立库存还是总部库存
$alias = 'sgs';
$join = [
['store s', 'sgs.store_id = s.store_id', 'inner'],
['goods_sku gs', 'sgs.sku_id = gs.sku_id', 'inner'],
];
$condition = [
['sgs.sku_id', 'in', array_column($this->goods_list, 'sku_id')],
['sgs.status', '=', 1],
];
if($this->available_store_ids != 'all'){
$condition[] = ['sgs.store_id', 'in', $this->available_store_ids];
}
$field = "sgs.sku_id,sgs.store_id,IF(s.stock_type = 'store', sgs.stock, gs.stock) as stock";
$store_sku_list = model('store_goods_sku')->getList($condition, $field, '', $alias, $join);
$store_id_data = [];
$sku_num_data = array_column($this->goods_list, 'num','sku_id');
$goods_model = new \app\model\goods\Goods();
foreach($store_sku_list as $store_sku_info){
//如果库存不足尝试库存转换
if($store_sku_info['stock'] < $sku_num_data[$store_sku_info['sku_id']]){
$store_sku_info = $goods_model->goodsStockTransform([$store_sku_info], $store_sku_info['store_id'], 'store')[0];
}
if($store_sku_info['stock'] >= $sku_num_data[$store_sku_info['sku_id']]){
$store_id_data[$store_sku_info['store_id']][$store_sku_info['sku_id']] = $store_sku_info['sku_id'];
}
}
foreach($store_id_data as $store_id=>$data){
if(count($data) < count($sku_num_data)){
unset($store_id_data[$store_id]);
}
}
$this->available_store_ids = array_keys($store_id_data);
$curr_store_id = $this->param['store_id'] ?? 0;
if(!in_array($curr_store_id, $this->available_store_ids)){
$this->available_store_ids[] = $curr_store_id;
}
}
}
/**
* 当前门店排到首位
* @param $store_list
* @return array
*/
protected function currStoreToFirstData($store_list)
{
$curr_store_id = $this->param['store_id'] ?? 0;
$curr_store = null;
foreach($store_list as $key=>$store_info){
if($store_info['store_id'] == $curr_store_id){
$curr_store = $store_info;
unset($store_list[$key]);
}
}
if(!is_null($curr_store)){
array_unshift($store_list, $curr_store);
}
return array_values($store_list);
}
}