2020-07-18 15:24:31 +00:00
< ? php
// +----------------------------------------------------------------------
// | ShopXO 国内领先企业级B2C免费开源电商系统
// +----------------------------------------------------------------------
2021-03-16 02:34:52 +00:00
// | Copyright (c) 2011~2099 http://shopxo.net All rights reserved.
2020-07-18 15:24:31 +00:00
// +----------------------------------------------------------------------
2021-03-16 02:34:52 +00:00
// | Licensed ( https://opensource.org/licenses/mit-license.php )
2020-07-18 15:24:31 +00:00
// +----------------------------------------------------------------------
// | Author: Devil
// +----------------------------------------------------------------------
namespace app\service ;
2021-07-18 15:42:10 +00:00
use think\facade\Db ;
2020-07-18 15:24:31 +00:00
use app\service\WarehouseService ;
2023-02-09 11:04:35 +00:00
use app\service\GoodsService ;
2020-07-18 15:24:31 +00:00
/**
* 订单拆分服务层
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2020 - 07 - 18
* @ desc description
*/
class OrderSplitService
{
/**
* 订单拆分入口
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2020 - 07 - 18
* @ desc description
* @ param [ array ] $params [ 输入参数 ]
*/
public static function Run ( $params = [])
{
// 请求参数
$p = [
[
'checked_type' => 'is_array' ,
'key_name' => 'goods' ,
2023-02-09 11:04:35 +00:00
'error_msg' => MyLang ( 'goods_empty_or_format_error_tips' ),
2020-07-18 15:24:31 +00:00
],
];
$ret = ParamsChecked ( $params , $p );
if ( $ret !== true )
{
return DataReturn ( $ret , - 1 );
}
// 商品仓库集合
2022-04-14 15:25:24 +00:00
$warehouse_goods = self :: GoodsWarehouseAggregate ( $params );
2025-03-03 09:49:22 +00:00
// 存在多个订单,但是订单模式非(快递、同城),则设置为快递模式
if ( count ( $warehouse_goods ) > 1 && ! in_array ( $params [ 'site_model' ], [ 0 , 1 ]))
2022-12-13 08:59:44 +00:00
{
$params [ 'site_model' ] = 0 ;
$params [ 'common_site_type' ] = 0 ;
}
2020-07-24 07:11:13 +00:00
// 分组商品基础处理
$data = self :: GroupGoodsBaseHandle ( $warehouse_goods , $params );
// 生成订单仓库分组商品数据处理钩子
$hook_name = 'plugins_service_buy_group_goods_handle' ;
2021-07-18 15:42:10 +00:00
$ret = EventReturnHandle ( MyEventTrigger ( $hook_name , [
2020-07-24 07:11:13 +00:00
'hook_name' => $hook_name ,
'is_backend' => true ,
'params' => $params ,
'data' => & $data ,
]));
if ( isset ( $ret [ 'code' ]) && $ret [ 'code' ] != 0 )
{
return $ret ;
}
// 根据扩展数据重新计算金额
if ( ! empty ( $data ))
{
foreach ( $data as & $v )
{
// 是否存在扩展数据
if ( ! empty ( $v [ 'order_base' ][ 'extension_data' ]))
{
// 扩展数据金额计算
$ext = self :: ExtensionDataPriceHandle ( $v [ 'order_base' ][ 'extension_data' ]);
// 增加/减少
2024-04-15 02:25:01 +00:00
$v [ 'order_base' ][ 'increase_price' ] = PriceBeautify ( PriceNumberFormat ( $v [ 'order_base' ][ 'increase_price' ] + $ext [ 'inc' ]));
$v [ 'order_base' ][ 'preferential_price' ] = PriceBeautify ( PriceNumberFormat ( $v [ 'order_base' ][ 'preferential_price' ] + $ext [ 'dec' ]));
2020-07-24 07:11:13 +00:00
// 实际金额/总额处理
2024-04-15 02:25:01 +00:00
$v [ 'order_base' ][ 'actual_price' ] = PriceBeautify ( PriceNumberFormat (( $v [ 'order_base' ][ 'actual_price' ] + $ext [ 'inc' ]) - $ext [ 'dec' ]));
$v [ 'order_base' ][ 'total_price' ] = PriceBeautify ( PriceNumberFormat ( $v [ 'order_base' ][ 'total_price' ]));
2020-07-24 07:11:13 +00:00
2020-12-25 06:53:40 +00:00
// 防止实际金额负数
if ( $v [ 'order_base' ][ 'actual_price' ] < 0 )
{
$v [ 'order_base' ][ 'actual_price' ] = 0 ;
}
2020-07-24 07:11:13 +00:00
}
}
}
// 返回数据
2023-01-19 09:44:03 +00:00
return DataReturn ( MyLang ( 'operate_success' ), 0 , $data );
2020-07-18 15:24:31 +00:00
}
2020-07-24 07:11:13 +00:00
/**
* 扩展数据解析金额
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2020 - 07 - 23
* @ desc description
* @ param [ array ] $data [ 扩展数据 ]
*/
public static function ExtensionDataPriceHandle ( $data )
{
$inc = 0 ;
$dec = 0 ;
if ( ! empty ( $data ))
{
if ( ! is_array ( $data ))
{
$data = json_decode ( $data , true );
}
foreach ( $data as $v )
{
if ( isset ( $v [ 'type' ]) && isset ( $v [ 'price' ]) && $v [ 'price' ] > 0 )
{
switch ( $v [ 'type' ])
{
// 减
case 0 :
$dec += $v [ 'price' ];
break ;
// 加
case 1 :
$inc += $v [ 'price' ];
break ;
}
}
}
}
return [
'inc' => $inc ,
'dec' => $dec ,
];
}
/**
* 分组商品基础处理
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2020 - 07 - 23
* @ desc description
* @ param [ array ] $data [ 分组商品 ]
* @ param [ array ] $params [ 输入参数 ]
*/
public static function GroupGoodsBaseHandle ( $data , $params )
{
if ( ! empty ( $data ))
{
foreach ( $data as & $v )
{
// 当前仓库的商品总价
$total_price = PriceNumberFormat ( array_sum ( array_column ( $v [ 'goods_items' ], 'total_price' )));
// 订单基础信息
$v [ 'order_base' ] = [
// 总价
2024-04-15 02:25:01 +00:00
'total_price' => PriceBeautify ( $total_price ),
2020-07-24 07:11:13 +00:00
// 订单实际支付金额(已减去优惠金额, 已加上增加金额)
2024-04-15 02:25:01 +00:00
'actual_price' => PriceBeautify ( $total_price ),
2020-07-24 07:11:13 +00:00
// 优惠金额
2024-04-15 02:25:01 +00:00
'preferential_price' => 0.00 ,
2020-07-24 07:11:13 +00:00
// 增加金额
2024-04-15 02:25:01 +00:00
'increase_price' => 0.00 ,
2020-07-24 07:11:13 +00:00
// 商品总数
2024-04-15 02:25:01 +00:00
'goods_count' => count ( $v [ 'goods_items' ]),
2020-07-24 07:11:13 +00:00
// 规格重量总计
2024-04-15 02:25:01 +00:00
'spec_weight_total' => array_sum ( array_map ( function ( $v ) { return $v [ 'spec_weight' ] * $v [ 'stock' ];}, $v [ 'goods_items' ])),
2022-07-17 14:27:23 +00:00
// 规格体积总计
2024-04-15 02:25:01 +00:00
'spec_volume_total' => array_sum ( array_map ( function ( $v ) { return $v [ 'spec_volume' ] * $v [ 'stock' ];}, $v [ 'goods_items' ])),
2020-07-24 07:11:13 +00:00
// 购买总数
2024-04-15 02:25:01 +00:00
'buy_count' => array_sum ( array_column ( $v [ 'goods_items' ], 'stock' )),
2020-07-24 07:11:13 +00:00
// 默认地址
2024-04-15 02:25:01 +00:00
'address' => $params [ 'address' ],
2020-07-24 07:11:13 +00:00
// 自提地址列表
2024-04-15 02:25:01 +00:00
'extraction_address' => $params [ 'extraction_address' ],
2020-07-24 07:11:13 +00:00
// 当前使用的站点模式
2024-04-15 02:25:01 +00:00
'site_model' => $params [ 'site_model' ],
2020-07-24 07:11:13 +00:00
// 公共站点模式
2024-04-15 02:25:01 +00:00
'common_site_type' => $params [ 'common_site_type' ],
// 商品售价是否展示
'goods_price_show_status' => ( array_sum ( array_filter ( array_column ( $v [ 'goods_items' ], 'show_field_price_status' ))) > 0 ) ? 1 : 0 ,
// 商品原价是否展示
'goods_original_price_show_status' => ( array_sum ( array_filter ( array_column ( $v [ 'goods_items' ], 'show_field_original_price_status' ))) > 0 ) ? 1 : 0 ,
2020-07-24 07:11:13 +00:00
// 仓库组扩展展示数据
// name 名称
// price 金额
// type 类型( 0减少, 1增加)
// tips 提示信息
// business 业务类型(内容格式不限)
// ext 扩展数据(内容格式不限)
// $extension_data = [
// [
// 'name' => '感恩节9折',
// 'price' => 23,
// 'type' => 0,
// 'tips' => '-¥23元',
// 'business' => null,
// 'ext' => null,
// ],
// ];
2024-04-15 02:25:01 +00:00
'extension_data' => [],
2020-07-24 07:11:13 +00:00
];
}
}
return $data ;
}
2020-07-18 15:24:31 +00:00
/**
* 商品仓库集合
* @ author Devil
* @ blog http :// gong . gg /
* @ version 1.0 . 0
* @ date 2020 - 07 - 18
* @ desc description
2022-04-14 15:25:24 +00:00
* @ param [ array ] $params [ 输入参数 ]
2020-07-18 15:24:31 +00:00
*/
2022-04-14 15:25:24 +00:00
public static function GoodsWarehouseAggregate ( $params )
2020-07-18 15:24:31 +00:00
{
2025-09-23 13:22:38 +00:00
// 仓库查询数据
$field = 'w.*,wgs.inventory' ;
$order_by = 'w.level desc,w.is_default desc,wgs.inventory desc' ;
// 订单地址坐标
$lng = '' ;
$lat = '' ;
if ( ! empty ( $params [ 'address' ]))
{
if ( isset ( $params [ 'address' ][ 'lng' ]) && $params [ 'address' ][ 'lng' ] != 0 && isset ( $params [ 'address' ][ 'lat' ]) && $params [ 'address' ][ 'lat' ] != 0 )
{
$lng = $params [ 'address' ][ 'lng' ];
$lat = $params [ 'address' ][ 'lat' ];
}
}
// 没有地址坐标泽取当前用户坐标
if ( empty ( $lng ) && empty ( $lat ))
{
// 当前坐标
$request_params = empty ( $params [ 'params' ]) ? [] : $params [ 'params' ];
$lng = empty ( $request_params [ 'lng' ]) ? ( empty ( $request_params [ 'user_lng' ]) ? '' : $request_params [ 'user_lng' ]) : $request_params [ 'lng' ];
$lat = empty ( $request_params [ 'lat' ]) ? ( empty ( $request_params [ 'user_lat' ]) ? '' : $request_params [ 'user_lat' ]) : $request_params [ 'lat' ];
}
// 加入坐标优先级
if ( ! empty ( $lng ) && ! empty ( $lat ))
{
$field .= ',ROUND(6378.138*2*ASIN(SQRT(POW(SIN((' . $lat . '*PI()/180-w.lat*PI()/180)/2),2)+COS(' . $lat . '*PI()/180)*COS(w.lat*PI()/180)*POW(SIN((' . $lng . '*PI()/180-w.lng*PI()/180)/2),2)))*1000) AS distance' ;
$order_by = 'distance asc, ' . $order_by ;
}
2020-12-23 09:32:10 +00:00
// 默认仓库
$warehouse_default = [];
2020-07-20 14:38:53 +00:00
// 数据分组
2020-07-18 15:24:31 +00:00
$result = [];
2022-04-14 15:25:24 +00:00
foreach ( $params [ 'goods' ] as $v )
2020-07-18 15:24:31 +00:00
{
// 不存在规格则使用默认
2023-02-09 11:04:35 +00:00
$spec = empty ( $v [ 'spec' ]) ? [[ 'type' => GoodsService :: GoodsSpecDefaultName (), 'value' => 'default' ]] : $v [ 'spec' ];
2020-07-18 15:24:31 +00:00
2023-09-10 12:13:30 +00:00
// 获取商品库存、仓库商品壳仓库商品规格都必须等于当前商品
2020-07-18 15:24:31 +00:00
$where = [
2020-12-23 09:32:10 +00:00
[ 'wgs.goods_id' , '=' , $v [ 'goods_id' ]],
[ 'wgs.md5_key' , '=' , md5 ( implode ( '' , array_column ( $spec , 'value' )))],
[ 'wgs.inventory' , '>' , 0 ],
2023-09-10 12:13:30 +00:00
[ 'wg.goods_id' , '=' , $v [ 'goods_id' ]],
2020-12-23 09:32:10 +00:00
[ 'wg.is_enable' , '=' , 1 ],
[ 'w.is_enable' , '=' , 1 ],
[ 'w.is_delete_time' , '=' , 0 ],
2020-07-18 15:24:31 +00:00
];
2025-09-23 13:22:38 +00:00
$warehouse = Db :: name ( 'WarehouseGoodsSpec' ) -> alias ( 'wgs' ) -> join ( 'warehouse_goods wg' , 'wgs.warehouse_id=wg.warehouse_id' ) -> join ( 'warehouse w' , 'wg.warehouse_id=w.id' ) -> where ( $where ) -> field ( $field ) -> order ( $order_by ) -> select () -> toArray ();
2020-07-18 15:24:31 +00:00
2022-04-14 15:25:24 +00:00
// 商品仓库分配仓库组合钩子
$hook_name = 'plugins_service_buy_group_goods_warehouse_handle' ;
MyEventTrigger ( $hook_name , [
'hook_name' => $hook_name ,
'is_backend' => true ,
'params' => $params ,
'spec' => $spec ,
'where' => $where ,
2025-09-23 13:22:38 +00:00
'goods' => $v ,
2022-04-14 15:25:24 +00:00
'data' => & $warehouse ,
]);
2020-07-18 15:24:31 +00:00
// 商品仓库分组
if ( ! empty ( $warehouse ))
{
foreach ( $warehouse as $w )
{
// 是否还存在未分配的数量
if ( $v [ 'stock' ] > 0 )
{
2020-07-19 14:40:12 +00:00
// 赋值数据
$temp_v = $v ;
// 购买数量计算
2020-12-23 09:32:10 +00:00
if ( $temp_v [ 'stock' ] > $w [ 'inventory' ] && $w [ 'inventory' ] > 0 )
2020-07-19 14:40:12 +00:00
{
$temp_v [ 'stock' ] = $w [ 'inventory' ];
}
// 总价计算
2025-04-25 12:21:19 +00:00
$temp_v [ 'total_price' ] = PriceBeautify ( PriceNumberFormat ( floatval ( $temp_v [ 'price' ]) * $temp_v [ 'stock' ]));
2020-07-19 14:40:12 +00:00
// 减除数量
2020-07-18 15:24:31 +00:00
$v [ 'stock' ] -= $w [ 'inventory' ];
// 是否第一次赋值
if ( ! array_key_exists ( $w [ 'id' ], $result ))
{
2020-07-19 14:40:12 +00:00
// 仓库
2025-04-25 12:21:19 +00:00
unset ( $w [ 'is_enable' ], $w [ 'is_delete_time' ], $w [ 'contacts_name' ], $w [ 'contacts_tel' ], $w [ 'add_time' ], $w [ 'upd_time' ]);
2022-08-02 09:23:10 +00:00
$warehouse_handle = WarehouseService :: WarehouseListHandle ([ $w ]);
2020-07-18 15:24:31 +00:00
$result [ $w [ 'id' ]] = $warehouse_handle [ 0 ];
$result [ $w [ 'id' ]][ 'goods_items' ] = [];
unset ( $result [ $w [ 'id' ]][ 'is_default' ], $result [ $w [ 'id' ]][ 'level' ], $result [ $w [ 'id' ]][ 'inventory' ]);
}
// 商品归属到仓库下
2020-07-19 14:40:12 +00:00
$result [ $w [ 'id' ]][ 'goods_items' ] = array_merge ( $result [ $w [ 'id' ]][ 'goods_items' ], [ $temp_v ]);
2020-07-18 15:24:31 +00:00
} else {
break ;
}
}
} else {
// 未获取到仓库则使用默认仓库
if ( empty ( $warehouse_default ))
{
2025-11-11 01:03:21 +00:00
// 先获取默认仓库
2020-07-18 15:24:31 +00:00
$warehouse_default = Db :: name ( 'Warehouse' ) -> where ([ 'is_default' => 1 , 'is_enable' => 1 , 'is_delete_time' => 0 ]) -> field ( 'id,name,alias,lng,lat,province,city,county,address' ) -> find ();
2025-11-11 01:03:21 +00:00
if ( empty ( $warehouse_default ))
{
// 没有默认仓库则获取最早的一个仓库
$warehouse_default = Db :: name ( 'Warehouse' ) -> where ([ 'is_enable' => 1 , 'is_delete_time' => 0 ]) -> field ( 'id,name,alias,lng,lat,province,city,county,address' ) -> order ( 'id asc' ) -> find ();
}
2020-07-18 15:24:31 +00:00
}
2025-09-23 13:22:38 +00:00
$temp_warehouse_default = $warehouse_default ;
2022-04-14 15:25:24 +00:00
// 商品仓库分配默认仓库组合钩子
$hook_name = 'plugins_service_buy_group_goods_default_warehouse_handle' ;
MyEventTrigger ( $hook_name , [
'hook_name' => $hook_name ,
'is_backend' => true ,
'params' => $params ,
2025-09-23 13:22:38 +00:00
'goods' => $v ,
'data' => & $temp_warehouse_default ,
2022-04-14 15:25:24 +00:00
]);
// 存在默认仓库则继续分配
2025-09-23 13:22:38 +00:00
if ( ! empty ( $temp_warehouse_default ))
2020-07-18 15:24:31 +00:00
{
2025-09-23 13:22:38 +00:00
if ( ! array_key_exists ( $temp_warehouse_default [ 'id' ], $result ))
2020-07-18 15:24:31 +00:00
{
2020-07-19 14:40:12 +00:00
// 仓库
2025-09-23 13:22:38 +00:00
$warehouse_handle = WarehouseService :: WarehouseListHandle ([ $temp_warehouse_default ]);
$result [ $temp_warehouse_default [ 'id' ]] = $warehouse_handle [ 0 ];
$result [ $temp_warehouse_default [ 'id' ]][ 'goods_items' ] = [];
2020-07-18 15:24:31 +00:00
}
// 商品归属到仓库下
2025-09-23 13:22:38 +00:00
$result [ $temp_warehouse_default [ 'id' ]][ 'goods_items' ][] = $v ;
2020-07-18 15:24:31 +00:00
}
}
}
return array_values ( $result );
}
}
?>