| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- <?php
- namespace addons\StarChain\common\services;
- use addons\StarChain\common\enums\ShippingTypeEnum;
- use addons\StarChain\common\enums\StarChainEnum;
- use addons\StarChain\common\helpers\ArrayHelper;
- use addons\StarChain\common\models\Goods;
- use addons\StarChain\common\models\GoodsAttr;
- use addons\StarChain\common\models\MallOrder;
- use addons\StarChain\common\models\Order;
- use addons\StarChain\common\models\Region;
- use common\enums\StatusEnum;
- use common\logic\order\BaseOrderForm;
- use common\models\user\UserAddress;
- use Exception;
- use Yii;
- use yii\helpers\Json;
- /**
- * 供应链订单相关服务
- */
- class ChainOrderService extends BaseService
- {
- /**
- * 下单前检测
- *
- * @param BaseOrderForm $form 商城订单数据
- * @param boolean $is_new_record
- * @return array
- */
- public function createBeforeCheck($form, $is_new_record = false)
- {
- // 获取购买的AttrId
- $order_goods = $form->order_goods;
- $attr_ids = array_column($order_goods, 'goods_attr_id');
- // 获取SKU
- $sku = GoodsAttr::getSkuByAttrIDs($attr_ids, 'sku_id, mall_goods_id, chain_goods_id, attr_id');
- if (empty($sku) || (count($sku) != count($attr_ids))) {
- throw new Exception('下单商品SKU有误,请重新下单');
- }
- // 重组sku 添加数量
- $sku = array_map(function ($item) use ($order_goods) {
- $goods = ArrayHelper::first($order_goods, function ($goods) use ($item) {
- return $goods['goods_attr_id'] == $item['attr_id'];
- });
- $item['goods_attr_name'] = $goods['goods_attr_name'];
- $item['goods_name'] = $goods['goods_name'];
- $item['num'] = $goods['num'];
- return $item;
- }, $sku);
- // 获取用户收货地址信息
- if (empty($extra['address'])) {
- $address = UserAddress::getOne([['id' => $form['address_id']], ['user_id' => $form['user_id']]], true);
- $extra['address'] = $address;
- }
- $group_order_goods = $form->group_order_goods;
- // 检测起购
- $this->checkBuyStartQty($sku);
- // 未选择地址不进行计算运费
- if (!empty($address)) {
- // 地址编码
- $district = Region::getDistrictByRegion($address['province'], $address['city'], $address['district'], $address['town']);
- if (empty($district)) {
- throw new Exception('地址信息有误,请联系管理员处理');
- }
- $spuInfoList = array_map(function ($item) {
- return [
- 'quantity' => $item['num'],
- 'spuId' => $item['chain_goods_id'],
- ];
- }, $sku);
- $params = [
- 'spuInfoList' => $spuInfoList,
- 'cityId' => $district->parent_code,
- ];
- // 检测可售
- if ($is_new_record) {
- $this->checkGoodsLimitByRegionCode($sku, $district->region_code);
- }
- // 库存监测
- if ($is_new_record) {
- $this->checkGoodsLimitBySkuStock($sku, $district->region_code);
- }
- // 运费
- $freight = $this->api->calculate($params);
- $form->marketing['deduct']['shipping_fee'] = [
- 'name' => '运费',
- 'money' => $freight,
- ];
- foreach ($group_order_goods as $k => &$v) {
- if ($v['mch_order_info']) {
- // 标识
- $v['mch_order_info']['order_source'] = StarChainEnum::PLUGIN_SIGN;
- // 邮费
- $v['mch_order_info']['shipping_type'] = ShippingTypeEnum::LOGISTICS; // 默认物流配送
- $v['mch_order_info']['shipping_money'] = $freight;
- // 收货地址
- $v['mch_order_info']['province'] = $address['province_id'];
- $v['mch_order_info']['city'] = $address['city_id'];
- $v['mch_order_info']['area'] = $address['district_id'];
- $v['mch_order_info']['town'] = $address['town_id'];
- $v['mch_order_info']['region_name'] = $address['province'] .' '. $address['city'] .' '. $address['district'].' '.$address['town'];
- $v['mch_order_info']['address'] = $address['detail'];
- $v['mch_order_info']['receiver_name'] = $address['name'];
- $v['mch_order_info']['mobile'] = $address['mobile'];
- }
- }
- // 计算总额
- $form['total_pay_money'] = bcadd($form['total_pay_money'], $freight, 2);
- }
- $form->group_order_goods = $group_order_goods;
- return $form;
- }
-
- /**
- * 创建订单
- *
- * @param integer $order_id
- * @param string $order_no
- * @return void
- */
- public static function createOrder($order_id/* , $order_no */)
- {
- /**
- * @var MallOrder|null
- */
- $order = MallOrder::getOrder($order_id);
- if (!$order->isChainOrder()) return false;
- if (!$order->pay_status == StatusEnum::ENABLED) return false;
- /**
- * @var array|null
- */
- $details = $order->detail;
- if (empty($details)) return false;
- // 已经创建订单 不执行
- // if ($order->hasChainOrder()) return false;
- // 下单商品
- $attr_ids = array_column($details, 'goods_attr_id');
- // 获取SKU
- $sku = GoodsAttr::getSkuByAttrIDs($attr_ids, 'sku_id, mall_goods_id, chain_goods_id, attr_id');
- if (empty($sku) || (count($sku) != count($attr_ids))) throw new Exception('下单商品SKU有误,请重新下单');
- // 重组sku 添加数量
- $sku = array_map(function ($item) use ($details) {
- $detail = ArrayHelper::first($details, function ($goods) use ($item) {
- return $goods['goods_attr_id'] == $item['attr_id'];
- });
- $item['num'] = $detail['num'];
- $item['mall_order_id'] = $detail['order_id'];
- $item['order_detail_id'] = $detail['id'];
- return $item;
- }, $sku);
- // 下单数据
- $goods_list = array_map(function ($item) {
- return [
- 'goodsQty' => $item['num'],
- 'skuId' => $item['sku_id'],
- 'spuId' => $item['chain_goods_id'],
- 'mall_order_id' => $item['mall_order_id'],
- 'order_detail_id' => $item['order_detail_id'],
- ];
- }, $sku);
- if (empty($goods_list)) throw new Exception('下单数据为空');
- // 地址信息
- $region = explode(' ', $order->region_name);
- $region = Region::getAddress($region);
- // 地址编码
- $area_code = Region::getAreaCode($region);
- if ($area_code === false) throw new Exception('该地址无法下单');
- $dto = [
- 'orderSource' => 1,
- 'goodsList' => $goods_list, // 下单商品
- 'shipArea' => trim(implode(',', $region), ','),
- 'shipAreaCode' => trim(implode(',', array_reverse(explode(',', $area_code)))),
- 'shipName' => $order->receiver_name,
- 'shipAddress' => $order->address,
- 'shipMobile' => $order->mobile,
- 'outOrderSn' => $order->order_no,
- 'buyerMemo' => $order->remark,
- ];
- /**
- * @var Order|null $order_model
- */
- $order_model = null;
- // 添加
- Yii::$app->db->transaction(function () use ($order, $dto, &$order_model) {
- $order_model = Order::createOrder($order, $dto);
- });
- // 创建订单
- try {
- $dto['goodsList'] = array_map(function ($item) {
- return [
- 'goodsQty' => $item['goodsQty'],
- 'skuId' => $item['skuId'],
- ];
- }, $dto['goodsList']);
- $order_data = (new self(['mall_id' => $order->mall_id]))->api->submitOrder($dto);
- } catch (Exception $e) {
- $order_model->orderError($e->getMessage());
- throw new Exception($e->getMessage());
- }
- // 修改状态
- Yii::$app->db->transaction(function () use ($order_data, $order_model, $order) {
- $order->changeOrderSource();
- if ($order_model->orderSuccess($order_data['orderList']) === false) throw new \Exception('修改状态失败');
- });
- }
- /**
- * 起购检测
- *
- * @param array $spu_id
- * @return void
- */
- protected function checkBuyStartQty(array $skus)
- {
- $data_list = $this->api->listSkuBySpuIds(array_unique(array_column($skus, 'chain_goods_id')));
- foreach ($skus as $sku) {
- // 供应链端商品信息
- $chain_goods = ArrayHelper::first($data_list, function ($item) use ($sku) {
- return $sku['chain_goods_id'] == $item['spuId'];
- });
- // 供应链sku
- $chain_sku = ArrayHelper::first($chain_goods['data'], function ($item) use ($sku) {
- return $item['skuId'] == $sku['sku_id'];
- });
- if ($chain_sku['buyStartQty'] > $sku['num']) {
- throw new Exception('「' . $sku['goods_attr_name'] . '」最低起购数量为' . $chain_sku['buyStartQty']);
- }
- }
- }
- /**
- * 商品区域限制检测
- *
- * @param array $skus
- * @param string $region_code
- * @return true
- * @throws Exception
- */
- protected function checkGoodsLimitByRegionCode(array $skus, string $region_code)
- {
- $spu_ids = array_unique(array_column($skus, 'chain_goods_id'));
- $goods = Goods::getInfoBySpuIds($spu_ids, 'name, is_limit_area, limit_area_type, limit_area');
- try {
- foreach ($goods as $item) {
- $limit_area = Json::decode($item->limit_area) ?? [];
- // 未开启限制
- if ($item->is_limit_area == 0) return true;
- // 限制类型
- if ($item->limit_area_type == 1 && in_array($region_code, $limit_area)) {
- throw new Exception('商品: 「' . $item->name . '」, 对区域: 「' . $region_code . '」, 已开启区域限制1, 请选择其他商品');
- } else if (!in_array($region_code, $limit_area)) {
- throw new Exception('商品: 「' . $item->name . '」, 对区域: 「' . $region_code . '」, 已开启区域限制0, 请选择其他商品');
- }
- }
- } catch (Exception $e) {
- // 如果区域编码不是6位,进行处理
- if (strlen($region_code) != 6) {
- // 区域编码处理
- $region_code = substr($region_code, 0, 6);
- $this->checkGoodsLimitByRegionCode($skus, $region_code);
- }
- throw new Exception($e->getMessage());
- }
- }
- /**
- * 库存限制坚持
- *
- * @param array $skus
- * @return void
- * @throws Exception
- */
- protected function checkGoodsLimitBySkuStock(array $skus, string $region_code)
- {
- $data = array_map(function ($item) {
- return [
- 'skuId' => $item['sku_id'],
- 'skuNum' => $item['num'],
- ];
- }, $skus);
- $data = $this->api->checkSkuStock($data, $region_code);
- foreach ($data as $item) {
- if (!($item['sailState'] && $item['stockState'])) {
- throw new Exception($item['msg'] ?? sprintf('「%s」库存限制购买', $item['skuId']));
- }
- }
- }
- }
|