panghu 8 meses atrás
pai
commit
469963781f

+ 417 - 0
app/Http/Controllers/Api/OrderController.php

@@ -0,0 +1,417 @@
+<?php
+
+namespace App\Http\Controllers\Api;
+
+
+
+use App\Http\Controllers\ApiController;
+use App\Servers\CommonServer;
+use App\Servers\OrderServer;
+use App\Servers\RedisDataServer;
+use App\Servers\ShoppingCartServer;
+use Carbon\Carbon;
+use Illuminate\Validation\Rules\In;
+
+/**
+ * 外卖订单
+ */
+class OrderController extends ApiController
+{
+
+    /**
+     * 前端获取订单状态
+     */
+    function getOrderStatus()
+    {
+        $statusArr = [
+            0=>'全部',
+            1=>'待支付',
+            2=>'制作中',
+            3=>'已完成',
+            4=>'已取消',
+            5=>'退款',
+        ];
+
+        $data = [];
+        foreach ($statusArr as $key=>$value){
+            $data[] = [
+                'key' => $key,
+                'name' => $value,
+            ];
+        }
+
+        return $this->apiResponseSuccess('成功',array_values($data));
+    }
+
+    /**
+     * 下单
+     */
+    function createOrder()
+    {
+        $m_id = $this->getMemberId();//用户id
+        $commonServer = CommonServer::creatServer();
+        $shop_id = $commonServer->filtrationStr('shop_id');//商家id
+        $order_type = $commonServer->filtrationStr('$order_type',1);//订单类型 1堂食订单 2打包订单
+        $table_number = $commonServer->filtrationStr('table_number');//桌号
+        $diner_number = $commonServer->filtrationStr('diner_number');//就餐人数
+        $note = $commonServer->filtrationStr('note');//备注
+
+        if (empty($shop_id)) return $this->apiResponseError('商家错误');
+        if (!in_array($order_type,[1,2])){
+            return $this->apiResponseError('就餐方式错误');
+        }
+        if (empty($table_number) || $table_number < 0) return $this->apiResponseError('桌号错误');
+        if (empty($diner_number) || $table_number < 0) return $this->apiResponseError('就餐人数错误');
+        if (!empty($note) && mb_strlen($note) > 30 ) return $this->apiResponseError('备注最大30');
+
+
+        //获取购买的商品信息
+        $goods = ShoppingCartServer::creatServer()->getShoppingList($m_id,$shop_id);
+        if (count($goods['goods_list']) <= 0) {
+            return $this->apiResponseError('商品信息错误');
+        }
+        //加锁
+        $lock_key = $shop_id.'lockOrderCreate';
+        $lock_value = uniqid(bin2hex(random_bytes(10)), true);
+        $lock = RedisDataServer::creatServer()->lockKey($lock_key,$lock_value,500);
+        if (!$lock){
+            return $this->apiResponseError('下单人数过多,请稍候');
+        }
+        //下单
+        $res = OrderServer::creatServer()->createOrder($m_id,$shop_id,$order_type,$table_number,$diner_number,$note,$goods);
+
+        //删除锁key-防止死锁
+        RedisDataServer::creatServer()->unLockKey($lock_key,$lock_value);
+        if ($res['code'] == 0) {
+            return $this->apiResponseError($res['msg']);
+        }
+
+        return $this->apiResponseSuccess('订单创建成功', $res['data']);
+    }
+
+
+    /**
+     * 获取订单支付信息
+     * @return \Illuminate\Http\JsonResponse
+     */
+    function getOrderPayInfo()
+    {
+        $m_id = $this->getMemberId();//用户id
+        $commonServer = CommonServer::creatServer();
+        $order_id = $commonServer->filtrationStr('order_id');//订单id
+        if (empty($order_id)) {
+            return $this->apiResponseError('缺少必要参数');
+        }
+        $member = Member::where('id', $m_id)->select(['id', 'money'])->first();
+        if (empty($member)) {
+            return $this->apiResponseError('会员信息错误');
+        }
+        $order_info = Order::where('id', $order_id)
+            ->where('m_id', $m_id)
+            ->where('order_status', 1)
+            ->select(['id', 'order_status', 'order_money','pay_money','coupon_money', 'order_sn', 'shop_id','created_at'])
+            ->first();
+        if (empty($order_info)) {
+            return $this->apiResponseError('订单已失效');
+        }
+        $order_info->{'member_money'} = $member['money'];//用户余额
+        //订单过期时间
+        $end_time = config('order.order_repeal_time', 10) * 60;
+        $order_info->{'time'} = strtotime($order_info->{'created_at'}) + $end_time;
+        return $this->apiResponseSuccess('获取数据成功', $order_info);
+    }
+
+    /**
+     * 支付订单
+     */
+    function payOrder()
+    {
+        $m_id = $this->getMemberId();//用户id
+        $commonServer = CommonServer::creatServer();
+        $order_id = $commonServer->filtrationStr('order_id');//订单id
+        $pay_type = $commonServer->filtrationStr('pay_type',1);//支付方式 1微信 2支付宝 3余额支付
+        $system_type = request()->input('system_type',2);//1微信h5 2微信小程序 3qq小程序
+
+        if (empty($order_id)) return $this->apiResponseError('请选择订单');
+        if (!in_array($pay_type, [1, 2, 3])) return $this->apiResponseError('支付方式错误');
+        if (!in_array($system_type, [1, 2, 3])) return $this->apiResponseError('来源平台错误');
+        $order_info = Order::where('id', $order_id)
+            ->where('m_id', $m_id)
+            ->where('order_status', 1)
+            ->select(['id', 'order_status','order_money', 'pay_money', 'order_sn', 'm_id','shop_id'])
+            ->first();
+        if (empty($order_info)) {
+            return $this->apiResponseError('订单已失效');
+        }
+
+        //获取商家状态
+        $shop_status = Shop::where('id', $order_info['shop_id'])->value('status');
+        if ($shop_status != 1) {
+            return $this->apiResponseError('商家已闭店');
+        }
+        //定义返回参数
+        $data = ['pay_status' => false, 'wx_pay' => [], 'zfb_pay' => []];
+        if($pay_type == 1) {
+            //微信支付
+            $notify_url = route('notify.order_wx');
+            $wx_openid = MemberOpenId::where('m_id', $m_id)->where('type', $system_type)->value('openid');
+            if (empty($wx_openid)) {
+                return $this->apiResponseError('用户信息错误');
+            }
+            $wx_pay = WeixinServer::creatServer()->wxJsPay($order_info->{'order_sn'}, $order_info->{'pay_money'}, $notify_url, '外卖订单', $wx_openid);
+            $data['wx_pay'] = $wx_pay;
+        }elseif ($pay_type == 2) {
+            $data['zfb_pay'] = [];
+        }else{//余额支付
+
+            $member = Member::where('id', $m_id)->select(['id', 'money'])->first();
+            if (empty($member)) {
+                return $this->apiResponseError('会员信息错误');
+            }
+            if ($member->{'money'} < $order_info->{'pay_money'}) {
+                return $this->apiResponseError('余额不足');
+            }
+
+            //余额扣款
+            $ret = OrderServer::creatServer()->balancePay($order_info);
+            if (empty($ret)) {
+                return $this->apiResponseError('余额支付失败');
+            }
+            $data['pay_status'] = true;
+        }
+
+        return $this->apiResponseSuccess('成功', $data);
+
+    }
+
+
+    /**
+     * 用户获取外卖订单列表
+     */
+    function getOrderList()
+    {
+        $m_id = $this->getMemberId();//用户id
+        $commonServer = CommonServer::creatServer();
+        $status = $commonServer->filtrationStr('status',-1);//状态 0全部 1待支付 2待接单 3配送中 4待评价 5退款/撤销
+
+        $where = [['o.m_id',$m_id], ['o.is_del',0]];
+
+        $list = Order::from('order as o')
+            ->leftJoin('shops as s','s.id','=','o.shop_id')
+            ->where($where)
+            ->where(function ($q) use ($status){
+                if ($status == 1){
+                    $q->where('o.order_status',1);
+                }elseif ($status == 2){
+                    $q->where('o.order_status',2);
+                }elseif ($status == 3){
+                    $q->whereIn('o.order_status',[4,5,6]);
+                }elseif ($status == 4){
+                    $q->where('o.order_status',7);
+                    $q->where('o.is_comment',0);
+                }elseif ($status == 5){
+                    $q->whereIn('o.order_status',[3,8,9,10]);
+                }
+            })
+            ->select(['o.id','o.order_sn','o.order_status','o.pay_money','o.is_comment','o.goods_number','o.created_at','o.shop_id','s.shop_name','s.shop_logo'])
+            ->orderBy('o.id','desc')
+            ->paginate(10);
+        foreach ($list as $value){
+            $value->{'refund_status'} = OrderDetails::where('order_id',$value->{'id'})->value('refund_status');
+            $value->{'shop_name'} = $commonServer->truncateChineseString($value->{'shop_name'},16);
+            $value->{'item'} = OrderItem::where('order_id',$value->{'id'})->select(['goods_name','goods_img'])->orderBy('id','asc')->get();
+            $value->initializeModel();
+        }
+
+        return $this->apiResponseSuccess('成功', [
+            'items' => $list->items(),
+            'total' => $list->total(),
+            'limit' => 10,
+        ]);
+    }
+
+
+    /**
+     * 取消订单
+     */
+    function cancelOrder()
+    {
+        $m_id = $this->getMemberId();//用户id
+        $commonServer = CommonServer::creatServer();
+        $order_id = $commonServer->filtrationStr('order_id');//订单id
+        $refund_msg = $commonServer->filtrationStr('refund_msg','');//退款原因
+        if (empty($order_id) || !is_numeric($order_id)) {
+            return $this->apiResponseError('请选择订单');
+        }
+        if (empty($refund_msg)) return $this->apiResponseError('请选择原因');
+
+        $order_info = Order::where('m_id', $m_id)
+            ->where('id', $order_id)
+            ->where('is_del',0)
+            ->select(['id','order_sn','m_id','operate_id','school_id', 'time', 'order_type','order_status','pay_money','pay_type','pay_code', 'shop_id','coupon_id'])
+            ->first();
+        if (empty($order_info)) return $this->apiResponseError('订单信息错误');
+
+        if (!in_array($order_info['order_status'], [2,4])) {
+            return $this->apiResponseError('当前订单不能取消');
+        }
+
+        //获取需要的配送时间
+        $date = date('Y-m-d H:i:s');
+        $current_time = Carbon::parse($date, config('app.timezone'))->format('Y-m-d H:i:s');
+        //获取需要的配送时间
+        $delivery_time = ShopServer::creatServer()->getShopDeliveryTime($order_info->{'shop_id'});
+        $time = Carbon::parse($order_info->{'time'}, config('app.timezone'))->subMinutes($delivery_time + 30)->format('Y-m-d H:i:s');
+
+        if ($order_info->{'order_status'} == 2 || $current_time < $time){//订单状态为待接单或者当前时间小于预定送达时间 - ($delivery_time + 30)
+            $ret = OrderServer::creatServer()->refundPay($order_info,'用户取消订单,原因:'.$refund_msg);
+            if (empty($ret)) {
+                return $this->apiResponseError('退款失败');
+            }
+
+            $refund_sn = $ret['refund_sn'];
+            $refund_money = $ret['refund_money'];
+            Order::where('id', $order_info->{'id'})->update(['order_status' => 8]);
+            OrderDetails::where('order_id', $order_info->{'id'})->update(['refund_status' => 2,'refund_sn'=>$refund_sn,'refund_money'=>$refund_money,'refund_msg'=>$refund_msg]);
+            //添加记录
+            OrderRecordServer::creatServer()->writeRecord($order_info->{'id'},$order_info->{'shop_id'},0,0,'用户发起订单退款,退款完成,原因:'.$refund_msg);
+
+            //回退优惠卷
+            CouponServer::creatServer()->backCoupon($order_info->{'m_id'},$order_info->{'coupon_id'});
+            //获取订单商品,商品不是无限库存需要回退库存
+            $goods = OrderItem::from('order_item as i')
+                ->leftJoin('goods as g','g.id','=','i.goods_id')
+                ->where('i.order_id',$order_id)
+                ->select(['i.goods_number','i.goods_id','i.goods_spec_id','i.seckill_money','g.is_infinite','g.stock'])
+                ->get();
+            foreach ($goods as $value){
+                if ($value->{'is_infinite'} != 1){//回退库存
+                    Goods::where('id',$value['goods_id'])->increment('stock',$value['goods_number']);
+                }
+                if ($value->{'seckill_money'} > 0){
+                    $key_name = 'seckill_'.$value['goods_id'];
+
+                    RedisDataServer::creatServer()->addOneQueue($key_name, 1);
+                }
+            }
+            //投递用户订单统计任务
+            JobServer::creatServer()->sendMemberOrderTotal($order_info->{'m_id'},$order_info->{'school_id'},1,$order_info->{'created_at'},0,$order_info->{'pay_money'});
+            //投递商户订单统计任务
+            JobServer::creatServer()->sendShopOrderTotal($order_info->{'shop_id'},$order_info->{'school_id'},1,$order_info->{'created_at'},0,$order_info->{'pay_money'});
+            JobServer::creatServer()->sendSchoolOrderTotal($order_info->{'school_id'},1,$order_info->{'created_at'},0,$order_info->{'pay_money'});
+
+            return $this->apiResponseSuccess('退款成功');
+        }else{//已接单需要商家同意
+            $ret = Order::where('id', $order_info->{'id'})->update(['order_status' => 8]);
+            OrderDetails::where('order_id', $order_info->{'id'})->update(['refund_status' => 1,'refund_msg'=>$refund_msg]);
+            if (empty($ret)) {
+                return $this->apiResponseError('申请退款失败');
+            } else {
+                //添加记录
+                OrderRecordServer::creatServer()->writeRecord($order_info->{'id'},$order_info->{'shop_id'},0,0,'用户发起订单退款,等待商家确认,原因:'.$refund_msg);
+                //投递打印任务
+                JobServer::creatServer()->cancelOrderPrintJob($order_info->{'id'},$order_info->{'shop_id'},1);
+                return $this->apiResponseSuccess('等待商家同意中');
+            }
+        }
+
+    }
+
+
+    /**
+     * 订单详情
+     */
+    function getOrderInfo()
+    {
+        $m_id = $this->getMemberId();//用户id
+        $commonServer = CommonServer::creatServer();
+        $order_id = $commonServer->filtrationStr('order_id');//订单id
+
+        if (empty($order_id)) return $this->apiResponseError('请选择订单');
+
+        $where = [['o.m_id',$m_id], ['o.is_del',0], ['o.id',$order_id]];
+
+        $order = Order::from('order as o')
+            ->leftJoin('order_address as a','a.order_id','=','o.id')
+            ->leftJoin('order_details as d','d.order_id','=','o.id')
+            ->where($where)
+            ->select(['o.id','o.order_sn','o.time','o.pay_type','o.m_id','o.note','o.order_status','o.pay_money','o.is_comment','o.goods_number','o.coupon_money','o.shop_id','o.created_at','d.refund_status','d.pack_price','d.delivery_money','d.finish_time','d.finish_image','a.school_id','a.dorm_id','a.consignee','a.phone as consignee_tel','a.address'])
+            ->first();
+        if (empty($order)) return $this->apiResponseError('订单不存在');
+        $order->{'school_name'} = School::where('id',$order->{'school_id'})->value('school_name');
+        $order->{'dorm_name'} = SchoolDorm::where('id',$order->{'dorm_id'})->value('name');
+        $order->{'shop'} = Shop::where('id',$order->{'shop_id'})->select(['shop_name','shop_logo','shop_phone'])->first();
+        $order->{'item'} = OrderItem::where('order_id',$order_id)
+            ->select(['goods_name','goods_img','goods_attr','goods_number','goods_price'])
+            ->orderBy('id','asc')
+            ->get();
+
+        //获取最新的骑手id
+        $rider_id = OrderRecord::where('order_id',$order_id)->where('rider_id','>',0)->orderBy('id','desc')->value('rider_id');
+        if (!empty($rider_id)){
+            $rider = Rider::where('id',$rider_id)->select(['rider_name','phone'])->first();
+        }else{
+            $rider['rider_name'] = '';
+            $rider['phone'] = '';
+        }
+        $order->{'rider'} = $rider;
+
+        $order->initializeModel();
+
+        return $this->apiResponseSuccess('成功', $order);
+    }
+
+
+    /**
+     * 修改收货地址
+     */
+    function updateAddress()
+    {
+        $m_id = $this->getMemberId();//用户id
+        $commonServer = CommonServer::creatServer();
+        $order_id = $commonServer->filtrationStr('order_id');//订单id
+        $address_id = $commonServer->filtrationStr('address_id', '');//地址id
+        if (empty($order_id) || !is_numeric($order_id)) {
+            return $this->apiResponseError('缺少必要参数');
+        }
+        if (empty($address_id)) {
+            return $this->apiResponseError('请输入新地址信息');
+        }
+
+        $where = [['m_id', $m_id], ['id',$order_id], ['is_del', 0]];
+        $order = Order::where($where)
+            ->select(['id', 'order_sn', 'order_status', 'm_id'])
+            ->orderBy('id', 'desc')
+            ->first();
+        if (empty($order)) {
+            return $this->apiResponseError('订单信息错误');
+        }
+        if ($order->{'order_status'} > 2) {
+            return $this->apiResponseError('订单状态错误');
+        }
+        //获取地址信息
+        $address_info = MemberAddress::where('m_id',$m_id)
+            ->where('id',$address_id)
+            ->where('is_del',0)
+            ->select(['id','phone','school_id','dorm_id','consignee','address'])
+            ->first();
+        if (empty($address_info)) {
+            return $this->apiResponseError('地址信息错误');
+        }
+
+        $info = OrderAddress::where('m_id',$m_id)->where('order_id',$order_id)->select(['id','school_id'])->first();
+        //判断收货地址是否在一个学校
+        if ($info->{'school_id'} != $address_info->{'school_id'}) {
+            return $this->apiResponseError('收货地址与该订单不在同一学校');
+        }
+
+        $res = OrderServer::creatServer()->saveAddress($m_id,$order_id, $address_info);
+
+        if (!$res) {
+            return $this->apiResponseError('修改失败');
+        }
+        //添加记录
+        OrderRecordServer::creatServer()->writeRecord($order_id,0,0,0,'用户修改收货地址');
+        return $this->apiResponseSuccess('修改成功');
+    }
+}

+ 48 - 0
app/Jobs/PrintOrderJob.php

@@ -0,0 +1,48 @@
+<?php
+
+namespace App\Jobs;
+
+use App\Models\ShopPrinter;
+use App\Servers\printer\PrinterServer;
+use Illuminate\Bus\Queueable;
+use Illuminate\Contracts\Queue\ShouldBeUnique;
+use Illuminate\Contracts\Queue\ShouldQueue;
+use Illuminate\Foundation\Bus\Dispatchable;
+use Illuminate\Queue\InteractsWithQueue;
+use Illuminate\Queue\SerializesModels;
+
+class PrintOrderJob implements ShouldQueue
+{
+    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+
+    private $order_id;
+    private $shop_id;
+    /**
+     * Create a new job instance.
+     *
+     * @return void
+     */
+    public function __construct($order_id, $shop_id)
+    {
+        $this->order_id = $order_id;
+        $this->shop_id = $shop_id;
+    }
+
+    /**
+     * Execute the job.
+     *
+     */
+    public function handle()
+    {
+        $order_id = $this->order_id;
+        var_dump('外卖订单打印消息队列处理',$order_id);
+        $shop_id = $this->shop_id;
+        //获取商家打印机
+        $printer = ShopPrinter::where('shop_id',$shop_id)->where('is_del',0)->get();
+        foreach ($printer as $value){
+            $res = PrinterServer::creatServer()->sendPrints($value->{'brand_id'},$value->{'sn'},$order_id);
+            var_dump($res);
+        }
+        return true;
+    }
+}

+ 94 - 0
app/Models/Order.php

@@ -0,0 +1,94 @@
+<?php
+
+namespace App\Models;
+
+use DateTimeInterface;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 外卖订单
+ */
+class Order extends Model
+{
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected $table = 'order';
+
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected $primaryKey = 'id';
+
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public $timestamps = true;
+
+
+    /**
+     * 不能被批量赋值的属性
+     *
+     * @var array
+     */
+    protected $guarded = ['id', 'updated_at', 'created_at'];
+
+    private $orderStatusEnum=[
+        1=>'待支付',
+        2=>'制作中',
+        3=>'已完成',
+        4=>'已取消',
+        5=>'退款',
+    ];
+    private $refundStatusEnum=[
+        1=>'等待商家同意',
+        2=>'退款成功',
+        3=>'拒绝退款',
+    ];
+
+    private $payTypeEnum=[
+        1=>'微信',
+        2=>'支付宝',
+        3=>'余额支付',
+    ];
+
+    private $orderTypeEnum=[
+        1=>'堂食订单',
+        2=>'打包订单',
+    ];
+
+    /**
+     * 为数组 / JSON 序列化准备日期。
+     *
+     * @param DateTimeInterface $date
+     * @return string
+     */
+    protected function serializeDate(DateTimeInterface $date)
+    {
+        return $date->format($this->dateFormat ?: 'Y-m-d H:i:s');
+    }
+
+    /**
+     * 序列化数据字典
+     */
+    function initializeModel(){
+        if($this->{'order_status'}!==null){
+            if ($this->{'order_status'} == 8){
+                $this->{'order_status_str'}=empty($this->refundStatusEnum[$this->{'refund_status'}])?'无':$this->refundStatusEnum[$this->{'refund_status'}];
+            }else{
+                $this->{'order_status_str'}=empty($this->orderStatusEnum[$this->{'order_status'}])?'无':$this->orderStatusEnum[$this->{'order_status'}];
+            }
+        }
+        if($this->{'pay_type'}!==null){
+            $this->{'pay_type_str'}=empty($this->payTypeEnum[$this->{'pay_type'}])?'无':$this->payTypeEnum[$this->{'pay_type'}];
+
+        }
+    }
+
+}

+ 43 - 0
app/Models/OrderItem.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Models;
+
+use DateTimeInterface;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 外卖订单商品子表
+ */
+class OrderItem extends Model
+{
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected $table = 'order_item';
+
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected $primaryKey = 'id';
+
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public $timestamps = true;
+
+
+    /**
+     * 不能被批量赋值的属性
+     *
+     * @var array
+     */
+    protected $guarded = ['id', 'updated_at', 'created_at'];
+
+
+}

+ 53 - 0
app/Models/ShopPrinter.php

@@ -0,0 +1,53 @@
+<?php
+
+namespace App\Models;
+
+use DateTimeInterface;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * 商家打印机表
+ */
+class ShopPrinter extends Model
+{
+    /**
+     * The table associated with the model.
+     *
+     * @var string
+     */
+    protected $table = 'shops_printer';
+
+    /**
+     * The primary key associated with the table.
+     *
+     * @var string
+     */
+    protected $primaryKey = 'id';
+
+    /**
+     * Indicates if the model should be timestamped.
+     *
+     * @var bool
+     */
+    public $timestamps = true;
+
+
+    /**
+     * 不能被批量赋值的属性
+     *
+     * @var array
+     */
+    protected $guarded = ['id', 'updated_at', 'created_at'];
+
+
+    /**
+     * 为数组 / JSON 序列化准备日期。
+     *
+     * @param DateTimeInterface $date
+     * @return string
+     */
+    protected function serializeDate(DateTimeInterface $date)
+    {
+        return $date->format($this->dateFormat ?: 'Y-m-d H:i:s');
+    }
+}

+ 50 - 0
app/Servers/JobServer.php

@@ -0,0 +1,50 @@
+<?php
+
+
+namespace App\Servers;
+
+
+
+
+use App\Jobs\PrintOrderJob;
+
+/**
+ * Redis数据缓存类
+ */
+class JobServer
+{
+
+
+    static private $server = '';
+
+
+    private function __construct()
+    {
+
+    }
+
+    /**
+     * 创建对象
+     * @return JobServer
+     */
+    static function creatServer()
+    {
+        if (empty(self::$server)) {
+            self::$server = new  JobServer();
+        }
+        return self::$server;
+    }
+
+    /**
+     * 外卖订单小票打印任务
+     * @param $order_id
+     * @param $shop_id
+     * @param $time
+     * @return void
+     */
+    function shopOrderPrintJob($order_id,$shop_id)
+    {
+        PrintOrderJob::dispatch($order_id,$shop_id)->onConnection('redis')->onQueue('printOrder');
+    }
+
+}

+ 206 - 0
app/Servers/OrderServer.php

@@ -0,0 +1,206 @@
+<?php
+
+
+namespace App\Servers;
+
+
+
+use App\Models\Config;
+use App\Models\ErrorRecord;
+use App\Models\Goods;
+use App\Models\Order;
+use App\Models\OrderItem;
+use Carbon\Carbon;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 外卖订单管理
+ */
+class OrderServer
+{
+
+    static private $server = null;
+
+
+    private function __construct()
+    {
+
+    }
+
+    /**
+     * 创建对象
+     * @return OrderServer
+     */
+    static function creatServer()
+    {
+        if (empty(self::$server)) self::$server = new OrderServer();
+        return self::$server;
+    }
+
+    function createOrder($m_id,$shop_id,$order_type,$table_number,$diner_number,$note,$goods_data)
+    {
+        DB::beginTransaction();
+        try {
+            //手续费比例
+            $service_num = CommonServer::creatServer()->getConfigValue('service_num');
+            if (empty($service_num)) {
+                $service_num = 0.6;
+            }
+            //商品金额
+            $goods_money = $goods_data['total_goods_money'];//商品总价
+            $goods_number = $goods_data['total_num'];//商品总数
+            $pack_price = $goods_data['pack_price'];//打包费
+            $order_money = bcadd($goods_money, $pack_price, 2);//订单金额 =(商品金额 + 打包费)
+            //预留优惠卷金额
+            $coupon_money = 0;
+            //用户支付金额=订单金额 - 优惠卷金额
+            $pay_money = bcsub($order_money,$coupon_money,2);
+            $service_money = bcdiv(bcmul($pay_money,$service_num,2),100,2);//交易支付手续费
+            //商家到账金额 = 订单金额-交易支付手续费
+            $shop_money = bcsub($order_money,$service_money,2);
+            //信息入库
+            $order_info = [
+                'order_sn' => CommonServer::creatServer()->createOrderNo('WDO'),
+                'order_type' => $order_type,
+                'm_id' => $m_id,
+                'shop_id' => $shop_id,
+                'order_money' => $order_money,
+                'pay_money' => $pay_money,
+                'goods_number' => $goods_number,
+                'table_number' => $table_number,
+                'diner_number' => $diner_number,
+                'note' => $note,
+                'service_num' => $service_num,
+                'service_money' => $service_money,
+                'pack_price' => $pack_price,
+                'shop_money' => $shop_money,
+            ];
+            //主表信息入库
+            $order = Order::create($order_info);
+            $order_id = $order->{'id'};
+            if (empty($order_id)){
+                DB::rollBack();
+                return ['code' => 0, 'msg' => '订单创建失败'];
+            }
+            //商品信息入库
+            $goods_total_money = 0;//商品总金额
+            foreach ($goods_data['goods_list'] as $goods){
+                if ($shop_id != $goods['shop_id']){
+                    DB::rollBack();
+                    return ['code' => 0, 'msg' => '商品与商家不符'];
+                }
+                $goods_info = [
+                    'm_id' => $m_id,
+                    'shop_id' => $shop_id,
+                    'order_id' => $order_id,
+                    'goods_id' => $goods['goods_id'],
+                    'goods_spec_id' => empty($goods['goods_spec_id']) ? '' : $goods['goods_spec_id'],
+                    'goods_name' => $goods['goods_name'],
+                    'goods_img' => $goods['goods_image'],
+                    'goods_attr' => trim($goods['goods_attr'],','),
+                    'goods_price' => $goods['price'],
+                    'goods_number' => $goods['goods_number'],
+                    'goods_money' => $goods['goods_money'],
+                ];
+                //总商品金额
+                $goods_total_money = bcadd($goods_total_money,$goods_info['goods_money'],2);
+                //商品没有设置无限库存,扣减库存
+                if ($goods['is_infinite'] != 1){
+                    $goodsStock = Goods::where('id',$goods_info['goods_id'])->select(['id','stock'])->first();
+                    if (empty($goodsStock)){
+                        DB::rollBack();
+                        return ['code' => 0, 'msg' => '商品不存在'];
+                    }
+                    //剩余库存
+                    $surplus_stock = bcsub($goodsStock->{'stock'},$goods_info['goods_number']);
+                    if ($surplus_stock < 0){
+                        DB::rollBack();
+                        return ['code' => 0, 'msg' => $goods_info['goods_name'].'商品库存不足'];
+                    }
+
+                    $update['stock'] = $surplus_stock;
+                    if ($surplus_stock <= 0){//设置商品售罄
+                        $update['status'] = 3;
+                    }
+
+                    Goods::where('id',$goods_info['goods_id'])->update($update);
+                }
+
+                OrderItem::create($goods_info);
+            }
+
+            //删除购物车
+            $shopping = ShoppingCartServer::creatServer()->delShopping($m_id,$shop_id);
+            if ($shopping['code'] == 0){
+                DB::rollBack();
+                return ['code' => 0, 'msg' => '下单失败'];
+            }
+
+            DB::commit();
+            return ['code' => 1, 'msg' => '成功', 'data' => ['order_id'=>$order_id]];
+        }catch (\Exception $e){
+            DB::rollBack();
+            return ['code'=>0,'msg'=>'下单出错'];
+        }
+    }
+
+
+    /**
+     * 支付回调
+     * @param $pay_type
+     * @param $order_sn
+     * @param $pay_code
+     * @param $pay_money
+     * @param $notify_info
+     * @return bool
+     */
+    function NotifyPay($pay_type,$order_sn, $pay_code, $pay_money, $notify_info)
+    {
+        $order_info = Order::where('order_sn', $order_sn)->where('order_status', 1)->first();
+        if (empty($order_info)) {
+            ErrorRecord::create(['msg' => $order_sn . '订单支付状态错误', 'data' => serialize($notify_info)]);
+            return false;
+        }
+//        $is_test = env('TEST_SERVE', false);
+        $is_test=config('weixin.test_serve',false);
+        if ($order_info->{'pay_money'} != $pay_money && !$is_test) {
+            Order::where('id', $order_info->{'id'})->update(['pay_code' => $pay_code]);
+            ErrorRecord::create(['msg' => $order_info->{'order_sn'} . '支付金额不匹配', 'data' => serialize($notify_info)]);
+            return false;
+        }
+
+        $date = date('Y-m-d H:i:s');
+        $shop_id = $order_info->{'shop_id'};
+        //店铺订单序号生成
+        $key = $shop_id . '_number';
+        $total_count = RedisDataServer::creatServer()->getData($key);
+        if (empty($total_count)){
+            $total_count = '1';
+
+            // 获取当前时间戳
+            $now = time();
+            // 获取今天结束的时间戳
+            $endOfDay = strtotime("tomorrow") - 1;
+            // 计算剩余时间(秒)
+            $secondsLeft = bcsub($endOfDay,$now,1);
+            RedisDataServer::creatServer()->setData($key,$total_count,'str',$secondsLeft);
+        }
+        RedisDataServer::creatServer()->setIncr($key);
+
+        //订单更新信息
+        $update['pay_type'] = $pay_type;
+        $update['pay_time'] = $date;
+        $update['pay_code'] = $pay_code;
+        $update['number'] = $total_count;
+        $update['order_status'] = 2;
+
+        //更新订单信息
+        Order::where('id', $order_info->{'id'})->update($update);
+
+        // 投递打印消息
+        JobServer::creatServer()->shopOrderPrintJob($order_info->{'id'},$order_info->{'shop_id'});
+
+        return true;
+
+    }
+}

+ 162 - 0
app/Servers/printer/NoteFormatterServer.php

@@ -0,0 +1,162 @@
+<?php
+
+
+namespace App\Servers\printer;
+
+
+/**
+ * 打印机格式化服务
+ */
+class NoteFormatterServer
+{
+    /**
+     * 58mm 系列打印机模板
+     */
+    public const ROW_MAX_CHAR_LEN = 32;//行最大字符长度
+    private const MAX_NAME_CHAR_LEN = 20;//最大名称字符长度
+    private const LAST_ROW_MAX_NAME_CHAR_LEN = 16;//最后一行最大名称字符长度
+    private const MAX_QUANTITY_CHAR_LEN = 6;//数量最大长度
+    private const MAX_PRICE_CHAR_LEN = 6;//价格最大长度
+    /**
+     * 错误信息
+     * @var string
+     */
+    private $errorMsg = '';
+
+    static private $server = '';
+
+
+    private function __construct()
+    {
+    }
+
+
+
+    /**
+     * 创建对象
+     * @return NoteFormatterServer
+     */
+    static function creatServer()
+    {
+        if (empty(self::$server)) {
+            self::$server = new NoteFormatterServer();
+        }
+        return self::$server;
+    }
+
+
+    /**
+     * 格式化菜品列表(用于58mm打印机)
+     * 注意:默认字体排版,若是字体宽度倍大后不适用
+     * 58mm打印机一行可打印32个字符 汉子按照2个字符算
+     * 分3列: 名称20字符一般用16字符4空格填充  数量6字符  单价6字符,不足用英文空格填充 名称过长换行
+     *
+     */
+
+    public static function formatPrintOrderItem($foodName, $quantity, $price,$is_yly=0)
+    {
+        $orderNameEmpty = str_repeat(" ", self::MAX_NAME_CHAR_LEN);
+        $foodNameLen = self::CalcGbkLenForPrint($foodName);
+//         print("foodNameLen=".$foodNameLen."\n");
+
+        $quantityStr = '*' . $quantity;
+        $quantityLen = self::CalcAsciiLenForPrint($quantityStr);
+        // print("quantityLen=".$quantityLen."\n");
+
+        $priceStr = '' . round($price, 2);
+        $priceLen = self::CalcAsciiLenForPrint($priceStr);
+        // print("priceLen=".$priceLen);
+
+        $result = $foodName;
+        $mod = $foodNameLen % self::ROW_MAX_CHAR_LEN;
+        // print("mod=".$mod."\n");
+
+        if ($mod <= self::LAST_ROW_MAX_NAME_CHAR_LEN) {
+            // 保证各个列的宽度固定,不足部分,利用空格填充
+            //make sure all the column length fixed, fill with space if not enough
+            $result = $result . str_repeat(" ", self::MAX_NAME_CHAR_LEN - $mod);
+
+        } else {
+            // 另起新行
+            // new line
+            if ($is_yly){
+                $result = $result . "\n";
+            }else{
+                $result = $result . "<BR>";
+            }
+            $result = $result . $orderNameEmpty;
+        }
+
+        $result = $result . $quantityStr . str_repeat(" ", self::MAX_QUANTITY_CHAR_LEN - $quantityLen);
+        $result = $result . $priceStr . str_repeat(" ", self::MAX_PRICE_CHAR_LEN - $priceLen);
+
+//        $result = '<L><HB>'.$result . "</L></HB><BR>";
+
+        return $result;
+    }
+
+    /**
+     * 大趋智能格式化菜品列表(用于58mm打印机)
+     * @param $foodName
+     * @param $quantity
+     * @param $price
+     * @return string
+     */
+    public static function trenditFormatOrderItem($foodName, $quantity, $price)
+    {
+        $orderNameEmpty = str_repeat(" ", self::MAX_NAME_CHAR_LEN);
+        $foodNameLen = self::CalcGbkLenForPrint($foodName);
+//         print("foodNameLen=".$foodNameLen."\n");
+
+        $quantityStr = '*' . $quantity;
+        $quantityLen = self::CalcAsciiLenForPrint($quantityStr);
+        // print("quantityLen=".$quantityLen."\n");
+
+        $priceStr = '' . round($price, 2);
+        $priceLen = self::CalcAsciiLenForPrint($priceStr);
+        // print("priceLen=".$priceLen);
+
+        $result = $foodName;
+        $mod = $foodNameLen % self::ROW_MAX_CHAR_LEN;
+        // print("mod=".$mod."\n");
+
+        if ($mod <= self::LAST_ROW_MAX_NAME_CHAR_LEN) {
+            // 保证各个列的宽度固定,不足部分,利用空格填充
+            //make sure all the column length fixed, fill with space if not enough
+            $result = $result . str_repeat(" ", self::MAX_NAME_CHAR_LEN - $mod);
+
+        } else {
+            // 另起新行
+            // new line
+//            $result = $result . '<BR>';
+            $result = $result . $orderNameEmpty;
+        }
+
+        $result = $result . $quantityStr . str_repeat(" ", self::MAX_QUANTITY_CHAR_LEN - $quantityLen);
+        $result = $result . $priceStr . str_repeat(" ", self::MAX_PRICE_CHAR_LEN - $priceLen);
+
+        $result = '<LEFT><font# height=2>'.$result . '</font#></LEFT><BR>';
+
+        return $result;
+    }
+
+
+    public static function CalcGbkLenForPrint($data)
+    {
+        return (strlen($data) + mb_strlen($data, "UTF8")) / 2;
+    }
+
+    public static function CalcAsciiLenForPrint($data)
+    {
+        return strlen($data);
+    }
+
+    /**
+     * @return string
+     */
+    public function getErrorMsg(): string
+    {
+        return $this->errorMsg;
+    }
+
+}

+ 165 - 0
app/Servers/printer/PrinterServer.php

@@ -0,0 +1,165 @@
+<?php
+
+
+namespace App\Servers\printer;
+
+
+
+use App\Models\ErrorRecord;
+use App\Models\Order;
+use App\Models\OrderItem;
+
+/**
+ * 打印机服务
+ */
+class PrinterServer
+{
+    /**
+     * 错误信息
+     * @var string
+     */
+    private $errorMsg = '';
+
+    static private $server = '';
+
+
+    private function __construct()
+    {
+    }
+
+
+
+    /**
+     * 创建对象
+     * @return PrinterServer
+     */
+    static function creatServer()
+    {
+        if (empty(self::$server)) {
+            self::$server = new PrinterServer();
+        }
+        return self::$server;
+    }
+
+    /**
+     * 添加打印机
+     * @param $brand_id
+     * @param $sn
+     * @param $key
+     * @param string $name
+     * @return bool
+     */
+    function addPrinter($brand_id,$sn,$key,$name='')
+    {
+        if ($brand_id == 1){//商鹏
+            $sendServer = SpyunServer::creatServer();
+        }elseif ($brand_id == 2){//飞鹅
+            $sendServer = FeieYunServer::creatServer();
+        }elseif ($brand_id == 3){//芯烨
+            $sendServer = XprinterServer::creatServer();
+        }elseif ($brand_id == 4){//佳博
+            $sendServer = PoscomServer::creatServer();
+        }elseif ($brand_id == 5){//大趋智能
+            $sendServer = TrenditServer::creatServer();
+        }elseif ($brand_id == 6){//易联云
+            $sendServer = YlyServer::creatServer();
+        }
+
+
+        $result = $sendServer->addPrinter($sn,$key,$name);
+
+        if (!$result) {
+            $this->errorMsg = $sendServer->getErrorMsg();
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 删除打印机
+     * @param $brand_id
+     * @param $sn
+     * @return bool
+     */
+    function delPrinter($brand_id,$sn)
+    {
+        if ($brand_id == 1){//商鹏
+            $sendServer = SpyunServer::creatServer();
+        }elseif ($brand_id == 2){//飞鹅
+            $sendServer = FeieYunServer::creatServer();
+        }elseif ($brand_id == 3){//芯烨
+            $sendServer = XprinterServer::creatServer();
+        }elseif ($brand_id == 4){//佳博
+            $sendServer = PoscomServer::creatServer();
+        }elseif ($brand_id == 5){//大趋智能
+            $sendServer = TrenditServer::creatServer();
+        }elseif ($brand_id == 6){//易联云
+            $sendServer = YlyServer::creatServer();
+        }
+
+        $result = $sendServer->deletePrinter($sn);
+
+        if (!$result) {
+            $this->errorMsg = $sendServer->getErrorMsg();
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 发送打印
+     * @return bool
+     */
+    function sendPrints($brand_id,$sn,$order_id,$is_test=0)
+    {
+        if (!$is_test){
+            $order = Order::where('id',$order_id)
+                ->where('is_del',0)
+                ->where('order_status',2)
+                ->select(['id','order_sn','m_id','order_type','number','note','pay_money','goods_number','pack_price','created_at','shop_id'])
+                ->first();
+            if (empty($order)) {
+                ErrorRecord::create(['msg' => '订单不存在打印失败:', 'data' => $order_id]);
+                $this->errorMsg = '订单不存在';
+                return false;
+            }
+            $order->{'item'} = OrderItem::where('order_id',$order_id)->select(['goods_name','goods_attr','goods_number','goods_price'])->get();
+        }else{
+            $order = [];
+        }
+
+
+        if ($brand_id == 1){
+            $sendServer = SpyunServer::creatServer();
+        }elseif ($brand_id == 2){//飞鹅
+            $sendServer = FeieYunServer::creatServer();
+        }elseif ($brand_id == 3){//芯烨
+            $sendServer = XprinterServer::creatServer();
+        }elseif ($brand_id == 4){//佳博
+            $sendServer = PoscomServer::creatServer();
+        }elseif ($brand_id == 5){//大趋智能
+            $sendServer = TrenditServer::creatServer();
+        }elseif ($brand_id == 6){//易联云
+            $sendServer = YlyServer::creatServer();
+        }
+
+        $result = $sendServer->prints($is_test,$sn,$order);
+
+        if (!$result) {
+            $this->errorMsg = $sendServer->getErrorMsg();
+            ErrorRecord::create(['msg' => '订单不存在打印失败:'.$sendServer->getErrorMsg(), 'data' => $order_id]);
+            return false;
+        }
+        return $result;
+    }
+
+
+    /**
+     * @return string
+     */
+    public function getErrorMsg(): string
+    {
+        return $this->errorMsg;
+    }
+
+}

+ 442 - 0
app/Servers/printer/SpyunServer.php

@@ -0,0 +1,442 @@
+<?php
+
+namespace App\Servers\printer;
+
+
+
+use App\Models\ErrorRecord;
+
+/**
+ * 商鹏云打印机
+ */
+class SpyunServer
+{
+    static private $server = '';
+    /**
+     * 基本请求地址
+     */
+    const BASE_URI = 'https://open.spyun.net/v1/';
+
+    /**
+     * 连接超时时间
+     */
+    const CONNECTTIMEOUT = 1;
+
+    /**
+     * 超时时间
+     */
+    const TIMEOUT = 4;
+
+    /**
+     * @var string
+     */
+    protected $appid;
+
+    /**
+     * @var $appsecret
+     */
+    protected $appsecret;
+
+    /**
+     * @var string
+     */
+    protected $errorMsg='';
+    private function __construct()
+    {
+
+        $this->appid = 'sp666bb6c23d74d';
+        $this->appsecret = '763b867b7927cf7907a8b2fc3bc0eddf';
+    }
+
+    /**
+     * 创建对象
+     * @return SpyunServer
+     */
+    static function creatServer()
+    {
+        if (empty(self::$server)) {
+            self::$server = new  SpyunServer();
+        }
+        return self::$server;
+    }
+
+    /**
+     * 添加打印机
+     * @param $sn
+     * @param $pkey
+     * @param $name
+     * @return mixed
+     */
+    public function addPrinter($sn, $pkey, $name)
+    {
+        $res = $this->http_request('POST','printer/add', $this->makeRequestParams([
+            'sn' => $sn,
+            'pkey' => $pkey,
+            'name' => $name,
+        ]));
+        if (empty($res) && !isset($res['errorcode'])){
+            return false;
+        }
+        if ($res['errorcode'] != 0){
+            $this->errorMsg = $res['errormsg'];
+            ErrorRecord::create(['msg' => $sn . '尚鹏云打印机绑定失败', 'data' => json_encode($res)]);
+            return false;
+        }
+        return true;
+    }
+    /**
+     * 删除打印机
+     * @param string $sn
+     * @return bool
+     */
+    public function deletePrinter($sn)
+    {
+        $res = $this->http_request('DELETE','printer/delete', $this->makeRequestParams([
+            'sn' => $sn,
+        ]));
+        if (empty($res) && !isset($res['errorcode'])){
+            return false;
+        }
+        if ($res['errorcode'] != 0){
+            $this->errorMsg = $res['errormsg'];
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 打印订单
+     * @param int $sn
+     * @param array $order
+     * @param int $times
+     * @return bool
+     */
+    public function prints($is_test,$sn, $order, $times = 1)
+    {
+        if ($is_test){
+            $content = $this->getSpyunDemoContent();
+        }else{
+            $content = $this->getSpyunContent($order);
+        }
+
+
+        $res =  $this->http_request('POST',"printer/print", $this->makeRequestParams([
+            'sn' => $sn,
+            'content' => $content,
+            'times' => $times
+        ]));
+
+        if (empty($res) && !isset($res['errorcode'])){
+            return false;
+        }
+        if ($res['errorcode'] != 0){
+            $this->errorMsg = $res['errormsg'];
+            ErrorRecord::create(['msg' => $sn . '尚鹏云打印机打印失败', 'data' => $res['errormsg']]);
+            return false;
+        }
+        return $res['id'];
+    }
+
+    /**
+     * 用户取消订单打印
+     * @param $sn
+     * @param $order
+     * @param $times
+     * @return false|mixed
+     */
+    function cancelOrderPrints($sn, $order, $times = 1)
+    {
+
+        $content = $this->getSpyunCancelOrderContent($order);
+
+
+        $res =  $this->http_request('POST',"printer/print", $this->makeRequestParams([
+            'sn' => $sn,
+            'content' => $content,
+            'times' => $times
+        ]));
+
+        if (empty($res) && !isset($res['errorcode'])){
+            return false;
+        }
+        if ($res['errorcode'] != 0){
+            $this->errorMsg = $res['errormsg'];
+            ErrorRecord::create(['msg' => $sn . '尚鹏云打印机打印失败', 'data' => $res['errormsg']]);
+            return false;
+        }
+        return $res['id'];
+    }
+
+
+    /**
+     * @param $order_id
+     * @return string
+     */
+    function getSpyunContent($order)
+    {
+        $orderItem = $order->{'item'};
+
+        $NoteFormatterServer = NoteFormatterServer::creatServer();
+        $content = '<CB>#' . $order->{'number'} . ' 君子校园</CB><BR>';
+        $content .= '<C>' . $order->{'shop_name'} . '<C><BR>';
+        $content .= str_repeat('-', 32) . "<BR>";
+
+        $content .= '<CB>建议制作时间:' . $order->{'time_str'} . '</CB><BR>';
+        $content .= '期望送达时间:' . $order->{'time'} . '<BR>';
+        //下单时间
+
+        $content .= str_repeat('-', 32) . "<BR>";
+        $content .= '下单时间:'.$order->{'created_at'}. '<BR>';
+        $content .= '订单编号:'.$order->{'order_sn'}. '<BR>';
+        $content .= str_repeat('-', 32) . "<BR>";
+        //商品信息
+        foreach ($orderItem as $value){
+            $goods_name = $value->{'goods_name'} . '(' . $value->{'goods_attr'} . ')';
+            $content .=  '<H>'.$NoteFormatterServer::formatPrintOrderItem($goods_name, $value->{'goods_number'}, $value->{'goods_price'}). '</H><BR>';
+        }
+        $content .= '<B>共:' . $order->{'goods_number'} . '件</B><BR>';
+        $content .= '<L1>' . '备注:'.$order->{'note'} . '</L1><BR>';
+        $content .= str_repeat('-', 32) . '<BR>';
+        $content .= '打包费:' . $order->{'pack_price'} .  '<BR>';
+        $content .= '促销优惠:' . $order->{'coupon_money'} .  '<BR>';
+        $content .= '<H>' . '合计支付:' . $order->{'pay_money'} .  '</H><BR>';
+        $content .= str_repeat('-', 32) . '<BR>';
+
+        $content .= '<L1>' . $order->{'consignee'} . '<L1><BR>';
+        $content .= '<L1>' . $order->{'phone'} . '<L1><BR>';
+        $content .= '<L1>' . $order->{'school_name'} . $order->{'dorm_name'} . $order->{'address'} . '<L1><BR>';
+        $content .= '<QRCODE>'.$order->{'m_id'} . '_' .$order->{'order_sn'}.'</QRCODE>';
+        $content .= '<BR>';
+        $content .= '<CB>***结束***</CB><BR><BR>';
+
+        return $content;
+    }
+
+    function getSpyunCancelOrderContent($order)
+    {
+        $content = '<CB>#' . $order->{'number'} . ' XXXX</CB><BR>';
+//        $content .= '<C>' . 店铺名称 . '<C><BR>';
+        $content .= str_repeat('-', 32) . "<BR>";
+
+        $content .= '<CB>用户申请取消订单并退款,请处理</CB><BR>';
+        //下单时间
+
+        $content .= str_repeat('-', 32) . "<BR>";
+        $content .= '下单时间:'.$order->{'created_at'}. '<BR>';
+        $content .= '订单编号:'.$order->{'order_sn'}. '<BR>';
+        $content .= str_repeat('-', 32) . "<BR>";
+
+        $content .= '<L1>' . $order->{'consignee'} . '<L1><BR>';
+        $content .= '<L1>' . $order->{'phone'} . '<L1><BR>';
+        $content .= '<L1>' . $order->{'school_name'} . $order->{'dorm_name'} . $order->{'address'} . '<L1><BR>';
+        $content .= '<QRCODE>'.$order->{'m_id'} . '_' .$order->{'order_sn'}.'</QRCODE>';
+        $content .= '<BR>';
+        $content .= '<CB>***结束***</CB><BR><BR>';
+
+        return $content;
+    }
+
+    function getSpyunDemoContent()
+    {
+        $orderItem = [
+                [
+                    'goods_name' => '测试商品名称(规格名称)',
+                    'goods_number' => '2',
+                    'goods_price' => '9.9',
+                ],
+                [
+                    'goods_name' => '测试商品名称(规格名称)',
+                    'goods_number' => '3',
+                    'goods_price' => '9.9',
+                ],
+            ];
+
+        $NoteFormatterServer = NoteFormatterServer::creatServer();
+        $content = '<CB>#1 平台名称</CB><BR>';
+        $content .= '<C>店铺名称<C><BR>';
+        $content .= str_repeat('-', 32) . "<BR>";
+
+        $content .= '<CB>期望送达时间:' . date('Y-m-d H:i:s') . '</CB><BR>';
+        //下单时间
+
+        $content .= str_repeat('-', 32) . "<BR>";
+        $content .= '下单时间:'.date('Y-m-d H:i:s'). '<BR>';
+        $content .= '订单编号:123456789<BR>';
+        $content .= str_repeat('-', 32) . "<BR>";
+        //商品信息
+        foreach ($orderItem as $value){
+            $content .=  '<H>'.$NoteFormatterServer::formatPrintOrderItem($value['goods_name'], $value['goods_number'], $value['goods_price']). '</H><BR>';
+        }
+        $content .= '<B>共:5件</B><BR>';
+        $content .= '<L1>备注:无</L1><BR>';
+        $content .= str_repeat('-', 32) . '<BR>';
+        $content .= '打包费:5.00<BR>';
+        $content .= '促销优惠:0.00<BR>';
+        $content .= '<H>合计支付:54.5</H><BR>';
+        $content .= str_repeat('-', 32) . '<BR>';
+
+        $content .= '<L1>测试姓名<L1><BR>';
+        $content .= '<L1>测试电话<L1><BR>';
+        $content .= '<L1>测试地址地址地址地址<L1><BR>';
+        $content .= '<QRCODE>123456789</QRCODE>';
+        $content .= '<BR>';
+        $content .= '<CB>***结束***</CB><BR><BR>';
+
+        return $content;
+    }
+
+    /**
+     * 修改打印机信息
+     * @param $sn
+     * @param string $name
+     * @return array
+     */
+    public function updatePrinter($sn, $name)
+    {
+        return $this->http_request('PATCH','printer/update', $this->makeRequestParams([
+            'sn' => $sn,
+            'name' => $name
+        ]));
+    }
+
+    /**
+     * 修改打印机参数
+     * @param $sn
+     * @param null|int $auto_cut
+     * @param null|string $voice
+     * @return array
+     */
+    public function updatePrinterSetting($sn, $auto_cut = null, $voice = null)
+    {
+        return $this->http_request('PATCH','printer/setting', $this->makeRequestParams([
+            'sn' => $sn,
+            'auto_cut' => $auto_cut,
+            'voice' => $voice
+        ]));
+    }
+
+    /**
+     * 获取打印机信息
+     * @param string $sn
+     * @return array
+     */
+    public function getPrinter($sn)
+    {
+        return $this->http_request('GET','printer/info', $this->makeRequestParams([
+            'sn' =>  $sn
+        ]));
+    }
+
+
+
+    /**
+     * 清空待打印订单
+     * @param int $sn
+     * @return array
+     */
+    public function deletePrints($sn)
+    {
+        return $this->http_request('DELETE',"printer/cleansqs", $this->makeRequestParams([
+            'sn' => $sn
+        ]));
+    }
+
+    /**
+     * 查询打印订单状态
+     * @param string $id
+     * @return array
+     */
+    public function getPrintsStatus($id)
+    {
+        return $this->http_request('GET',"printer/order/status", $this->makeRequestParams([
+            'id' => $id
+        ]));
+    }
+
+    /**
+     * 查询打印机历史打印订单数
+     * @param string $sn
+     * @param string $date
+     * @return array
+     */
+    public function getPrintsOrders($sn, $date)
+    {
+        return $this->http_request('GET',"printer/order/number", $this->makeRequestParams([
+            'sn' => $sn,
+            'date' => $date
+        ]));
+    }
+
+    /**
+     * 创建请求参数
+     * @param array $params
+     * @return array
+     */
+    public function makeRequestParams(array $params = [])
+    {
+        $params['appid'] = $this->appid;
+        $params['timestamp'] = time();
+        $params['sign'] = $this->makeSign($params);
+
+        return $params;
+    }
+
+    /**
+     * 创建签名
+     * @param array $params
+     * @return string
+     */
+    public function makeSign(array $params)
+    {
+        ksort($params);
+        $sign = "";
+        foreach ($params as $k => $v) {
+            if ($k != "sign" && $k != "appsecret" && $v !== "" && !is_array($v) && !is_null($v)) {
+                $sign .= $k . "=" . $v . "&";
+            }
+        }
+        $sign = rtrim($sign, '&');
+        $sign .= "&appsecret=" . $this->appsecret;
+
+        return strtoupper(md5($sign));
+    }
+
+    protected function http_request($method, $uri, array $params = [])
+    {
+        $ch = curl_init();
+        $url = self::BASE_URI . $uri;
+        if ($method == 'GET' || $method == 'DELETE') {
+            $url .= '?' . http_build_query($params);
+        } else {
+            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
+        }
+        curl_setopt($ch, CURLOPT_URL, $url);
+        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, self::CONNECTTIMEOUT);
+        curl_setopt($ch, CURLOPT_TIMEOUT, self::TIMEOUT);
+        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
+        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
+        $response = curl_exec($ch);
+        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+        $http_error = curl_error($ch);
+        $http_errno = curl_errno($ch);
+        curl_close($ch);
+
+        $response = json_decode($response, 1);
+        if ($http_code != 200) {
+            $this->errorMsg = $http_error;
+        }
+
+        return $response;
+    }
+
+    /**
+     * 获取错误信息
+     * @return string
+     */
+    function getErrorMsg()
+    {
+        return $this->errorMsg;
+    }
+}

+ 23 - 0
config/weixin.php

@@ -0,0 +1,23 @@
+<?php
+
+return [
+    //微信支付号
+    'mch_id' => env('WX_MCH_ID',''),
+    //微信支付密钥
+    'private_key' => env('WX_PRIVATE_KEY',''),
+    //微信支付证书地址
+    'cert_file' => env('WX_CERT_FILE',''),
+    //微信支付私钥证书地址
+    'key_file'=>env('WX_KEY_FILE',''),
+    //微信公众号appid
+    'app_id'=>env('WX_APPID',''),
+    //微信公众号密钥
+    'app_secret'=>env('WX_APPSECRET',''),
+    //微信小程序id
+    'applet_id'=>env('APPLET_ID',''),
+    //微信小程序密钥
+    'applet_key'=>env('APPLET_KEY',''),
+    //是否是测试
+    'test_serve'=>env('TEST_SERVE',''),
+
+];