You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
yanzong/app/store/service/order/EOrder.php

289 lines
11 KiB

<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\store\service\order;
use think\facade\Db;
use app\store\model\eorder\Setting as SettingModel;
use app\store\model\store\Address as StoreAddressModel;
use app\store\model\eorder\Template as EOrderTemplateModel;
use app\store\service\order\Delivery as DeliveryService;
use app\common\service\BaseService;
use app\common\service\Order as OrderService;
use app\common\service\Goods as GoodsService;
use app\common\service\order\Shipping as ShippingService;
use app\common\library\helper;
use app\common\library\eOrder\Facade as EOrderFacade;
use app\store\model\Order as OrderModel;
use cores\exception\BaseException;
/**
* 服务层:电子面单发货事件
* Class EOrder
* @package app\store\service\order
*/
class EOrder extends BaseService
{
// 发货方式: 电子面单
const DELIVERY_METHOD_EORDER = 30;
// 电子面单模板
private string $eorderContent = '';
/**
* 电子面单发货
* @param int $orderId
* @param array $param
* @return bool
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function eorder(int $orderId, array $param): bool
{
// 设置默认的参数
$param = helper::setQueryDefaultValue($param, [
// 发货方式: 电子面单
'deliveryMethod' => self::DELIVERY_METHOD_EORDER,
// 整单发货
'isAllPack' => false,
// 发货的商品
'packGoodsData' => [],
// 同步至微信小程序《发货信息录入》
'syncMpWeixinShipping' => 1,
]);
// 获取订单详情
$detail = OrderModel::detail($orderId);
// 验证订单是否满足发货条件
$DeliveryService = new DeliveryService;
if (!$DeliveryService->verifyDelivery([$detail])) {
$this->error = $DeliveryService->getError();
return false;
}
// 执行订单发货操作
Db::transaction(function () use ($DeliveryService, $orderId, $detail, $param) {
// 获取电子面单模板记录
$templateInfo = $this->getEOrderTemplateInfo($param['templateId']);
// 请求API获取电子面单内容
$eOrderTemplate = $this->getEOrderTemplate($orderId, $param['addressId'], $param['packGoodsData'], $templateInfo);
// 订单发货事件
$DeliveryService->deliveryEvent($detail, array_merge($param, [
// 物流公司ID
'expressId' => $templateInfo['express_id'],
// 物流单号
'expressNo' => $eOrderTemplate['expressNo'],
// 电子面单内容
'eorderHtml' => $this->getEOrderContent(),
]));
// 获取已发货的订单
$completed = OrderModel::detail($orderId, ['goods', 'trade']);
// 发货信息同步微信平台
(new ShippingService)->syncMpWeixinShipping($completed, [
// 同步至微信小程序《发货信息录入》
'syncMpWeixinShipping' => $param['syncMpWeixinShipping'],
// 物流模式:1物流配送 3虚拟商品 4用户自提
'logisticsType' => ShippingService::DELIVERY_EXPRESS,
// 物流公司ID
'expressId' => $templateInfo['express_id'],
// 物流单号
'expressNo' => $eOrderTemplate['expressNo'],
]);
});
return true;
}
/**
* 电子面单发货
* @param int $orderId 订单ID
* @param int $addressId 收货地址ID
* @param array $packGoodsData 发货的商品
* @param $templateInfo
* @return array
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getEOrderTemplate(int $orderId, int $addressId, array $packGoodsData, $templateInfo): array
{
// 订单详情
$orderInfo = OrderModel::detail($orderId, ['goods', 'address']);
// 获取电子面单模板记录
$templateInfo = $this->getEOrderTemplateInfo($templateInfo['template_id']);
// 获取电子面单基础设置
$options = $this->getEOrderOption();
// 实例化电子面单API驱动
$EOrderApi = EOrderFacade::store($templateInfo['provider']);
// 设置API配置参数
$EOrderApi->setOptions($options['providerConfig']);
// 设置电子面单模板信息
$EOrderApi->setEleTemplate($this->getEleTemplate($templateInfo));
// 设置发货单信息
$EOrderApi->setDeliverOrder($this->getDeliverOrder($orderInfo, $packGoodsData));
// 设置发件人信息
$EOrderApi->setSender($this->getSender($addressId));
// 设置收件人信息
$EOrderApi->setReceiver($this->getReceiver($orderInfo));
// 获取电子面单
$result = $EOrderApi->handle();
// 记录电子面单的内容
$this->eorderContent = $result['content'];
return $result;
}
/**
* 获取收件人信息
* @param $orderInfo
* @return array
*/
private function getReceiver($orderInfo): array
{
$addressInfo = $orderInfo['address'];
return [
'name' => $addressInfo['name'],
'mobile' => $addressInfo['phone'],
'provinceName' => $addressInfo['region']['province'],
'cityName' => $addressInfo['region']['city'],
'expAreaName' => $addressInfo['region']['region'],
'address' => $addressInfo['detail']
];
}
/**
* 获取发件人信息
* @param int $addressId
* @return array
*/
private function getSender(int $addressId): array
{
$addressInfo = StoreAddressModel::detail($addressId);
return [
'name' => $addressInfo['name'],
'mobile' => $addressInfo['phone'],
'provinceName' => $addressInfo['region']['province'],
'cityName' => $addressInfo['region']['city'],
'expAreaName' => $addressInfo['region']['region'],
'address' => $addressInfo['detail']
];
}
/**
* 获取发货单信息
* @param $orderInfo
* @param array $packGoodsData 发货的商品
* @return array
*/
private function getDeliverOrder($orderInfo, array $packGoodsData): array
{
// 构建商品信息
$commodity = $this->buildCommodity($orderInfo, $packGoodsData);
return [
// 订单编号,不可重复提交
'orderCode' => OrderService::createOrderNo(),
// 包裹总重量kg
'weight' => helper::getArrayColumnSum($commodity, 'goodsWeight'),
// 包裹数
'quantity' => 1,
//是 否通知快递员上门揽件 0通知 1不通知
'isNotice' => 1,
// 商品信息
'commodity' => $commodity,
];
}
/**
* 构建商品信息
* @param $orderInfo
* @param array $packGoodsData 发货的商品
* @return array
*/
private function buildCommodity($orderInfo, array $packGoodsData): array
{
$commodity = [];
$orderGoodsIds = helper::getArrayColumn($packGoodsData, 'orderGoodsId');
foreach ($orderInfo['goods'] as $goods) {
if (in_array($goods['order_goods_id'], $orderGoodsIds)) {
$goodsProps = !empty($goods['goods_props']) ? GoodsService::goodsPropsToAttr($goods['goods_props']) : '';
$commodity[$goods['order_goods_id']] = [
'orderGoodsId' => $goods['order_goods_id'], // 订单商品ID
'goodsName' => $goods['goods_name'], // 商品名称
'goodsProps' => $goodsProps, // 商品规格
'goodsquantity' => $goods['total_num'], // 商品数量
'goodsWeight' => $goods['goods_weight'] // 商品重量kg
];
}
}
return $commodity;
}
/**
* 获取电子面单模板信息
* @param $templateInfo
* @return array
* @throws BaseException
*/
private function getEleTemplate($templateInfo): array
{
$shipperCodeKey = $templateInfo['provider'] === 'kdniao' ? 'kdniao_code' : 'kuaidi100_code';
$shipperCode = $templateInfo['express'][$shipperCodeKey] ?? null;
if (empty($shipperCode)) {
$codeEnum = ['kdniao' => '快递鸟', 'kd100' => '快递100'];
throwError("很抱歉,物流公司记录不存在{$codeEnum[$templateInfo['provider']]}编码,请先补充");
}
return [
'shipperCode' => $templateInfo['express'][$shipperCodeKey],
'customerName' => $templateInfo['config']['customerName'],
'customerPwd' => $templateInfo['config']['customerPwd'],
'sendSite' => $templateInfo['config']['sendSite'],
'monthCode' => $templateInfo['config']['monthCode'],
'payType' => $templateInfo['config']['payType'],
];
}
/**
* 获取电子面单模板记录
* @param int $templateId
* @return EOrderTemplateModel|false|\think\Model
* @throws BaseException
*/
private function getEOrderTemplateInfo(int $templateId)
{
$model = EOrderTemplateModel::detail($templateId);
empty($model) && throwError('未找到电子面单模板记录');
return EOrderTemplateModel::related($model, ['express']);
}
/**
* 获取电子面单基础设置
* @return array|mixed
* @throws BaseException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
private function getEOrderOption()
{
$options = SettingModel::getBasic();
!$options['enable'] && throwError('很抱歉,电子面单功能尚未开启');
return $options;
}
/**
* 返回电子面单内容
* @return string
*/
public function getEOrderContent(): string
{
return $this->eorderContent;
}
}