Merge pull request !275 from 杨建炊/hotfix/yjc_jd_print
This commit is contained in:
杨建炊 2024-12-28 07:35:52 +00:00 committed by Gitee
commit 6083b1f6c5
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
46 changed files with 4265 additions and 27 deletions

View File

@ -60,7 +60,7 @@ class CheckSkuQualityPeriod extends Command
$updateIds = [];
foreach ($purchaseRecords as $v) {
// 单独采购单后续总和小于库存表示该sku没有卖完
$totalPurchaseNum = PurchaseRecords::query()->where('created_at', '>=', $v->created_at)
$totalPurchaseNum = PurchaseRecords::query()->where('created_at', '>', $v->created_at)
->where('external_sku_id', "=", $v->external_sku_id)
->where("status", 1)->sum('num');
if ($totalPurchaseNum < $v->stock) {

View File

@ -0,0 +1,40 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class CancelLogisticEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $shopId;
public $orderSn;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($shopId, $orderSn)
{
$this->shopId = $shopId;
$this->orderSn = $orderSn;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}

View File

@ -10,6 +10,9 @@ class BusinessOrderFilter extends Filters
{
protected function ids($value)
{
if(is_string($value)){
$value = explode(",", $value);
}
return $this->builder->whereIn('id', $value);
}

View File

@ -9,12 +9,14 @@ use App\Models\BusinessOrder;
use App\Models\BusinessOrderItem;
use App\Models\GoodsSku;
use App\Models\Shop;
use App\Services\Ship\WayBillService;
use App\Models\Waybill;
use App\Services\WayBill\JingDong\WayBillService;
use App\Utils\DateTimeUtils;
use Carbon\Carbon;
use Illuminate\Http\Request;
use App\Http\Resources\BusinessOrderResource;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Maatwebsite\Excel\Facades\Excel;
class BusinessOrderController extends Controller
@ -27,17 +29,25 @@ class BusinessOrderController extends Controller
$builder = BusinessOrder::query()
->with([
'shop:id,name',
'items:id,business_order_id,goods_name,goods_number,external_sku_id'
'items:id,business_order_id,goods_name,goods_number,external_sku_id',
"waybill"
])
->whereIn('shop_id', $shopIds)
->filter();
$externalSkuIds = $request->get('external_sku_ids');
$externalSkuId = $request->get('external_sku_id');
if (!empty($externalSkuId)) {
$externalSkuIds = $externalSkuId;
}
if ($externalSkuIds) {
if (is_string($externalSkuIds)) {
$externalSkuIds = explode(",", $externalSkuIds);
}
$ids = BusinessOrderItem::query()->whereIn('external_sku_id', $externalSkuIds)->pluck('business_order_id');
$builder->whereIn('id', $ids);
}
if($request->get("is_export")){
if ($request->get("is_export")) {
$params = $request->validate([
'confirm_at_start' => 'required',
'confirm_at_end' => 'required',
@ -52,7 +62,7 @@ class BusinessOrderController extends Controller
throw new \Exception("导出时间超出一个月");
}
return Excel::download(new BusinessOrderExport($builder->get()->toArray()), $startDate . '~' . $endDate."订单数据" . '.xlsx');
return Excel::download(new BusinessOrderExport($builder->get()->toArray()), $startDate . '~' . $endDate . "订单数据" . '.xlsx');
}
$businessOrders = $builder->orderByDesc('confirm_at')
->paginate($request->get('per_page'));
@ -177,24 +187,25 @@ class BusinessOrderController extends Controller
->whereIn('shop_id', $shopIds)
->filter();
$externalSkuIds = $request->get('external_sku_ids');
if ($externalSkuIds) {
$ids = BusinessOrderItem::query()->whereIn('external_sku_id', $externalSkuIds)->pluck('business_order_id');
$builder->whereIn('id', $ids);
}
if ($ids = $request->input('ids')) {
if (is_string($ids)) {
$ids = explode(",", $ids);
}
$builder->whereIn('id', $ids);
}
$businessOrders = $builder->get();
$waybill = new WayBillService();
$waybill->setOrders($businessOrders);
$contents = $waybill->getContents();
// 待打印数据
[$documents, $orderIds] = $waybill->getDocumentsAndOrderIds($contents);
$contents = $waybill->getWayBillContents();
return response([
'documents' => $this->combinationPrintDocuments($documents),
'order_ids' => implode(',', $orderIds),
'data' => $contents
]);
}
@ -251,9 +262,11 @@ class BusinessOrderController extends Controller
$orderIds = $request->input('order_ids');
$orderIds = explode(',', $orderIds);
BusinessOrder::query()
->where('id', $orderIds)
->increment('print_status');
->whereIn('id', $orderIds)
->update(['print_status' => 1]);
Waybill::query()
->where('order_id', $orderIds)
->update(['status' => Waybill::$STATUS_PRINT_SUCCESS]);
return response(['message' => 'success']);
}
}

View File

@ -0,0 +1,74 @@
<?php
namespace App\Http\Controllers\Business;
use App\Events\BusinessOrderCancelEvent;
use App\Events\CancelLogisticEvent;
use App\Exports\BusinessOrderExport;
use App\Exports\OrderBlankExport;
use App\Http\Controllers\Controller;
use App\Models\BusinessOrder;
use App\Models\BusinessOrderItem;
use App\Models\GoodsSku;
use App\Models\Shop;
use App\Models\Waybill;
use App\Services\Business\BusinessFactory;
use App\Services\WayBill\JingDong\JingDongService;
use App\Services\WayBill\JingDong\WayBillService;
use App\Utils\DateTimeUtils;
use Carbon\Carbon;
use Illuminate\Http\Request;
use App\Http\Resources\BusinessOrderResource;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Maatwebsite\Excel\Facades\Excel;
class WaybillController extends Controller
{
public function queryTrace(Request $request)
{
$params = $request->validate([
'order_id' => 'required',
], [
'order_id.required' => '订单id',
]);
$waybill = Waybill::query()->where("order_id", $params['order_id'])->firstOrFail();
$jingDongService = new JingDongService();
return $jingDongService->queryTrace($waybill);
}
public function cancel(Request $request)
{
$params = $request->validate([
'order_id' => 'required',
], [
'order_id.required' => '订单id',
]);
$waybill = Waybill::query()->where("order_id", $params['order_id'])->firstOrFail();
if (empty($waybill->waybill_code)) {
throw new \Exception("无快递单号可取消");
}
try{
//取消快团团物流
$shop = Shop::query()->findOrFail($waybill->shop_id);
$client = BusinessFactory::init()->make($shop['plat_id'])->setShop($shop);
$client->cancelLogistic($waybill->order_sn, $waybill->waybill_code);
//取消京东物流
$jingDongService = new JingDongService();
$jingDongService->cancelOrder($waybill);
}catch(\Exception $exception) {
Log::error("取消快团团或者京东物流异常", ["error" => $exception->getMessage()]);
}
$waybill->waybill_code = '';
$waybill->encryptedData = '';
$waybill->status = Waybill::$STATUS_INIT;
$waybill->cancel = 1;
$waybill->save();
BusinessOrder::query()->where("id", $params['order_id'])->update(['print_status' => 0]);
return response(['message' => 'success']);
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace App\Http\Controllers\Shop;
use App\Http\Controllers\Controller;
use App\Models\BusinessGoodsSku;
use App\Models\DeveloperConfig;
use App\Models\GoodsSku;
use App\Models\Shop;
use App\Http\Resources\ShopsResource;
use App\Models\ShopSender;
use App\Models\ShopShip;
use App\Services\Business\KuaiTuanTuan\FaceSheet;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use App\Services\Business\BusinessFactory;
use Illuminate\Validation\Rule;
use App\Models\BusinessOrderItem;
class ShopSendsController extends Controller
{
public function index(Request $request)
{
$shopSender = ShopSender::query()->filter()->paginate($request->get('per_page'));
return JsonResource::collection($shopSender);
}
public function store(Request $request)
{
$params = $request->validate([
'id' => 'sometimes',
'shop_id' => 'required|int',
'province' => 'required',
'city' => 'required',
'district' => 'required',
'detail' => 'required',
'name' => 'required',
'mobile' => 'required',
'sort' => 'sometimes',
'wp_code' => 'sometimes',
], [
'shop_id.required' => '请选择店铺',
'province.required' => '请选择省份',
'city.required' => '请选择城市',
'district.required' => '请选择地区',
'detail.required' => '请填写详细地址',
]);
$params['wp_code'] = $params['wp_code'] ?? 'JD';
$params['country'] = $params['country'] ?? '中国';
if (empty($params['id'])) {
$shopSender = new ShopSender();
$shopSender->fill($params);
$shopSender->save();
} else {
ShopSender::query()->where('id', $params['id'])->update($params);
}
return response($this->res, $this->res['httpCode']);
}
}

View File

@ -2,6 +2,7 @@
namespace App\Listeners;
use App\Events\CancelLogisticEvent;
use App\Events\CreateLogisticEvent;
use App\Models\Shop;
use App\Models\Waybill;
@ -11,9 +12,6 @@ use Illuminate\Queue\InteractsWithQueue;
class CancelLogisticListener implements ShouldQueue
{
public $connection = 'redis';
public $queue = 'listeners';
/**
* Create the event listener.
@ -31,7 +29,7 @@ class CancelLogisticListener implements ShouldQueue
* @param CreateLogisticEvent $event
* @return void
*/
public function handle(CreateLogisticEvent $event)
public function handle(CancelLogisticEvent $event)
{
$waybillNo = Waybill::query()
->where('shop_id', $event->shopId)

View File

@ -3,6 +3,7 @@
namespace App\Listeners;
use App\Events\CreateLogisticEvent;
use App\Models\BusinessOrder;
use App\Models\Shop;
use App\Services\Business\BusinessFactory;
use Illuminate\Contracts\Queue\ShouldQueue;
@ -10,10 +11,6 @@ use Illuminate\Queue\InteractsWithQueue;
class CreateLogisticListener implements ShouldQueue
{
public $connection = 'redis';
public $queue = 'listeners';
/**
* Create the event listener.
*
@ -27,12 +24,12 @@ class CreateLogisticListener implements ShouldQueue
/**
* Handle the event.
*
* @param CreateLogisticEvent $event
* @param CreateLogisticEvent $event
* @return void
*/
public function handle(CreateLogisticEvent $event)
{
$shop = Shop::query()->findOrFail($event->shopId);
$shop = Shop::query()->findOrFail($event->shopId);;
$client = BusinessFactory::init()->make($shop['plat_id'])->setShop($shop);
$client->createLogistic($event->orderSn, $event->waybillNo);
}

View File

@ -23,6 +23,8 @@ class BusinessOrder extends Model
'print_status',
'ids',
'pno',
'order_sn',
'id',
];
protected $fillable = [
@ -72,4 +74,9 @@ class BusinessOrder extends Model
{
return $this->belongsTo(Shop::class, 'shop_id', 'id');
}
public function waybill()
{
return $this->belongsTo(Waybill::class, 'id', 'order_id');
}
}

View File

@ -2,9 +2,16 @@
namespace App\Models;
use App\Models\traits\Filter;
use Illuminate\Database\Eloquent\Model;
class ShopSender extends Model
{
use Filter;
protected $guarded = [];
//查询字段
public $fieldSearchable = [
'shop_id',
];
}

View File

@ -2,6 +2,7 @@
namespace App\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Hash;
@ -11,6 +12,7 @@ class User extends Authenticatable
{
use Notifiable;
use HasRoles;
use SoftDeletes;
/**
* The attributes that are mass assignable.

View File

@ -10,4 +10,9 @@ class Waybill extends Model
public static $BUSINESS_EXPRESS_CODE = 247;
public static $AIR_FREIGHT_CODE = 266;
public static $STATUS_INIT = 0;
public static $STATUS_CREATE_WAYBILL_CODE = 1;
public static $STATUS_CREATE_WAYBILL_ENCRYPTED_DATA = 2;
public static $STATUS_PRINT_SUCCESS = 3;
}

View File

@ -3,6 +3,7 @@
namespace App\Providers;
use App\Events\BusinessOrdersUpdate;
use App\Events\CancelLogisticEvent;
use App\Events\StockUpdateEvent;
use App\Events\GroupSetEvent;
use App\Events\BatchStockUpdateEvent;
@ -47,6 +48,9 @@ class EventServiceProvider extends ServiceProvider
CreateLogisticEvent::class => [
CreateLogisticListener::class
],
CancelLogisticEvent::class => [
CancelLogisticListener::class
],
];
/**

View File

@ -4,6 +4,7 @@ namespace App\Services\Business;
use App\Events\BusinessOrderCancelEvent;
use App\Events\BusinessOrdersUpdate;
use App\Events\CancelLogisticEvent;
use App\Models\BusinessGoodsSku;
use App\Models\BusinessOrder;
use App\Models\BusinessOrderItem;
@ -55,7 +56,7 @@ abstract class BusinessClient
$orderRecord->update($order);
}
if (!empty($order['cancel_status'])) {
event(new BusinessOrderCancelEvent($shopId, $order['order_sn']));
event(new CancelLogisticEvent($shopId, $order['order_sn']));
}
$goodsSkuNum = 0;
foreach ($order['sub_order_list'] as $item) {
@ -154,7 +155,7 @@ abstract class BusinessClient
'headers' => ['Content-type' => 'application/x-www-form-urlencoded;charset=UTF-8'],
'form_params' => $params
];
$res = (new Client())->request($method, $url, $headers);
$res = (new Client(['verify'=>false]))->request($method, $url, $headers);
$size = $res->getBody()->getSize();
$res = json_decode($res->getBody()->getContents(), true);
$paramsJson = json_encode($params, 256);

View File

@ -374,7 +374,6 @@ class KuaiTuanTuan extends BusinessClient
public function createLogistic($orderSn, $waybillNo)
{
[$type, $appendParams] = Order::createOrderLogistic($orderSn, $waybillNo);
return $this->doRequest($type, $appendParams);
}

View File

@ -0,0 +1,244 @@
<?php
namespace App\Services\WayBill\JingDong;
use App\Enum\Pickup\ConsignType;
use App\Models\BusinessOrder;
use App\Models\OrderItem;
use App\Models\Pickup;
use App\Models\Waybill;
use App\Services\Pickup\Exceptions\KdNiaoException;
use App\Utils\Env\EnvUtils;
use Carbon\Carbon;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Log;
use Lop\LopOpensdkPhp\Filters\ErrorResponseFilter;
use Lop\LopOpensdkPhp\Filters\IsvFilter;
use Lop\LopOpensdkPhp\Options;
use Lop\LopOpensdkPhp\Support\DefaultClient;
use Lop\LopOpensdkPhp\Support\GenericRequest;
use Psr\Http\Message\ResponseInterface;
class JingDongService
{
public $baseUrl;
public $appKey;
public $appSecret;
public $accessToken;
public $customerCode;
public static $CANCEL_TYPE = [
1 => '预约信息有误',
2 => '快递员无法取件',
3 => '上门太慢',
4 => '运费太贵',
7 => '联系不上快递员',
8 => '快递员要求取消',
11 => '其他(如疫情管控,无法寄 件)',
9 => '预约信息有误',
];
public function __construct()
{
$this->baseUrl = "https://api.jdl.com";
$this->appKey = "5ee218f6619e438db8755ee560c3eaa7";
$this->appSecret = "7ffb176f75014ebbb37061f051024bf3";
$this->accessToken = "4e411a1d178147cdb58b5579a0df378d";//每年都会过期 https://oauth.jdl.com/oauth/authorize?client_id=YOUR_APP_KEY&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code
//生产环境域名https://oauth.jdl.com 预发环境域名https://uat-oauth.jdl.com
$this->domain = "FreshMedicineDelivery";//对接方案的编码 生鲜快递
$this->customerCode = "028K4188368";//月结编码
/*if (!EnvUtils::checkIsProduce()) {
//沙箱环境
$this->baseUrl = "https://test-api.jdl.com";
$this->appKey = "62d07644754843cc882fca7c01476c4f";
$this->appSecret = "0c2c8b6b7c10481ea639f6daa09ac02e";
$this->accessToken = "78c246c0ab564e67add6296a9eaf04a1";;//每年都会过期 https://oauth.jdl.com/oauth/authorize?client_id=YOUR_APP_KEY&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code
$this->customerCode = "27K1234912";//月结编码
}*/
}
public function request($body, $path)
{
// 生产环境: https://api.jdl.com
$client = new DefaultClient($this->baseUrl);
// 系统参数应用的app_ley和app_secret可从【控制台-应用管理-概览】中查看access_token是用户授权时获取的令牌用户授权相关说明请查看https://cloud.jdl.com/#/devSupport/53392
$isvFilter = new IsvFilter($this->appKey, $this->appSecret, $this->accessToken);
$errorResponseFilter = new ErrorResponseFilter();
$request = new GenericRequest();
$request->setDomain($this->domain);//对接方案的编码,应用订购对接方案后可在订阅记录查看
$request->setPath($path);//api的path可在API文档查看
$request->setMethod("POST");//只支持POST
// 序列化后的JSON字符串
$request->setBody(json_encode([$body]));
// 为请求添加ISV模式过滤器自动根据算法计算开放平台鉴权及签名信息
$request->addFilter($isvFilter);
// 为请求添加错误响应解析过滤器,如果不添加需要手动解析错误响应
$request->addFilter($errorResponseFilter);
$options = new Options();
$options->setAlgorithm(Options::MD5_SALT);
Log::info("京东请求body:{$path}", [$body]);
$response = $client->execute($request, $options);
$response = json_decode($response->getBody(), true);
Log::info("京东返回请求response", [$response]);
if (!isset($response['code']) || ($response['code'] != 0 && $response['code'] != 1 && $response['code'] != 1000)) {
throw new \Exception($response['message'] ?? "code异常");
}
return $response;
}
private function buildCargoes($extend)
{
return [
"quantity" => $extend["quantity"] ?? 1,
"goodsName" => "鲜花",
"volume" => ($extend['volume'] ?? 0) > 0 ? $extend['volume'] : 100,
"weight" => $extend['weight'] ?? 1,
"packageQty" => 1
];
}
public function buildContact($params)
{
return [
'senderName' => $params['name'] ?? '',
'senderPhone' => $params['mobile'] ?? '',
'senderAddress' => substr($params['province_name'] . $params['city_name'] . $params['area_name'] . $params['address_detail'], 0, 350),
];
}
public function createOrder(Waybill $pickup)
{
$path = "/freshmedicinedelivery/delivery/create/order/v1";
$pickupData = $pickup->toArray();
$body = [
"orderId" => $pickupData['order_sn'],
"senderContactRequest" => [
'senderName' => $pickupData['sender_name'] ?? '',
'senderPhone' => $pickupData['sender_mobile'] ?? '',
'senderAddress' => substr($pickupData['sender_province'] . $pickupData['sender_city']
. $pickupData['sender_district'] . $pickupData['sender_detail'], 0, 350)
],
"customerCode" => $this->customerCode,
"remark" => $pickup['note'] ?? '',
"salePlatform" => '0030001',//其他平台
"cargoesRequest" => $this->buildCargoes($pickup),
"receiverContactRequest" => [
'receiverName' => $pickupData['recipient_name'] ?? '',
'receiverPhone' => $pickupData['recipient_mobile'] ?? '',
'receiverAddress' => substr($pickupData['recipient_province'] . $pickupData['recipient_city'] . $pickupData['recipient_district'] . $pickupData['recipient_detail'], 0, 350)
],
"channelOrderId" => $pickupData['order_sn'],
"promiseTimeType" => 26,//22医药冷链 26冷链专送,29医药专送
"goodsType" => 7,//1:普通2:生鲜常温5:鲜活6:控温7:冷藏8:冷冻9:深冷21:医药冷藏23:医药控温24:医药常温25:医药冷冻27:医药深冷
//"pickUpStartTime" => Carbon::today()->startOfDay()->addDays(2)->addHours(19)->toDateTimeString(),
//"pickUpEndTime" => Carbon::today()->startOfDay()->addDays(2)->addHours(21)->toDateTimeString(),
];
$response = $this->request($body, $path);
return $response['data'];
}
public function cancelOrder(Waybill $pickup)
{
$path = "/freshmedicinedelivery/delivery/cancel/waybill/v1";
$pickupData = $pickup->toArray();
$body = [
"waybillNo" => $pickupData['waybill_code'],
"customerCode" => $this->customerCode,
"interceptReason" => "订单信息有误",
];
$response = $this->request($body, $path);
return $response['data'];
}
public function pullData(Waybill $pickup)
{
//云打印
$this->domain = "jdcloudprint";
$path = "/PullDataService/pullData";
$pickupData = $pickup->toArray();
$body = [
"cpCode" => "JD",
"wayBillInfos" => [[
'orderNo' => $pickupData['order_sn'],
'jdWayBillCode' => $pickupData['waybill_code'],
]],
"parameters" => ["ewCustomerCode" => $this->customerCode],
"objectId" => $pickupData['object_id'],
];
$response = $this->request($body, $path);
return $response['prePrintDatas'];
}
public function queryOrder(Waybill $pickup)
{
$path = "/ecap/v1/orders/details/query";
$pickupData = $pickup->toArray();
$body = [
"waybillCode" => $pickupData['ship_sn'] ?? '',
"orderCode" => $pickupData['out_order_sn'] ?? "",
"customerCode" => $this->customerCode,
"orderOrigin" => 2,
];
$response = $this->request($body, $path);
return $response['data'];
}
public function subscribe(Waybill $pickup)
{
$path = "/jd/tracking/subscribe";
$pickupData = $pickup->toArray();
$body = [
"referenceNumber" => $pickupData['ship_sn'] ?? '',
"referenceType" => 20000,
"customerCode" => $this->customerCode,
];
$this->domain = "Tracking_JD";//对接方案的编码
$response = $this->request($body, $path);
return $response['data'];
}
public function queryFee(Waybill $pickup)
{
$path = "/ecap/v1/orders/actualfee/query";
$pickupData = $pickup->toArray();
$body = [
"waybillCode" => $pickupData['ship_sn'] ?? '',
"orderCode" => $pickupData['out_order_sn'] ?? "",
"customerCode" => $this->customerCode,
"orderOrigin" => 2,
];
$response = $this->request($body, $path);
return $response['data'];
}
public function queryTrace(Waybill $pickup)
{
$path = "/freshmedicinedelivery/delivery/query/waybill/gis/v1";
$pickupData = $pickup->toArray();
$body = [
"waybillNo" => $pickupData['waybill_code'] ?? '',
"customerCode" => $this->customerCode,
];
$response = $this->request($body, $path);
return $response['data'];
}
}

View File

@ -0,0 +1,281 @@
<?php
namespace App\Services\WayBill\JingDong;
use App\Events\CreateLogisticEvent;
use App\Http\Enum\BusinessOrderShippingStatus;
use App\Models\BusinessOrder;
use App\Models\GoodsSku;
use App\Models\ShopSender;
use App\Models\ShopShip;
use App\Models\Waybill;
use App\Services\Business\KuaiTuanTuan\FaceSheet;
class WayBillService
{
public $orders;
public $objectId;
public $adminUser;
// 标准模板
public $templateUrl = 'https://template-content.jd.com/template-oss?tempCode=jdkd76x130';
// 时效类型
public $timedDeliveryCode;
/**
* 新版京东打印-下单
* @return array
*/
public function getWayBillContents()
{
// 已下单过的订单不再下单
$contents = [];
$this->adminUser = auth('api')->user();
$jingDongService = new JingDongService();
foreach ($this->orders as $shopId => $order) {
// 订单取消的情况暂不处理
$shopSend = $this->getShopSend($shopId);
foreach ($order as $item) {
[$sender, $orderInfo, $senderConfig] = $this->prepareRequest($item, $shopSend);
$waybill = $this->saveWayBill($item, $shopSend, $senderConfig);
if (empty($waybill->waybill_code)) {
$resp = $jingDongService->createOrder($waybill);
if (isset($resp['waybillNo'])) {
$waybill->status = Waybill::$STATUS_CREATE_WAYBILL_CODE;
$waybill->waybill_code = $resp['waybillNo'];
$waybill->save();
//物流发货
event(new CreateLogisticEvent($waybill->shop_id, $waybill->order_sn, $waybill->waybill_code));
}
}
//返回面单待打印数据
if (empty($waybill->encryptedData)) {
// 延时0.5秒 防止订单查询不到
usleep(0.5 * 1000000);
$resp = $jingDongService->pullData($waybill);
if (!empty($resp[0]['perPrintData'])) {
$waybill->status = Waybill::$STATUS_CREATE_WAYBILL_ENCRYPTED_DATA;
$waybill->templateUrl = $this->templateUrl;
$waybill->encryptedData = $resp[0]['perPrintData'];
$waybill->save();
}
}
$contents[$item['id']] = $waybill;
}
}
return $contents;
}
public function getDocumentsAndOrderIds($contents)
{
// 打印单,根据商品排序
$items = [];
foreach ($contents as $docId => $content) {
foreach ($content['items'] as $item) {
if ($item['is_single']) {
$items[$item['external_sku_id']][] = $docId;
}
}
}
ksort($items);
$documents = $orderIds = $hasIds = [];
foreach ($items as $docIds) {
$docIds = array_unique($docIds);
$docIds = array_diff($docIds, $hasIds);
$hasIds = array_merge($hasIds, $docIds);
foreach ($docIds as $docId) {
$orderIds[] = $contents[$docId]['order_id'];
$documents[] = $contents[$docId];
}
}
return [$documents, $orderIds];
}
private function saveWayBill($order, $shopShip, $senderConfig)
{
$waybill = Waybill::query()->firstOrNew(
['order_sn' => $order['order_sn']]
);
$waybill->shop_id = $order['shop_id'];
$waybill->object_id = $this->objectId;
$waybill->sender_country = $senderConfig['country'];
$waybill->sender_province = $senderConfig['province'];
$waybill->sender_city = $senderConfig['city'];
$waybill->sender_district = $senderConfig['district'];
$waybill->sender_detail = $senderConfig['detail'];
$waybill->sender_name = $senderConfig['name'];
$waybill->sender_mobile = (int)$senderConfig['mobile'];
$waybill->recipient_province = $order['recipient_province'];
$waybill->recipient_city = $order['recipient_city'];
$waybill->recipient_district = $order['recipient_district'];
$waybill->recipient_detail = $order['recipient_detail'];
$waybill->recipient_name = $order['recipient_name'];
$waybill->recipient_mobile = $order['recipient_mobile'];
$waybill->user_id = $this->adminUser->id ?? 0;
$waybill->wp_code = $senderConfig['wp_code'];
$waybill->order_sn = $order['order_sn'];
$waybill->order_id = $order['id'];
$waybill->participate_no = $order['participate_no'];
$waybill->note = $order['note'];
$waybill->items = json_encode($order['items'], 256);
$waybill->save();
return $waybill;
}
private function getTimedDelivery($order)
{
$this->timedDeliveryCode = Waybill::$BUSINESS_EXPRESS_CODE;
$address = [
'辽宁省' => [],
'吉林省' => [],
'黑龙江省' => [],
'甘肃省' => [],
'海南省' => [],
'宁夏回族自治区' => [
'银川市', '石嘴山市', '吴忠市', '固原市'
],
'青海省' => [
'西宁市', '海东市', '海北藏族自治州', '黄南藏族自治州', '海南藏族自治州', '玉树藏族自治州'
],
];
if (isset($address[$order['recipient_province']])) {
if (empty($address[$order['recipient_province']])) {
$this->timedDeliveryCode = Waybill::$AIR_FREIGHT_CODE;
}
if ($address[$order['recipient_province']] && in_array($order['recipient_city'], $address[$order['recipient_province']], true)) {
$this->timedDeliveryCode = Waybill::$AIR_FREIGHT_CODE;
}
}
}
private function prepareRequest($order, $shopSend)
{
$this->setObjectId();
$items = [];
foreach ($order['items'] as $item) {
$items[] = [
'name' => $item['name'],
'count' => $item['count'],
];
}
if (empty($shopSend)) {
abort(404, '发货人信息未匹配');
}
$senderConfig = $shopSend;
$sender = [
'address' => [
'city' => $senderConfig['city'],
'country' => $senderConfig['country'],
'detail' => $senderConfig['detail'],
'district' => $senderConfig['district'],
'province' => $senderConfig['province'],
],
'name' => $senderConfig['name'],
'mobile' => $senderConfig['mobile'],
];
$orderInfo = [
'object_id' => $this->objectId,
'order_info' => [
'order_channels_type' => 'PDD',
'trade_order_list' => [$order['order_sn']],
],
'package_info' => [
'items' => $items,
],
'recipient' => [
'address' => [
'city' => $order['recipient_city'],
'detail' => $order['recipient_detail'],
'district' => $order['recipient_district'],
'province' => $order['recipient_province'],
],
'name' => $order['recipient_name'],
'mobile' => $order['recipient_mobile'],
],
'template_url' => $this->templateUrl,
];
return [$sender, $orderInfo, $senderConfig];
}
public function setObjectId()
{
$this->objectId = date('YmdHis') . str_pad(mt_rand(1, 9999999), 7, '0', STR_PAD_LEFT);
return $this;
}
public function setOrders($orders)
{
$orders = $orders->toArray();
// 订单拆分组合
foreach ($orders as $order) {
if ($order['shipping_status'] != BusinessOrderShippingStatus::UNSHIP) {
continue;
}
if ($order['cancel_status'] == 1) {
continue;
}
$info = [
'id' => $order['id'],
'shop_id' => $order['shop_id'],
'order_sn' => $order['order_sn'],
'recipient_province' => $order['receiver_address_province'],
'recipient_city' => $order['receiver_address_city'],
'recipient_district' => $order['receiver_address_district'],
'recipient_detail' => $order['receiver_address_detail'],
'recipient_name' => $order['receiver_name'],
'recipient_mobile' => $order['receiver_mobile'],
'participate_no' => $order['is_supplier'] ? $order['participate_no'] : $order['supply_participate_no'],
'note' => $order['business_note'] ? $order['business_note'] . ',' . $order['buyer_memo'] : $order['buyer_memo'],
'items' => []
];
$note = "";
foreach ($order['items'] as $item) {
$count = $item['goods_number'] - $item['already_cancel_number'];
$info['items'][] = [
'is_single' => true,
'should_print' => true,
'name' => $item['goods_name'],
'count' => $count,
'external_sku_id' => $item['external_sku_id'],
];
$note .= $item['goods_name'] . " " . $count . "件,";
}
$note .= "[备注:" . $info['note'] . "]";
$info['note'] = $note;
$this->orders[$order['shop_id']][] = $info;
}
return $this;
}
private function getShopSend($shopId)
{
return ShopSender::query()
->where('status', 1)->orderBy('sort')
->first();
}
private function getShopShip($shopId)
{
return ShopShip::query()
->select(['id', 'shop_id', 'access_token', 'owner_id'])
->where('shop_id', $shopId)
->with([
'senders' => function ($query) {
$query->where('status', 1)->orderBy('sort');
}
])
->first();
}
}

View File

@ -39,7 +39,8 @@
},
"autoload": {
"psr-4": {
"App\\": "app/"
"App\\": "app/",
"Lop\\LopOpensdkPhp\\" : "extend/lop-opensdk-php/src/"
},
"classmap": [
"database/seeds",

View File

@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddFieldToWaybillsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
if (Schema::hasColumns('waybills', ["status"])) {
return;
}
Schema::table('waybills', function (Blueprint $table) {
$table->integer('status')->default(0)->comment('状态 0待申请物流单 1已申请物流 2已申请面单 3已打印');
$table->index('order_id');
$table->index('order_sn');
$table->index('waybill_code');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('waybills', function (Blueprint $table) {
//
$table->dropColumn('status');
$table->dropIndex('order_id');
$table->dropIndex('order_sn');
$table->dropIndex('waybill_code');
});
}
}

12
extend/lop-opensdk-php/.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
# Created by https://www.toptal.com/developers/gitignore/api/composer
# Edit at https://www.toptal.com/developers/gitignore?templates=composer
### Composer ###
composer.phar
/vendor/
# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
# composer.lock
# End of https://www.toptal.com/developers/gitignore/api/composer

View File

View File

@ -0,0 +1,18 @@
{
"name": "lop/lop-opensdk-php",
"type": "library",
"version": "1.0.0",
"autoload": {
"psr-4": {
"Lop\\LopOpensdkPhp\\": "src/"
}
},
"require": {
"php": ">=5.6",
"ext-json": "*",
"guzzlehttp/guzzle": "^6.5"
},
"require-dev": {
"phpunit/phpunit": "^5.7"
}
}

2284
extend/lop-opensdk-php/composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
<?php
namespace Lop\LopOpensdkPhp;
interface Client
{
/**
* @param Request $request
* @param Options $options
* @return Response
* @throws SdkException
*/
function execute($request, $options);
}

View File

@ -0,0 +1,14 @@
<?php
namespace Lop\LopOpensdkPhp;
interface Executor
{
/**
* @param Request $request
* @param Options $options
* @return Response
* @throws SdkException
*/
function execute($request, $options);
}

View File

@ -0,0 +1,13 @@
<?php
namespace Lop\LopOpensdkPhp;
interface ExecutorFactory
{
/**
* @param string $baseUri
* @return Executor
* @throws SdkException
*/
function create($baseUri);
}

View File

@ -0,0 +1,15 @@
<?php
namespace Lop\LopOpensdkPhp;
interface Filter
{
/**
* @param Request $request
* @param Options $options
* @param FilterChain $chain
* @return Response
* @throws SdkException
*/
function doFilter($request, $options, $chain);
}

View File

@ -0,0 +1,14 @@
<?php
namespace Lop\LopOpensdkPhp;
interface FilterChain
{
/**
* @param Request $request
* @param Options $options
* @return Response
* @throws SdkException
*/
function doFilter($request, $options);
}

View File

@ -0,0 +1,24 @@
<?php
namespace Lop\LopOpensdkPhp\Filters;
use Lop\LopOpensdkPhp\Filter;
class ErrorResponseFilter implements Filter
{
const ERROR_RESPONSE_PATTERN = "/^{\"error_response\":{\"en_desc\":\"(.*)\",\"zh_desc\":\"(.*)\",\"code\":(.*)}}$/";
function doFilter($request, $options, $chain)
{
$response = $chain->doFilter($request, $options);
$matches = array();
if (preg_match(self::ERROR_RESPONSE_PATTERN, $response->getBody(), $matches) === 1) {
$response->setSucceed(false);
$response->setEnDesc($matches[1]);
$response->setZhDesc($matches[2]);
$response->setCode(intval($matches[3]));
}
return $response;
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace Lop\LopOpensdkPhp\Filters;
use Lop\LopOpensdkPhp\Filter;
use Lop\LopOpensdkPhp\SdkException;
class IsvFilter implements Filter
{
/**
* @var string
*/
private $appKey;
/**
* @var string
*/
private $appSecret;
/**
* @var string
*/
private $accessToken;
/**
* @param string $appKey
* @param string $appSecret
* @param string $accessToken
*/
public function __construct($appKey, $appSecret, $accessToken)
{
$this->appKey = $appKey;
$this->appSecret = $appSecret;
$this->accessToken = $accessToken;
}
/**
* @throws SdkException
*/
function doFilter($request, $options, $chain)
{
$request->setHeader("lop-tz", strval(date("Z") / 3600));
$timestamp = date("Y-m-d H:i:s");
$content = implode("", array(
$this->appSecret,
"access_token", $this->accessToken,
"app_key", $this->appKey,
"method", $request->getPath(),
"param_json", $request->getBody(),
"timestamp", $timestamp,
"v", "2.0",
$this->appSecret
));
$sign = Utils::sign($options->getAlgorithm(), $content, $this->appSecret);
$request->setQuery("app_key", $this->appKey);
$request->setQuery("access_token", $this->accessToken);
$request->setQuery("timestamp", $timestamp);
$request->setQuery("v", "2.0");
$request->setQuery("sign", $sign);
$request->setQuery("algorithm", $options->getAlgorithm());
return $chain->doFilter($request, $options);
}
}

View File

@ -0,0 +1,59 @@
<?php
namespace Lop\LopOpensdkPhp\Filters;
use Lop\LopOpensdkPhp\Filter;
use Lop\LopOpensdkPhp\SdkException;
class LoggerFilter implements Filter
{
/**
* @var resource
*/
private $file;
/**
* @param resource $file
*/
public function __construct($file)
{
$this->file = $file;
}
function doFilter($request, $options, $chain)
{
$this->printf("[%s, Request ] Domain: %s, Path: %s, Method: %s", $request->getRequestId(),
$request->getDomain(), $request->getPath(), $request->getMethod());
$this->printf("[%s, Request ] Queries: %s", $request->getRequestId(), json_encode($request->getQueries()));
$this->printf("[%s, Request ] Headers: %s", $request->getRequestId(), json_encode($request->getHeaders()));
$this->printf("[%s, Request ] Body: %s", $request->getRequestId(), $request->getBody());
try {
$response = $chain->doFilter($request, $options);
} catch (SdkException $e) {
$this->printf("[%s, Response ] Error: %s", $e->getMessage());
throw $e;
}
$this->printf("[%s, Response ] Succeed: %t, TraceId: %s, EnDesc: %s, ZhDesc: %s, Code: %d, Status: %d",
$request->getRequestId(), $response->isSucceed(), $response->getTraceId(),
$response->getEnDesc(), $response->getZhDesc(), $response->getCode(), $response->getStatus());
$this->printf("[%s, Response ] Body: %s", $request->getRequestId(), $response->getBody());
return $response;
}
/**
* @param string $format
* @param mixed ...$values
* @return void
*/
private function printf($format, ...$values)
{
fwrite($this->file, date("Y/m/d H:i:s"));
fwrite($this->file, " ");
fwrite($this->file, sprintf($format, $values));
fwrite($this->file, "\n");
}
}

View File

@ -0,0 +1,58 @@
<?php
namespace Lop\LopOpensdkPhp\Filters;
use Lop\LopOpensdkPhp\Filter;
use Lop\LopOpensdkPhp\SdkException;
class PartnerFilter implements Filter
{
/**
* @var string
*/
private $appKey;
/**
* @var string
*/
private $appSecret;
/**
* @param string $appKey
* @param string $appSecret
*/
public function __construct($appKey, $appSecret)
{
$this->appKey = $appKey;
$this->appSecret = $appSecret;
}
/**
* @throws SdkException
*/
function doFilter($request, $options, $chain)
{
$request->setHeader("lop-tz", strval(date("Z") / 3600));
$timestamp = date("Y-m-d H:i:s");
$content = implode("", array(
$this->appSecret,
"access_token", "",
"app_key", $this->appKey,
"method", $request->getPath(),
"param_json", $request->getBody(),
"timestamp", $timestamp,
"v", "2.0",
$this->appSecret
));
$sign = Utils::sign($options->getAlgorithm(), $content, $this->appSecret);
$request->setQuery("app_key", $this->appKey);
$request->setQuery("timestamp", $timestamp);
$request->setQuery("v", "2.0");
$request->setQuery("sign", $sign);
$request->setQuery("algorithm", $options->getAlgorithm());
return $chain->doFilter($request, $options);
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Lop\LopOpensdkPhp\Filters;
use Lop\LopOpensdkPhp\Options;
use Lop\LopOpensdkPhp\SdkException;
abstract class Utils
{
/**
* Signature data with given algorithm and secret.
*
* @param string $algorithm
* @param string $secret
* @param string $data
* @return string
* @throws SdkException
*/
public static function sign($algorithm, $data, $secret)
{
if ($algorithm == Options::MD5_SALT) {
return md5($data);
} else if ($algorithm == Options::SM3_SALT) {
throw new SdkException("Algorithm sm3-salt not supported yet");
} else if ($algorithm == Options::HMAC_MD5) {
return base64_encode(hash_hmac("md5", $data, $secret, true));
} else if ($algorithm == Options::HMAC_SHA1) {
return base64_encode(hash_hmac("sha1", $data, $secret, true));
} else if ($algorithm == Options::HMAC_SHA256) {
return base64_encode(hash_hmac("sha256", $data, $secret, true));
} else if ($algorithm == Options::HMAC_SHA512) {
return base64_encode(hash_hmac("sha512", $data, $secret, true));
}
throw new SdkException("Algorithm " . $algorithm . " not supported yet");
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace Lop\LopOpensdkPhp;
class Options
{
const MD5_SALT = "md5-salt";
const SM3_SALT = "sm3-salt";
const HMAC_MD5 = "HMacMD5";
const HMAC_SHA1 = "HMacSHA1";
const HMAC_SHA256 = "HMacSHA256";
const HMAC_SHA512 = "HMacSHA512";
/**
* @var string
*/
private $algorithm;
public function __construct()
{
$this->algorithm = self::MD5_SALT;
}
/**
* @return string
*/
public function getAlgorithm()
{
return $this->algorithm;
}
/**
* @param string $algorithm
*/
public function setAlgorithm($algorithm)
{
$this->algorithm = $algorithm;
}
}

View File

@ -0,0 +1,137 @@
<?php
namespace Lop\LopOpensdkPhp;
interface Request
{
/**
* @return string
*/
function getDomain();
/**
* @param string $domain
* @return void
*/
function setDomain($domain);
/**
* @return string
*/
function getPath();
/**
* @param string $path
* @return void
*/
function setPath($path);
/**
* @return string
*/
function getMethod();
/**
* @param string $method
* @return void
*/
function setMethod($method);
/**
* @param string $key
* @return bool
*/
function hasQuery($key);
/**
* @param string $key
* @return string
*/
function getQuery($key);
/**
* @param string $key
* @param string $value
* @return void
*/
function setQuery($key, $value);
/**
* @return string[]
*/
function getQueries();
/**
* @param string $key
* @return bool
*/
function hasHeader($key);
/**
* @param string $key
* @return string
*/
function getHeader($key);
/**
* @param string $key
* @param string $value
* @return void
*/
function setHeader($key, $value);
/**
* @return string[]
*/
function getHeaders();
/**
* @param Filter $filter
* @return void
*/
function addFilter($filter);
/**
* @return Filter[]
*/
function getFilters();
/**
* @return mixed
*/
function getEntity();
/**
* @return string
*/
function getBody();
/**
* @param string $body
* @return void
*/
function setBody($body);
/**
* @return string
*/
function getRequestId();
/**
* @param string $requestId
* @return void
*/
function setRequestId($requestId);
/**
* @return string
*/
function getResponseType();
/**
* @param string $responseType
* @return void
*/
function setResponseType($responseType);
}

View File

@ -0,0 +1,94 @@
<?php
namespace Lop\LopOpensdkPhp;
interface Response
{
/**
* @return bool
*/
function isSucceed();
/**
* @param bool $succeed
* @return void
*/
function setSucceed($succeed);
/**
* @return string
*/
function getTraceId();
/**
* @param string $traceId
* @return void
*/
function setTraceId($traceId);
/**
* @return string
*/
function getZhDesc();
/**
* @param string $zhDesc
* @return void
*/
function setZhDesc($zhDesc);
/**
* @return string
*/
function getEnDesc();
/**
* @param string $enDesc
* @return void
*/
function setEnDesc($enDesc);
/**
* @return int
*/
function getCode();
/**
* @param int $code
* @return void
*/
function setCode($code);
/**
* @return int
*/
function getStatus();
/**
* @param int $status
* @return void
*/
function setStatus($status);
/**
* @return string
*/
function getBody();
/**
* @param string $body
* @return void
*/
function setBody($body);
/**
* @return mixed
*/
function getEntity();
/**
* @param mixed $entity
* @return void
*/
function setEntity($entity);
}

View File

@ -0,0 +1,27 @@
<?php
namespace Lop\LopOpensdkPhp;
use Exception;
class SdkException extends Exception
{
/**
* @var Response $response
*/
private $response;
public function __construct($message = "", $code = 0, $response = null, $previous = null)
{
parent::__construct($message, $code, $previous);
$this->response = $response;
}
/**
* @return Response
*/
public function getResponse()
{
return $this->response;
}
}

View File

@ -0,0 +1,79 @@
<?php
namespace Lop\LopOpensdkPhp\Support;
use Lop\LopOpensdkPhp\Client;
use Lop\LopOpensdkPhp\ExecutorFactory;
use Lop\LopOpensdkPhp\SdkException;
use Lop\LopOpensdkPhp\Version;
class DefaultClient implements Client
{
private $baseUri;
/**
* @var ExecutorFactory
*/
private $executorFactory;
public function __construct($baseUri)
{
$this->baseUri = $baseUri;
$this->executorFactory = new DefaultExecutorFactory();
}
/**
* @throws SdkException
*/
function execute($request, $options)
{
if (empty($request->getRequestId())) {
$request->setRequestId(uniqid());
}
if (empty($request->getBody())) {
$request->setBody(json_encode($request->getEntity()));
}
if (!$request->hasQuery("LOP-DN")) {
$request->setQuery("LOP-DN", $request->getDomain());
}
if (!$request->hasHeader("User-Agent")) {
$request->setHeader("User-Agent", "lop-opensdk/php@" . Version::VERSION);
}
$executor = $this->executorFactory->create($this->baseUri);
$chain = new DefaultFilterChain($executor, $request->getFilters());
$response = $chain->doFilter($request, $options);
if (!$response->isSucceed()) {
return $response;
}
if (empty($request->getResponseType())) {
return $response;
}
$entity = json_decode($response->getBody());
if (json_last_error() != JSON_ERROR_NONE) {
throw new SdkException("json decode failed", 0, $response);
}
if (!settype($entity, $request->getResponseType())) {
throw new SdkException("set entity to response type failed", 0, $response);
}
$response->setEntity($entity);
return $response;
}
/**
* @param ExecutorFactory $executorFactory
*/
public function setExecutorFactory($executorFactory)
{
$this->executorFactory = $executorFactory;
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace Lop\LopOpensdkPhp\Support;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Psr7\Request;
use Lop\LopOpensdkPhp\Executor;
use Lop\LopOpensdkPhp\SdkException;
class DefaultExecutor implements Executor
{
/**
* @var string
*/
private $baseUri;
/**
* @param string $baseUri
*/
public function __construct($baseUri)
{
$this->baseUri = $baseUri;
}
/**
* @throws SdkException
*/
function execute($request, $options)
{
$uri = $this->baseUri . $request->getPath();
$httpRequest = new Request($request->getMethod(), $uri, $request->getHeaders(), $request->getBody());
$client = new Client(['verify' => false]);
try {
$httpResponse = $client->send($httpRequest, [
"query" => $request->getQueries(),
"http_errors" => false
]);
} catch (GuzzleException $e) {
throw new SdkException("", 0, null, $e);
}
$response = new GenericResponse();
$response->setSucceed($httpResponse->getStatusCode() == 200);
$response->setStatus($httpResponse->getStatusCode());
$response->setBody($httpResponse->getBody()->getContents());
$traceIds = $httpResponse->getHeader("Lop-Trace-Id");
if (count($traceIds) > 0) {
$response->setTraceId($traceIds[0]);
}
return $response;
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace Lop\LopOpensdkPhp\Support;
use GuzzleHttp\Client;
use Lop\LopOpensdkPhp\ExecutorFactory;
class DefaultExecutorFactory implements ExecutorFactory
{
function create($baseUri)
{
return new DefaultExecutor($baseUri);
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace Lop\LopOpensdkPhp\Support;
use Lop\LopOpensdkPhp\Executor;
use Lop\LopOpensdkPhp\Filter;
use Lop\LopOpensdkPhp\FilterChain;
use Lop\LopOpensdkPhp\SdkException;
class DefaultFilterChain implements FilterChain
{
/**
* @var Executor
*/
private $executor;
/**
* @var Filter[]
*/
private $filters;
/**
* @var int
*/
private $position;
/**
* @param Executor $executor
* @param Filter[] $filters
*/
public function __construct($executor, $filters)
{
$this->executor = $executor;
$this->filters = $filters;
$this->position = 0;
}
/**
* @throws SdkException
*/
function doFilter($request, $options)
{
if ($this->position < count($this->filters)) {
$filter = $this->filters[$this->position];
$this->position++;
return $filter->doFilter($request, $options, $this);
} else {
return $this->executor->execute($request, $options);
}
}
}

View File

@ -0,0 +1,184 @@
<?php
namespace Lop\LopOpensdkPhp\Support;
use Lop\LopOpensdkPhp\Filter;
use Lop\LopOpensdkPhp\Request;
class GenericRequest implements Request
{
/**
* @var string
*/
private $domain;
/**
* @var string
*/
private $path;
/**
* @var string
*/
private $method;
/**
* @var string[]
*/
private $queries;
/**
* @var string[]
*/
private $headers;
/**
* @var Filter[]
*/
private $filters;
/**
* @var string
*/
private $body;
/**
* @var string
*/
private $requestId;
/**
* @var string
*/
private $responseType;
public function __construct()
{
$this->queries = array();
$this->headers = array();
$this->filters = array();
}
function getDomain()
{
return $this->domain;
}
function setDomain($domain)
{
$this->domain = $domain;
}
function getPath()
{
return $this->path;
}
function setPath($path)
{
$this->path = $path;
}
function getMethod()
{
return $this->method;
}
function setMethod($method)
{
$this->method = $method;
}
function hasQuery($key)
{
return array_key_exists($key, $this->queries);
}
function getQuery($key)
{
return $this->queries[$key];
}
function setQuery($key, $value)
{
$this->queries[$key] = $value;
}
function getQueries()
{
return $this->queries;
}
function hasHeader($key)
{
return array_key_exists($key, $this->headers);
}
function getHeader($key)
{
return $this->headers[$key];
}
function setHeader($key, $value)
{
$this->headers[$key] = $value;
}
function getHeaders()
{
return $this->headers;
}
function addFilter($filter)
{
$this->filters[] = $filter;
}
function getFilters()
{
return $this->filters;
}
function getEntity()
{
return null;
}
function getBody()
{
return $this->body;
}
function setBody($body)
{
$this->body = $body;
}
function getRequestId()
{
return $this->requestId;
}
function setRequestId($requestId)
{
$this->requestId = $requestId;
}
/**
* @return string
*/
function getResponseType()
{
return $this->responseType;
}
/**
* @param string $responseType
* @return void
*/
function setResponseType($responseType)
{
$this->responseType = $responseType;
}
}

View File

@ -0,0 +1,129 @@
<?php
namespace Lop\LopOpensdkPhp\Support;
use Lop\LopOpensdkPhp\Response;
class GenericResponse implements Response
{
/**
* @var bool
*/
private $succeed;
/**
* @var string
*/
private $traceId;
/**
* @var string
*/
private $zhDesc;
/**
* @var string
*/
private $enDesc;
/**
* @var int
*/
private $code;
/**
* @var string
*/
private $status;
/**
* @var string
*/
private $body;
/**
* @var mixed
*/
private $entity;
function isSucceed()
{
return $this->succeed;
}
function setSucceed($succeed)
{
$this->succeed = $succeed;
}
function getTraceId()
{
return $this->traceId;
}
function setTraceId($traceId)
{
$this->traceId = $traceId;
}
function getZhDesc()
{
return $this->zhDesc;
}
function setZhDesc($zhDesc)
{
$this->zhDesc = $zhDesc;
}
function getEnDesc()
{
return $this->enDesc;
}
function setEnDesc($enDesc)
{
$this->enDesc = $enDesc;
}
function getCode()
{
return $this->code;
}
function setCode($code)
{
$this->code = $code;
}
function getStatus()
{
return $this->status;
}
function setStatus($status)
{
$this->status = $status;
}
function getBody()
{
return $this->body;
}
function setBody($body)
{
$this->body = $body;
}
function getEntity()
{
return $this->entity;
}
function setEntity($entity)
{
$this->entity = $entity;
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace Lop\LopOpensdkPhp;
class Version
{
const VERSION = "1.0.0";
}

View File

@ -72,9 +72,13 @@ Route::middleware(['auth:api', 'check.permissions'])->group(function () {
Route::get('shop/ship', [ShipController::class, 'index'])->name('shop_ship.index');
Route::get('print/orders', [BusinessOrderController::class, 'print'])->name('order.print');
Route::put('print/success', [BusinessOrderController::class, 'printSuccess'])->name('order.printSuccess');
Route::get('waybill/queryTrace', [\App\Http\Controllers\Business\WaybillController::class, 'queryTrace']);
Route::post('waybill/cancel', [\App\Http\Controllers\Business\WaybillController::class, 'cancel']);
// 发货信息
Route::get('shop/ship/senders', [ShipController::class, 'getSenders'])->name('shop_ship.senders.get');
Route::post('shop/ship/senders', [ShipController::class, 'saveSenders'])->name('shop_ship.senders.save');
Route::resource('shop_sends', 'Shop\ShopSendsController', ['only' => ['index', 'store']]);
// 数据中心
Route::get('data_center/sales_report', [DataCenterController::class, 'salesReport'])->name('sales_report.index');
//供应商

View File

@ -1,5 +1,6 @@
<?php
use App\Services\Business\BusinessFactory;
use Illuminate\Foundation\Inspiring;
/*
@ -14,5 +15,7 @@ use Illuminate\Foundation\Inspiring;
*/
Artisan::command('inspire', function () {
$order= \App\Models\BusinessOrder::query()->find(6582);
BusinessFactory::init()->make($order->shop->plat_id)->setShop($order->shop)->queryStatusAndSync($order);
$this->comment(Inspiring::quote());
})->describe('Display an inspiring quote');