// +---------------------------------------------------------------------- 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; } }